diff --git a/backup.py b/backup.py index 708595c5..196e024a 100644 --- a/backup.py +++ b/backup.py @@ -99,17 +99,12 @@ async def create_backup_and_send_to_admins(xui) -> None: async def _send_backup_to_admins(backup_file_path: str) -> None: try: from bot import bot + with open(backup_file_path, "rb") as backup_file: - backup_input_file = BufferedInputFile( - file=backup_file.read(), - filename=os.path.basename(backup_file_path) - ) + backup_input_file = BufferedInputFile(file=backup_file.read(), filename=os.path.basename(backup_file_path)) admin_ids = ADMIN_ID if isinstance(ADMIN_ID, list) else [ADMIN_ID] for admin_id in admin_ids: - await bot.send_document( - chat_id=admin_id, - document=backup_input_file - ) + await bot.send_document(chat_id=admin_id, document=backup_input_file) logger.info(f"Бэкап базы данных отправлен админу: {admin_id}") except Exception as e: logger.error(f"Ошибка при отправке бэкапа в Telegram: {e}") diff --git a/handlers/admin/admin_backups.py b/handlers/admin/admin_backups.py index 51eee005..e838b891 100644 --- a/handlers/admin/admin_backups.py +++ b/handlers/admin/admin_backups.py @@ -12,14 +12,11 @@ router = Router() AdminPanelCallback.filter(F.action == "backups"), IsAdminFilter(), ) -async def handle_backups( - callback_query: CallbackQuery -): +async def handle_backups(callback_query: CallbackQuery): kb = build_admin_back_kb("management") await callback_query.message.edit_text( - text="💾 Инициализация резервного копирования базы данных...", - reply_markup=kb + text="💾 Инициализация резервного копирования базы данных...", reply_markup=kb ) exception = await backup_database() @@ -29,7 +26,4 @@ async def handle_backups( else: text = "✅ Резервная копия успешно создана и отправлена администраторам." - await callback_query.message.edit_text( - text=text, - reply_markup=kb - ) + await callback_query.message.edit_text(text=text, reply_markup=kb) diff --git a/handlers/admin/admin_bans.py b/handlers/admin/admin_bans.py index a515a14e..9ab8e7cf 100644 --- a/handlers/admin/admin_bans.py +++ b/handlers/admin/admin_bans.py @@ -15,13 +15,8 @@ router = Router() AdminPanelCallback.filter(F.action == "bans"), IsAdminFilter(), ) -async def handle_bans( - callback_query: CallbackQuery -): - text = ( - "🚫 Заблокировавшие бота" - "\n\nЗдесь можно просматривать и удалять пользователей, которые забанили вашего бота!" - ) +async def handle_bans(callback_query: CallbackQuery): + text = "🚫 Заблокировавшие бота\n\nЗдесь можно просматривать и удалять пользователей, которые забанили вашего бота!" await callback_query.message.edit_text( text=text, @@ -33,10 +28,7 @@ async def handle_bans( AdminPanelCallback.filter(F.action == "bans_export"), IsAdminFilter(), ) -async def handle_bans_export( - callback_query: CallbackQuery, - session: Any -): +async def handle_bans_export(callback_query: CallbackQuery, session: Any): kb = build_admin_back_kb("management") try: @@ -53,9 +45,7 @@ async def handle_bans_export( csv_output.seek(0) - document = BufferedInputFile( - file=csv_output.getvalue().encode("utf-8"), filename="banned_users.csv" - ) + document = BufferedInputFile(file=csv_output.getvalue().encode("utf-8"), filename="banned_users.csv") await callback_query.message.answer_document( document=document, @@ -72,10 +62,7 @@ async def handle_bans_export( AdminPanelCallback.filter(F.action == "bans_delete_banned"), IsAdminFilter(), ) -async def handle_bans_delete_banned( - callback_query: CallbackQuery, - session: Any -): +async def handle_bans_delete_banned(callback_query: CallbackQuery, session: Any): kb = build_admin_back_kb("bans") try: @@ -92,9 +79,7 @@ async def handle_bans_delete_banned( for tg_id in blocked_ids: await delete_user_data(session, tg_id) - await session.execute( - "DELETE FROM blocked_users WHERE tg_id = ANY($1)", blocked_ids - ) + await session.execute("DELETE FROM blocked_users WHERE tg_id = ANY($1)", blocked_ids) await callback_query.message.answer( text=f"🗑️ Удалены данные о {len(blocked_ids)} пользователях и связанных записях.", diff --git a/handlers/admin/admin_coupons.py b/handlers/admin/admin_coupons.py index ba930fa0..b65ea5e4 100644 --- a/handlers/admin/admin_coupons.py +++ b/handlers/admin/admin_coupons.py @@ -22,22 +22,16 @@ class AdminCouponsState(StatesGroup): IsAdminFilter(), ) async def handle_coupons( - callback_query: types.CallbackQuery, + callback_query: types.CallbackQuery, ): - await callback_query.message.edit_text( - text="🛠 Меню управления купонами:", - reply_markup=build_coupons_kb() - ) + await callback_query.message.edit_text(text="🛠 Меню управления купонами:", reply_markup=build_coupons_kb()) @router.callback_query( AdminPanelCallback.filter(F.action == "coupons_create"), IsAdminFilter(), ) -async def handle_coupons_create( - callback_query: types.CallbackQuery, - state: FSMContext -): +async def handle_coupons_create(callback_query: types.CallbackQuery, state: FSMContext): text = ( "🎫 Введите данные для создания купона в формате:\n\n" "📝 код 💰 сумма 🔢 лимит\n\n" @@ -51,15 +45,8 @@ async def handle_coupons_create( await state.set_state(AdminCouponsState.waiting_for_coupon_data) -@router.message( - AdminCouponsState.waiting_for_coupon_data, - IsAdminFilter() -) -async def handle_coupon_data_input( - message: types.Message, - state: FSMContext, - session: Any -): +@router.message(AdminCouponsState.waiting_for_coupon_data, IsAdminFilter()) +async def handle_coupon_data_input(message: types.Message, state: FSMContext, session: Any): text = message.text.strip() parts = text.split() @@ -83,10 +70,7 @@ async def handle_coupon_data_input( coupon_amount = float(parts[1]) usage_limit = int(parts[2]) except ValueError: - text = ( - "⚠️ Проверьте правильность введенных данных!\n" - "💱 Сумма должна быть числом, а лимит — целым числом." - ) + text = "⚠️ Проверьте правильность введенных данных!\n💱 Сумма должна быть числом, а лимит — целым числом." await message.answer( text=text, @@ -103,10 +87,7 @@ async def handle_coupon_data_input( f"🔢 Лимит использования: {usage_limit} раз" ) - await message.answer( - text=text, - reply_markup=kb - ) + await message.answer(text=text, reply_markup=kb) await state.clear() except Exception as e: @@ -117,10 +98,7 @@ async def handle_coupon_data_input( AdminPanelCallback.filter(F.action == "coupons_list"), IsAdminFilter(), ) -async def handle_coupons_list( - callback_query: types.CallbackQuery, - session: Any -): +async def handle_coupons_list(callback_query: types.CallbackQuery, session: Any): try: page = int(callback_query.data.split(":")[1]) if ":" in callback_query.data else 1 per_page = 10 @@ -147,10 +125,7 @@ async def handle_coupons_list( f"✅ Использовано: {coupon['usage_count']} раз\n\n" ) - await callback_query.message.edit_text( - text=coupon_list, - reply_markup=kb - ) + await callback_query.message.edit_text(text=coupon_list, reply_markup=kb) except Exception as e: logger.error(f"Ошибка при получении списка купонов: {e}") @@ -162,9 +137,7 @@ async def handle_coupons_list( IsAdminFilter(), ) async def handle_coupon_delete( - callback_query: types.CallbackQuery, - callback_data: AdminCouponDeleteCallback, - session: Any + callback_query: types.CallbackQuery, callback_data: AdminCouponDeleteCallback, session: Any ): coupon_code = callback_data.coupon_code diff --git a/handlers/admin/admin_panel.py b/handlers/admin/admin_panel.py index a5594caa..eb9eb744 100644 --- a/handlers/admin/admin_panel.py +++ b/handlers/admin/admin_panel.py @@ -10,52 +10,28 @@ from keyboards.admin.panel_kb import build_panel_kb, AdminPanelCallback, build_m router = Router() -@router.callback_query( - AdminPanelCallback.filter(F.action == "admin"), - IsAdminFilter() -) +@router.callback_query(AdminPanelCallback.filter(F.action == "admin"), IsAdminFilter()) async def handle_admin_callback_query(callback_query: CallbackQuery, state: FSMContext): - text = ( - "🤖 Панель администратора" - f"\n📌 Версия бота: {version}" - ) + text = f"🤖 Панель администратора\n📌 Версия бота: {version}" await state.clear() - await callback_query.message.edit_text( - text=text, - reply_markup=build_panel_kb() - ) + await callback_query.message.edit_text(text=text, reply_markup=build_panel_kb()) -@router.callback_query( - F.data == "admin", - IsAdminFilter() -) +@router.callback_query(F.data == "admin", IsAdminFilter()) async def handle_admin_callback_query(callback_query: CallbackQuery, state: FSMContext): await handle_admin_message(callback_query.message, state) -@router.message( - Command("admin"), - IsAdminFilter() -) +@router.message(Command("admin"), IsAdminFilter()) async def handle_admin_message(message: types.Message, state: FSMContext): - text = ( - "🤖 Панель администратора" - f"\n📌 Версия бота: {version}" - ) + text = f"🤖 Панель администратора\n📌 Версия бота: {version}" await state.clear() - await message.answer( - text=text, - reply_markup=build_panel_kb() - ) + await message.answer(text=text, reply_markup=build_panel_kb()) -@router.callback_query( - AdminPanelCallback.filter(F.action == "management"), - IsAdminFilter() -) +@router.callback_query(AdminPanelCallback.filter(F.action == "management"), IsAdminFilter()) async def handle_management(callback_query: CallbackQuery): await callback_query.message.edit_text( text="🤖 Управление ботом", diff --git a/handlers/admin/admin_restart.py b/handlers/admin/admin_restart.py index 157bf13b..58c1a115 100644 --- a/handlers/admin/admin_restart.py +++ b/handlers/admin/admin_restart.py @@ -33,17 +33,8 @@ async def handle_restart_confirm(callback_query: CallbackQuery): capture_output=True, text=True, ) - await callback_query.message.edit_text( - text="🔄 Бот успешно перезагружен!", - reply_markup=kb - ) + await callback_query.message.edit_text(text="🔄 Бот успешно перезагружен!", reply_markup=kb) except subprocess.CalledProcessError: - await callback_query.message.edit_text( - text="🔄 Бот успешно перезагружен!", - reply_markup=kb - ) + await callback_query.message.edit_text(text="🔄 Бот успешно перезагружен!", reply_markup=kb) except Exception as e: - await callback_query.message.edit_text( - text=f"⚠️ Ошибка при перезагрузке бота: {e.stderr}", - reply_markup=kb - ) + await callback_query.message.edit_text(text=f"⚠️ Ошибка при перезагрузке бота: {e.stderr}", reply_markup=kb) diff --git a/handlers/admin/admin_sender.py b/handlers/admin/admin_sender.py index e82598bd..70563437 100644 --- a/handlers/admin/admin_sender.py +++ b/handlers/admin/admin_sender.py @@ -22,9 +22,7 @@ class AdminSender(StatesGroup): AdminPanelCallback.filter(F.action == "sender"), IsAdminFilter(), ) -async def handle_sender( - callback_query: CallbackQuery -): +async def handle_sender(callback_query: CallbackQuery): await callback_query.message.edit_text( text="✍️ Выберите группу пользователей для рассылки:", reply_markup=build_sender_kb(), @@ -35,11 +33,7 @@ async def handle_sender( AdminSenderCallback.filter(), IsAdminFilter(), ) -async def handle_sender_callback( - callback_query: CallbackQuery, - callback_data: AdminSenderCallback, - state: FSMContext -): +async def handle_sender_callback(callback_query: CallbackQuery, callback_data: AdminSenderCallback, state: FSMContext): await callback_query.message.edit_text( text="✍️ Введите текст сообщения для рассылки:", reply_markup=build_admin_back_kb("sender"), @@ -52,11 +46,7 @@ async def handle_sender_callback( AdminSender.waiting_for_message, IsAdminFilter(), ) -async def handle_message_input( - message: types.Message, - state: FSMContext, - session: Any -): +async def handle_message_input(message: types.Message, state: FSMContext, session: Any): text_message = message.text try: @@ -64,20 +54,26 @@ async def handle_message_input( send_to = state_data.get("type", "all") if send_to == "subscribed": - tg_ids = await session.fetch(""" + tg_ids = await session.fetch( + """ SELECT DISTINCT c.tg_id FROM connections c JOIN keys k ON c.tg_id = k.tg_id WHERE k.expiry_time > $1 - """, int(datetime.utcnow().timestamp() * 1000)) + """, + int(datetime.utcnow().timestamp() * 1000), + ) elif send_to == "unsubscribed": - tg_ids = await session.fetch(""" + tg_ids = await session.fetch( + """ SELECT c.tg_id FROM connections c LEFT JOIN keys k ON c.tg_id = k.tg_id GROUP BY c.tg_id HAVING COUNT(k.tg_id) = 0 OR MAX(k.expiry_time) <= $1 - """, int(datetime.utcnow().timestamp() * 1000)) + """, + int(datetime.utcnow().timestamp() * 1000), + ) else: tg_ids = await session.fetch("SELECT DISTINCT tg_id FROM connections") @@ -87,10 +83,7 @@ async def handle_message_input( for record in tg_ids: tg_id = record["tg_id"] try: - await message.bot.send_message( - chat_id=tg_id, - text=text_message - ) + await message.bot.send_message(chat_id=tg_id, text=text_message) success_count += 1 except Exception: pass @@ -102,10 +95,7 @@ async def handle_message_input( f"\n❌ Не доставлено: {total_users - success_count}" ) - await message.answer( - text=text, - reply_markup=build_admin_back_kb("stats") - ) + await message.answer(text=text, reply_markup=build_admin_back_kb("stats")) except Exception as e: logger.error(f"❗ Ошибка при подключении к базе данных: {e}") diff --git a/handlers/admin/admin_servers.py b/handlers/admin/admin_servers.py index 84675bfc..51257e9a 100644 --- a/handlers/admin/admin_servers.py +++ b/handlers/admin/admin_servers.py @@ -9,9 +9,13 @@ from config import ADMIN_PASSWORD, ADMIN_USERNAME, DATABASE_URL from database import create_server, check_unique_server_name, delete_server, get_keys_by_server, get_servers from filters.admin import IsAdminFilter from keyboards.admin.panel_kb import AdminPanelCallback, build_admin_back_kb -from keyboards.admin.servers_kb import build_manage_server_kb, \ - build_delete_server_kb, \ - build_manage_cluster_kb, build_clusters_editor_kb, AdminServerEditorCallback +from keyboards.admin.servers_kb import ( + build_manage_server_kb, + build_delete_server_kb, + build_manage_cluster_kb, + build_clusters_editor_kb, + AdminServerEditorCallback, +) router = Router() @@ -28,9 +32,7 @@ class AdminServersEditor(StatesGroup): AdminPanelCallback.filter(F.action == "servers"), IsAdminFilter(), ) -async def handle_servers( - callback_query: types.CallbackQuery -): +async def handle_servers(callback_query: types.CallbackQuery): servers = await get_servers_from_db() text = ( @@ -51,36 +53,23 @@ async def handle_servers( AdminPanelCallback.filter(F.action == "clusters_add"), IsAdminFilter(), ) -async def handle_clusters_add( - callback_query: types.CallbackQuery, - state: FSMContext -): +async def handle_clusters_add(callback_query: types.CallbackQuery, state: FSMContext): text = ( "🔧 Введите имя нового кластера:\n\n" "Имя кластера должно быть уникальным!\n" "Пример: cluster1 или us_east_1" ) - await callback_query.message.edit_text( - text=text, - reply_markup=build_admin_back_kb("servers") - ) + await callback_query.message.edit_text(text=text, reply_markup=build_admin_back_kb("servers")) await state.set_state(AdminServersEditor.waiting_for_cluster_name) -@router.message( - AdminServersEditor.waiting_for_cluster_name, - IsAdminFilter() -) -async def handle_cluster_name_input( - message: types.Message, - state: FSMContext -): +@router.message(AdminServersEditor.waiting_for_cluster_name, IsAdminFilter()) +async def handle_cluster_name_input(message: types.Message, state: FSMContext): if not message.text: await message.answer( - text="❌ Имя кластера не может быть пустым. Попробуйте снова.", - reply_markup=build_admin_back_kb("servers") + text="❌ Имя кластера не может быть пустым. Попробуйте снова.", reply_markup=build_admin_back_kb("servers") ) return @@ -101,18 +90,11 @@ async def handle_cluster_name_input( await state.set_state(AdminServersEditor.waiting_for_server_name) -@router.message( - AdminServersEditor.waiting_for_server_name, - IsAdminFilter() -) -async def handle_server_name_input( - message: types.Message, - state: FSMContext -): +@router.message(AdminServersEditor.waiting_for_server_name, IsAdminFilter()) +async def handle_server_name_input(message: types.Message, state: FSMContext): if not message.text: await message.answer( - text="❌ Имя сервера не может быть пустым. Попробуйте снова.", - reply_markup=build_admin_back_kb("servers") + text="❌ Имя сервера не может быть пустым. Попробуйте снова.", reply_markup=build_admin_back_kb("servers") ) return @@ -121,7 +103,7 @@ async def handle_server_name_input( if not await check_unique_server_name(server_name): await message.answer( text="❌ Сервер с таким именем уже существует. Пожалуйста, выберите другое имя.", - reply_markup=build_admin_back_kb("servers") + reply_markup=build_admin_back_kb("servers"), ) return @@ -144,18 +126,12 @@ async def handle_server_name_input( await state.set_state(AdminServersEditor.waiting_for_api_url) -@router.message( - AdminServersEditor.waiting_for_api_url, - IsAdminFilter() -) -async def handle_api_url_input( - message: types.Message, - state: FSMContext -): +@router.message(AdminServersEditor.waiting_for_api_url, IsAdminFilter()) +async def handle_api_url_input(message: types.Message, state: FSMContext): if not message.text or not message.text.strip().startswith("https://"): await message.answer( text="❌ API URL должен начинаться с https://. Попробуйте снова.", - reply_markup=build_admin_back_kb("servers") + reply_markup=build_admin_back_kb("servers"), ) return @@ -182,18 +158,12 @@ async def handle_api_url_input( await state.set_state(AdminServersEditor.waiting_for_subscription_url) -@router.message( - AdminServersEditor.waiting_for_subscription_url, - IsAdminFilter() -) -async def handle_subscription_url_input( - message: types.Message, - state: FSMContext -): +@router.message(AdminServersEditor.waiting_for_subscription_url, IsAdminFilter()) +async def handle_subscription_url_input(message: types.Message, state: FSMContext): if not message.text or not message.text.strip().startswith("https://"): await message.answer( text="❌ subscription_url должен начинаться с https://. Попробуйте снова.", - reply_markup=build_admin_back_kb("servers") + reply_markup=build_admin_back_kb("servers"), ) return @@ -216,20 +186,14 @@ async def handle_subscription_url_input( await state.set_state(AdminServersEditor.waiting_for_inbound_id) -@router.message( - AdminServersEditor.waiting_for_inbound_id, - IsAdminFilter() -) -async def handle_inbound_id_input( - message: types.Message, - state: FSMContext -): +@router.message(AdminServersEditor.waiting_for_inbound_id, IsAdminFilter()) +async def handle_inbound_id_input(message: types.Message, state: FSMContext): inbound_id = message.text.strip() if not inbound_id.isdigit(): await message.answer( text="❌ inbound_id должен быть числовым значением. Попробуйте снова.", - reply_markup=build_admin_back_kb("servers") + reply_markup=build_admin_back_kb("servers"), ) return @@ -261,13 +225,10 @@ async def handle_inbound_id_input( await state.clear() -@router.callback_query( - AdminServerEditorCallback.filter(F.action == "clusters_manage"), - IsAdminFilter() -) +@router.callback_query(AdminServerEditorCallback.filter(F.action == "clusters_manage"), IsAdminFilter()) async def handle_clusters_manage( - callback_query: types.CallbackQuery, - callback_data: AdminServerEditorCallback, + callback_query: types.CallbackQuery, + callback_data: AdminServerEditorCallback, ): cluster_name = callback_data.data @@ -280,23 +241,15 @@ async def handle_clusters_manage( ) -@router.callback_query( - AdminServerEditorCallback.filter(F.action == "servers_availability"), - IsAdminFilter() -) -async def handle_servers_availability( - callback_query: types.CallbackQuery, - callback_data: AdminServerEditorCallback -): +@router.callback_query(AdminServerEditorCallback.filter(F.action == "servers_availability"), IsAdminFilter()) +async def handle_servers_availability(callback_query: types.CallbackQuery, callback_data: AdminServerEditorCallback): cluster_name = callback_data.data servers = await get_servers(session) cluster_servers = servers.get(cluster_name, []) if not cluster_servers: - await callback_query.message.answer( - text=f"Кластер '{cluster_name}' не содержит серверов." - ) + await callback_query.message.answer(text=f"Кластер '{cluster_name}' не содержит серверов.") return text = ( @@ -304,13 +257,9 @@ async def handle_servers_availability( "Это может занять до 1 минуты, пожалуйста, подождите..." ) - in_progress_message = await callback_query.message.answer( - text=text - ) + in_progress_message = await callback_query.message.answer(text=text) - text = ( - f"🖥️ Проверка доступности серверов для кластера {cluster_name} завершена:\n\n" - ) + text = f"🖥️ Проверка доступности серверов для кластера {cluster_name} завершена:\n\n" for server in cluster_servers: xui = AsyncApi(server["api_url"], username=ADMIN_USERNAME, password=ADMIN_PASSWORD) @@ -319,34 +268,21 @@ async def handle_servers_availability( await xui.login() online_users = len(await xui.client.online()) - text += ( - f"🌍 {server['server_name']}: {online_users} активных пользователей.\n" - ) + text += f"🌍 {server['server_name']}: {online_users} активных пользователей.\n" except Exception as e: text += f"❌ {server['server_name']}: Не удалось получить информацию. Ошибка: {e}\n" - await in_progress_message.edit_text( - text=text, - reply_markup=build_admin_back_kb("servers") - ) + await in_progress_message.edit_text(text=text, reply_markup=build_admin_back_kb("servers")) -@router.callback_query( - AdminServerEditorCallback.filter(F.action == "servers_manage"), - IsAdminFilter() -) -async def handle_servers_manage( - callback_query: types.CallbackQuery, - callback_data: AdminServerEditorCallback -): +@router.callback_query(AdminServerEditorCallback.filter(F.action == "servers_manage"), IsAdminFilter()) +async def handle_servers_manage(callback_query: types.CallbackQuery, callback_data: AdminServerEditorCallback): server_name = callback_data.data servers = await get_servers_from_db() cluster_name, server = next( - ((c, s) for c, cs in servers.items() - for s in cs if s["server_name"] == server_name), - (None, None) + ((c, s) for c, cs in servers.items() for s in cs if s["server_name"] == server_name), (None, None) ) if server: @@ -366,19 +302,11 @@ async def handle_servers_manage( reply_markup=build_manage_server_kb(server_name, cluster_name), ) else: - await callback_query.message.edit_text( - text="❌ Сервер не найден." - ) + await callback_query.message.edit_text(text="❌ Сервер не найден.") -@router.callback_query( - AdminServerEditorCallback.filter(F.action == "servers_delete"), - IsAdminFilter() -) -async def handle_servers_delete( - callback_query: types.CallbackQuery, - callback_data: AdminServerEditorCallback -): +@router.callback_query(AdminServerEditorCallback.filter(F.action == "servers_delete"), IsAdminFilter()) +async def handle_servers_delete(callback_query: types.CallbackQuery, callback_data: AdminServerEditorCallback): server_name = callback_data.data await callback_query.message.edit_text( @@ -387,32 +315,20 @@ async def handle_servers_delete( ) -@router.callback_query( - AdminServerEditorCallback.filter(F.action == "servers_delete_confirm"), - IsAdminFilter() -) -async def handle_servers_delete_confirm( - callback_query: types.CallbackQuery, - callback_data: AdminServerEditorCallback -): +@router.callback_query(AdminServerEditorCallback.filter(F.action == "servers_delete_confirm"), IsAdminFilter()) +async def handle_servers_delete_confirm(callback_query: types.CallbackQuery, callback_data: AdminServerEditorCallback): server_name = callback_data.data await delete_server(server_name, session) await callback_query.message.edit_text( - text=f"🗑️ Сервер {server_name} успешно удален.", - reply_markup=build_admin_back_kb("servers") + text=f"🗑️ Сервер {server_name} успешно удален.", reply_markup=build_admin_back_kb("servers") ) -@router.callback_query( - AdminServerEditorCallback.filter(F.action == "servers_add"), - IsAdminFilter() -) +@router.callback_query(AdminServerEditorCallback.filter(F.action == "servers_add"), IsAdminFilter()) async def handle_servers_add( - callback_query: types.CallbackQuery, - callback_data: AdminServerEditorCallback, - state: FSMContext + callback_query: types.CallbackQuery, callback_data: AdminServerEditorCallback, state: FSMContext ): cluster_name = callback_data.data @@ -432,13 +348,10 @@ async def handle_servers_add( await state.set_state(AdminServersEditor.waiting_for_server_name) -@router.callback_query( - AdminServerEditorCallback.filter(F.action == "clusters_backup"), - IsAdminFilter() -) +@router.callback_query(AdminServerEditorCallback.filter(F.action == "clusters_backup"), IsAdminFilter()) async def handle_clusters_backup( - callback_query: types.CallbackQuery, - callback_data: AdminServerEditorCallback, + callback_query: types.CallbackQuery, + callback_data: AdminServerEditorCallback, ): cluster_name = callback_data.data diff --git a/handlers/admin/admin_stats.py b/handlers/admin/admin_stats.py index 0a74d69f..48ad79bb 100644 --- a/handlers/admin/admin_stats.py +++ b/handlers/admin/admin_stats.py @@ -17,10 +17,7 @@ router = Router() AdminPanelCallback.filter(F.action == "stats"), IsAdminFilter(), ) -async def handle_stats( - callback_query: CallbackQuery, - session: Any -): +async def handle_stats(callback_query: CallbackQuery, session: Any): try: total_users = await session.fetchval("SELECT COUNT(*) FROM users") total_keys = await session.fetchval("SELECT COUNT(*) FROM keys") @@ -35,13 +32,9 @@ async def handle_stats( total_payments_month = await session.fetchval( "SELECT COALESCE(SUM(amount), 0) FROM payments WHERE created_at >= date_trunc('month', CURRENT_DATE)" ) - total_payments_all_time = await session.fetchval( - "SELECT COALESCE(SUM(amount), 0) FROM payments" - ) + total_payments_all_time = await session.fetchval("SELECT COALESCE(SUM(amount), 0) FROM payments") - registrations_today = await session.fetchval( - "SELECT COUNT(*) FROM users WHERE created_at >= CURRENT_DATE" - ) + registrations_today = await session.fetchval("SELECT COUNT(*) FROM users WHERE created_at >= CURRENT_DATE") registrations_week = await session.fetchval( "SELECT COUNT(*) FROM users WHERE created_at >= date_trunc('week', CURRENT_DATE)" ) @@ -49,9 +42,7 @@ async def handle_stats( "SELECT COUNT(*) FROM users WHERE created_at >= date_trunc('month', CURRENT_DATE)" ) - users_updated_today = await session.fetchval( - "SELECT COUNT(*) FROM users WHERE updated_at >= CURRENT_DATE" - ) + users_updated_today = await session.fetchval("SELECT COUNT(*) FROM users WHERE updated_at >= CURRENT_DATE") active_keys = await session.fetchval( "SELECT COUNT(*) FROM keys WHERE expiry_time > $1", @@ -81,10 +72,7 @@ async def handle_stats( f" 🏦 За все время: {total_payments_all_time} ₽\n" ) - await callback_query.message.edit_text( - text=stats_message, - reply_markup=build_stats_kb() - ) + await callback_query.message.edit_text(text=stats_message, reply_markup=build_stats_kb()) except Exception as e: logger.error(f"Error in user_stats_menu: {e}") @@ -93,46 +81,28 @@ async def handle_stats( AdminPanelCallback.filter(F.action == "stats_export_users_csv"), IsAdminFilter(), ) -async def handle_export_users_csv( - callback_query: CallbackQuery, - session: Any -): +async def handle_export_users_csv(callback_query: CallbackQuery, session: Any): kb = build_admin_back_kb("stats") try: export = await export_users_csv(session) - await callback_query.message.answer_document( - document=export, - caption="📥 Экспорт пользователей в CSV" - ) + await callback_query.message.answer_document(document=export, caption="📥 Экспорт пользователей в CSV") except Exception as e: logger.error(f"Ошибка при экспорте пользователей в CSV: {e}") - await callback_query.message.edit_text( - text=f"❗ Произошла ошибка при экспорте: {e}", - reply_markup=kb - ) + await callback_query.message.edit_text(text=f"❗ Произошла ошибка при экспорте: {e}", reply_markup=kb) @router.callback_query( AdminPanelCallback.filter(F.action == "stats_export_payments_csv"), IsAdminFilter(), ) -async def handle_export_payments_csv( - callback_query: CallbackQuery, - session: Any -): +async def handle_export_payments_csv(callback_query: CallbackQuery, session: Any): kb = build_admin_back_kb("stats") try: export = await export_payments_csv(session) - await callback_query.message.answer_document( - document=export, - caption="📥 Экспорт платежей в CSV" - ) + await callback_query.message.answer_document(document=export, caption="📥 Экспорт платежей в CSV") except Exception as e: logger.error(f"Ошибка при экспорте платежей в CSV: {e}") - await callback_query.message.edit_text( - text=f"❗ Произошла ошибка при экспорте: {e}", - reply_markup=kb - ) + await callback_query.message.edit_text(text=f"❗ Произошла ошибка при экспорте: {e}", reply_markup=kb) diff --git a/handlers/admin/admin_user_editor.py b/handlers/admin/admin_user_editor.py index a3aec08a..2d470b56 100644 --- a/handlers/admin/admin_user_editor.py +++ b/handlers/admin/admin_user_editor.py @@ -590,4 +590,3 @@ async def delete_user(callback_query: types.CallbackQuery, session: Any): await callback_query.message.answer( f"❌ Произошла ошибка при удалении пользователя с ID {tg_id}. Попробуйте снова." ) - diff --git a/handlers/admin/admin_users.py b/handlers/admin/admin_users.py index 2520299a..4601d646 100644 --- a/handlers/admin/admin_users.py +++ b/handlers/admin/admin_users.py @@ -15,14 +15,25 @@ from filters.admin import IsAdminFilter from handlers.keys.key_utils import ( delete_key_from_cluster, delete_key_from_db, - renew_key_in_cluster, update_subscription, + renew_key_in_cluster, + update_subscription, ) from handlers.utils import sanitize_key_name from keyboards.admin.panel_kb import AdminPanelCallback, build_admin_back_kb -from keyboards.admin.users_kb import build_user_edit_kb, build_key_edit_kb, build_key_delete_kb, \ - build_user_delete_kb, AdminUserEditorCallback, build_editor_kb, build_users_balance_kb, \ - build_users_balance_change_kb, build_user_key_kb, build_users_key_expiry_kb, AdminUserKeyEditorCallback, \ - build_users_key_show_kb +from keyboards.admin.users_kb import ( + build_user_edit_kb, + build_key_edit_kb, + build_key_delete_kb, + build_user_delete_kb, + AdminUserEditorCallback, + build_editor_kb, + build_users_balance_kb, + build_users_balance_change_kb, + build_user_key_kb, + build_users_key_expiry_kb, + AdminUserKeyEditorCallback, + build_users_key_show_kb, +) from logger import logger router = Router() @@ -42,10 +53,7 @@ class UserEditorState(StatesGroup): AdminPanelCallback.filter(F.action == "search_user"), IsAdminFilter(), ) -async def handle_search_user( - callback_query: CallbackQuery, - state: FSMContext -): +async def handle_search_user(callback_query: CallbackQuery, state: FSMContext): text = ( "🔍 Поиск пользователя" "\n\n📌 Введите ID, Username или перешлите сообщение пользователя." @@ -55,36 +63,20 @@ async def handle_search_user( ) await state.set_state(UserEditorState.waiting_for_user_data) - await callback_query.message.edit_text( - text=text, - reply_markup=build_admin_back_kb() - ) + await callback_query.message.edit_text(text=text, reply_markup=build_admin_back_kb()) @router.callback_query( AdminPanelCallback.filter(F.action == "search_key"), IsAdminFilter(), ) -async def handle_search_key( - callback_query: CallbackQuery, - state: FSMContext -): +async def handle_search_key(callback_query: CallbackQuery, state: FSMContext): await state.set_state(UserEditorState.waiting_for_key_name) - await callback_query.message.edit_text( - text="🔑 Введите имя ключа для поиска:", - reply_markup=build_admin_back_kb() - ) + await callback_query.message.edit_text(text="🔑 Введите имя ключа для поиска:", reply_markup=build_admin_back_kb()) -@router.message( - UserEditorState.waiting_for_user_data, - IsAdminFilter() -) -async def handle_user_data_input( - message: types.Message, - state: FSMContext, - session: Any -): +@router.message(UserEditorState.waiting_for_user_data, IsAdminFilter()) +async def handle_user_data_input(message: types.Message, state: FSMContext, session: Any): kb = build_admin_back_kb() if message.forward_from: @@ -93,23 +85,18 @@ async def handle_user_data_input( return if not message.text: - await message.answer( - text="🚫 Пожалуйста, отправьте текстовое сообщение.", - reply_markup=kb - ) + await message.answer(text="🚫 Пожалуйста, отправьте текстовое сообщение.", reply_markup=kb) return if message.text.isdigit(): tg_id = int(message.text) else: # Удаление '@' символа в начале сообщения - username = message.text.strip().lstrip('@') + username = message.text.strip().lstrip("@") # Удаление начала ссылки на профиль - username = username.replace('https://t.me/', '') + username = username.replace("https://t.me/", "") - user = await session.fetchrow( - "SELECT tg_id FROM users WHERE username = $1", username - ) + user = await session.fetchrow("SELECT tg_id FROM users WHERE username = $1", username) if not user: await message.answer( @@ -123,32 +110,19 @@ async def handle_user_data_input( await process_user_search(message, state, session, tg_id) -@router.message( - UserEditorState.waiting_for_key_name, - IsAdminFilter() -) -async def handle_key_name_input( - message: types.Message, - state: FSMContext, - session: Any -): +@router.message(UserEditorState.waiting_for_key_name, IsAdminFilter()) +async def handle_key_name_input(message: types.Message, state: FSMContext, session: Any): kb = build_admin_back_kb() if not message.text: - await message.answer( - text="🚫 Пожалуйста, отправьте текстовое сообщение.", - reply_markup=kb - ) + await message.answer(text="🚫 Пожалуйста, отправьте текстовое сообщение.", reply_markup=kb) return key_name = sanitize_key_name(message.text) key_details = await get_key_details(key_name, session) if not key_details: - await message.answer( - text="🚫 Пользователь с указанным именем ключа не найден.", - reply_markup=kb - ) + await message.answer(text="🚫 Пользователь с указанным именем ключа не найден.", reply_markup=kb) return await process_user_search(message, state, session, key_details["tg_id"]) @@ -159,46 +133,28 @@ async def handle_key_name_input( IsAdminFilter(), ) async def handle_send_message( - callback_query: types.CallbackQuery, - callback_data: AdminUserEditorCallback, - state: FSMContext + callback_query: types.CallbackQuery, callback_data: AdminUserEditorCallback, state: FSMContext ): tg_id = callback_data.tg_id await callback_query.message.edit_text( - text="✉️ Введите текст сообщения, которое вы хотите отправить пользователю:", - reply_markup=build_editor_kb(tg_id) + text="✉️ Введите текст сообщения, которое вы хотите отправить пользователю:", reply_markup=build_editor_kb(tg_id) ) await state.update_data(tg_id=tg_id) await state.set_state(UserEditorState.waiting_for_message_text) -@router.message( - UserEditorState.waiting_for_message_text, - IsAdminFilter() -) -async def handle_message_text_input( - message: types.Message, - state: FSMContext -): +@router.message(UserEditorState.waiting_for_message_text, IsAdminFilter()) +async def handle_message_text_input(message: types.Message, state: FSMContext): data = await state.get_data() tg_id = data.get("tg_id") try: - await message.bot.send_message( - chat_id=tg_id, - text=message.text - ) - await message.answer( - text="✅ Сообщение успешно отправлено.", - reply_markup=build_editor_kb(tg_id) - ) + await message.bot.send_message(chat_id=tg_id, text=message.text) + await message.answer(text="✅ Сообщение успешно отправлено.", reply_markup=build_editor_kb(tg_id)) except Exception as e: - await message.answer( - text=f"❌ Не удалось отправить сообщение: {e}", - reply_markup=build_editor_kb(tg_id) - ) + await message.answer(text=f"❌ Не удалось отправить сообщение: {e}", reply_markup=build_editor_kb(tg_id)) await state.clear() @@ -208,37 +164,28 @@ async def handle_message_text_input( IsAdminFilter(), ) async def handle_trial_restore( - callback_query: types.CallbackQuery, - callback_data: AdminUserEditorCallback, - session: Any + callback_query: types.CallbackQuery, callback_data: AdminUserEditorCallback, session: Any ): tg_id = callback_data.tg_id await restore_trial(tg_id, session) - await callback_query.message.edit_text( - text="✅ Триал успешно восстановлен!", - reply_markup=build_editor_kb(tg_id) - ) + await callback_query.message.edit_text(text="✅ Триал успешно восстановлен!", reply_markup=build_editor_kb(tg_id)) -@router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_balance_edit"), - IsAdminFilter() -) -async def handle_balance_change( - callback_query: CallbackQuery, - callback_data: AdminUserEditorCallback, - session: Any -): +@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_balance_edit"), IsAdminFilter()) +async def handle_balance_change(callback_query: CallbackQuery, callback_data: AdminUserEditorCallback, session: Any): tg_id = callback_data.tg_id - records = await session.fetch(""" + records = await session.fetch( + """ SELECT amount, payment_system, status, created_at FROM payments WHERE tg_id = $1 ORDER BY created_at DESC LIMIT 5 - """, tg_id) + """, + tg_id, + ) balance = await get_user_balance(tg_id, session) @@ -263,21 +210,12 @@ async def handle_balance_change( else: text += "\n 🚫 Отсутствуют" - await callback_query.message.edit_text( - text=text, - reply_markup=build_users_balance_kb(tg_id) - ) + await callback_query.message.edit_text(text=text, reply_markup=build_users_balance_kb(tg_id)) -@router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_balance_add"), - IsAdminFilter() -) +@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_balance_add"), IsAdminFilter()) async def handle_balance_add( - callback_query: CallbackQuery, - callback_data: AdminUserEditorCallback, - state: FSMContext, - session: Any + callback_query: CallbackQuery, callback_data: AdminUserEditorCallback, state: FSMContext, session: Any ): tg_id = callback_data.tg_id amount = callback_data.data @@ -292,19 +230,12 @@ async def handle_balance_add( await callback_query.message.edit_text( text="✍️ Введите сумму, которую хотите добавить на баланс пользователя:", - reply_markup=build_users_balance_change_kb(tg_id) + reply_markup=build_users_balance_change_kb(tg_id), ) -@router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_balance_take"), - IsAdminFilter() -) -async def handle_balance_take( - callback_query: CallbackQuery, - callback_data: AdminUserEditorCallback, - state: FSMContext -): +@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_balance_take"), IsAdminFilter()) +async def handle_balance_take(callback_query: CallbackQuery, callback_data: AdminUserEditorCallback, state: FSMContext): tg_id = callback_data.tg_id await state.update_data(tg_id=tg_id, op_type="take") @@ -312,19 +243,12 @@ async def handle_balance_take( await callback_query.message.edit_text( text="✍️ Введите сумму, которую хотите вычесть из баланса пользователя:", - reply_markup=build_users_balance_change_kb(tg_id) + reply_markup=build_users_balance_change_kb(tg_id), ) -@router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_balance_set"), - IsAdminFilter() -) -async def handle_balance_set( - callback_query: CallbackQuery, - callback_data: AdminUserEditorCallback, - state: FSMContext -): +@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_balance_set"), IsAdminFilter()) +async def handle_balance_set(callback_query: CallbackQuery, callback_data: AdminUserEditorCallback, state: FSMContext): tg_id = callback_data.tg_id await state.update_data(tg_id=tg_id, op_type="set") @@ -332,27 +256,19 @@ async def handle_balance_set( await callback_query.message.edit_text( text="✍️ Введите баланс, который хотите установить пользователю:", - reply_markup=build_users_balance_change_kb(tg_id) + reply_markup=build_users_balance_change_kb(tg_id), ) -@router.message( - UserEditorState.waiting_for_balance, - IsAdminFilter() -) -async def handle_balance_input( - message: types.Message, - state: FSMContext, - session: Any -): +@router.message(UserEditorState.waiting_for_balance, IsAdminFilter()) +async def handle_balance_input(message: types.Message, state: FSMContext, session: Any): data = await state.get_data() tg_id = data.get("tg_id") op_type = data.get("op_type") if not message.text.isdigit() or int(message.text) < 0: await message.answer( - text="🚫 Пожалуйста, введите корректную сумму!", - reply_markup=build_users_balance_change_kb(tg_id) + text="🚫 Пожалуйста, введите корректную сумму!", reply_markup=build_users_balance_change_kb(tg_id) ) return @@ -368,21 +284,12 @@ async def handle_balance_input( text = f"✅ Баланс пользователя изменен на {amount}Р" await set_user_balance(tg_id, amount, session) - await message.answer( - text=text, - reply_markup=build_users_balance_change_kb(tg_id) - ) + await message.answer(text=text, reply_markup=build_users_balance_change_kb(tg_id)) -@router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_key_edit"), - IsAdminFilter() -) +@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_key_edit"), IsAdminFilter()) async def handle_key_edit( - callback_query: CallbackQuery, - callback_data: CallbackData, - session: Any, - update: bool = False + callback_query: CallbackQuery, callback_data: CallbackData, session: Any, update: bool = False ): email = callback_data.data key_details = await get_key_details(email, session) @@ -403,42 +310,24 @@ async def handle_key_edit( ) if not update or not callback_data.edit: - await callback_query.message.edit_text( - text=text, - reply_markup=build_key_edit_kb(key_details, email) - ) + await callback_query.message.edit_text(text=text, reply_markup=build_key_edit_kb(key_details, email)) else: await callback_query.message.edit_text( - text=text, - reply_markup=build_users_key_expiry_kb(callback_data.tg_id, email) + text=text, reply_markup=build_users_key_expiry_kb(callback_data.tg_id, email) ) -@router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_expiry_edit"), - IsAdminFilter() -) -async def handle_change_expiry( - callback_query: CallbackQuery, - callback_data: AdminUserEditorCallback -): +@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_expiry_edit"), IsAdminFilter()) +async def handle_change_expiry(callback_query: CallbackQuery, callback_data: AdminUserEditorCallback): tg_id = callback_data.tg_id email = callback_data.data - await callback_query.message.edit_reply_markup( - reply_markup=build_users_key_expiry_kb(tg_id, email) - ) + await callback_query.message.edit_reply_markup(reply_markup=build_users_key_expiry_kb(tg_id, email)) -@router.callback_query( - AdminUserKeyEditorCallback.filter(F.action == "add"), - IsAdminFilter() -) +@router.callback_query(AdminUserKeyEditorCallback.filter(F.action == "add"), IsAdminFilter()) async def handle_expiry_add( - callback_query: CallbackQuery, - callback_data: AdminUserKeyEditorCallback, - state: FSMContext, - session: Any + callback_query: CallbackQuery, callback_data: AdminUserKeyEditorCallback, state: FSMContext, session: Any ): tg_id = callback_data.tg_id email = callback_data.data @@ -463,18 +352,13 @@ async def handle_expiry_add( await callback_query.message.edit_text( text="✍️ Введите количество дней, которое хотите добавить к времени действия ключа:", - reply_markup=build_users_key_show_kb(tg_id, email) + reply_markup=build_users_key_show_kb(tg_id, email), ) -@router.callback_query( - AdminUserKeyEditorCallback.filter(F.action == "take"), - IsAdminFilter() -) +@router.callback_query(AdminUserKeyEditorCallback.filter(F.action == "take"), IsAdminFilter()) async def handle_expiry_take( - callback_query: CallbackQuery, - callback_data: AdminUserKeyEditorCallback, - state: FSMContext + callback_query: CallbackQuery, callback_data: AdminUserKeyEditorCallback, state: FSMContext ): tg_id = callback_data.tg_id email = callback_data.data @@ -484,18 +368,13 @@ async def handle_expiry_take( await callback_query.message.edit_text( text="✍️ Введите количество дней, которое хотите вычесть из времени действия ключа:", - reply_markup=build_users_key_show_kb(tg_id, email) + reply_markup=build_users_key_show_kb(tg_id, email), ) -@router.callback_query( - AdminUserKeyEditorCallback.filter(F.action == "set"), - IsAdminFilter() -) +@router.callback_query(AdminUserKeyEditorCallback.filter(F.action == "set"), IsAdminFilter()) async def handle_expiry_set( - callback_query: CallbackQuery, - callback_data: AdminUserKeyEditorCallback, - state: FSMContext + callback_query: CallbackQuery, callback_data: AdminUserKeyEditorCallback, state: FSMContext ): tg_id = callback_data.tg_id email = callback_data.data @@ -509,21 +388,11 @@ async def handle_expiry_set( "\n Пример: 2025-02-09 09:01" ) - await callback_query.message.edit_text( - text=text, - reply_markup=build_users_key_show_kb(tg_id, email) - ) + await callback_query.message.edit_text(text=text, reply_markup=build_users_key_show_kb(tg_id, email)) -@router.message( - UserEditorState.waiting_for_expiry_time, - IsAdminFilter() -) -async def handle_expiry_time_input( - message: types.Message, - state: FSMContext, - session: Any -): +@router.message(UserEditorState.waiting_for_expiry_time, IsAdminFilter()) +async def handle_expiry_time_input(message: types.Message, state: FSMContext, session: Any): data = await state.get_data() tg_id = data.get("tg_id") email = data.get("email") @@ -532,7 +401,7 @@ async def handle_expiry_time_input( if op_type != "set" and (not message.text.isdigit() or int(message.text) < 0): await message.answer( text="🚫 Пожалуйста, введите корректное количество дней!", - reply_markup=build_users_key_show_kb(tg_id, email) + reply_markup=build_users_key_show_kb(tg_id, email), ) return @@ -555,9 +424,7 @@ async def handle_expiry_time_input( await change_expiry_time(key_details["expiry_time"] - days * 24 * 3600 * 1000, email, session) else: try: - expiry_time = int( - datetime.strptime(message.text, "%Y-%m-%d %H:%M").timestamp() * 1000 - ) + expiry_time = int(datetime.strptime(message.text, "%Y-%m-%d %H:%M").timestamp() * 1000) text = f"✅ Время действия ключа изменено на {message.text}" await change_expiry_time(expiry_time, email, session) except ValueError: @@ -565,21 +432,11 @@ async def handle_expiry_time_input( except Exception as e: text = f"❗ Произошла ошибка во время изменения времени действия ключа: {e}" - await message.answer( - text=text, - reply_markup=build_users_key_show_kb(tg_id, email) - ) + await message.answer(text=text, reply_markup=build_users_key_show_kb(tg_id, email)) -@router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_update_key"), - IsAdminFilter() -) -async def handle_update_key( - callback_query: CallbackQuery, - callback_data: AdminUserEditorCallback, - session: Any -): +@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_update_key"), IsAdminFilter()) +async def handle_update_key(callback_query: CallbackQuery, callback_data: AdminUserEditorCallback, session: Any): tg_id = callback_data.tg_id email = callback_data.data @@ -591,51 +448,32 @@ async def handle_update_key( except Exception as e: logger.error(f"Ошибка при обновлении ключа {email} администратором: {e}") await callback_query.message.answer( - text=f"❗ Произошла ошибка при обновлении ключа: {e}", - reply_markup=build_user_key_kb(tg_id, email) + text=f"❗ Произошла ошибка при обновлении ключа: {e}", reply_markup=build_user_key_kb(tg_id, email) ) -@router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_delete_key"), - IsAdminFilter() -) -async def handle_delete_key( - callback_query: types.CallbackQuery, - callback_data: AdminUserEditorCallback, - session: Any -): +@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_delete_key"), IsAdminFilter()) +async def handle_delete_key(callback_query: types.CallbackQuery, callback_data: AdminUserEditorCallback, session: Any): email = callback_data.data - client_id = await session.fetchval( - "SELECT client_id FROM keys WHERE email = $1", email - ) + client_id = await session.fetchval("SELECT client_id FROM keys WHERE email = $1", email) if client_id is None: await callback_query.message.edit_text( - text="🚫 Ключ не найден!", - reply_markup=build_editor_kb(callback_data.tg_id) + text="🚫 Ключ не найден!", reply_markup=build_editor_kb(callback_data.tg_id) ) return await callback_query.message.edit_text( - text="❓ Вы уверены, что хотите удалить ключ?", - reply_markup=build_key_delete_kb(callback_data.tg_id, email) + text="❓ Вы уверены, что хотите удалить ключ?", reply_markup=build_key_delete_kb(callback_data.tg_id, email) ) -@router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_delete_key_confirm"), - IsAdminFilter() -) +@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_delete_key_confirm"), IsAdminFilter()) async def handle_delete_key_confirm( - callback_query: types.CallbackQuery, - callback_data: AdminUserEditorCallback, - session: Any + callback_query: types.CallbackQuery, callback_data: AdminUserEditorCallback, session: Any ): email = callback_data.data - record = await session.fetchrow( - "SELECT client_id FROM keys WHERE email = $1", email - ) + record = await session.fetchrow("SELECT client_id FROM keys WHERE email = $1", email) kb = build_editor_kb(callback_data.tg_id) @@ -647,48 +485,28 @@ async def handle_delete_key_confirm( tasks = [] for cluster_name, cluster_servers in clusters.items(): for _ in cluster_servers: - tasks.append( - delete_key_from_cluster(cluster_name, email, client_id) - ) + tasks.append(delete_key_from_cluster(cluster_name, email, client_id)) await asyncio.gather(*tasks) await delete_key_from_servers() await delete_key_from_db(client_id, session) - await callback_query.message.edit_text( - text="✅ Ключ успешно удален.", - reply_markup=kb - ) + await callback_query.message.edit_text(text="✅ Ключ успешно удален.", reply_markup=kb) else: - await callback_query.message.edit_text( - text="🚫 Ключ не найден или уже удален.", - reply_markup=kb - ) + await callback_query.message.edit_text(text="🚫 Ключ не найден или уже удален.", reply_markup=kb) -@router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_delete_user"), - IsAdminFilter() -) -async def handle_delete_user( - callback_query: types.CallbackQuery, - callback_data: AdminUserEditorCallback -): +@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_delete_user"), IsAdminFilter()) +async def handle_delete_user(callback_query: types.CallbackQuery, callback_data: AdminUserEditorCallback): tg_id = callback_data.tg_id await callback_query.message.edit_text( - text=f"❗️ Вы уверены, что хотите удалить пользователя с ID {tg_id}?", - reply_markup=build_user_delete_kb(tg_id) + text=f"❗️ Вы уверены, что хотите удалить пользователя с ID {tg_id}?", reply_markup=build_user_delete_kb(tg_id) ) -@router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_delete_user_confirm"), - IsAdminFilter() -) +@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_delete_user_confirm"), IsAdminFilter()) async def handle_delete_user_confirm( - callback_query: types.CallbackQuery, - callback_data: AdminUserEditorCallback, - session: Any + callback_query: types.CallbackQuery, callback_data: AdminUserEditorCallback, session: Any ): tg_id = callback_data.tg_id key_records = await session.fetch("SELECT email, client_id FROM keys WHERE tg_id = $1", tg_id) @@ -709,8 +527,7 @@ async def handle_delete_user_confirm( try: await delete_user_data(session, tg_id) await callback_query.message.edit_text( - text=f"🗑️ Пользователь с ID {tg_id} был удален.", - reply_markup=build_editor_kb(callback_data.tg_id) + text=f"🗑️ Пользователь с ID {tg_id} был удален.", reply_markup=build_editor_kb(callback_data.tg_id) ) except Exception as e: logger.error(f"Ошибка при удалении данных из базы данных для пользователя {tg_id}: {e}") @@ -719,37 +536,19 @@ async def handle_delete_user_confirm( ) -@router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_editor"), - IsAdminFilter() -) +@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_editor"), IsAdminFilter()) async def handle_editor( - callback_query: types.CallbackQuery, - callback_data: AdminUserEditorCallback, - state: FSMContext, - session: Any + callback_query: types.CallbackQuery, callback_data: AdminUserEditorCallback, state: FSMContext, session: Any ): - await process_user_search( - callback_query.message, - state, - session, - callback_data.tg_id, - callback_data.edit - ) + await process_user_search(callback_query.message, state, session, callback_data.tg_id, callback_data.edit) async def process_user_search( - message: types.Message, - state: FSMContext, - session: Any, - tg_id: int, - edit: bool = False + message: types.Message, state: FSMContext, session: Any, tg_id: int, edit: bool = False ) -> None: await state.clear() - balance = await session.fetchval( - "SELECT balance FROM connections WHERE tg_id = $1", tg_id - ) + balance = await session.fetchval("SELECT balance FROM connections WHERE tg_id = $1", tg_id) if balance is None: await message.answer( @@ -758,15 +557,9 @@ async def process_user_search( ) return - username = await session.fetchval( - "SELECT username FROM users WHERE tg_id = $1", tg_id - ) - key_records = await session.fetch( - "SELECT email, expiry_time FROM keys WHERE tg_id = $1", tg_id - ) - referral_count = await session.fetchval( - "SELECT COUNT(*) FROM referrals WHERE referrer_tg_id = $1", tg_id - ) + username = await session.fetchval("SELECT username FROM users WHERE tg_id = $1", tg_id) + key_records = await session.fetch("SELECT email, expiry_time FROM keys WHERE tg_id = $1", tg_id) + referral_count = await session.fetchval("SELECT COUNT(*) FROM referrals WHERE referrer_tg_id = $1", tg_id) text = ( f"📊 Информация о пользователе" @@ -780,17 +573,11 @@ async def process_user_search( if edit: try: - await message.edit_text( - text=text, - reply_markup=kb - ) + await message.edit_text(text=text, reply_markup=kb) except TelegramBadRequest: pass else: - await message.answer( - text=text, - reply_markup=kb - ) + await message.answer(text=text, reply_markup=kb) async def get_key_details(email, session): @@ -827,9 +614,7 @@ async def change_expiry_time(expiry_time: int, email: str, session: Any) -> Exce if client_id is None: return ValueError(f"User with email {email} was not found") - server_id = await session.fetchrow( - "SELECT server_id FROM keys WHERE client_id = $1", client_id - ) + server_id = await session.fetchrow("SELECT server_id FROM keys WHERE client_id = $1", client_id) if not server_id: return ValueError(f"User with client_id {server_id} was not found") @@ -859,7 +644,8 @@ async def change_expiry_time(expiry_time: int, email: str, session: Any) -> Exce async def get_user_balance(tg_id: int, session: Any) -> float: try: return await session.fetchval( - "SELECT balance FROM connections WHERE tg_id = $1", tg_id, + "SELECT balance FROM connections WHERE tg_id = $1", + tg_id, ) except Exception as e: logger.error(f"Ошибка при получении баланса для пользователя {tg_id}: {e}") @@ -870,7 +656,8 @@ async def add_user_balance(tg_id: int, balance: int, session: Any) -> None: try: await session.execute( "UPDATE connections SET balance = balance + $1 WHERE tg_id = $2", - balance, tg_id, + balance, + tg_id, ) except Exception as e: logger.error(f"Ошибка при добавлении баланса для пользователя {tg_id}: {e}") @@ -880,7 +667,8 @@ async def set_user_balance(tg_id: int, balance: int, session: Any) -> None: try: await session.execute( "UPDATE connections SET balance = $1 WHERE tg_id = $2", - balance, tg_id, + balance, + tg_id, ) except Exception as e: logger.error(f"Ошибка при установке баланса для пользователя {tg_id}: {e}") diff --git a/handlers/keys/key_utils.py b/handlers/keys/key_utils.py index c1d6b66c..80461348 100644 --- a/handlers/keys/key_utils.py +++ b/handlers/keys/key_utils.py @@ -105,7 +105,6 @@ async def create_client_on_server( await asyncio.sleep(0.7) - async def renew_key_in_cluster(cluster_id, email, client_id, new_expiry_time, total_gb): try: servers = await get_servers() diff --git a/handlers/keys/keys.py b/handlers/keys/keys.py index 787bc25b..7bbf3eb8 100644 --- a/handlers/keys/keys.py +++ b/handlers/keys/keys.py @@ -73,7 +73,7 @@ router = Router() @router.callback_query(F.data == "view_keys") @router.message(F.text == "/subs") async def process_callback_or_message_view_keys( - callback_query_or_message: types.Message | types.CallbackQuery, session: Any + callback_query_or_message: types.Message | types.CallbackQuery, session: Any ): if isinstance(callback_query_or_message, types.CallbackQuery): chat_id = callback_query_or_message.message.chat.id @@ -258,9 +258,7 @@ async def process_callback_update_subscription(callback_query: types.CallbackQue await process_callback_view_key(callback_query, session) except Exception as e: logger.error(f"Ошибка при обновлении ключа {email} пользователем: {e}") - await handle_error( - tg_id, callback_query, f"Ошибка при обновлении подписки: {e}" - ) + await handle_error(tg_id, callback_query, f"Ошибка при обновлении подписки: {e}") @router.callback_query(F.data.startswith("delete_key|")) @@ -335,9 +333,7 @@ async def process_callback_renew_key(callback_query: types.CallbackQuery, sessio @router.callback_query(F.data.startswith("confirm_delete|")) -async def process_callback_confirm_delete( - callback_query: types.CallbackQuery, session: Any -): +async def process_callback_confirm_delete(callback_query: types.CallbackQuery, session: Any): email = callback_query.data.split("|")[1] try: record = await get_key_details(email, session) @@ -413,7 +409,8 @@ async def process_callback_renew_plan(callback_query: types.CallbackQuery, sessi required_amount = cost - balance logger.info( - f"[RENEW] Пользователю {tg_id} не хватает {required_amount}₽. Запуск доплаты через {USE_NEW_PAYMENT_FLOW}") + f"[RENEW] Пользователю {tg_id} не хватает {required_amount}₽. Запуск доплаты через {USE_NEW_PAYMENT_FLOW}" + ) await create_temporary_data( session, diff --git a/keyboards/admin/bans_kb.py b/keyboards/admin/bans_kb.py index 958d0a14..0c5554d4 100644 --- a/keyboards/admin/bans_kb.py +++ b/keyboards/admin/bans_kb.py @@ -6,16 +6,8 @@ from keyboards.admin.panel_kb import build_admin_back_btn, AdminPanelCallback def build_bans_kb() -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() - builder.button( - text="📄 Выгрузить в CSV", - callback_data=AdminPanelCallback(action="bans_export").pack() - ) - builder.button( - text="🗑️ Удалить из БД", - callback_data=AdminPanelCallback(action="bans_delete_banned").pack() - ) - builder.row( - build_admin_back_btn("management") - ) + builder.button(text="📄 Выгрузить в CSV", callback_data=AdminPanelCallback(action="bans_export").pack()) + builder.button(text="🗑️ Удалить из БД", callback_data=AdminPanelCallback(action="bans_delete_banned").pack()) + builder.row(build_admin_back_btn("management")) builder.adjust(1) return builder.as_markup() diff --git a/keyboards/admin/coupons_kb.py b/keyboards/admin/coupons_kb.py index 41ebd8c3..c24d705c 100644 --- a/keyboards/admin/coupons_kb.py +++ b/keyboards/admin/coupons_kb.py @@ -11,17 +11,9 @@ class AdminCouponDeleteCallback(CallbackData, prefix="admin_coupon_delete"): def build_coupons_kb() -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() - builder.button( - text="➕ Создать купон", - callback_data=AdminPanelCallback(action="coupons_create").pack() - ) - builder.button( - text="Купоны", - callback_data=AdminPanelCallback(action="coupons_list").pack() - ) - builder.row( - build_admin_back_btn() - ) + builder.button(text="➕ Создать купон", callback_data=AdminPanelCallback(action="coupons_create").pack()) + builder.button(text="Купоны", callback_data=AdminPanelCallback(action="coupons_list").pack()) + builder.row(build_admin_back_btn()) return builder.as_markup() @@ -32,12 +24,8 @@ def build_coupons_list_kb(coupons: list) -> InlineKeyboardMarkup: coupon_code = coupon["code"] builder.button( text=f"❌ Удалить {coupon_code}", - callback_data=AdminCouponDeleteCallback( - coupon_code=coupon_code - ).pack(), + callback_data=AdminCouponDeleteCallback(coupon_code=coupon_code).pack(), ) - builder.row( - build_admin_back_btn("coupons") - ) + builder.row(build_admin_back_btn("coupons")) return builder.as_markup() diff --git a/keyboards/admin/panel_kb.py b/keyboards/admin/panel_kb.py index 9b85a216..6b16151f 100644 --- a/keyboards/admin/panel_kb.py +++ b/keyboards/admin/panel_kb.py @@ -9,76 +9,36 @@ class AdminPanelCallback(CallbackData, prefix="admin_panel"): def build_panel_kb() -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() - builder.button( - text="👤 Поиск пользователя", - callback_data=AdminPanelCallback(action="search_user").pack() - ) - builder.button( - text="🔑 Поиск по названию ключа", - callback_data=AdminPanelCallback(action="search_key").pack() - ) + builder.button(text="👤 Поиск пользователя", callback_data=AdminPanelCallback(action="search_user").pack()) + builder.button(text="🔑 Поиск по названию ключа", callback_data=AdminPanelCallback(action="search_key").pack()) builder.row( - InlineKeyboardButton( - text="🖥️ Серверы", - callback_data=AdminPanelCallback(action="servers").pack() - ), - InlineKeyboardButton( - text="🎟️ Купоны", - callback_data=AdminPanelCallback(action="coupons").pack() - ) - ) - builder.button( - text="📢 Рассылка", - callback_data=AdminPanelCallback(action="sender").pack() + InlineKeyboardButton(text="🖥️ Серверы", callback_data=AdminPanelCallback(action="servers").pack()), + InlineKeyboardButton(text="🎟️ Купоны", callback_data=AdminPanelCallback(action="coupons").pack()), ) + builder.button(text="📢 Рассылка", callback_data=AdminPanelCallback(action="sender").pack()) builder.row( - InlineKeyboardButton( - text="📊 Статистика", - callback_data=AdminPanelCallback(action="stats").pack() - ), - InlineKeyboardButton( - text="🤖 Управление", - callback_data=AdminPanelCallback(action="management").pack() - ) - ) - builder.button( - text="Личный кабинет", - callback_data="profile" + InlineKeyboardButton(text="📊 Статистика", callback_data=AdminPanelCallback(action="stats").pack()), + InlineKeyboardButton(text="🤖 Управление", callback_data=AdminPanelCallback(action="management").pack()), ) + builder.button(text="Личный кабинет", callback_data="profile") builder.adjust(1, 1, 2, 1, 2, 1) return builder.as_markup() def build_management_kb() -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() - builder.button( - text="💾 Создать резервную копию", - callback_data=AdminPanelCallback(action="backups").pack() - ) - builder.button( - text="🚫 Заблокировавшие бота", - callback_data=AdminPanelCallback(action="bans").pack() - ) - builder.button( - text="🔄 Перезагрузить бота", - callback_data=AdminPanelCallback(action="restart").pack() - ) - builder.row( - build_admin_back_btn() - ) + builder.button(text="💾 Создать резервную копию", callback_data=AdminPanelCallback(action="backups").pack()) + builder.button(text="🚫 Заблокировавшие бота", callback_data=AdminPanelCallback(action="bans").pack()) + builder.button(text="🔄 Перезагрузить бота", callback_data=AdminPanelCallback(action="restart").pack()) + builder.row(build_admin_back_btn()) builder.adjust(1) return builder.as_markup() def build_restart_kb() -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() - builder.button( - text="✅ Да, перезагрузить", - callback_data=AdminPanelCallback(action="restart_confirm").pack() - ) - builder.row( - build_admin_back_btn() - ) + builder.button(text="✅ Да, перезагрузить", callback_data=AdminPanelCallback(action="restart_confirm").pack()) + builder.row(build_admin_back_btn()) builder.adjust(1) return builder.as_markup() @@ -89,9 +49,7 @@ def build_admin_back_kb(action: str = "admin") -> InlineKeyboardMarkup: def build_admin_singleton_kb(text: str, action: str) -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() - builder.row( - build_admin_btn(text, action) - ) + builder.row(build_admin_btn(text, action)) return builder.as_markup() diff --git a/keyboards/admin/sender_kb.py b/keyboards/admin/sender_kb.py index bfe9ad39..d0acfc59 100644 --- a/keyboards/admin/sender_kb.py +++ b/keyboards/admin/sender_kb.py @@ -11,26 +11,9 @@ class AdminSenderCallback(CallbackData, prefix="admin_sender"): def build_sender_kb() -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() - builder.button( - text="👥 Все пользователи", - callback_data=AdminSenderCallback( - type="all" - ).pack() - ) - builder.button( - text="✅ Пользователи с подпиской", - callback_data=AdminSenderCallback( - type="subscribed" - ).pack() - ) - builder.button( - text="❌ Пользователи без подписки", - callback_data=AdminSenderCallback( - type="unsubscribed" - ).pack() - ) - builder.row( - build_admin_back_btn() - ) + builder.button(text="👥 Все пользователи", callback_data=AdminSenderCallback(type="all").pack()) + builder.button(text="✅ Пользователи с подпиской", callback_data=AdminSenderCallback(type="subscribed").pack()) + builder.button(text="❌ Пользователи без подписки", callback_data=AdminSenderCallback(type="unsubscribed").pack()) + builder.row(build_admin_back_btn()) builder.adjust(1) return builder.as_markup() diff --git a/keyboards/admin/servers_kb.py b/keyboards/admin/servers_kb.py index d7dd239c..e857408b 100644 --- a/keyboards/admin/servers_kb.py +++ b/keyboards/admin/servers_kb.py @@ -16,19 +16,11 @@ def build_clusters_editor_kb(servers: dict) -> InlineKeyboardMarkup: for cluster_name in servers: builder.button( text=f"⚙️ {cluster_name}", - callback_data=AdminServerEditorCallback( - action="clusters_manage", - data=cluster_name - ).pack() + callback_data=AdminServerEditorCallback(action="clusters_manage", data=cluster_name).pack(), ) - builder.button( - text="➕ Добавить кластер", - callback_data=AdminPanelCallback(action="clusters_add").pack() - ) - builder.row( - build_admin_back_btn() - ) + builder.button(text="➕ Добавить кластер", callback_data=AdminPanelCallback(action="clusters_add").pack()) + builder.row(build_admin_back_btn()) builder.adjust(1) return builder.as_markup() @@ -39,36 +31,22 @@ def build_manage_cluster_kb(cluster_servers, cluster_name) -> InlineKeyboardMark for server in cluster_servers: builder.button( text=f"🌍 {server['server_name']}", - callback_data=AdminServerEditorCallback( - action="servers_manage", - data=server["server_name"] - ).pack() + callback_data=AdminServerEditorCallback(action="servers_manage", data=server["server_name"]).pack(), ) builder.button( text="➕ Добавить сервер", - callback_data=AdminServerEditorCallback( - action="servers_add", - data=cluster_name - ).pack() + callback_data=AdminServerEditorCallback(action="servers_add", data=cluster_name).pack(), ) builder.button( text="🌐 Доступность серверов", - callback_data=AdminServerEditorCallback( - action="servers_availability", - data=cluster_name - ).pack() + callback_data=AdminServerEditorCallback(action="servers_availability", data=cluster_name).pack(), ) builder.button( text="💾 Создать бэкап кластера", - callback_data=AdminServerEditorCallback( - action="clusters_backup", - data=cluster_name - ).pack() - ) - builder.row( - build_admin_back_btn("servers") + callback_data=AdminServerEditorCallback(action="clusters_backup", data=cluster_name).pack(), ) + builder.row(build_admin_back_btn("servers")) builder.adjust(1) return builder.as_markup() @@ -76,18 +54,10 @@ def build_manage_cluster_kb(cluster_servers, cluster_name) -> InlineKeyboardMark def build_manage_server_kb(server_name: str, cluster_name: str) -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() builder.button( - text="🗑️ Удалить", - callback_data=AdminServerEditorCallback( - action="servers_delete", - data=server_name - ).pack() + text="🗑️ Удалить", callback_data=AdminServerEditorCallback(action="servers_delete", data=server_name).pack() ) builder.button( - text="🔙 Назад", - callback_data=AdminServerEditorCallback( - action="clusters_manage", - data=cluster_name - ).pack() + text="🔙 Назад", callback_data=AdminServerEditorCallback(action="clusters_manage", data=cluster_name).pack() ) builder.adjust(1) return builder.as_markup() @@ -96,18 +66,10 @@ def build_manage_server_kb(server_name: str, cluster_name: str) -> InlineKeyboar def build_delete_server_kb(server_name: str) -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() builder.button( - text="✅ Да", - callback_data=AdminServerEditorCallback( - action="servers_delete_confirm", - data=server_name - ).pack() + text="✅ Да", callback_data=AdminServerEditorCallback(action="servers_delete_confirm", data=server_name).pack() ) builder.button( - text="🔙 Назад", - callback_data=AdminServerEditorCallback( - action="servers_manage", - data=server_name - ).pack() + text="🔙 Назад", callback_data=AdminServerEditorCallback(action="servers_manage", data=server_name).pack() ) builder.adjust(1) return builder.as_markup() diff --git a/keyboards/admin/stats_kb.py b/keyboards/admin/stats_kb.py index 4e1db626..3a6e4092 100644 --- a/keyboards/admin/stats_kb.py +++ b/keyboards/admin/stats_kb.py @@ -6,20 +6,14 @@ from keyboards.admin.panel_kb import build_admin_back_btn, AdminPanelCallback def build_stats_kb() -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() - builder.button( - text="🔄 Обновить", - callback_data=AdminPanelCallback(action="stats").pack() - ) + builder.button(text="🔄 Обновить", callback_data=AdminPanelCallback(action="stats").pack()) builder.button( text="📥 Выгрузить пользователей в CSV", - callback_data=AdminPanelCallback(action="stats_export_users_csv").pack() + callback_data=AdminPanelCallback(action="stats_export_users_csv").pack(), ) builder.button( - text="📥 Выгрузить оплаты в CSV", - callback_data=AdminPanelCallback(action="stats_export_payments_csv").pack() - ) - builder.row( - build_admin_back_btn() + text="📥 Выгрузить оплаты в CSV", callback_data=AdminPanelCallback(action="stats_export_payments_csv").pack() ) + builder.row(build_admin_back_btn()) builder.adjust(1) return builder.as_markup() diff --git a/keyboards/admin/users_kb.py b/keyboards/admin/users_kb.py index 6eb8537c..78378f9d 100644 --- a/keyboards/admin/users_kb.py +++ b/keyboards/admin/users_kb.py @@ -32,47 +32,25 @@ def build_user_edit_kb(tg_id: int, key_records: list) -> InlineKeyboardMarkup: days = (expiry - current_time).days builder.button( text=f"🔑 {email} ({'<1' if days < 1 else days} дн.)", - callback_data=AdminUserEditorCallback( - action="users_key_edit", - tg_id=tg_id, - data=str(email) - ).pack() + callback_data=AdminUserEditorCallback(action="users_key_edit", tg_id=tg_id, data=str(email)).pack(), ) builder.button( - text="✉️ Сообщение", - callback_data=AdminUserEditorCallback( - action="users_send_message", - tg_id=tg_id - ).pack() + text="✉️ Сообщение", callback_data=AdminUserEditorCallback(action="users_send_message", tg_id=tg_id).pack() ) builder.button( text="💸 Изменить баланс", - callback_data=AdminUserEditorCallback( - action="users_balance_edit", - tg_id=tg_id - ).pack() + callback_data=AdminUserEditorCallback(action="users_balance_edit", tg_id=tg_id).pack(), ) builder.button( text="♻️ Восстановить триал", - callback_data=AdminUserEditorCallback( - action="users_trial_restore", - tg_id=tg_id - ).pack() + callback_data=AdminUserEditorCallback(action="users_trial_restore", tg_id=tg_id).pack(), ) builder.button( - text="❌ Удалить клиента", - callback_data=AdminUserEditorCallback( - action="users_delete_user", - tg_id=tg_id - ).pack() - ) - builder.row( - build_editor_btn("🔄 Обновить данные", tg_id, edit=True) - ) - builder.row( - build_admin_back_btn() + text="❌ Удалить клиента", callback_data=AdminUserEditorCallback(action="users_delete_user", tg_id=tg_id).pack() ) + builder.row(build_editor_btn("🔄 Обновить данные", tg_id, edit=True)) + builder.row(build_admin_back_btn()) builder.adjust(1) return builder.as_markup() @@ -81,10 +59,7 @@ def build_users_balance_change_kb(tg_id: int) -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() builder.button( text="🔙 Назад", # todo: fix magic text was set - callback_data=AdminUserEditorCallback( - action="users_balance_edit", - tg_id=tg_id - ).pack() + callback_data=AdminUserEditorCallback(action="users_balance_edit", tg_id=tg_id).pack(), ) return builder.as_markup() @@ -94,44 +69,23 @@ def build_users_balance_kb(tg_id: int) -> InlineKeyboardMarkup: for month, amount in RENEWAL_PRICES.items(): builder.button( text=f"+ {amount}Р ({month} мес.)", - callback_data=AdminUserEditorCallback( - action="users_balance_add", - tg_id=tg_id, - data=amount - ).pack() + callback_data=AdminUserEditorCallback(action="users_balance_add", tg_id=tg_id, data=amount).pack(), ) builder.button( text=f"- {amount}Р ({month} мес.)", - callback_data=AdminUserEditorCallback( - action="users_balance_add", - tg_id=tg_id, - data=-amount - ).pack() + callback_data=AdminUserEditorCallback(action="users_balance_add", tg_id=tg_id, data=-amount).pack(), ) builder.button( - text="💵 Добавить", - callback_data=AdminUserEditorCallback( - action="users_balance_add", - tg_id=tg_id - ).pack() + text="💵 Добавить", callback_data=AdminUserEditorCallback(action="users_balance_add", tg_id=tg_id).pack() ) builder.button( - text="💵 Вычесть", - callback_data=AdminUserEditorCallback( - action="users_balance_take", - tg_id=tg_id - ).pack() + text="💵 Вычесть", callback_data=AdminUserEditorCallback(action="users_balance_take", tg_id=tg_id).pack() ) builder.button( text="💵 Установить баланс", - callback_data=AdminUserEditorCallback( - action="users_balance_set", - tg_id=tg_id - ).pack() - ) - builder.row( - build_editor_back_btn(tg_id, True) + callback_data=AdminUserEditorCallback(action="users_balance_set", tg_id=tg_id).pack(), ) + builder.row(build_editor_back_btn(tg_id, True)) builder.adjust(2, 2, 2, 2, 2, 1) return builder.as_markup() @@ -140,12 +94,7 @@ def build_users_key_show_kb(tg_id: int, email: str) -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() builder.button( text="🔙 Назад", # todo: fix magic text was set - callback_data=AdminUserEditorCallback( - action="users_key_edit", - tg_id=tg_id, - data=email, - edit=True - ).pack() + callback_data=AdminUserEditorCallback(action="users_key_edit", tg_id=tg_id, data=email, edit=True).pack(), ) return builder.as_markup() @@ -156,53 +105,25 @@ def build_users_key_expiry_kb(tg_id: int, email: str) -> InlineKeyboardMarkup: month = int(month) builder.button( text=f"+ {month} мес.", - callback_data=AdminUserKeyEditorCallback( - action="add", - tg_id=tg_id, - data=email, - month=month - ).pack() + callback_data=AdminUserKeyEditorCallback(action="add", tg_id=tg_id, data=email, month=month).pack(), ) builder.button( text=f"- {month} мес.", - callback_data=AdminUserKeyEditorCallback( - action="add", - tg_id=tg_id, - data=email, - month=-month - ).pack() + callback_data=AdminUserKeyEditorCallback(action="add", tg_id=tg_id, data=email, month=-month).pack(), ) builder.button( - text="⏳ Добавить дни", - callback_data=AdminUserKeyEditorCallback( - action="add", - tg_id=tg_id, - data=email - ).pack() + text="⏳ Добавить дни", callback_data=AdminUserKeyEditorCallback(action="add", tg_id=tg_id, data=email).pack() ) builder.button( - text="⏳ Вычесть дни", - callback_data=AdminUserKeyEditorCallback( - action="take", - tg_id=tg_id, - data=email - ).pack() + text="⏳ Вычесть дни", callback_data=AdminUserKeyEditorCallback(action="take", tg_id=tg_id, data=email).pack() ) builder.button( text="⏳ Установить дату истечения", - callback_data=AdminUserKeyEditorCallback( - action="set", - tg_id=tg_id, - data=email - ).pack() + callback_data=AdminUserKeyEditorCallback(action="set", tg_id=tg_id, data=email).pack(), ) builder.button( text="🔙 Назад", # todo: fix magic text was set - callback_data=AdminUserEditorCallback( - action="users_key_edit", - tg_id=tg_id, - data=email - ).pack() + callback_data=AdminUserEditorCallback(action="users_key_edit", tg_id=tg_id, data=email).pack(), ) builder.adjust(2, 2, 2, 2, 2, 1) return builder.as_markup() @@ -212,14 +133,9 @@ def build_user_delete_kb(tg_id: int): builder = InlineKeyboardBuilder() builder.button( text="❌ Да, удалить!", - callback_data=AdminUserEditorCallback( - action="users_delete_user_confirm", - tg_id=tg_id - ).pack() - ) - builder.row( - build_editor_back_btn(tg_id, True) + callback_data=AdminUserEditorCallback(action="users_delete_user_confirm", tg_id=tg_id).pack(), ) + builder.row(build_editor_back_btn(tg_id, True)) builder.adjust(1) return builder.as_markup() @@ -227,12 +143,7 @@ def build_user_delete_kb(tg_id: int): def build_user_key_kb(tg_id: int, email: str) -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() builder.button( - text=f"🔙 Назад", - callback_data=AdminUserEditorCallback( - action="users_key_edit", - tg_id=tg_id, - data=email - ).pack() + text=f"🔙 Назад", callback_data=AdminUserEditorCallback(action="users_key_edit", tg_id=tg_id, data=email).pack() ) builder.adjust(1) return builder.as_markup() @@ -243,30 +154,18 @@ def build_key_edit_kb(key_details: dict, email: str) -> InlineKeyboardMarkup: builder.button( text="⏳ Время истечения", callback_data=AdminUserEditorCallback( - action="users_expiry_edit", - data=email, - tg_id=key_details["tg_id"] - ).pack() + action="users_expiry_edit", data=email, tg_id=key_details["tg_id"] + ).pack(), ) builder.button( text="🔄 Перевыпустить", - callback_data=AdminUserEditorCallback( - action="users_update_key", - data=email, - tg_id=key_details["tg_id"] - ).pack() + callback_data=AdminUserEditorCallback(action="users_update_key", data=email, tg_id=key_details["tg_id"]).pack(), ) builder.button( text="❌ Удалить", - callback_data=AdminUserEditorCallback( - action="users_delete_key", - data=email, - tg_id=key_details["tg_id"] - ).pack() - ) - builder.row( - build_editor_back_btn(key_details["tg_id"], True) + callback_data=AdminUserEditorCallback(action="users_delete_key", data=email, tg_id=key_details["tg_id"]).pack(), ) + builder.row(build_editor_back_btn(key_details["tg_id"], True)) builder.adjust(1) return builder.as_markup() @@ -276,16 +175,10 @@ def build_key_delete_kb(tg_id: int, email: str) -> InlineKeyboardMarkup: builder.row( InlineKeyboardButton( text="✅ Да, удалить", - callback_data=AdminUserEditorCallback( - action="users_delete_key_confirm", - data=email, - tg_id=tg_id - ).pack() + callback_data=AdminUserEditorCallback(action="users_delete_key_confirm", data=email, tg_id=tg_id).pack(), ) ) - builder.row( - build_editor_back_btn(tg_id) - ) + builder.row(build_editor_back_btn(tg_id)) builder.adjust(1) return builder.as_markup() @@ -296,9 +189,7 @@ def build_editor_kb(tg_id: int, edit: bool = False) -> InlineKeyboardMarkup: def build_editor_singleton_kb(text: str, tg_id: int, edit: bool = False) -> InlineKeyboardMarkup: builder = InlineKeyboardBuilder() - builder.row( - build_editor_btn(text, tg_id, edit) - ) + builder.row(build_editor_btn(text, tg_id, edit)) return builder.as_markup() @@ -308,10 +199,5 @@ def build_editor_back_btn(tg_id: int, edit: bool = False) -> InlineKeyboardButto def build_editor_btn(text: str, tg_id: int, edit: bool = False) -> InlineKeyboardButton: return InlineKeyboardButton( - text=text, - callback_data=AdminUserEditorCallback( - action="users_editor", - tg_id=tg_id, - edit=edit - ).pack() + text=text, callback_data=AdminUserEditorCallback(action="users_editor", tg_id=tg_id, edit=edit).pack() ) diff --git a/middlewares/delete.py b/middlewares/delete.py index 29281507..af20634f 100644 --- a/middlewares/delete.py +++ b/middlewares/delete.py @@ -22,20 +22,15 @@ pass_callbacks = [ class DeleteMessageMiddleware(BaseMiddleware): async def __call__( - self, - handler: Callable[[TelegramObject, dict[str, Any]], Awaitable[Any]], - event: TelegramObject, - data: dict[str, Any], + self, + handler: Callable[[TelegramObject, dict[str, Any]], Awaitable[Any]], + event: TelegramObject, + data: dict[str, Any], ) -> Any: if isinstance(event, Message): - if ( - not event.text - or not event.text.startswith("/start") - ): + if not event.text or not event.text.startswith("/start"): try: - await event.bot.delete_message( - event.chat.id, event.message_id - 1 - ) + await event.bot.delete_message(event.chat.id, event.message_id - 1) except Exception: pass await event.delete() diff --git a/utils/csv_export.py b/utils/csv_export.py index 08cc1c59..4b39c023 100644 --- a/utils/csv_export.py +++ b/utils/csv_export.py @@ -35,10 +35,7 @@ async def export_users_csv(session: Any) -> BufferedInputFile: # Перемещение указателя в начало для чтения buffer.seek(0) - return BufferedInputFile( - file=buffer.getvalue().encode("utf-8-sig"), - filename="users_export.csv" - ) + return BufferedInputFile(file=buffer.getvalue().encode("utf-8-sig"), filename="users_export.csv") async def export_payments_csv(session: Any) -> BufferedInputFile: @@ -95,7 +92,4 @@ def _export_payments_csv(payments: list, filename: str) -> BufferedInputFile: # Перемещение указателя в начало для чтения buffer.seek(0) - return BufferedInputFile( - file=buffer.getvalue().encode("utf-8-sig"), - filename=filename - ) + return BufferedInputFile(file=buffer.getvalue().encode("utf-8-sig"), filename=filename)