Compare commits

...

2 Commits

Author SHA1 Message Date
815cc544d5 Merge pull request 'feat: Allow assigned admins to access admin panel via command and buttons' (#6) from v2_functions into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #6
2026-02-18 04:29:01 +00:00
6b24388faa feat: Allow assigned admins to access admin panel via command and buttons
Some checks failed
continuous-integration/drone/pr Build is failing
- Modified check_admin_access() to check both super admins (.env) and assigned admins (DB)
- Updated /admin command handler to support both admin types
- Replaced all is_admin() checks with async check_admin_access() in admin panel
- Assigned admins can now use /admin command and navigate via buttons
- Super admin check (is_super_admin) remains unchanged for admin management
- Added proper async/await for database queries in all admin checks
2026-02-18 13:28:29 +09:00
3 changed files with 146 additions and 107 deletions

1
.gitignore vendored
View File

@@ -60,3 +60,4 @@ venv.bak/
# Системные файлы
.DS_Store
Thumbs.db.bot.pid
*.bak

21
main.py
View File

@@ -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

View File

@@ -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