From 26da97187c1ffe2c5d1f88249584fe550bc26eb0 Mon Sep 17 00:00:00 2001 From: Capybara-z Date: Wed, 3 Dec 2025 02:26:17 +0300 Subject: [PATCH 1/2] Refactor sender button parsing / Add tariff hooks --- handlers/admin/sender/sender_utils.py | 15 ++++++-------- handlers/tariffs/addons/key_addons_main.py | 5 +++++ handlers/tariffs/addons/key_addons_pack.py | 5 +++++ hooks/processors.py | 23 ++++++++++++++++++++++ 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/handlers/admin/sender/sender_utils.py b/handlers/admin/sender/sender_utils.py index 287e3a16..6c108771 100644 --- a/handlers/admin/sender/sender_utils.py +++ b/handlers/admin/sender/sender_utils.py @@ -93,16 +93,12 @@ def strip_html_tags(text: str) -> str: def parse_message_buttons(text: str) -> tuple[str, InlineKeyboardMarkup | None]: - buttons_match = re.search(r"(<[^>]+>)?\s*BUTTONS\s*:\s*(]+>)?", text, re.IGNORECASE) - if not buttons_match: + if "BUTTONS:" not in text: return text, None - clean_text = text[: buttons_match.start()].strip() - - buttons_section = text[buttons_match.start() :].strip() - buttons_text = strip_html_tags(buttons_section) - - buttons_text = re.sub(r"^.*?BUTTONS\s*:\s*", "", buttons_text, flags=re.IGNORECASE).strip() + parts = text.split("BUTTONS:", 1) + clean_text = parts[0].strip() + buttons_text = parts[1].strip() if not buttons_text: return clean_text, None @@ -112,7 +108,8 @@ def parse_message_buttons(text: str) -> tuple[str, InlineKeyboardMarkup | None]: for line in button_lines: try: - button_data = json.loads(line) + cleaned_line = re.sub(r'([^<]*)', r"\1", line) + button_data = json.loads(cleaned_line) if not isinstance(button_data, dict) or "text" not in button_data: logger.warning(f"[Sender] Неверный формат кнопки: {line}") diff --git a/handlers/tariffs/addons/key_addons_main.py b/handlers/tariffs/addons/key_addons_main.py index e29de73a..aa8e4076 100644 --- a/handlers/tariffs/addons/key_addons_main.py +++ b/handlers/tariffs/addons/key_addons_main.py @@ -31,6 +31,8 @@ from handlers.texts import ( UNLIMITED_TRAFFIC_LABEL, ) from handlers.utils import edit_or_send_message +from hooks.hook_buttons import insert_hook_buttons +from hooks.processors import process_addons_menu from logger import logger from ..buy.key_tariffs import calculate_config_price @@ -294,6 +296,9 @@ async def render_addons_screen(callback: CallbackQuery, state: FSMContext, sessi builder.row(InlineKeyboardButton(text=BACK, callback_data=f"view_key|{email}")) + module_buttons = await process_addons_menu(email=email, session=session) + builder = insert_hook_buttons(builder, module_buttons) + await edit_or_send_message( target_message=callback.message, text=text, diff --git a/handlers/tariffs/addons/key_addons_pack.py b/handlers/tariffs/addons/key_addons_pack.py index 8db38cef..ebd0ae3c 100644 --- a/handlers/tariffs/addons/key_addons_pack.py +++ b/handlers/tariffs/addons/key_addons_pack.py @@ -28,6 +28,8 @@ from handlers.texts import ( UNLIMITED_TRAFFIC_LABEL, ) from handlers.utils import edit_or_send_message +from hooks.hook_buttons import insert_hook_buttons +from hooks.processors import process_addons_menu from logger import logger from ..buy.key_tariffs import calculate_config_price @@ -302,6 +304,9 @@ async def render_addons_screen(callback: CallbackQuery, state: FSMContext, sessi ) builder.row(InlineKeyboardButton(text=BACK, callback_data=f"view_key|{email}")) + module_buttons = await process_addons_menu(email=email, session=session) + builder = insert_hook_buttons(builder, module_buttons) + await edit_or_send_message( target_message=callback.message, text=text, diff --git a/hooks/processors.py b/hooks/processors.py index 4ccd4dfd..69cf1fa4 100644 --- a/hooks/processors.py +++ b/hooks/processors.py @@ -570,6 +570,29 @@ async def process_check_discount_validity( return None +async def process_addons_menu( + email: str, + session: Any, + **kwargs, +) -> list: + """ + Обрабатывает хук addons_menu. + + Возвращает список операций для модификации кнопок в меню конфигуратора тарифов. + """ + try: + results = await run_hooks( + "addons_menu", + email=email, + session=session, + **kwargs, + ) + return results if results else [] + except Exception as e: + logger.warning(f"[ADDONS_MENU] Ошибка при обработке хука: {e}") + return [] + + async def process_connect_device_menu( chat_id: int, session: Any, From ef59eeac4c509f7f889296c51a37ef58fe048e70 Mon Sep 17 00:00:00 2001 From: Capybara-z Date: Thu, 4 Dec 2025 00:49:01 +0300 Subject: [PATCH 2/2] Refactor admin key display logic --- handlers/admin/users/users_keys.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/handlers/admin/users/users_keys.py b/handlers/admin/users/users_keys.py index da28223a..040f59a2 100644 --- a/handlers/admin/users/users_keys.py +++ b/handlers/admin/users/users_keys.py @@ -100,12 +100,36 @@ async def handle_key_edit( tariff_name = "—" subgroup_title = "—" + base_devices = None + base_traffic = None + is_configurable = False if key_obj.tariff_id: - result = await session.execute(select(Tariff.name, Tariff.subgroup_title).where(Tariff.id == key_obj.tariff_id)) + result = await session.execute( + select(Tariff.name, Tariff.subgroup_title, Tariff.device_limit, Tariff.traffic_limit, Tariff.configurable) + .where(Tariff.id == key_obj.tariff_id) + ) row = result.first() if row: tariff_name = row[0] subgroup_title = row[1] or "—" + base_devices = row[2] + base_traffic = row[3] + is_configurable = bool(row[4]) + + devices_line = "" + traffic_line = "" + if is_configurable: + sel_dev, cur_dev = key_obj.selected_device_limit, key_obj.current_device_limit + if sel_dev is not None or cur_dev is not None: + base_dev = sel_dev if sel_dev is not None else (base_devices if base_devices is not None else cur_dev) + extra = f" + {cur_dev - base_dev} (докуплено)" if (base_dev is not None and cur_dev is not None and cur_dev > base_dev) else "" + devices_line = f"📱 Устройства: {base_dev}{extra}\n" + + sel_traf, cur_traf = key_obj.selected_traffic_limit, key_obj.current_traffic_limit + if sel_traf is not None or cur_traf is not None: + base_traf = sel_traf if sel_traf is not None else (base_traffic if base_traffic is not None else cur_traf) + extra = f" + {cur_traf - base_traf} ГБ (докуплено)" if (base_traf is not None and cur_traf is not None and cur_traf > base_traf) else "" + traffic_line = f"📊 Трафик: {base_traf} ГБ{extra}\n" text = ( "🔑 Информация о подписке\n\n" @@ -117,6 +141,8 @@ async def handle_key_edit( f"🆔 ID клиента: {key_obj.tg_id or '—'}\n" f"📁 Группа: {subgroup_title}\n" f"📦 Тариф: {tariff_name}\n" + f"{devices_line}" + f"{traffic_line}" "" )