diff --git a/handlers/admin/admin.py b/handlers/admin/admin.py index ed2cd4f2..fa41353f 100644 --- a/handlers/admin/admin.py +++ b/handlers/admin/admin.py @@ -15,96 +15,96 @@ from database import ( get_tg_id_by_client_id, update_key_expiry, ) -from middlewares.admin import admin_only router = Router() @router.message(Command("add_balance")) -@admin_only() -async def cmd_add_balance(message: types.Message): - try: - _, client_id, amount = message.text.split() - amount = float(amount) +async def cmd_add_balance(message: types.Message, is_admin: bool): + if is_admin: + try: + _, client_id, amount = message.text.split() + amount = float(amount) - if not await check_connection_exists(int(client_id)): - await message.reply(f"Клиент с ID {client_id} не найден.") - return + if not await check_connection_exists(int(client_id)): + await message.reply(f"Клиент с ID {client_id} не найден.") + return - await add_balance_to_client(int(client_id), amount) - await message.reply(f"Баланс клиента {client_id} увеличен на {amount} у.е.") - except ValueError: - await message.reply( - "Пожалуйста, используйте формат: /add_balance " - ) - except Exception as e: - await message.reply(f"Произошла ошибка: {e}") + await add_balance_to_client(int(client_id), amount) + await message.reply(f"Баланс клиента {client_id} увеличен на {amount} у.е.") + except ValueError: + await message.reply( + "Пожалуйста, используйте формат: /add_balance " + ) + except Exception as e: + await message.reply(f"Произошла ошибка: {e}") @router.message(Command("update_key_expiry")) -@admin_only() -async def cmd_update_key_expiry(message: types.Message): - try: - parts = message.text.split(maxsplit=2) - if len(parts) != 3: +async def cmd_update_key_expiry(message: types.Message, is_admin: bool): + if is_admin: + try: + parts = message.text.split(maxsplit=2) + if len(parts) != 3: + await message.reply( + "Пожалуйста, используйте формат: /update_key_expiry " + ) + return + + _, email, expiry_time_str = parts + expiry_time = int( + datetime.strptime(expiry_time_str, "%Y-%m-%d %H:%M:%S").timestamp() + * 1000 + ) + + client_id = await get_client_id_by_email(email) + if client_id is None: + await message.reply(f"Клиент с email {email} не найден.") + return + + await update_key_expiry(client_id, expiry_time) + + conn = await asyncpg.connect(DATABASE_URL) + try: + record = await conn.fetchrow( + "SELECT server_id FROM keys WHERE client_id = $1", client_id + ) + if not record: + await message.reply("Клиент не найден в базе данных.") + return + + server_id = record["server_id"] + tg_id = await get_tg_id_by_client_id(client_id) + + session = await login_with_credentials( + server_id, ADMIN_USERNAME, ADMIN_PASSWORD + ) + + logger.info( + f"Попытка обновить панель для server_id: {server_id}, tg_id: {tg_id}, client_id: {client_id}, email: {email}, expiryTime: {expiry_time}" + ) + + success = await extend_client_key_admin( + session, server_id, tg_id, client_id, email, expiry_time + ) + + logger.info( + f"Статус обновления панели: {'Успешно' if success else 'Не удалось'}" + ) + if success: + await message.reply( + f"Время истечения ключа для клиента {client_id} ({email}) обновлено и синхронизировано с панелью." + ) + else: + await message.reply( + f"Время истечения ключа для клиента {client_id} ({email}) обновлено, но не удалось синхронизировать с панелью." + ) + + finally: + await conn.close() + except ValueError: await message.reply( "Пожалуйста, используйте формат: /update_key_expiry " ) - return - - _, email, expiry_time_str = parts - expiry_time = int( - datetime.strptime(expiry_time_str, "%Y-%m-%d %H:%M:%S").timestamp() * 1000 - ) - - client_id = await get_client_id_by_email(email) - if client_id is None: - await message.reply(f"Клиент с email {email} не найден.") - return - - await update_key_expiry(client_id, expiry_time) - - conn = await asyncpg.connect(DATABASE_URL) - try: - record = await conn.fetchrow( - "SELECT server_id FROM keys WHERE client_id = $1", client_id - ) - if not record: - await message.reply("Клиент не найден в базе данных.") - return - - server_id = record["server_id"] - tg_id = await get_tg_id_by_client_id(client_id) - - session = await login_with_credentials( - server_id, ADMIN_USERNAME, ADMIN_PASSWORD - ) - - logger.info( - f"Попытка обновить панель для server_id: {server_id}, tg_id: {tg_id}, client_id: {client_id}, email: {email}, expiryTime: {expiry_time}" - ) - - success = await extend_client_key_admin( - session, server_id, tg_id, client_id, email, expiry_time - ) - - logger.info( - f"Статус обновления панели: {'Успешно' if success else 'Не удалось'}" - ) - if success: - await message.reply( - f"Время истечения ключа для клиента {client_id} ({email}) обновлено и синхронизировано с панелью." - ) - else: - await message.reply( - f"Время истечения ключа для клиента {client_id} ({email}) обновлено, но не удалось синхронизировать с панелью." - ) - - finally: - await conn.close() - except ValueError: - await message.reply( - "Пожалуйста, используйте формат: /update_key_expiry " - ) - except Exception as e: - await message.reply(f"Произошла ошибка: {e}") + except Exception as e: + await message.reply(f"Произошла ошибка: {e}") diff --git a/handlers/admin/admin_panel.py b/handlers/admin/admin_panel.py index 5253c3e5..8a4db300 100644 --- a/handlers/admin/admin_panel.py +++ b/handlers/admin/admin_panel.py @@ -17,7 +17,6 @@ from backup import backup_database from bot import bot from config import ADMIN_ID, DATABASE_URL from handlers.commands import send_message_to_all_clients -from middlewares.admin import admin_only router = Router() @@ -28,96 +27,100 @@ class UserEditorState(StatesGroup): @router.message(Command("admin")) -@admin_only() -async def handle_admin_command(message: types.Message): - keyboard = InlineKeyboardMarkup( - inline_keyboard=[ - [ - InlineKeyboardButton( - text="Статистика пользователей", callback_data="user_stats" - ) - ], - [ - InlineKeyboardButton( - text="Редактор пользователей", callback_data="user_editor" - ) - ], - [ - InlineKeyboardButton( - text="Отправить сообщение всем клиентам", - callback_data="send_to_alls", - ) - ], - [InlineKeyboardButton(text="Создать бэкап", callback_data="backups")], - [ - InlineKeyboardButton( - text="Перезапустить бота", callback_data="restart_bot" - ) - ], - ] - ) - await bot.send_message( - message.chat.id, "Панель администратора", reply_markup=keyboard - ) +async def handle_admin_command(message: types.Message, is_admin: bool): + if is_admin: + keyboard = InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text="Статистика пользователей", callback_data="user_stats" + ) + ], + [ + InlineKeyboardButton( + text="Редактор пользователей", callback_data="user_editor" + ) + ], + [ + InlineKeyboardButton( + text="Отправить сообщение всем клиентам", + callback_data="send_to_alls", + ) + ], + [InlineKeyboardButton(text="Создать бэкап", callback_data="backups")], + [ + InlineKeyboardButton( + text="Перезапустить бота", callback_data="restart_bot" + ) + ], + ] + ) + await bot.send_message( + message.chat.id, "Панель администратора.", reply_markup=keyboard + ) + else: + await bot.send_message(message.chat.id, "У вас нет доступа к этой команде.") @router.callback_query(F.data == "user_stats") -@admin_only() -async def user_stats_menu(callback_query: CallbackQuery): - conn = await asyncpg.connect(DATABASE_URL) - try: - total_users = await conn.fetchval("SELECT COUNT(*) FROM connections") - total_keys = await conn.fetchval("SELECT COUNT(*) FROM keys") - total_referrals = await conn.fetchval("SELECT COUNT(*) FROM referrals") +async def user_stats_menu(callback_query: CallbackQuery, is_admin: bool): + if is_admin: + conn = await asyncpg.connect(DATABASE_URL) + try: + total_users = await conn.fetchval("SELECT COUNT(*) FROM connections") + total_keys = await conn.fetchval("SELECT COUNT(*) FROM keys") + total_referrals = await conn.fetchval("SELECT COUNT(*) FROM referrals") - active_keys = await conn.fetchval( - "SELECT COUNT(*) FROM keys WHERE expiry_time > $1", - int(datetime.utcnow().timestamp() * 1000), - ) - expired_keys = total_keys - active_keys + active_keys = await conn.fetchval( + "SELECT COUNT(*) FROM keys WHERE expiry_time > $1", + int(datetime.utcnow().timestamp() * 1000), + ) + expired_keys = total_keys - active_keys - stats_message = ( - f"🔹 Общая статистика пользователей:\n" - f"• Всего пользователей: {total_users}\n" - f"• Всего ключей: {total_keys}\n" - f"• Всего рефералов: {total_referrals}\n" - f"• Активные ключи: {active_keys}\n" - f"• Истекшие ключи: {expired_keys}" - ) + stats_message = ( + f"🔹 Общая статистика пользователей:\n" + f"• Всего пользователей: {total_users}\n" + f"• Всего ключей: {total_keys}\n" + f"• Всего рефералов: {total_referrals}\n" + f"• Активные ключи: {active_keys}\n" + f"• Истекшие ключи: {expired_keys}" + ) - back_button = InlineKeyboardButton( - text="Назад", callback_data="back_to_admin_menu" - ) - keyboard = InlineKeyboardMarkup(inline_keyboard=[[back_button]]) + back_button = InlineKeyboardButton( + text="Назад", callback_data="back_to_admin_menu" + ) + keyboard = InlineKeyboardMarkup(inline_keyboard=[[back_button]]) - await callback_query.message.edit_text( - stats_message, reply_markup=keyboard, parse_mode="HTML" - ) - finally: - await conn.close() - - await callback_query.answer() + await callback_query.message.edit_text( + stats_message, reply_markup=keyboard, parse_mode="HTML" + ) + finally: + await conn.close() + await callback_query.answer() @router.callback_query(F.data == "send_to_alls") -@admin_only() -async def handle_send_to_all(callback_query: CallbackQuery, state: FSMContext): - await send_message_to_all_clients(callback_query.message, state, from_panel=True) - await callback_query.answer() +async def handle_send_to_all( + callback_query: CallbackQuery, state: FSMContext, is_admin: bool +): + if is_admin: + await send_message_to_all_clients( + callback_query.message, state, from_panel=True + ) + await callback_query.answer() @router.callback_query(F.data == "backups") -@admin_only() -async def handle_backup(message: Message): - await message.answer("Запускаю бэкап базы данных...") - await backup_database() - await message.answer("Бэкап завершен и отправлен админу.") +async def handle_backup(message: Message, is_admin: bool): + if is_admin: + await message.answer("Запускаю бэкап базы данных...") + await backup_database() + await message.answer("Бэкап завершен и отправлен админу.") @router.callback_query(F.data == "restart_bot") -@admin_only() -async def handle_restart(callback_query: CallbackQuery): - if callback_query.from_user.id == ADMIN_ID: +async def handle_restart(callback_query: CallbackQuery, is_admin: bool): + if is_admin: try: result = subprocess.run( ["sudo", "systemctl", "restart", "bot.service"], @@ -130,47 +133,44 @@ async def handle_restart(callback_query: CallbackQuery): await callback_query.message.answer( f"Бот будет перезапущен через 30 секунд {e.stderr}" ) - else: - await callback_query.answer( - "У вас нет доступа к этой команде.", show_alert=True - ) @router.callback_query(F.data == "user_editor") -@admin_only() -async def user_editor_menu(callback_query: CallbackQuery): - keyboard = InlineKeyboardMarkup( - inline_keyboard=[ - [ - InlineKeyboardButton( - text="Поиск по имени ключа", callback_data="search_by_key_name" - ) - ], - [ - InlineKeyboardButton( - text="Поиск по tg_id", callback_data="search_by_tg_id" - ) - ], - [ - InlineKeyboardButton(text="Назад", callback_data="back_to_admin_menu") - ], # Back button - ] - ) - await callback_query.message.edit_text( - "Выберите метод поиска:", reply_markup=keyboard - ) +async def user_editor_menu(callback_query: CallbackQuery, is_admin: bool): + if is_admin: + keyboard = InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text="Поиск по имени ключа", callback_data="search_by_key_name" + ) + ], + [ + InlineKeyboardButton( + text="Поиск по tg_id", callback_data="search_by_tg_id" + ) + ], + [ + InlineKeyboardButton( + text="Назад", callback_data="back_to_admin_menu" + ) + ], # Back button + ] + ) + await callback_query.message.edit_text( + "Выберите метод поиска:", reply_markup=keyboard + ) @router.callback_query(F.data == "back_to_admin_menu") -@admin_only() -async def back_to_admin_menu(callback_query: CallbackQuery): +async def back_to_admin_menu(callback_query: CallbackQuery, is_admin: bool): try: await callback_query.message.delete() except Exception: pass tg_id = callback_query.from_user.id - if tg_id == ADMIN_ID: + if is_admin: keyboard = InlineKeyboardMarkup( inline_keyboard=[ [ @@ -198,8 +198,6 @@ async def back_to_admin_menu(callback_query: CallbackQuery): ] ) await bot.send_message(tg_id, "Панель администратора", reply_markup=keyboard) - else: - await bot.send_message(tg_id, "У вас нет доступа к этой команде.") async def handle_error(tg_id, callback_query, message): diff --git a/middlewares/admin.py b/middlewares/admin.py index 92cb2212..f709d3cf 100644 --- a/middlewares/admin.py +++ b/middlewares/admin.py @@ -28,30 +28,3 @@ class AdminMiddleware(BaseMiddleware): data["is_admin"] = True return await handler(event, data) - - -def admin_only(): - def decorator(func): - @wraps(func) - async def wrapper(*args, **kwargs): - # Извлекаем объект события (Message или CallbackQuery) - event = args[0] - - # Определяем ID пользователя - user_id = event.from_user.id if hasattr(event, "from_user") else None - - if user_id not in int(ADMIN_ID): - # Можно отправить сообщение или просто return - if isinstance(event, Message): - await event.answer("У вас нет доступа к этой команде.") - elif isinstance(event, CallbackQuery): - await event.answer( - "У вас нет доступа к этому действию.", show_alert=True - ) - return None - - return await func(*args, **kwargs) - - return wrapper - - return decorator