diff --git a/app/bot/handlers/__init__.py b/app/bot/handlers/__init__.py index 1def746..7a20130 100644 --- a/app/bot/handlers/__init__.py +++ b/app/bot/handlers/__init__.py @@ -1,13 +1,13 @@ -from . import subscribe, active_triggers -from . import unsubscribe -from . import my_subscriptions from . import cancel_input -from . import notification_switch_mode +from . import debug from . import help +from . import my_subscriptions +from . import notification_switch_mode from . import registration from . import settings from . import start -from . import debug +from . import subscribe, active_triggers +from . import unsubscribe from ..states import UserStateManager state_manager = UserStateManager() @@ -31,4 +31,6 @@ def register_handlers(bot, app): def register_callbacks(bot, app): notification_switch_mode.register_callback_notification(bot, app, state_manager) active_triggers.register_callbacks_active_triggers(bot, app, state_manager) - cancel_input.register_callback_cancel_input(bot,state_manager) \ No newline at end of file + cancel_input.register_callback_cancel_input(bot,state_manager) + subscribe.register_callback_subscribe(bot, app, state_manager) + unsubscribe.register_callback_unsubscribe(bot, app, state_manager) \ No newline at end of file diff --git a/app/bot/handlers/subscribe.py b/app/bot/handlers/subscribe.py index cf14c19..1513cb4 100644 --- a/app/bot/handlers/subscribe.py +++ b/app/bot/handlers/subscribe.py @@ -1,13 +1,13 @@ -from telebot.types import Message, InlineKeyboardMarkup, InlineKeyboardButton +from telebot import TeleBot, logger +from telebot.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery from app import Subscriptions from app.bot.constants import UserStates -from app.bot.processors.subscribe_processor import process_subscription_button +from app.bot.processors.subscribe_processor import process_subscription_button, process_subscribe_all_regions from app.bot.states import UserStateManager from app.bot.utils.auth import auth -from app.bot.utils.regions import get_sorted_regions, format_regions_list, format_regions_list_marked -from telebot import TeleBot, logger +from app.bot.utils.regions import get_sorted_regions, format_regions_list_marked def register_handlers(bot: TeleBot, app, state_manager: UserStateManager): @@ -36,6 +36,7 @@ def register_handlers(bot: TeleBot, app, state_manager: UserStateManager): regions_text = format_regions_list_marked(regions, subscribed) markup = InlineKeyboardMarkup() + markup.add(InlineKeyboardButton("Подписаться на все регионы", callback_data="subscribe_all")) markup.add(InlineKeyboardButton(text="Отмена", callback_data="cancel_input")) bot_message = bot.send_message(chat_id, @@ -44,3 +45,17 @@ def register_handlers(bot: TeleBot, app, state_manager: UserStateManager): bot.register_next_step_handler(message, process_subscription_button, app, bot, chat_id, state_manager, bot_message.message_id) + +def register_callback_subscribe(bot: TeleBot, app, state_manager): + @bot.callback_query_handler(func=lambda call: call.data == "subscribe_all") + def handle_subscribe_all_button(call: CallbackQuery): + chat_id = call.message.chat.id + username = f"{call.from_user.username}" if call.from_user.username else "N/A" + + with app.app_context(): + if not auth(chat_id, app): + bot.send_message(chat_id, "Вы не авторизованы для использования этого бота.") + logger.warning(f"Неавторизованный пользователь {chat_id} @{username}") + state_manager.set_state(chat_id, UserStates.REGISTRATION) + return + process_subscribe_all_regions(call, app, bot, chat_id, state_manager) diff --git a/app/bot/handlers/unsubscribe.py b/app/bot/handlers/unsubscribe.py index 89a7094..f2879fb 100644 --- a/app/bot/handlers/unsubscribe.py +++ b/app/bot/handlers/unsubscribe.py @@ -1,10 +1,12 @@ -from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton -from telebot import logger +from telebot import logger, TeleBot +from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery + from app.bot.constants import UserStates +from app.bot.keyboards.settings_menu import get_settings_menu +from app.bot.processors.unsubscribe_processor import process_unsubscribe_button, process_unsubscribe_all_regions from app.bot.utils.auth import auth from app.bot.utils.helpers import get_user_subscribed_regions from app.bot.utils.regions import format_regions_list -from app.bot.processors.unsubscribe_processor import process_unsubscribe_button def register_handlers(bot, app, state_manager): @@ -14,22 +16,48 @@ def register_handlers(bot, app, state_manager): with app.app_context(): chat_id = message.chat.id username = f"{message.from_user.username}" if message.from_user.username else "N/A" + if not auth(chat_id, app): bot.send_message(chat_id, "Вы не авторизованы для использования этого бота.") logger.warning(f"Неавторизованный пользователь {chat_id} @{username}") state_manager.set_state(chat_id, UserStates.REGISTRATION) return - else: - state_manager.set_state(chat_id, UserStates.WAITING_INPUT) user_subscriptions = get_user_subscribed_regions(chat_id) + + # ✅ Предварительная проверка: есть ли подписки + if not user_subscriptions: + bot.send_message(chat_id, "ℹ️ У вас нет активных подписок для отписки.",reply_markup=get_settings_menu()) + state_manager.set_state(chat_id, UserStates.SETTINGS_MENU) + return + + # Есть подписки — предлагаем меню отписки + state_manager.set_state(chat_id, UserStates.WAITING_INPUT) formated_user_subscriptions = format_regions_list(user_subscriptions) markup = InlineKeyboardMarkup() + markup.add(InlineKeyboardButton("Отписаться от всех регионов", callback_data="unsubscribe_all")) markup.add(InlineKeyboardButton("Отмена", callback_data="cancel_input")) bot.send_message(chat_id, - f"Введите номер(а) региона(ов) через запятую подписки которых вы хотите удалить:\n\n{formated_user_subscriptions}", + f"Введите номер(а) региона(ов) через запятую, от которых вы хотите отписаться:\n\n{formated_user_subscriptions}", reply_markup=markup) - bot.register_next_step_handler(message, process_unsubscribe_button, app, bot, chat_id, state_manager) \ No newline at end of file + bot.register_next_step_handler(message, process_unsubscribe_button, app, bot, chat_id, state_manager) + + + +def register_callback_unsubscribe(bot: TeleBot, app, state_manager): + @bot.callback_query_handler(func=lambda call: call.data == "unsubscribe_all") + def handle_subscribe_all_button(call: CallbackQuery): + chat_id = call.message.chat.id + username = f"{call.from_user.username}" if call.from_user.username else "N/A" + + with app.app_context(): + if not auth(chat_id, app): + bot.send_message(chat_id, "Вы не авторизованы для использования этого бота.") + logger.warning(f"Неавторизованный пользователь {chat_id} @{username}") + state_manager.set_state(chat_id, UserStates.REGISTRATION) + return + + process_unsubscribe_all_regions(call, app, bot, state_manager) diff --git a/app/bot/processors/subscribe_processor.py b/app/bot/processors/subscribe_processor.py index cdf77db..efc90ad 100644 --- a/app/bot/processors/subscribe_processor.py +++ b/app/bot/processors/subscribe_processor.py @@ -75,3 +75,50 @@ def process_subscription_button(message: Message, app, bot, chat_id: int, state_ # Показываем меню bot.send_message(chat_id, f"✅ Подписка на регионы: {', '.join(subbed_regions)} оформлена.", reply_markup=get_settings_menu()) + +def process_subscribe_all_regions(call, app, bot, chat_id: int, state_manager): + try: + with app.app_context(): + username = f"{call.from_user.username}" if call.from_user.username else "N/A" + + # Получаем все активные регионы + active_regions = Regions.query.filter_by(active=True).all() + active_region_ids = {r.region_id for r in active_regions} + + # Получаем уже подписанные регионы + existing_subs = Subscriptions.query.filter_by(chat_id=chat_id).all() + existing_region_ids = {sub.region_id for sub in existing_subs if sub.active} + + newly_added = [] + for region in active_regions: + if region.region_id in existing_region_ids: + continue + + existing = next((sub for sub in existing_subs if sub.region_id == region.region_id), None) + if existing: + existing.active = True + db.session.add(existing) + else: + new_sub = Subscriptions(chat_id=chat_id, region_id=region.region_id, active=True) + db.session.add(new_sub) + newly_added.append(str(region.region_id)) + + db.session.commit() + + # Логирование действия + if newly_added: + log_user_event(chat_id, app, username, f"Подписался на все регионы: {', '.join(newly_added)}") + + bot.answer_callback_query(call.id) + bot.clear_step_handler_by_chat_id(chat_id) + + bot.delete_message(chat_id, call.message.message_id) + + bot.send_message(chat_id, + "✅ Вы подписались на все доступные регионы.", + reply_markup=get_settings_menu()) + + state_manager.set_state(chat_id, UserStates.SETTINGS_MENU) + + except Exception as e: + bot.send_message(chat_id, "⚠️ Не удалось выполнить подписку. Попробуйте позже.") diff --git a/app/bot/processors/unsubscribe_processor.py b/app/bot/processors/unsubscribe_processor.py index 912a967..9657e51 100644 --- a/app/bot/processors/unsubscribe_processor.py +++ b/app/bot/processors/unsubscribe_processor.py @@ -1,13 +1,15 @@ from flask import Flask from telebot import TeleBot, logger -from telebot.types import Message, InlineKeyboardMarkup, InlineKeyboardButton -from app.bot.keyboards.settings_menu import get_settings_menu -from app.bot.utils.helpers import get_user_subscribed_regions +from telebot.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery + from app import Subscriptions +from app.bot.constants import UserStates +from app.bot.keyboards.settings_menu import get_settings_menu +from app.bot.states import UserStateManager +from app.bot.utils.helpers import get_user_subscribed_regions from app.bot.utils.tg_audit import log_user_event from app.extensions.db import db -from app.bot.states import UserStateManager -from app.bot.constants import UserStates + def process_unsubscribe_button(message: Message, app: Flask, bot: TeleBot, chat_id: int, state_manager: UserStateManager): unsubbed_regions = [] @@ -62,4 +64,39 @@ def process_unsubscribe_button(message: Message, app: Flask, bot: TeleBot, chat_ f"⚠ Регионы с ID {', '.join(invalid_regions)} не найдены среди ваших подписок и не были изменены.") state_manager.set_state(chat_id, UserStates.SETTINGS_MENU) - bot.send_message(chat_id, "⚙ Вернулись в меню настроек.", reply_markup=get_settings_menu()) \ No newline at end of file + bot.send_message(chat_id, "⚙ Вернулись в меню настроек.", reply_markup=get_settings_menu()) + + +def process_unsubscribe_all_regions(call: CallbackQuery, app: Flask, bot: TeleBot, state_manager: UserStateManager): + chat_id = call.message.chat.id + username = f"{call.from_user.username}" if call.from_user.username else "N/A" + + try: + with app.app_context(): + subscriptions = Subscriptions.query.filter_by(chat_id=chat_id, active=True).all() + if not subscriptions: + bot.answer_callback_query(call.id, text="❗ У вас нет активных подписок.") + return + + for sub in subscriptions: + sub.active = False + db.session.add(sub) + + db.session.commit() + + log_user_event(chat_id, app, username, "Отписался от всех регионов") + + bot.answer_callback_query(call.id) + bot.clear_step_handler_by_chat_id(chat_id) + + bot.delete_message(chat_id, call.message.message_id) + bot.send_message(chat_id, + "✅ Вы успешно отписались от всех регионов.", + reply_markup=get_settings_menu()) + state_manager.set_state(chat_id, UserStates.SETTINGS_MENU) + + + except Exception as e: + state_manager.set_state(chat_id, UserStates.SETTINGS_MENU) + bot.send_message(chat_id, "⚠ Произошла ошибка при отписке. Попробуйте позже.",reply_markup=get_settings_menu()) + return