From 998c7f3ef50c94d8362e4d0354872d690dbb5f9d Mon Sep 17 00:00:00 2001 From: ihor-chaban Date: Sun, 1 Dec 2024 21:51:26 -0500 Subject: [PATCH 01/11] Update auth and order API versions --- tgtg_scanner/tgtg/tgtg_client.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tgtg_scanner/tgtg/tgtg_client.py b/tgtg_scanner/tgtg/tgtg_client.py index 4bd1f09..7d46309 100644 --- a/tgtg_scanner/tgtg/tgtg_client.py +++ b/tgtg_scanner/tgtg/tgtg_client.py @@ -25,15 +25,15 @@ BASE_URL = "https://apptoogoodtogo.com/api/" API_ITEM_ENDPOINT = "item/v8/" FAVORITE_ITEM_ENDPOINT = "user/favorite/v1/{}/update" -AUTH_BY_EMAIL_ENDPOINT = "auth/v4/authByEmail" -AUTH_POLLING_ENDPOINT = "auth/v4/authByRequestPollingId" -SIGNUP_BY_EMAIL_ENDPOINT = "auth/v4/signUpByEmail" -REFRESH_ENDPOINT = "auth/v4/token/refresh" -ACTIVE_ORDER_ENDPOINT = "order/v7/active" -INACTIVE_ORDER_ENDPOINT = "order/v7/inactive" -CREATE_ORDER_ENDPOINT = "order/v7/create/" -ABORT_ORDER_ENDPOINT = "order/v7/{}/abort" -ORDER_STATUS_ENDPOINT = "order/v7/{}/status" +AUTH_BY_EMAIL_ENDPOINT = "auth/v5/authByEmail" +AUTH_POLLING_ENDPOINT = "auth/v5/authByRequestPollingId" +SIGNUP_BY_EMAIL_ENDPOINT = "auth/v5/signUpByEmail" +REFRESH_ENDPOINT = "auth/v5/token/refresh" +ACTIVE_ORDER_ENDPOINT = "order/v8/active" +INACTIVE_ORDER_ENDPOINT = "order/v8/inactive" +CREATE_ORDER_ENDPOINT = "order/v8/create/" +ABORT_ORDER_ENDPOINT = "order/v8/{}/abort" +ORDER_STATUS_ENDPOINT = "order/v8/{}/status" MANUFACTURERITEM_ENDPOINT = "manufactureritem/v2/" USER_AGENTS = [ "TGTG/{} Dalvik/2.1.0 (Linux; U; Android 9; Nexus 5 Build/M4B30Z)", From bf501731ceed38e205c8832a8f8c993160ca32b5 Mon Sep 17 00:00:00 2001 From: ihor-chaban Date: Mon, 2 Dec 2024 12:00:14 -0500 Subject: [PATCH 02/11] Add possibility to reserve multiple bags at once --- tgtg_scanner/models/reservations.py | 17 ++++++++++++++--- tgtg_scanner/notifiers/telegram.py | 7 ++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tgtg_scanner/models/reservations.py b/tgtg_scanner/models/reservations.py index f94b489..0f49d62 100644 --- a/tgtg_scanner/models/reservations.py +++ b/tgtg_scanner/models/reservations.py @@ -30,14 +30,19 @@ def __init__(self, client: TgtgClient) -> None: self.active_orders: Dict[str, Order] = {} def reserve(self, item_id: str, display_name: str, amount: int = 1) -> None: - """Create a new reservation + """Create a new reservation or increase the amount in the existing reservation Args: item_id (str): Item ID display_name (str): Item display name amount (int, optional): Amount. Defaults to 1. """ - self.reservation_query.append(Reservation(item_id, amount, display_name)) + for reservation in self.reservation_query: + if reservation.item_id == item_id: + reservation.amount += amount + break + else: + self.reservation_query.append(Reservation(item_id, amount, display_name)) def make_orders(self, state: Dict[str, Item], callback: Callable[[Reservation], None]) -> None: """Create orders for reservations @@ -50,8 +55,14 @@ def make_orders(self, state: Dict[str, Item], callback: Callable[[Reservation], item = state.get(reservation.item_id) if item and item.items_available > 0: try: + remaining_amount = reservation.amount + reservation.amount = min(reservation.amount, item.items_available) + remaining_amount -= reservation.amount self._create_order(reservation) - self.reservation_query.remove(reservation) + if remaining_amount > 0: + reservation.amount = remaining_amount + else: + self.reservation_query.remove(reservation) callback(reservation) except Exception as exc: log.warning("Order failed: %s", exc) diff --git a/tgtg_scanner/notifiers/telegram.py b/tgtg_scanner/notifiers/telegram.py index 1f1e14e..c4e0c87 100644 --- a/tgtg_scanner/notifiers/telegram.py +++ b/tgtg_scanner/notifiers/telegram.py @@ -222,7 +222,7 @@ async def _send(self, item: Union[Item, Reservation]) -> None: # type: ignore[o if self.image: image = self._unmask_image(self.image, item) elif isinstance(item, Reservation): - message = escape_markdown(f"{item.display_name} is reserved for 5 minutes", version=2) + message = escape_markdown(f"{item.display_name} is reserved for 5 minutes" if item.amount == 1 else f"{item.display_name} ({item.amount} bags) are reserved for 5 minutes", version=2) else: return await self._send_message(message, image) @@ -292,7 +292,7 @@ async def _reserve_item_menu(self, update: Update, _) -> None: @_private async def _cancel_reservations_menu(self, update: Update, _) -> None: buttons = [ - [InlineKeyboardButton(reservation.display_name, callback_data=reservation)] + [InlineKeyboardButton(f"{reservation.display_name} ({reservation.amount} bags)" if reservation.amount > 1 else reservation.display_name, callback_data=reservation)] for reservation in self.reservations.reservation_query ] if len(buttons) == 0: @@ -305,7 +305,8 @@ async def _cancel_reservations_menu(self, update: Update, _) -> None: async def _cancel_orders_menu(self, update: Update, _) -> None: self.reservations.update_active_orders() buttons = [ - [InlineKeyboardButton(order.display_name, callback_data=order)] for order in self.reservations.active_orders.values() + [InlineKeyboardButton(f"{order.display_name} ({order.amount} bags)" if order.amount > 1 else order.display_name, callback_data=order)] + for order in self.reservations.active_orders.values() ] if len(buttons) == 0: await update.message.reply_text("No active Orders") From dac4e2ced45486f826858554cb8f10a78881563e Mon Sep 17 00:00:00 2001 From: ihor-chaban Date: Mon, 2 Dec 2024 12:00:38 -0500 Subject: [PATCH 03/11] Fix typo --- tgtg_scanner/notifiers/telegram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgtg_scanner/notifiers/telegram.py b/tgtg_scanner/notifiers/telegram.py index c4e0c87..daee7ba 100644 --- a/tgtg_scanner/notifiers/telegram.py +++ b/tgtg_scanner/notifiers/telegram.py @@ -440,7 +440,7 @@ async def _callback_query_handler(self, update: Update, _) -> None: log.debug('Added "%s" to reservation queue', data.display_name) if isinstance(data, Reservation): self.reservations.reservation_query.remove(data) - await update.callback_query.answer(f"Removed {data.display_name} form reservation queue") + await update.callback_query.answer(f"Removed {data.display_name} from reservation queue") log.debug('Removed "%s" from reservation queue', data.display_name) if isinstance(data, Order): self.reservations.cancel_order(data.id) From a589c92b94a8df61bfc51d5491bf2ac96329a7bc Mon Sep 17 00:00:00 2001 From: Ihor Chaban Date: Fri, 6 Dec 2024 11:55:09 -0500 Subject: [PATCH 04/11] Update conditional statement for consistency --- tgtg_scanner/notifiers/telegram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgtg_scanner/notifiers/telegram.py b/tgtg_scanner/notifiers/telegram.py index daee7ba..172b8fd 100644 --- a/tgtg_scanner/notifiers/telegram.py +++ b/tgtg_scanner/notifiers/telegram.py @@ -222,7 +222,7 @@ async def _send(self, item: Union[Item, Reservation]) -> None: # type: ignore[o if self.image: image = self._unmask_image(self.image, item) elif isinstance(item, Reservation): - message = escape_markdown(f"{item.display_name} is reserved for 5 minutes" if item.amount == 1 else f"{item.display_name} ({item.amount} bags) are reserved for 5 minutes", version=2) + message = escape_markdown(f"{item.display_name} ({item.amount} bags) are reserved for 5 minutes" if item.amount > 1 else f"{item.display_name} is reserved for 5 minutes", version=2) else: return await self._send_message(message, image) From f1c3f075b99e7d1fb954a4349bb42346f4b278b4 Mon Sep 17 00:00:00 2001 From: Ihor Chaban Date: Sat, 7 Dec 2024 17:16:40 -0500 Subject: [PATCH 05/11] Keep reservation amount if order failed --- tgtg_scanner/models/reservations.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tgtg_scanner/models/reservations.py b/tgtg_scanner/models/reservations.py index 0f49d62..1ed3f76 100644 --- a/tgtg_scanner/models/reservations.py +++ b/tgtg_scanner/models/reservations.py @@ -65,6 +65,7 @@ def make_orders(self, state: Dict[str, Item], callback: Callable[[Reservation], self.reservation_query.remove(reservation) callback(reservation) except Exception as exc: + reservation.amount += remaining_amount log.warning("Order failed: %s", exc) def update_active_orders(self) -> None: From 1289f8e800b6cc8ff7692ebff873a1e805cd6881 Mon Sep 17 00:00:00 2001 From: ihor-chaban Date: Wed, 11 Dec 2024 20:26:53 -0500 Subject: [PATCH 06/11] Shorten long text on buttons --- tgtg_scanner/notifiers/telegram.py | 41 +++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/tgtg_scanner/notifiers/telegram.py b/tgtg_scanner/notifiers/telegram.py index 172b8fd..9e09eaa 100644 --- a/tgtg_scanner/notifiers/telegram.py +++ b/tgtg_scanner/notifiers/telegram.py @@ -58,6 +58,7 @@ class Telegram(Notifier): """Notifier for Telegram""" MAX_RETRIES = 10 + MAX_BUTTON_TEXT_LENGTH = 50 def __init__(self, config: Config, reservations: Reservations, favorites: Favorites): super().__init__(config, reservations, favorites) @@ -222,7 +223,14 @@ async def _send(self, item: Union[Item, Reservation]) -> None: # type: ignore[o if self.image: image = self._unmask_image(self.image, item) elif isinstance(item, Reservation): - message = escape_markdown(f"{item.display_name} ({item.amount} bags) are reserved for 5 minutes" if item.amount > 1 else f"{item.display_name} is reserved for 5 minutes", version=2) + message = escape_markdown( + ( + f"{item.display_name} ({item.amount} bags) are reserved for 5 minutes" + if item.amount > 1 + else f"{item.display_name} is reserved for 5 minutes" + ), + version=2, + ) else: return await self._send_message(message, image) @@ -284,7 +292,12 @@ async def _unmute(self, update: Update, _) -> None: async def _reserve_item_menu(self, update: Update, _) -> None: favorites = self.favorites.get_favorites() buttons = [ - [InlineKeyboardButton(f"{item.display_name}: {item.items_available}", callback_data=item)] for item in favorites + [ + InlineKeyboardButton( + Telegram._shorten_with_ellipsis(f"{item.display_name}: {item.items_available}"), callback_data=item + ) + ] + for item in favorites ] reply_markup = InlineKeyboardMarkup(buttons) await update.message.reply_text("Select a Bag to reserve", reply_markup=reply_markup) @@ -292,7 +305,16 @@ async def _reserve_item_menu(self, update: Update, _) -> None: @_private async def _cancel_reservations_menu(self, update: Update, _) -> None: buttons = [ - [InlineKeyboardButton(f"{reservation.display_name} ({reservation.amount} bags)" if reservation.amount > 1 else reservation.display_name, callback_data=reservation)] + [ + InlineKeyboardButton( + Telegram._shorten_with_ellipsis( + f"{reservation.display_name} ({reservation.amount} bags)" + if reservation.amount > 1 + else reservation.display_name + ), + callback_data=reservation, + ) + ] for reservation in self.reservations.reservation_query ] if len(buttons) == 0: @@ -305,7 +327,14 @@ async def _cancel_reservations_menu(self, update: Update, _) -> None: async def _cancel_orders_menu(self, update: Update, _) -> None: self.reservations.update_active_orders() buttons = [ - [InlineKeyboardButton(f"{order.display_name} ({order.amount} bags)" if order.amount > 1 else order.display_name, callback_data=order)] + [ + InlineKeyboardButton( + Telegram._shorten_with_ellipsis( + f"{order.display_name} ({order.amount} bags)" if order.amount > 1 else order.display_name + ), + callback_data=order, + ) + ] for order in self.reservations.active_orders.values() ] if len(buttons) == 0: @@ -501,3 +530,7 @@ async def _get_chat_id(self) -> None: def __repr__(self) -> str: return f"Telegram: {self.chat_ids}" + + @staticmethod + def _shorten_with_ellipsis(text: str, length: int = MAX_BUTTON_TEXT_LENGTH) -> str: + return text if len(text) <= length else text[: (length - 3) // 2] + "..." + text[-(length - 3) // 2 :] From 4d99103c226aee76815f03b930a9669c6d9dd035 Mon Sep 17 00:00:00 2001 From: ihor-chaban Date: Fri, 13 Dec 2024 15:25:02 +0100 Subject: [PATCH 07/11] Add docstring for _shorten_with_ellipsis method --- tgtg_scanner/notifiers/telegram.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tgtg_scanner/notifiers/telegram.py b/tgtg_scanner/notifiers/telegram.py index 9e09eaa..8f8806b 100644 --- a/tgtg_scanner/notifiers/telegram.py +++ b/tgtg_scanner/notifiers/telegram.py @@ -533,4 +533,5 @@ def __repr__(self) -> str: @staticmethod def _shorten_with_ellipsis(text: str, length: int = MAX_BUTTON_TEXT_LENGTH) -> str: + """Shorten text to length and add ellipsis in the middle""" return text if len(text) <= length else text[: (length - 3) // 2] + "..." + text[-(length - 3) // 2 :] From 3046c78df107f900335922f8a680675b78354d7b Mon Sep 17 00:00:00 2001 From: ihor-chaban Date: Fri, 13 Dec 2024 15:25:34 +0100 Subject: [PATCH 08/11] flake8 ignore E203 --- .flake8 | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..7f34500 --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +ignore = E203 From f87352403a2953ddfa16cee0b0ab97f06e10eb81 Mon Sep 17 00:00:00 2001 From: ihor-chaban Date: Fri, 13 Dec 2024 11:22:24 -0500 Subject: [PATCH 09/11] Change ignore to extend-ignore --- .flake8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index 7f34500..a40a644 100644 --- a/.flake8 +++ b/.flake8 @@ -1,2 +1,2 @@ [flake8] -ignore = E203 +extend-ignore = E203 From 6e1800a3b76743485a6bc1aa203b6f8ffa15a2b4 Mon Sep 17 00:00:00 2001 From: ihor-chaban Date: Thu, 19 Dec 2024 23:55:38 -0500 Subject: [PATCH 10/11] Replace .flake8 file with noqa comment --- .flake8 | 2 -- tgtg_scanner/notifiers/telegram.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index a40a644..0000000 --- a/.flake8 +++ /dev/null @@ -1,2 +0,0 @@ -[flake8] -extend-ignore = E203 diff --git a/tgtg_scanner/notifiers/telegram.py b/tgtg_scanner/notifiers/telegram.py index 8f8806b..2e8ddac 100644 --- a/tgtg_scanner/notifiers/telegram.py +++ b/tgtg_scanner/notifiers/telegram.py @@ -534,4 +534,4 @@ def __repr__(self) -> str: @staticmethod def _shorten_with_ellipsis(text: str, length: int = MAX_BUTTON_TEXT_LENGTH) -> str: """Shorten text to length and add ellipsis in the middle""" - return text if len(text) <= length else text[: (length - 3) // 2] + "..." + text[-(length - 3) // 2 :] + return text if len(text) <= length else text[: (length - 3) // 2] + "..." + text[-(length - 3) // 2 :] # noqa: E203 From 8c89eccdff5ac2ba0584146266cefcc4c79db625 Mon Sep 17 00:00:00 2001 From: ihor-chaban Date: Sun, 22 Dec 2024 00:14:18 -0500 Subject: [PATCH 11/11] Refactor _shorten_with_ellipsis for readability --- tgtg_scanner/notifiers/telegram.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tgtg_scanner/notifiers/telegram.py b/tgtg_scanner/notifiers/telegram.py index 2e8ddac..cfa0a6f 100644 --- a/tgtg_scanner/notifiers/telegram.py +++ b/tgtg_scanner/notifiers/telegram.py @@ -534,4 +534,8 @@ def __repr__(self) -> str: @staticmethod def _shorten_with_ellipsis(text: str, length: int = MAX_BUTTON_TEXT_LENGTH) -> str: """Shorten text to length and add ellipsis in the middle""" - return text if len(text) <= length else text[: (length - 3) // 2] + "..." + text[-(length - 3) // 2 :] # noqa: E203 + if len(text) <= length: + return text + else: + slice_size = (length - 3) // 2 + return text[:slice_size] + "..." + text[-slice_size:]