diff --git a/.gitignore b/.gitignore index e9bb22d..c0b2162 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,4 @@ venv.bak/ # Системные файлы .DS_Store Thumbs.db.bot.pid +*.bak diff --git a/main.py b/main.py index 2506ae7..89bf5ad 100644 --- a/main.py +++ b/main.py @@ -192,7 +192,26 @@ async def btn_main_menu(message: Message): async def cmd_admin(message: Message): """Обработчик команды /admin (регистронезависимо) - перенаправляет в admin_panel""" from src.core.config import ADMIN_IDS - if message.from_user.id not in ADMIN_IDS: + from src.core.database import async_session_maker + from src.core.models import User + from sqlalchemy import select + + # Проверяем, является ли пользователь главным администратором из .env + user_id = message.from_user.id + is_super_admin = user_id in ADMIN_IDS + + # Проверяем, является ли пользователь назначенным администратором + is_assigned_admin = False + if not is_super_admin: + async with async_session_maker() as session: + user = await session.execute( + select(User).where(User.telegram_id == user_id) + ) + user = user.scalar_one_or_none() + is_assigned_admin = user and user.is_admin + + # Если не администратор ни того, ни другого типа + if not (is_super_admin or is_assigned_admin): await message.answer("❌ Недостаточно прав для доступа к админ панели") return diff --git a/src/handlers/admin_panel.py b/src/handlers/admin_panel.py index 7df6dbc..14f54e0 100644 --- a/src/handlers/admin_panel.py +++ b/src/handlers/admin_panel.py @@ -113,7 +113,7 @@ admin_router = Router() def is_admin(user_id: int) -> bool: - """Проверка прав администратора""" + """Проверка прав администратора (быстрая проверка только .env)""" return user_id in ADMIN_IDS @@ -122,6 +122,25 @@ def is_super_admin(user_id: int) -> bool: return user_id in ADMIN_IDS +async def check_admin_access(user_id: int) -> bool: + """ + Асинхронная проверка доступа администратора. + Проверяет как главных администраторов (.env), так и назначенных (БД) + """ + # Сначала проверяем главных администраторов + if user_id in ADMIN_IDS: + return True + + # Затем проверяем назначенных администраторов в БД + async with async_session_maker() as session: + from sqlalchemy import select + result = await session.execute( + select(User).where(User.telegram_id == user_id, User.is_admin == True) + ) + user = result.scalar_one_or_none() + return user is not None + + def get_admin_main_keyboard() -> InlineKeyboardMarkup: """Главная админ-панель""" buttons = [ @@ -182,7 +201,7 @@ def get_winner_management_keyboard() -> InlineKeyboardMarkup: @admin_router.callback_query(F.data == "admin_panel") async def show_admin_panel(callback: CallbackQuery): """Показать админ-панель""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -217,7 +236,7 @@ async def show_admin_panel(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_lotteries") async def show_lottery_management(callback: CallbackQuery): """Управление розыгрышами""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -236,7 +255,7 @@ async def start_create_lottery(callback: CallbackQuery, state: FSMContext): # Сразу отвечаем на callback await callback.answer() - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): logging.warning(f"⚠️ Пользователь {callback.from_user.id} не является админом") await callback.message.answer("❌ Недостаточно прав") return @@ -264,7 +283,7 @@ async def start_create_lottery(callback: CallbackQuery, state: FSMContext): @admin_router.message(StateFilter(AdminStates.lottery_title)) async def process_lottery_title(message: Message, state: FSMContext): """Обработка названия розыгрыша (создание или редактирование)""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): await message.answer("❌ Недостаточно прав") return @@ -312,7 +331,7 @@ async def process_lottery_title(message: Message, state: FSMContext): @admin_router.message(StateFilter(AdminStates.lottery_description)) async def process_lottery_description(message: Message, state: FSMContext): """Обработка описания розыгрыша (создание или редактирование)""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): await message.answer("❌ Недостаточно прав") return @@ -370,7 +389,7 @@ async def process_lottery_description(message: Message, state: FSMContext): @admin_router.message(StateFilter(AdminStates.lottery_prizes)) async def process_lottery_prizes(message: Message, state: FSMContext): """Обработка призов розыгрыша (создание или редактирование)""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): await message.answer("❌ Недостаточно прав") return @@ -433,7 +452,7 @@ async def process_lottery_prizes(message: Message, state: FSMContext): @admin_router.callback_query(F.data == "confirm_create_lottery", StateFilter(AdminStates.lottery_confirm)) async def confirm_create_lottery(callback: CallbackQuery, state: FSMContext): """Подтверждение создания розыгрыша""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -476,7 +495,7 @@ async def confirm_create_lottery(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data == "admin_list_all_lotteries") async def list_all_lotteries(callback: CallbackQuery): """Список всех розыгрышей""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -526,7 +545,7 @@ async def list_all_lotteries(callback: CallbackQuery): @admin_router.callback_query(F.data.startswith("admin_lottery_detail_")) async def show_lottery_detail(callback: CallbackQuery): """Детальная информация о розыгрыше""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -609,7 +628,7 @@ async def show_lottery_detail(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_participants") async def show_participant_management(callback: CallbackQuery): """Управление участниками""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -623,7 +642,7 @@ async def show_participant_management(callback: CallbackQuery): @admin_router.callback_query(F.data.startswith("admin_participants_")) async def show_lottery_participants(callback: CallbackQuery): """Показать участников конкретного розыгрыша""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -675,7 +694,7 @@ async def show_lottery_participants(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_bulk_operations") async def show_bulk_operations_menu(callback: CallbackQuery): """Подменю массовых операций""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -702,7 +721,7 @@ async def show_bulk_operations_menu(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_add_participant") async def start_add_participant(callback: CallbackQuery, state: FSMContext): """Начать добавление участника""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -740,7 +759,7 @@ async def start_add_participant(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data.startswith("admin_add_part_to_")) async def choose_user_to_add(callback: CallbackQuery, state: FSMContext): """Выбор пользователя для добавления""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -768,7 +787,7 @@ async def choose_user_to_add(callback: CallbackQuery, state: FSMContext): @admin_router.message(StateFilter(AdminStates.add_participant_user)) async def process_add_participant(message: Message, state: FSMContext): """Обработка добавления участника""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): await message.answer("❌ Недостаточно прав") return @@ -823,7 +842,7 @@ async def process_add_participant(message: Message, state: FSMContext): @admin_router.callback_query(F.data == "admin_remove_participant") async def remove_participant_start(callback: CallbackQuery): """Начало процесса удаления участника""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -858,7 +877,7 @@ async def remove_participant_start(callback: CallbackQuery): @admin_router.callback_query(F.data.startswith("admin_remove_part_from_")) async def remove_participant_select_lottery(callback: CallbackQuery, state: FSMContext): """Выбор розыгрыша для удаления участника""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -889,7 +908,7 @@ async def remove_participant_select_lottery(callback: CallbackQuery, state: FSMC @admin_router.message(StateFilter(AdminStates.remove_participant_user)) async def process_remove_participant(message: Message, state: FSMContext): """Обработка удаления участника""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): await message.answer("❌ Недостаточно прав") return @@ -954,7 +973,7 @@ async def process_remove_participant(message: Message, state: FSMContext): @admin_router.callback_query(F.data == "admin_list_all_participants") async def list_all_participants(callback: CallbackQuery): """Список всех участников""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -1003,7 +1022,7 @@ async def list_all_participants(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_participants_report") async def generate_participants_report(callback: CallbackQuery): """Генерация отчета по участникам""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -1088,7 +1107,7 @@ async def generate_participants_report(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_export_participants") async def export_participants_data(callback: CallbackQuery): """Экспорт данных участников""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -1141,7 +1160,7 @@ async def export_participants_data(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_search_participants") async def start_search_participants(callback: CallbackQuery, state: FSMContext): """Начать поиск участников""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -1164,7 +1183,7 @@ async def start_search_participants(callback: CallbackQuery, state: FSMContext): @admin_router.message(StateFilter(AdminStates.participant_search)) async def process_search_participants(message: Message, state: FSMContext): """Обработка поиска участников""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): await message.answer("❌ Недостаточно прав") return @@ -1215,7 +1234,7 @@ async def process_search_participants(message: Message, state: FSMContext): @admin_router.callback_query(F.data == "admin_bulk_add_participant") async def start_bulk_add_participant(callback: CallbackQuery, state: FSMContext): """Начать массовое добавление участников""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -1253,7 +1272,7 @@ async def start_bulk_add_participant(callback: CallbackQuery, state: FSMContext) @admin_router.callback_query(F.data.startswith("admin_bulk_add_to_")) async def choose_users_bulk_add(callback: CallbackQuery, state: FSMContext): """Выбор пользователей для массового добавления""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -1282,7 +1301,7 @@ async def choose_users_bulk_add(callback: CallbackQuery, state: FSMContext): @admin_router.message(StateFilter(AdminStates.add_participant_bulk)) async def process_bulk_add_participant(message: Message, state: FSMContext): """Обработка массового добавления участников""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): await message.answer("❌ Недостаточно прав") return @@ -1336,7 +1355,7 @@ async def process_bulk_add_participant(message: Message, state: FSMContext): @admin_router.callback_query(F.data == "admin_bulk_remove_participant") async def start_bulk_remove_participant(callback: CallbackQuery, state: FSMContext): """Начать массовое удаление участников""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -1384,7 +1403,7 @@ async def start_bulk_remove_participant(callback: CallbackQuery, state: FSMConte @admin_router.callback_query(F.data.startswith("admin_bulk_remove_from_")) async def choose_users_bulk_remove(callback: CallbackQuery, state: FSMContext): """Выбор пользователей для массового удаления""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -1413,7 +1432,7 @@ async def choose_users_bulk_remove(callback: CallbackQuery, state: FSMContext): @admin_router.message(StateFilter(AdminStates.remove_participant_bulk)) async def process_bulk_remove_participant(message: Message, state: FSMContext): """Обработка массового удаления участников""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): await message.answer("❌ Недостаточно прав") return @@ -2044,7 +2063,7 @@ async def delete_lottery_execute(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_bulk_add_accounts") async def start_bulk_add_accounts(callback: CallbackQuery, state: FSMContext): """Начать массовое добавление участников по номерам счетов""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2082,7 +2101,7 @@ async def start_bulk_add_accounts(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data.startswith("admin_bulk_add_accounts_to_")) async def choose_accounts_bulk_add(callback: CallbackQuery, state: FSMContext): """Выбор номеров счетов для массового добавления""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2113,7 +2132,7 @@ async def choose_accounts_bulk_add(callback: CallbackQuery, state: FSMContext): @admin_router.message(StateFilter(AdminStates.add_participant_bulk_accounts)) async def process_bulk_add_accounts(message: Message, state: FSMContext): """Обработка массового добавления участников по номерам счетов""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): await message.answer("❌ Недостаточно прав") return @@ -2170,7 +2189,7 @@ async def process_bulk_add_accounts(message: Message, state: FSMContext): @admin_router.callback_query(F.data == "admin_bulk_remove_accounts") async def start_bulk_remove_accounts(callback: CallbackQuery, state: FSMContext): """Начать массовое удаление участников по номерам счетов""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2208,7 +2227,7 @@ async def start_bulk_remove_accounts(callback: CallbackQuery, state: FSMContext) @admin_router.callback_query(F.data.startswith("admin_bulk_remove_accounts_from_")) async def choose_accounts_bulk_remove(callback: CallbackQuery, state: FSMContext): """Выбор номеров счетов для массового удаления""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2238,7 +2257,7 @@ async def choose_accounts_bulk_remove(callback: CallbackQuery, state: FSMContext @admin_router.message(StateFilter(AdminStates.remove_participant_bulk_accounts)) async def process_bulk_remove_accounts(message: Message, state: FSMContext): """Обработка массового удаления участников по номерам счетов""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): await message.answer("❌ Недостаточно прав") return @@ -2299,7 +2318,7 @@ async def process_bulk_remove_accounts(message: Message, state: FSMContext): @admin_router.callback_query(F.data == "admin_participants_by_lottery") async def show_participants_by_lottery(callback: CallbackQuery): """Показать участников по розыгрышам""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2343,7 +2362,7 @@ async def show_participants_by_lottery(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_participants_report") async def show_participants_report(callback: CallbackQuery): """Отчет по участникам""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2410,7 +2429,7 @@ async def show_participants_report(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_edit_lottery") async def start_edit_lottery(callback: CallbackQuery, state: FSMContext): """Начать редактирование розыгрыша""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2447,7 +2466,7 @@ async def start_edit_lottery(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data.startswith("admin_edit_field_")) async def handle_edit_field(callback: CallbackQuery, state: FSMContext): """Обработка выбора поля для редактирования""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2488,7 +2507,7 @@ async def handle_edit_field(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data.startswith("admin_edit_")) async def redirect_to_edit_lottery(callback: CallbackQuery, state: FSMContext): """Редирект на редактирование розыгрыша из детального просмотра""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2509,7 +2528,7 @@ async def redirect_to_edit_lottery(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data.startswith("admin_edit_lottery_select_")) async def choose_edit_field(callback: CallbackQuery, state: FSMContext): """Выбор поля для редактирования""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2545,7 +2564,7 @@ async def choose_edit_field(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data.startswith("admin_toggle_active_")) async def toggle_lottery_active(callback: CallbackQuery, state: FSMContext): """Переключить активность розыгрыша""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2571,7 +2590,7 @@ async def toggle_lottery_active(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data == "admin_finish_lottery") async def start_finish_lottery(callback: CallbackQuery): """Завершить розыгрыш""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2609,7 +2628,7 @@ async def start_finish_lottery(callback: CallbackQuery): @admin_router.callback_query(F.data.startswith("admin_confirm_finish_")) async def confirm_finish_lottery(callback: CallbackQuery): """Подтвердить завершение розыгрыша""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2638,7 +2657,7 @@ async def confirm_finish_lottery(callback: CallbackQuery): @admin_router.callback_query(F.data.startswith("admin_do_finish_")) async def do_finish_lottery(callback: CallbackQuery): """Выполнить завершение розыгрыша""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2669,7 +2688,7 @@ async def do_finish_lottery(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_delete_lottery") async def start_delete_lottery(callback: CallbackQuery): """Удаление розыгрыша""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2709,7 +2728,7 @@ async def start_delete_lottery(callback: CallbackQuery): @admin_router.callback_query(F.data.startswith("admin_confirm_delete_")) async def confirm_delete_lottery(callback: CallbackQuery): """Подтвердить удаление розыгрыша""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2741,7 +2760,7 @@ async def confirm_delete_lottery(callback: CallbackQuery): @admin_router.callback_query(F.data.startswith("admin_do_delete_")) async def do_delete_lottery(callback: CallbackQuery): """Выполнить удаление розыгрыша""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2778,7 +2797,7 @@ async def do_delete_lottery(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_winners") async def show_winner_management(callback: CallbackQuery): """Управление победителями""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2792,7 +2811,7 @@ async def show_winner_management(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_set_manual_winner") async def start_set_manual_winner(callback: CallbackQuery, state: FSMContext): """Начать установку ручного победителя""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2836,7 +2855,7 @@ async def start_set_manual_winner(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data.startswith("admin_set_winner_")) async def handle_set_winner_from_lottery(callback: CallbackQuery, state: FSMContext): """Обработчик для кнопки 'Установить победителя' из карточки розыгрыша""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2850,7 +2869,7 @@ async def handle_set_winner_from_lottery(callback: CallbackQuery, state: FSMCont @admin_router.callback_query(F.data.startswith("admin_choose_winner_lottery_")) async def choose_winner_place(callback: CallbackQuery, state: FSMContext): """Выбор места для победителя""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -2887,7 +2906,7 @@ async def choose_winner_place(callback: CallbackQuery, state: FSMContext): @admin_router.message(StateFilter(AdminStates.set_winner_place)) async def process_winner_place(message: Message, state: FSMContext): """Обработка места победителя""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): await message.answer("❌ Недостаточно прав") return @@ -2935,7 +2954,7 @@ async def process_winner_place(message: Message, state: FSMContext): @admin_router.message(StateFilter(AdminStates.set_winner_user)) async def process_winner_user(message: Message, state: FSMContext): """Обработка пользователя-победителя (по ID, username или номеру счета)""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): await message.answer("❌ Недостаточно прав") return @@ -3035,7 +3054,7 @@ async def process_winner_user(message: Message, state: FSMContext): @admin_router.callback_query(F.data == "admin_list_winners") async def list_all_winners(callback: CallbackQuery): """Список всех победителей""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3102,7 +3121,7 @@ async def list_all_winners(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_edit_winner") async def edit_winner_start(callback: CallbackQuery): """Начало редактирования победителя""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3148,7 +3167,7 @@ async def edit_winner_start(callback: CallbackQuery): @admin_router.callback_query(F.data.startswith("admin_edit_winner_lottery_")) async def edit_winner_select_place(callback: CallbackQuery, state: FSMContext): """Выбор места победителя для редактирования""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3182,7 +3201,7 @@ async def edit_winner_select_place(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data.startswith("admin_edit_winner_id_")) async def edit_winner_details(callback: CallbackQuery): """Показать детали победителя (пока просто информационное сообщение)""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3225,7 +3244,7 @@ async def edit_winner_details(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_remove_winner") async def remove_winner_start(callback: CallbackQuery): """Начало удаления победителя""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3271,7 +3290,7 @@ async def remove_winner_start(callback: CallbackQuery): @admin_router.callback_query(F.data.startswith("admin_remove_winner_lottery_")) async def remove_winner_select_place(callback: CallbackQuery): """Выбор победителя для удаления""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3305,7 +3324,7 @@ async def remove_winner_select_place(callback: CallbackQuery): @admin_router.callback_query(F.data.startswith("admin_confirm_remove_winner_")) async def confirm_remove_winner(callback: CallbackQuery): """Подтверждение удаления победителя""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3347,7 +3366,7 @@ async def confirm_remove_winner(callback: CallbackQuery): @admin_router.callback_query(F.data.startswith("admin_do_remove_winner_")) async def do_remove_winner(callback: CallbackQuery): """Выполнение удаления победителя""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3393,7 +3412,7 @@ async def do_remove_winner(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_conduct_draw") async def choose_lottery_for_draw(callback: CallbackQuery): """Выбор розыгрыша для проведения""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3432,7 +3451,7 @@ async def choose_lottery_for_draw(callback: CallbackQuery): @admin_router.callback_query(F.data.regexp(r"^admin_conduct_\d+$")) async def conduct_lottery_draw_confirm(callback: CallbackQuery): """Запрос подтверждения проведения розыгрыша""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3490,7 +3509,7 @@ async def conduct_lottery_draw(callback: CallbackQuery): logger.info(f"🎯 conduct_lottery_draw HANDLER TRIGGERED! data={callback.data}, user={callback.from_user.id}") logger.info(f"conduct_lottery_draw вызван: callback.data={callback.data}, user_id={callback.from_user.id}") - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3582,7 +3601,7 @@ async def conduct_lottery_draw(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_stats") async def show_detailed_stats(callback: CallbackQuery): """Подробная статистика""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3658,7 +3677,7 @@ async def show_detailed_stats(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_settings") async def show_admin_settings(callback: CallbackQuery): """Настройки админ-панели""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3689,7 +3708,7 @@ async def show_admin_settings(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_export_data") async def export_data(callback: CallbackQuery): """Экспорт данных из системы""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3742,7 +3761,7 @@ async def export_data(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_cleanup") async def cleanup_old_data(callback: CallbackQuery): """Очистка старых данных""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3763,7 +3782,7 @@ async def cleanup_old_data(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_cleanup_old_lotteries") async def cleanup_old_lotteries(callback: CallbackQuery): """Очистка старых завершённых розыгрышей""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3811,7 +3830,7 @@ async def cleanup_old_lotteries(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_cleanup_inactive_users") async def cleanup_inactive_users(callback: CallbackQuery): """Очистка неактивных пользователей""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3872,7 +3891,7 @@ async def cleanup_inactive_users(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_cleanup_old_participations") async def cleanup_old_participations(callback: CallbackQuery): """Очистка старых участий""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3921,7 +3940,7 @@ async def cleanup_old_participations(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_system_info") async def show_system_info(callback: CallbackQuery): """Системная информация""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3951,7 +3970,7 @@ async def show_system_info(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_winner_display_settings") async def show_winner_display_settings(callback: CallbackQuery, state: FSMContext): """Настройка отображения победителей для розыгрышей""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -3993,7 +4012,7 @@ async def show_winner_display_settings(callback: CallbackQuery, state: FSMContex @admin_router.callback_query(F.data.startswith("admin_set_display_")) async def choose_display_type(callback: CallbackQuery, state: FSMContext): """Выбор типа отображения для конкретного розыгрыша""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -4032,7 +4051,7 @@ async def apply_display_type(callback: CallbackQuery, state: FSMContext): logger.info(f"🎭 Попытка смены типа отображения. Callback data: {callback.data}") - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): logger.warning(f"🚫 Отказ в доступе пользователю {callback.from_user.id}") await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -4096,7 +4115,7 @@ async def apply_display_type(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data == "admin_messages") async def show_messages_menu(callback: CallbackQuery): """Показать меню управления сообщениями""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -4119,7 +4138,7 @@ async def show_messages_menu(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_messages_recent") async def show_recent_messages(callback: CallbackQuery, page: int = 0): """Показать последние сообщения""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -4168,7 +4187,7 @@ async def show_recent_messages(callback: CallbackQuery, page: int = 0): @admin_router.callback_query(F.data.startswith("admin_message_view_")) async def view_message(callback: CallbackQuery): """Просмотр конкретного сообщения""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -4254,7 +4273,7 @@ async def view_message(callback: CallbackQuery): @admin_router.callback_query(F.data.startswith("admin_message_delete_")) async def delete_message(callback: CallbackQuery): """Удалить сообщение пользователя""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -4320,7 +4339,7 @@ async def delete_message(callback: CallbackQuery): @admin_router.callback_query(F.data.startswith("admin_messages_user_")) async def show_user_messages(callback: CallbackQuery): """Показать все сообщения конкретного пользователя""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Недостаточно прав", show_alert=True) return @@ -4470,7 +4489,7 @@ async def _notify_all_participants_about_results(bot, session: AsyncSession, lot @admin_router.callback_query(F.data == "admin_export_users") async def admin_export_users(callback: CallbackQuery): """Экспорт всех пользователей в XLSX""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -4568,7 +4587,7 @@ async def admin_export_users(callback: CallbackQuery): @admin_router.callback_query(F.data == "admin_import_users") async def admin_import_users_start(callback: CallbackQuery, state: FSMContext): """Начать импорт пользователей""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -4601,7 +4620,7 @@ async def admin_import_users_start(callback: CallbackQuery, state: FSMContext): @admin_router.message(StateFilter(AdminStates.import_users_json), F.document) async def admin_import_users_process(message: Message, state: FSMContext): """Обработка импорта пользователей из XLSX""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): return # Проверяем формат файла @@ -4775,7 +4794,7 @@ async def admin_import_users_process(message: Message, state: FSMContext): @admin_router.callback_query(F.data == "admin_broadcast") async def admin_broadcast_menu(callback: CallbackQuery, state: FSMContext): """Меню массовой рассылки""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -4822,7 +4841,7 @@ async def admin_broadcast_menu(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data == "admin_broadcast_start") async def admin_broadcast_start(callback: CallbackQuery, state: FSMContext): """Выбор типа рассылки""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -4851,7 +4870,7 @@ async def admin_broadcast_start(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data == "broadcast_type_direct") async def broadcast_type_direct(callback: CallbackQuery, state: FSMContext): """Рассылка в ЛС - запрос сообщения""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -4885,7 +4904,7 @@ async def broadcast_type_direct(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data.startswith("broadcast_type_")) async def broadcast_type_channel_or_group(callback: CallbackQuery, state: FSMContext): """Выбор канала или группы для рассылки""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -4939,7 +4958,7 @@ async def broadcast_type_channel_or_group(callback: CallbackQuery, state: FSMCon @admin_router.callback_query(F.data.startswith("broadcast_select_channel_")) async def broadcast_select_channel(callback: CallbackQuery, state: FSMContext): """Выбран канал/группа - запрос сообщения""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -4984,7 +5003,7 @@ async def broadcast_select_channel(callback: CallbackQuery, state: FSMContext): @admin_router.message(StateFilter(AdminStates.broadcast_message), F.text | F.photo | F.video | F.document) async def admin_broadcast_send(message: Message, state: FSMContext): """Обработка и отправка рассылки""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): return data = await state.get_data() @@ -5127,7 +5146,7 @@ async def _broadcast_channel(message: Message, state: FSMContext, data: dict): @admin_router.callback_query(F.data == "admin_broadcast_channels") async def admin_broadcast_channels_menu(callback: CallbackQuery, state: FSMContext): """Меню управления каналами""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -5171,7 +5190,7 @@ async def admin_broadcast_channels_menu(callback: CallbackQuery, state: FSMConte @admin_router.callback_query(F.data == "admin_broadcast_add_channel") async def admin_broadcast_add_channel_start(callback: CallbackQuery, state: FSMContext): """Начать добавление канала""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -5202,7 +5221,7 @@ async def admin_broadcast_add_channel_start(callback: CallbackQuery, state: FSMC @admin_router.message(StateFilter(AdminStates.broadcast_add_channel_id), F.text) async def admin_broadcast_add_channel_id(message: Message, state: FSMContext): """Обработка ID канала""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): return try: @@ -5268,7 +5287,7 @@ async def admin_broadcast_add_channel_id(message: Message, state: FSMContext): @admin_router.message(StateFilter(AdminStates.broadcast_add_channel_title), F.text) async def admin_broadcast_add_channel_description(message: Message, state: FSMContext): """Обработка описания канала""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): return data = await state.get_data() @@ -5332,7 +5351,7 @@ async def admin_broadcast_add_channel_description(message: Message, state: FSMCo @admin_router.callback_query(F.data == "admin_broadcast_stats") async def admin_broadcast_stats(callback: CallbackQuery, state: FSMContext): """Статистика рассылок""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -5386,7 +5405,7 @@ async def admin_broadcast_stats(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data == "admin_broadcast_inactive") async def admin_broadcast_inactive(callback: CallbackQuery, state: FSMContext): """Статистика по неактивным пользователям""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -5434,7 +5453,7 @@ async def admin_broadcast_inactive(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data == "admin_check_inactive_now") async def admin_check_inactive_now(callback: CallbackQuery, state: FSMContext): """Запустить проверку неактивных пользователей вручную""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -5467,7 +5486,7 @@ async def admin_check_inactive_now(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data == "admin_users") async def admin_users_menu(callback: CallbackQuery, state: FSMContext): """Меню управления пользователями""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -5504,7 +5523,7 @@ async def admin_users_menu(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data == "admin_users_search") async def admin_users_search_prompt(callback: CallbackQuery, state: FSMContext): """Запрос поискового запроса""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -5535,7 +5554,7 @@ async def admin_users_search_prompt(callback: CallbackQuery, state: FSMContext): @admin_router.message(AdminStates.user_management_search) async def admin_users_search_process(message: Message, state: FSMContext): """Обработка поискового запроса""" - if not is_admin(message.from_user.id): + if not await check_admin_access(message.from_user.id): return query = message.text.strip() @@ -5603,7 +5622,7 @@ async def admin_users_search_process(message: Message, state: FSMContext): @admin_router.callback_query(F.data.startswith("admin_users_list:")) async def admin_users_list(callback: CallbackQuery, state: FSMContext): """Список всех пользователей с пагинацией""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -5662,7 +5681,7 @@ async def admin_users_list(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data.startswith("admin_users_banned:")) async def admin_users_banned_list(callback: CallbackQuery, state: FSMContext): """Список заблокированных пользователей""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -5726,7 +5745,7 @@ async def admin_users_banned_list(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data.startswith("admin_user_view:")) async def admin_user_view(callback: CallbackQuery, state: FSMContext): """Просмотр информации о пользователе""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -5770,7 +5789,7 @@ async def admin_user_view(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data.startswith("admin_user_ban:")) async def admin_user_ban(callback: CallbackQuery, state: FSMContext): """Заблокировать пользователя в чате""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return @@ -5792,7 +5811,7 @@ async def admin_user_ban(callback: CallbackQuery, state: FSMContext): @admin_router.callback_query(F.data.startswith("admin_user_unban:")) async def admin_user_unban(callback: CallbackQuery, state: FSMContext): """Разблокировать пользователя в чате""" - if not is_admin(callback.from_user.id): + if not await check_admin_access(callback.from_user.id): await callback.answer("❌ Доступ запрещен", show_alert=True) return