Exemplo n.º 1
0
def test_get_item_fail(login_response):
    responses.add(responses.POST,
                  urljoin(BASE_URL, API_ITEM_ENDPOINT) + "1",
                  json={},
                  status=400)
    client = TgtgClient(email="*****@*****.**", password="******")
    with pytest.raises(TgtgAPIError):
        client.get_item(1)
Exemplo n.º 2
0
def test_get_item_fail(refresh_tokens_response):
    responses.add(responses.POST,
                  urljoin(BASE_URL, API_ITEM_ENDPOINT) + "1",
                  json={},
                  status=400)
    client = TgtgClient(**tgtg_client_fake_tokens)
    with pytest.raises(TgtgAPIError):
        client.get_item(1)
Exemplo n.º 3
0
    def test_get_items(self):
        username = environ.get("TGTG_USERNAME", None)
        timeout = environ.get("TGTG_TIMEOUT", 60)
        access_token = environ.get("TGTG_ACCESS_TOKEN", None)
        refresh_token = environ.get("TGTG_REFRESH_TOKEN", None)
        user_id = environ.get("TGTG_USER_ID", None)

        client = TgtgClient(
            email=username,
            timeout=timeout,
            access_token=access_token,
            refresh_token=refresh_token,
            user_id=user_id,
        )

        # Tests
        items = client.get_items(favorites_only=True)
        assert len(items) > 0
        item = items[0]
        item_id = item["item"]["item_id"]
        for prop in GLOBAL_PROPERTIES:
            assert prop in item
        for prop in ITEM_PROPERTIES:
            assert prop in item["item"]
        for prop in PRICE_PROPERTIES:
            assert prop in item["item"]["price_including_taxes"]

        client.set_favorite(item_id, False)
        client.set_favorite(item_id, True)

        item = client.get_item(item_id)

        assert item["item"]["item_id"] == item_id
Exemplo n.º 4
0
def test_get_item_success():
    responses.add(responses.POST,
                  urljoin(BASE_URL, API_ITEM_ENDPOINT) + "1",
                  json={},
                  status=200)
    client = TgtgClient(access_token="an_access_token", user_id=1234)
    assert client.get_item(1) == {}
    assert len(responses.calls) == 1
Exemplo n.º 5
0
    def test_get_one_item(self):
        client = TgtgClient(email=os.environ["TGTG_EMAIL"],
                            password=os.environ["TGTG_PASSWORD"])
        item_id = "36684"
        data = client.get_item(item_id)

        assert all(prop in data for prop in GLOBAL_PROPERTIES)
        assert all(prop in data["item"] for prop in ITEM_PROPERTIES)
        assert all(prop in data["store"] for prop in STORE_PROPERTIES)
        assert data["item"]["item_id"] == item_id
Exemplo n.º 6
0
def test_get_item_success(login_response):
    responses.add(responses.POST,
                  urljoin(BASE_URL, API_ITEM_ENDPOINT) + "1",
                  json={},
                  status=200)
    client = TgtgClient(email="*****@*****.**", password="******")
    assert client.get_item(1) == {}
    assert (len([
        call for call in responses.calls
        if API_ITEM_ENDPOINT in call.request.url
    ]) == 1)
Exemplo n.º 7
0
def test_get_item_success(refresh_tokens_response):
    responses.add(responses.POST,
                  urljoin(BASE_URL, API_ITEM_ENDPOINT) + "1",
                  json={},
                  status=200)
    client = TgtgClient(**tgtg_client_fake_tokens)
    assert client.get_item(1) == {}
    assert (len([
        call for call in responses.calls
        if API_ITEM_ENDPOINT in call.request.url
    ]) == 1)
Exemplo n.º 8
0
class Scanner():
    def __init__(self, notifiers: bool = True):
        self.config = Config(config_file) if path.isfile(
            config_file) else Config()
        if self.config.debug:
            # pylint: disable=E1103
            loggers = [
                logging.getLogger(name)
                for name in logging.root.manager.loggerDict
            ]
            # pylint: enable=E1103
            for logger in loggers:
                logger.setLevel(logging.DEBUG)
            log.info("Debugging mode enabled")
        self.metrics = Metrics()
        self.item_ids = self.config.item_ids
        self.amounts = {}
        try:
            self.tgtg_client = TgtgClient(
                email=self.config.tgtg["username"],
                timeout=self.config.tgtg["timeout"],
                access_token_lifetime=self.config.
                tgtg["access_token_lifetime"],
                max_polling_tries=self.config.tgtg["max_polling_tries"],
                polling_wait_time=self.config.tgtg["polling_wait_time"],
                access_token=self.config.tgtg["access_token"],
                refresh_token=self.config.tgtg["refresh_token"],
                user_id=self.config.tgtg["user_id"])
            self.tgtg_client.login()
            self.config.save_tokens(self.tgtg_client.access_token,
                                    self.tgtg_client.refresh_token,
                                    self.tgtg_client.user_id)
        except TgtgAPIError as err:
            raise err
        except Error as err:
            log.error(err)
            raise TGTGConfigurationError() from err
        if notifiers:
            if self.config.metrics:
                self.metrics.enable_metrics()
            self.notifiers = Notifiers(self.config)
            if not self.config.disable_tests:
                log.info("Sending test Notifications ...")
                self.notifiers.send(self._test_item)

    @property
    def _test_item(self) -> Item:
        """
        Returns an item for test notifications
        """
        items = sorted(self._get_favorites(),
                       key=lambda x: x.items_available,
                       reverse=True)
        if items:
            return items[0]
        items = sorted([
            Item(item)
            for item in self.tgtg_client.get_items(favorites_only=False,
                                                   latitude=53.5511,
                                                   longitude=9.9937,
                                                   radius=50)
        ],
                       key=lambda x: x.items_available,
                       reverse=True)
        return items[0]

    def _job(self) -> None:
        """
        Job iterates over all monitored items
        """
        for item_id in self.item_ids:
            try:
                if item_id != "":
                    item = Item(self.tgtg_client.get_item(item_id))
                    self._check_item(item)
            except Exception:
                log.error("itemID %s Error! - %s", item_id, sys.exc_info())
        for item in self._get_favorites():
            try:
                self._check_item(item)
            except Exception:
                log.error("check item error! - %s", sys.exc_info())
        log.debug("new State: %s", self.amounts)
        if len(self.amounts) == 0:
            log.warning("No items in observation! Did you add any favorites?")
        self.config.save_tokens(self.tgtg_client.access_token,
                                self.tgtg_client.refresh_token,
                                self.tgtg_client.user_id)

    def _get_favorites(self) -> list[Item]:
        """
        Get favorites as list of Items
        """
        items = []
        page = 1
        page_size = 100
        error_count = 0
        while error_count < 5:
            try:
                new_items = self.tgtg_client.get_items(favorites_only=True,
                                                       page_size=page_size,
                                                       page=page)
                items += new_items
                if len(new_items) < page_size:
                    break
                page += 1
            except Exception:
                log.error("get item error! - %s", sys.exc_info())
                error_count += 1
                self.metrics.get_favorites_errors.inc()
        return [Item(item) for item in items]

    def _check_item(self, item: Item) -> None:
        """
        Checks if the available item amount raised from zero to something and triggers notifications.
        """
        try:
            if self.amounts[
                    item.item_id] == 0 and item.items_available > self.amounts[
                        item.item_id]:
                self._send_messages(item)
                self.metrics.send_notifications.labels(
                    item.item_id, item.display_name).inc()
            self.metrics.item_count.labels(
                item.item_id, item.display_name).set(item.items_available)
        except Exception:
            self.amounts[item.item_id] = item.items_available
        finally:
            if self.amounts[item.item_id] != item.items_available:
                log.info("%s - new amount: %s", item.display_name,
                         item.items_available)
                self.amounts[item.item_id] = item.items_available

    def _send_messages(self, item: Item) -> None:
        """
        Send notifications for Item
        """
        log.info("Sending notifications for %s - %s bags available",
                 item.display_name, item.items_available)
        self.notifiers.send(item)

    def run(self) -> NoReturn:
        """
        Main Loop of the Scanner
        """
        log.info("Scanner started ...")
        while True:
            try:
                self._job()
                if self.tgtg_client.captcha_error_count > 10:
                    log.warning("Too many 403 Errors. Sleeping for 1 hour.")
                    sleep(60 * 60)
                    log.info("Continuing scanning.")
                    self.tgtg_client.captcha_error_count = 0
            except Exception:
                log.error("Job Error! - %s", sys.exc_info())
            finally:
                sleep(self.config.sleep_time * (0.9 + 0.2 * random()))

    def __del__(self) -> None:
        """
        Cleanup on shutdown
        """
        try:
            if hasattr(self, 'notifiers') and self.notifiers.telegram.updater:
                self.notifiers.telegram.updater.stop()
        except Exception as exc:
            log.warning(exc)
Exemplo n.º 9
0
class Scanner():
    def __init__(self, notifiers=True):
        self.config = Config(config_file) if path.isfile(
            config_file) else Config()
        if self.config.debug:
            # pylint: disable=E1103
            loggers = [
                logging.getLogger(name)
                for name in logging.root.manager.loggerDict
            ]
            # pylint: enable=E1103
            for logger in loggers:
                logger.setLevel(logging.DEBUG)
            log.info("Debugging mode enabled")
        self.metrics = Metrics()
        if self.config.metrics:
            self.metrics.enable_metrics()
        self.item_ids = self.config.item_ids
        self.amounts = {}
        try:
            self.tgtg_client = TgtgClient(
                email=self.config.tgtg["username"],
                timeout=self.config.tgtg["timeout"],
                access_token_lifetime=self.config.
                tgtg["access_token_lifetime"],
                max_polling_tries=self.config.tgtg["max_polling_tries"],
                polling_wait_time=self.config.tgtg["polling_wait_time"],
                access_token=self.config.tgtg["access_token"],
                refresh_token=self.config.tgtg["refresh_token"],
                user_id=self.config.tgtg["user_id"])
            self.tgtg_client.login()
        except TgtgAPIError as err:
            raise
        except Error as err:
            log.error(err)
            raise TGTGConfigurationError() from err
        if notifiers:
            self.notifiers = Notifiers(self.config)

    def _job(self):
        for item_id in self.item_ids:
            try:
                if item_id != "":
                    data = self.tgtg_client.get_item(item_id)
                    self._check_item(Item(data))
            except Exception:
                log.error("itemID %s Error! - %s", item_id, sys.exc_info())
        for data in self._get_favorites():
            try:
                self._check_item(Item(data))
            except Exception:
                log.error("check item error! - %s", sys.exc_info())
        log.debug("new State: %s", self.amounts)
        self.config.save_tokens(self.tgtg_client.access_token,
                                self.tgtg_client.refresh_token,
                                self.tgtg_client.user_id)

    def _get_favorites(self):
        items = []
        page = 1
        page_size = 100
        error_count = 0
        while True and error_count < 5:
            try:
                new_items = self.tgtg_client.get_items(favorites_only=True,
                                                       page_size=page_size,
                                                       page=page)
                items += new_items
                if len(new_items) < page_size:
                    break
                page += 1
            except Exception:
                log.error("get item error! - %s", sys.exc_info())
                error_count += 1
                self.metrics.get_favorites_errors.inc()
        return items

    def _check_item(self, item: Item):
        try:
            if self.amounts[
                    item.item_id] == 0 and item.items_available > self.amounts[
                        item.item_id]:
                self._send_messages(item)
                self.metrics.send_notifications.labels(
                    item.item_id, item.display_name).inc()
            self.metrics.item_count.labels(
                item.item_id, item.display_name).set(item.items_available)
        except Exception:
            self.amounts[item.item_id] = item.items_available
        finally:
            if self.amounts[item.item_id] != item.items_available:
                log.info("%s - new amount: %s", item.display_name,
                         item.items_available)
                self.amounts[item.item_id] = item.items_available

    def _send_messages(self, item: Item):
        log.info("Sending notifications for %s - %s bags available",
                 item.display_name, item.items_available)
        self.notifiers.send(item)

    def run(self):
        log.info("Scanner started ...")
        while True:
            try:
                self._job()
            except Exception:
                log.error("Job Error! - %s", sys.exc_info())
            finally:
                sleep(self.config.sleep_time * (0.9 + 0.2 * random()))

    def __del__(self):
        try:
            if self.notifiers.telegram.updater:
                self.notifiers.telegram.updater.stop()
        except:
            pass