diff --git a/app/handlers/admin/messages.py b/app/handlers/admin/messages.py index 5ddb2455..ce74b801 100644 --- a/app/handlers/admin/messages.py +++ b/app/handlers/admin/messages.py @@ -14,7 +14,9 @@ from app.keyboards.admin import ( get_admin_messages_keyboard, get_broadcast_target_keyboard, get_custom_criteria_keyboard, get_broadcast_history_keyboard, get_admin_pagination_keyboard, get_broadcast_media_keyboard, - get_media_confirm_keyboard, get_updated_message_buttons_selector_keyboard_with_media + get_media_confirm_keyboard, get_updated_message_buttons_selector_keyboard_with_media, + BROADCAST_BUTTONS, BROADCAST_BUTTON_ROWS, DEFAULT_BROADCAST_BUTTONS, + BROADCAST_BUTTON_LABELS ) from app.localization.texts import get_texts from app.database.crud.user import get_users_list @@ -23,69 +25,42 @@ from app.utils.decorators import admin_required, error_handler logger = logging.getLogger(__name__) +BUTTON_CONFIG = BROADCAST_BUTTONS +BUTTON_ROWS = BROADCAST_BUTTON_ROWS +DEFAULT_SELECTED_BUTTONS = DEFAULT_BROADCAST_BUTTONS +BUTTON_LABELS = BROADCAST_BUTTON_LABELS + def get_message_buttons_selector_keyboard(language: str = "ru") -> types.InlineKeyboardMarkup: - return types.InlineKeyboardMarkup(inline_keyboard=[ - [ - types.InlineKeyboardButton(text="💰 Пополнить баланс", callback_data="btn_balance"), - types.InlineKeyboardButton(text="🤝 Рефералы", callback_data="btn_referrals") - ], - [ - types.InlineKeyboardButton(text="🎫 Промокод", callback_data="btn_promocode") - ], - [ - types.InlineKeyboardButton(text="✅ Продолжить", callback_data="buttons_confirm") - ], - [ - types.InlineKeyboardButton(text="❌ Отмена", callback_data="admin_messages") - ] - ]) + return get_updated_message_buttons_selector_keyboard(list(DEFAULT_SELECTED_BUTTONS), language) def get_updated_message_buttons_selector_keyboard(selected_buttons: list, language: str = "ru") -> types.InlineKeyboardMarkup: - balance_text = "✅ Пополнить баланс" if "balance" in selected_buttons else "💰 Пополнить баланс" - referrals_text = "✅ Рефералы" if "referrals" in selected_buttons else "🤝 Рефералы" - promocode_text = "✅ Промокод" if "promocode" in selected_buttons else "🎫 Промокод" - - return types.InlineKeyboardMarkup(inline_keyboard=[ - [ - types.InlineKeyboardButton(text=balance_text, callback_data="btn_balance"), - types.InlineKeyboardButton(text=referrals_text, callback_data="btn_referrals") - ], - [ - types.InlineKeyboardButton(text=promocode_text, callback_data="btn_promocode") - ], - [ - types.InlineKeyboardButton(text="✅ Продолжить", callback_data="buttons_confirm") - ], - [ - types.InlineKeyboardButton(text="❌ Отмена", callback_data="admin_messages") - ] - ]) + return get_updated_message_buttons_selector_keyboard_with_media(selected_buttons, False, language) -def create_broadcast_keyboard(selected_buttons: list) -> types.InlineKeyboardMarkup: - keyboard = [] - - button_row = [] - if "balance" in selected_buttons: - button_row.append(types.InlineKeyboardButton(text="💰 Пополнить баланс", callback_data="balance_topup")) - - if "referrals" in selected_buttons: - button_row.append(types.InlineKeyboardButton(text="🤝 Рефералы", callback_data="menu_referrals")) - - if "promocode" in selected_buttons: - button_row.append(types.InlineKeyboardButton(text="🎫 Промокод", callback_data="menu_promocode")) - - if len(button_row) > 2: - keyboard.append(button_row[:2]) - if len(button_row) > 2: - keyboard.append(button_row[2:]) - elif button_row: - keyboard.append(button_row) - - keyboard.append([types.InlineKeyboardButton(text="🏠 На главную", callback_data="back_to_menu")]) - +def create_broadcast_keyboard(selected_buttons: list) -> Optional[types.InlineKeyboardMarkup]: + selected_buttons = selected_buttons or [] + keyboard: list[list[types.InlineKeyboardButton]] = [] + + for row in BUTTON_ROWS: + row_buttons: list[types.InlineKeyboardButton] = [] + for button_key in row: + if button_key not in selected_buttons: + continue + button_config = BUTTON_CONFIG[button_key] + row_buttons.append( + types.InlineKeyboardButton( + text=button_config["text"], + callback_data=button_config["callback"] + ) + ) + if row_buttons: + keyboard.append(row_buttons) + + if not keyboard: + return None + return types.InlineKeyboardMarkup(inline_keyboard=keyboard) @@ -495,7 +470,11 @@ async def show_button_selector_callback( ): data = await state.get_data() has_media = data.get('has_media', False) - selected_buttons = data.get('selected_buttons', []) + selected_buttons = data.get('selected_buttons') + + if selected_buttons is None: + selected_buttons = list(DEFAULT_SELECTED_BUTTONS) + await state.update_data(selected_buttons=selected_buttons) media_info = "" if has_media: @@ -507,11 +486,14 @@ async def show_button_selector_callback( Выберите кнопки, которые будут добавлены к сообщению рассылки: -💰 Пополнить баланс - откроет методы пополнения -🤝 Рефералы - откроет реферальную программу -🎫 Промокод - откроет форму ввода промокода +💰 Пополнить баланс — откроет методы пополнения +🤝 Рефералы — откроет реферальную программу +🎫 Промокод — откроет форму ввода промокода +🔗 Подключиться — поможет подключить приложение +📱 Подписка — покажет состояние подписки +🛠️ Техподдержка — свяжет с поддержкой -Кнопка "🏠 На главную" добавляется автоматически внизу.{media_info} +🏠 Кнопка "На главную" включена по умолчанию, но вы можете отключить её при необходимости.{media_info} Выберите нужные кнопки и нажмите "Продолжить": """ @@ -535,28 +517,38 @@ async def show_button_selector( db_user: User, state: FSMContext ): + data = await state.get_data() + selected_buttons = data.get('selected_buttons') + if selected_buttons is None: + selected_buttons = list(DEFAULT_SELECTED_BUTTONS) + await state.update_data(selected_buttons=selected_buttons) + + has_media = data.get('has_media', False) + text = """ 📘 Выбор дополнительных кнопок Выберите кнопки, которые будут добавлены к сообщению рассылки: -💰 Пополнить баланс - откроет методы пополнения -🤝 Рефералы - откроет реферальную программу -🎫 Промокод - откроет форму ввода промокода +💰 Пополнить баланс — откроет методы пополнения +🤝 Рефералы — откроет реферальную программу +🎫 Промокод — откроет форму ввода промокода +🔗 Подключиться — поможет подключить приложение +📱 Подписка — покажет состояние подписки +🛠️ Техподдержка — свяжет с поддержкой -Кнопка "🏠 На главную" добавляется автоматически внизу. +🏠 Кнопка "На главную" включена по умолчанию, но вы можете отключить её при необходимости. Выберите нужные кнопки и нажмите "Продолжить": """ - - data = await state.get_data() - if 'selected_buttons' not in data: - data['selected_buttons'] = [] - await state.set_data(data) - + + keyboard = get_updated_message_buttons_selector_keyboard_with_media( + selected_buttons, has_media, db_user.language + ) + await message.answer( text, - reply_markup=get_message_buttons_selector_keyboard(db_user.language), + reply_markup=keyboard, parse_mode="HTML" ) @@ -570,18 +562,24 @@ async def toggle_button_selection( ): button_type = callback.data.replace('btn_', '') data = await state.get_data() - selected_buttons = data.get('selected_buttons', []) - + selected_buttons = data.get('selected_buttons') + if selected_buttons is None: + selected_buttons = list(DEFAULT_SELECTED_BUTTONS) + else: + selected_buttons = list(selected_buttons) + if button_type in selected_buttons: selected_buttons.remove(button_type) else: selected_buttons.append(button_type) - - data['selected_buttons'] = selected_buttons - await state.set_data(data) - - keyboard = get_updated_message_buttons_selector_keyboard(selected_buttons, db_user.language) - + + await state.update_data(selected_buttons=selected_buttons) + + has_media = data.get('has_media', False) + keyboard = get_updated_message_buttons_selector_keyboard_with_media( + selected_buttons, has_media, db_user.language + ) + await callback.message.edit_reply_markup(reply_markup=keyboard) await callback.answer() @@ -597,7 +595,10 @@ async def confirm_button_selection( data = await state.get_data() target = data.get('broadcast_target') message_text = data.get('broadcast_message') - selected_buttons = data.get('selected_buttons', []) + selected_buttons = data.get('selected_buttons') + if selected_buttons is None: + selected_buttons = list(DEFAULT_SELECTED_BUTTONS) + await state.update_data(selected_buttons=selected_buttons) has_media = data.get('has_media', False) media_type = data.get('media_type') @@ -613,18 +614,12 @@ async def confirm_button_selection( } media_info = f"\n🖼️ Медиафайл: {media_type_names.get(media_type, media_type)}" - buttons_info = "" - if selected_buttons: - buttons_list = [] - if "balance" in selected_buttons: - buttons_list.append("💰 Пополнить баланс") - if "referrals" in selected_buttons: - buttons_list.append("🤝 Рефералы") - if "promocode" in selected_buttons: - buttons_list.append("🎫 Промокод") - buttons_info = f"\n📘 Дополнительные кнопки: {', '.join(buttons_list)}" - - buttons_info += "\n🏠 Основная кнопка: На главную" + ordered_keys = [button_key for row in BUTTON_ROWS for button_key in row] + selected_names = [BUTTON_LABELS[key] for key in ordered_keys if key in selected_buttons] + if selected_names: + buttons_info = f"\n📘 Кнопки: {', '.join(selected_names)}" + else: + buttons_info = "\n📘 Кнопки: отсутствуют" preview_text = f""" 📨 Предварительный просмотр рассылки @@ -685,42 +680,6 @@ async def confirm_button_selection( ) await callback.answer() - - -@admin_required -@error_handler -async def show_button_selector_callback( - callback: types.CallbackQuery, - db_user: User, - state: FSMContext -): - text = """ -📘 Выбор дополнительных кнопок - -Выберите кнопки, которые будут добавлены к сообщению рассылки: - -💰 Пополнить баланс - откроет методы пополнения -🤝 Рефералы - откроет реферальную программу -🎫 Промокод - откроет форму ввода промокода - -Кнопка "🏠 На главную" добавляется автоматически внизу. - -Выберите нужные кнопки и нажмите "Продолжить": -""" - - data = await state.get_data() - selected_buttons = data.get('selected_buttons', []) - - keyboard = get_updated_message_buttons_selector_keyboard(selected_buttons, db_user.language) - - await callback.message.edit_text( - text, - reply_markup=keyboard, - parse_mode="HTML" - ) - await callback.answer() - - @admin_required @error_handler async def confirm_broadcast( @@ -732,7 +691,9 @@ async def confirm_broadcast( data = await state.get_data() target = data.get('broadcast_target') message_text = data.get('broadcast_message') - selected_buttons = data.get('selected_buttons', []) + selected_buttons = data.get('selected_buttons') + if selected_buttons is None: + selected_buttons = list(DEFAULT_SELECTED_BUTTONS) has_media = data.get('has_media', False) media_type = data.get('media_type') media_file_id = data.get('media_file_id') @@ -771,7 +732,7 @@ async def confirm_broadcast( sent_count = 0 failed_count = 0 - broadcast_keyboard = create_broadcast_keyboard(selected_buttons) if selected_buttons else None + broadcast_keyboard = create_broadcast_keyboard(selected_buttons) for user in users: try: diff --git a/app/keyboards/admin.py b/app/keyboards/admin.py index 4a263967..9137d904 100644 --- a/app/keyboards/admin.py +++ b/app/keyboards/admin.py @@ -913,22 +913,30 @@ def get_welcome_text_keyboard(language: str = "ru", is_enabled: bool = True) -> return InlineKeyboardMarkup(inline_keyboard=keyboard) +DEFAULT_BROADCAST_BUTTONS = ("home",) + +BROADCAST_BUTTONS = { + "balance": {"text": "💰 Пополнить баланс", "callback": "balance_topup"}, + "referrals": {"text": "🤝 Рефералы", "callback": "menu_referrals"}, + "promocode": {"text": "🎫 Промокод", "callback": "menu_promocode"}, + "connect": {"text": "🔗 Подключиться", "callback": "subscription_connect"}, + "subscription": {"text": "📱 Подписка", "callback": "menu_subscription"}, + "support": {"text": "🛠️ Техподдержка", "callback": "menu_support"}, + "home": {"text": "🏠 На главную", "callback": "back_to_menu"}, +} + +BROADCAST_BUTTON_ROWS: tuple[tuple[str, ...], ...] = ( + ("balance", "referrals"), + ("promocode", "connect"), + ("subscription", "support"), + ("home",), +) + +BROADCAST_BUTTON_LABELS = {key: value["text"] for key, value in BROADCAST_BUTTONS.items()} + + def get_message_buttons_selector_keyboard(language: str = "ru") -> InlineKeyboardMarkup: - return InlineKeyboardMarkup(inline_keyboard=[ - [ - InlineKeyboardButton(text="💰 Пополнить баланс", callback_data="btn_balance"), - InlineKeyboardButton(text="🤝 Рефералы", callback_data="btn_referrals") - ], - [ - InlineKeyboardButton(text="🎫 Промокод", callback_data="btn_promocode") - ], - [ - InlineKeyboardButton(text="✅ Продолжить", callback_data="buttons_confirm") - ], - [ - InlineKeyboardButton(text="❌ Отмена", callback_data="admin_messages") - ] - ]) + return get_updated_message_buttons_selector_keyboard_with_media(list(DEFAULT_BROADCAST_BUTTONS), False, language) def get_broadcast_media_keyboard(language: str = "ru") -> InlineKeyboardMarkup: return InlineKeyboardMarkup(inline_keyboard=[ @@ -958,25 +966,33 @@ def get_media_confirm_keyboard(language: str = "ru") -> InlineKeyboardMarkup: ]) def get_updated_message_buttons_selector_keyboard_with_media(selected_buttons: list, has_media: bool = False, language: str = "ru") -> InlineKeyboardMarkup: - balance_text = "✅ Пополнить баланс" if "balance" in selected_buttons else "💰 Пополнить баланс" - referrals_text = "✅ Рефералы" if "referrals" in selected_buttons else "🤝 Рефералы" - promocode_text = "✅ Промокод" if "promocode" in selected_buttons else "🎫 Промокод" - - keyboard = [ - [ - InlineKeyboardButton(text=balance_text, callback_data="btn_balance"), - InlineKeyboardButton(text=referrals_text, callback_data="btn_referrals") - ], - [ - InlineKeyboardButton(text=promocode_text, callback_data="btn_promocode") - ] - ] - + selected_buttons = selected_buttons or [] + + keyboard: list[list[InlineKeyboardButton]] = [] + + for row in BROADCAST_BUTTON_ROWS: + row_buttons: list[InlineKeyboardButton] = [] + for button_key in row: + button_config = BROADCAST_BUTTONS[button_key] + base_text = button_config["text"] + if button_key in selected_buttons: + if " " in base_text: + toggle_text = f"✅ {base_text.split(' ', 1)[1]}" + else: + toggle_text = f"✅ {base_text}" + else: + toggle_text = base_text + row_buttons.append( + InlineKeyboardButton(text=toggle_text, callback_data=f"btn_{button_key}") + ) + if row_buttons: + keyboard.append(row_buttons) + if has_media: keyboard.append([ InlineKeyboardButton(text="🖼️ Изменить медиа", callback_data="change_media") ]) - + keyboard.extend([ [ InlineKeyboardButton(text="✅ Продолжить", callback_data="buttons_confirm") @@ -985,5 +1001,5 @@ def get_updated_message_buttons_selector_keyboard_with_media(selected_buttons: l InlineKeyboardButton(text="❌ Отмена", callback_data="admin_messages") ] ]) - + return InlineKeyboardMarkup(inline_keyboard=keyboard)