From aadd2edf45b6657fe03d3dfb37573d4f37e7757b Mon Sep 17 00:00:00 2001 From: hteppl Date: Wed, 15 Jan 2025 08:01:16 +0300 Subject: [PATCH] Optimize and fix admin handlers logic --- handlers/admin/admin_backups.py | 20 ++- handlers/admin/admin_coupons.py | 21 +-- handlers/admin/admin_panel.py | 10 +- handlers/admin/admin_restart.py | 19 ++- handlers/admin/admin_sender.py | 19 ++- handlers/admin/admin_servers.py | 53 ++++--- handlers/admin/admin_stats.py | 20 ++- handlers/admin/admin_users.py | 262 ++++++++++++++++++-------------- 8 files changed, 231 insertions(+), 193 deletions(-) diff --git a/handlers/admin/admin_backups.py b/handlers/admin/admin_backups.py index d287659b..6d14fba5 100644 --- a/handlers/admin/admin_backups.py +++ b/handlers/admin/admin_backups.py @@ -3,7 +3,7 @@ from aiogram.types import CallbackQuery from backup import backup_database from filters.admin import IsAdminFilter -from keyboards.admin.panel_kb import AdminPanelCallback +from keyboards.admin.panel_kb import AdminPanelCallback, build_admin_back_kb router = Router() @@ -12,11 +12,19 @@ router = Router() AdminPanelCallback.filter(F.action == "backups"), IsAdminFilter(), ) -async def handle_backup(callback_query: CallbackQuery): - await callback_query.message.answer( - text="💾 Инициализация резервного копирования базы данных..." +async def handle_backup( + callback_query: CallbackQuery +): + kb = build_admin_back_kb("management") + + await callback_query.message.edit_text( + text="💾 Инициализация резервного копирования базы данных...", + reply_markup=kb ) + await backup_database() - await callback_query.message.answer( - text="✅ Резервная копия успешно создана и отправлена администратору." + + await callback_query.message.edit_text( + text="✅ Резервная копия успешно создана и отправлена администратору.", + reply_markup=kb ) diff --git a/handlers/admin/admin_coupons.py b/handlers/admin/admin_coupons.py index ddcbf67b..b890b61e 100644 --- a/handlers/admin/admin_coupons.py +++ b/handlers/admin/admin_coupons.py @@ -23,15 +23,10 @@ class AdminCouponsState(StatesGroup): ) async def show_coupon_management_menu( callback_query: types.CallbackQuery, - state: FSMContext ): - await state.clear() - - kb = build_coupons_kb() - - await callback_query.message.answer( + await callback_query.message.edit_text( text="🛠 Меню управления купонами:", - reply_markup=kb + reply_markup=build_coupons_kb() ) @@ -49,7 +44,7 @@ async def handle_create_coupon( "Пример: 'COUPON1 50 5' 👈\n\n" ) - await callback_query.message.answer( + await callback_query.message.edit_text( text=text, reply_markup=build_admin_back_kb("coupons"), ) @@ -102,14 +97,14 @@ async def process_coupon_data( try: await create_coupon(coupon_code, coupon_amount, usage_limit, session) - result_message = ( + text = ( f"✅ Купон с кодом {coupon_code} успешно создан!\n" f"💰 Сумма: {coupon_amount} рублей \n" f"🔢 Лимит использования: {usage_limit} раз" ) await message.answer( - text=result_message, + text=text, reply_markup=kb ) await state.clear() @@ -130,8 +125,8 @@ async def show_coupon_list( coupons = await get_all_coupons(session) if not coupons: - await callback_query.message.answer( - text="❌ На данный момент нет доступных купонов. 🚫\nВы можете вернуться в меню управления. 🔙", + await callback_query.message.edit_text( + text="❌ На данный момент нет доступных купонов!", reply_markup=build_admin_back_kb("coupons"), ) return @@ -147,7 +142,7 @@ async def show_coupon_list( f"✅ Использовано: {coupon['usage_count']} раз\n\n" ) - await callback_query.message.answer( + await callback_query.message.edit_text( text=coupon_list, reply_markup=kb ) diff --git a/handlers/admin/admin_panel.py b/handlers/admin/admin_panel.py index d1ffbdf7..fe77f1d0 100644 --- a/handlers/admin/admin_panel.py +++ b/handlers/admin/admin_panel.py @@ -14,7 +14,11 @@ router = Router() IsAdminFilter() ) async def handle_admin_callback_query(callback_query: CallbackQuery, state: FSMContext): - await handle_admin_message(callback_query.message, state) + await state.clear() + await callback_query.message.edit_text( + text="🤖 Панель администратора", + reply_markup=build_panel_kb() + ) @router.callback_query( @@ -31,7 +35,7 @@ async def handle_admin_callback_query(callback_query: CallbackQuery, state: FSMC ) async def handle_admin_message(message: types.Message, state: FSMContext): await state.clear() - await message.message.answer( + await message.answer( text="🤖 Панель администратора", reply_markup=build_panel_kb() ) @@ -41,7 +45,7 @@ async def handle_admin_message(message: types.Message, state: FSMContext): AdminPanelCallback.filter(F.action == "management"), IsAdminFilter() ) -async def handle_restart(callback_query: CallbackQuery): +async def handle_management(callback_query: CallbackQuery): await callback_query.message.edit_text( text="🤖 Управление ботом", reply_markup=build_management_kb(), diff --git a/handlers/admin/admin_restart.py b/handlers/admin/admin_restart.py index 47cbc134..be39f694 100644 --- a/handlers/admin/admin_restart.py +++ b/handlers/admin/admin_restart.py @@ -14,10 +14,9 @@ router = Router() IsAdminFilter(), ) async def handle_restart(callback_query: CallbackQuery): - kb = build_restart_kb() - await callback_query.message.answer( - text="🤔 Вы уверены, что хотите перезапустить бота?", - reply_markup=kb, + await callback_query.message.edit_text( + text="🤔 Вы уверены, что хотите перезагрузить бота?", + reply_markup=build_restart_kb(), ) @@ -26,7 +25,7 @@ async def handle_restart(callback_query: CallbackQuery): IsAdminFilter(), ) async def confirm_restart_bot(callback_query: CallbackQuery): - kb = build_admin_back_kb("admin") + kb = build_admin_back_kb() try: subprocess.run( ["sudo", "systemctl", "restart", "bot.service"], @@ -34,17 +33,17 @@ async def confirm_restart_bot(callback_query: CallbackQuery): capture_output=True, text=True, ) - await callback_query.message.answer( - text="🔄 Бот успешно перезапущен.", + await callback_query.message.edit_text( + text="🔄 Бот успешно перезагружен!", reply_markup=kb ) except subprocess.CalledProcessError: - await callback_query.message.answer( - text="🔄 Бот успешно перезапущен.", + await callback_query.message.edit_text( + text="🔄 Бот успешно перезагружен!", reply_markup=kb ) except Exception as e: - await callback_query.message.answer( + 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 101aaf86..9eb91b55 100644 --- a/handlers/admin/admin_sender.py +++ b/handlers/admin/admin_sender.py @@ -26,14 +26,14 @@ class AdminSender(StatesGroup): async def handle_sender( callback_query: CallbackQuery ): - await callback_query.message.answer( + await callback_query.message.edit_text( text="✍️ Выберите группу пользователей для рассылки:", reply_markup=build_sender_kb(), ) @router.callback_query( - AdminSenderCallback, + AdminSenderCallback.filter(), IsAdminFilter(), ) async def handle_sender_callback( @@ -41,7 +41,7 @@ async def handle_sender_callback( callback_data: AdminSenderCallback, state: FSMContext ): - await callback_query.message.answer( + await callback_query.message.edit_text( text="✍️ Введите текст сообщения для рассылки:", reply_markup=build_admin_back_kb("sender"), ) @@ -93,11 +93,16 @@ async def process_message( except Exception: pass + text = ( + f"📤 Рассылка завершена!" + f"\n\n👥 Всего пользователей: {total_users}" + f"\n✅ Доставлено: {success_count}" + f"\n❌ Не доставлено: {total_users - success_count}" + ) + await message.answer( - f"📤 Рассылка завершена:\n" - f"👥 Всего пользователей: {total_users}\n" - f"✅ Доставлено: {success_count}\n" - f"❌ Не доставлено: {total_users - success_count}" + 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 0cab2ec4..1b12d60e 100644 --- a/handlers/admin/admin_servers.py +++ b/handlers/admin/admin_servers.py @@ -25,7 +25,7 @@ class AdminServersEditor(StatesGroup): @router.callback_query( - AdminPanelCallback.filter(F.action == "servers_editor"), + AdminPanelCallback.filter(F.action == "servers"), IsAdminFilter(), ) async def handle_servers_editor( @@ -41,7 +41,7 @@ async def handle_servers_editor( "⚠️ Важно: Кластеры удаляются автоматически, если удалить все серверы внутри них.\n\n" ) - await callback_query.message.answer( + await callback_query.message.edit_text( text=text, parse_mode="HTML", reply_markup=build_clusters_editor_kb(servers), @@ -62,7 +62,7 @@ async def handle_add_cluster( "Пример: cluster1 или us_east_1" ) - await callback_query.message.answer( + await callback_query.message.edit_text( text=text, parse_mode="HTML", ) @@ -93,10 +93,10 @@ async def handle_cluster_name_input( "Пример: server-frankfurt1, fra1" ) - await message.answer( + await message.edit_text( text=text, parse_mode="HTML", - reply_markup=build_admin_back_kb("servers_editor"), + reply_markup=build_admin_back_kb("servers"), ) await state.set_state(AdminServersEditor.waiting_for_server_name) @@ -135,10 +135,10 @@ async def handle_server_name_input( "URL должен быть без слэша на конце!\n" ) - await message.answer( + await message.edit_text( text=text, parse_mode="HTML", - reply_markup=build_admin_back_kb("servers_editor"), + reply_markup=build_admin_back_kb("servers"), ) await state.set_state(AdminServersEditor.waiting_for_api_url) @@ -174,7 +174,7 @@ async def handle_api_url_input( "Его можно увидеть в панели 3x-ui в информации о клиенте." ) - await message.answer( + await message.edit_text( text=text, parse_mode="HTML", reply_markup=build_cancel_kb(), @@ -210,10 +210,10 @@ async def handle_subscription_url_input( "Это номер подключения vless в вашей панели 3x-ui. Обычно это 1 при чистой настройке по гайду.\n\n" ) - await message.answer( + await message.edit_text( text=text, parse_mode="HTML", - reply_markup=build_admin_back_kb("servers_editor"), + reply_markup=build_admin_back_kb("servers"), ) await state.set_state(AdminServersEditor.waiting_for_inbound_id) @@ -254,9 +254,9 @@ async def handle_inbound_id_input( ) await conn.close() - await message.answer( + await message.edit_text( text=f"✅ Кластер {cluster_name} и сервер {server_name} успешно добавлены!", - reply_markup=build_admin_back_kb("servers_editor"), + reply_markup=build_admin_back_kb("servers"), ) await state.clear() @@ -275,7 +275,7 @@ async def handle_manage_cluster( servers = await get_servers_from_db() cluster_servers = servers.get(cluster_name, []) - await callback_query.message.answer( + await callback_query.message.edit_text( text=f"🔧 Управление серверами для кластера {cluster_name}", reply_markup=build_manage_cluster_kb(cluster_servers, cluster_name), ) @@ -295,7 +295,7 @@ async def handle_check_server_availability( cluster_servers = servers.get(cluster_name, []) if not cluster_servers: - await callback_query.answer( + await callback_query.message.answer( text=f"Кластер '{cluster_name}' не содержит серверов." ) return @@ -331,11 +331,9 @@ async def handle_check_server_availability( await in_progress_message.edit_text( text=text, - reply_markup=build_admin_back_kb("servers_editor") + reply_markup=build_admin_back_kb("servers") ) - await callback_query.answer() - @router.callback_query( AdminServerEditorCallback.filter(F.action == "servers_manage"), @@ -366,13 +364,15 @@ async def handle_manage_server( f"🔑 Inbound ID: {inbound_id}" ) - await callback_query.message.answer( + await callback_query.message.edit_text( text=text, parse_mode="HTML", reply_markup=build_manage_server_kb(server_name, cluster_name), ) else: - await callback_query.message.answer("❌ Сервер не найден.") + await callback_query.message.edit_text( + text="❌ Сервер не найден." + ) @router.callback_query( @@ -385,7 +385,7 @@ async def handle_delete_server( ): server_name = callback_data.data - await callback_query.message.answer( + await callback_query.message.edit_text( text=f"🗑️ Вы уверены, что хотите удалить сервер {server_name}?", reply_markup=build_delete_server_kb(server_name), ) @@ -410,9 +410,9 @@ async def handle_confirm_delete_server( ) await conn.close() - await callback_query.message.answer( + await callback_query.message.edit_text( text=f"🗑️ Сервер {server_name} успешно удален.", - reply_markup=build_admin_back_kb("servers_editor") + reply_markup=build_admin_back_kb("servers") ) @@ -435,10 +435,10 @@ async def handle_add_server( "Пример: server-asia, server-europe" ) - await callback_query.message.answer( + await callback_query.message.edit_text( text=text, parse_mode="HTML", - reply_markup=build_admin_back_kb("servers_editor"), + reply_markup=build_admin_back_kb("servers"), ) await state.set_state(AdminServersEditor.waiting_for_server_name) @@ -470,9 +470,8 @@ async def handle_backup_cluster( f"🔔 Бэкапы отправлены в боты панелей." ) - await callback_query.message.answer( + await callback_query.message.edit_text( text=text, parse_mode="HTML", - reply_markup=build_admin_back_kb("servers_editor"), + reply_markup=build_admin_back_kb("servers"), ) - await callback_query.answer() diff --git a/handlers/admin/admin_stats.py b/handlers/admin/admin_stats.py index 113a6caa..c83456a8 100644 --- a/handlers/admin/admin_stats.py +++ b/handlers/admin/admin_stats.py @@ -93,7 +93,7 @@ async def export_users_csv(callback_query: CallbackQuery, session: Any): ) if not users: - await callback_query.message.answer( + await callback_query.message.edit_text( text="📭 Нет пользователей для экспорта.", reply_markup=kb ) @@ -109,16 +109,15 @@ async def export_users_csv(callback_query: CallbackQuery, session: Any): file = BufferedInputFile(file_name.getvalue(), filename="users_export.csv") await callback_query.message.answer_document( - file, - caption="📥 Экспорт пользователей в CSV", - reply_markup=kb + document=file, + caption="📥 Экспорт пользователей в CSV" ) file_name.close() except Exception as e: logger.error(f"Ошибка при экспорте пользователей в CSV: {e}") - await callback_query.message.answer( - text="❗ Произошла ошибка при экспорте пользователей.", + await callback_query.message.edit_text( + text=f"❗ Произошла ошибка при экспорте: {e}", reply_markup=kb ) @@ -148,7 +147,7 @@ async def export_payments_csv(callback_query: CallbackQuery, session: Any): ) if not payments: - await callback_query.message.answer( + await callback_query.message.edit_text( text="📭 Нет платежей для экспорта.", reply_markup=kb ) @@ -165,14 +164,13 @@ async def export_payments_csv(callback_query: CallbackQuery, session: Any): await callback_query.message.answer_document( document=file, - caption="📥 Экспорт платежей в CSV", - reply_markup=kb + caption="📥 Экспорт платежей в CSV" ) file_name.close() except Exception as e: logger.error(f"Ошибка при экспорте платежей в CSV: {e}") - await callback_query.message.answer( - text="❗ Произошла ошибка при экспорте платежей.", + await callback_query.message.edit_text( + text=f"❗ Произошла ошибка при экспорте: {e}", reply_markup=kb ) diff --git a/handlers/admin/admin_users.py b/handlers/admin/admin_users.py index be8b5361..a0ffb8a8 100644 --- a/handlers/admin/admin_users.py +++ b/handlers/admin/admin_users.py @@ -6,8 +6,8 @@ from aiogram import Bot, F, Router, types from aiogram.fsm.context import FSMContext from aiogram.fsm.state import State, StatesGroup from aiogram.types import CallbackQuery -from config import TOTAL_GB +from config import TOTAL_GB from database import delete_user_data, get_client_id_by_email, get_servers_from_db, restore_trial, update_key_expiry from filters.admin import IsAdminFilter from handlers.keys.key_utils import ( @@ -18,7 +18,7 @@ from handlers.keys.key_utils import ( 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_user_delete_kb, AdminUserEditorCallback, build_editor_kb from logger import logger router = Router() @@ -35,7 +35,7 @@ class UserEditorState(StatesGroup): @router.callback_query( - AdminPanelCallback.filter(F.action == "users_search"), + AdminPanelCallback.filter(F.action == "search_user"), IsAdminFilter(), ) async def handle_users_search( @@ -44,19 +44,19 @@ async def handle_users_search( ): text = ( "🔍 Введите ID или Username пользователя для поиска:" - "\n— ID - числовой айди пользователя" - "\n— Username - юзернейм пользователя, начинающийся с @ или https://t.me/" + "\n\n🆔 ID - числовой айди" + "\n📝 Username - юзернейм пользователя" ) await state.set_state(UserEditorState.waiting_for_user_data) - await callback_query.message.answer( + await callback_query.message.edit_text( text=text, - reply_markup=build_admin_back_kb("users_editor") + reply_markup=build_admin_back_kb() ) @router.callback_query( - AdminPanelCallback.filter(F.action == "users_search_key"), + AdminPanelCallback.filter(F.action == "search_key"), IsAdminFilter(), ) async def handle_users_search_key( @@ -64,9 +64,9 @@ async def handle_users_search_key( state: FSMContext ): await state.set_state(UserEditorState.waiting_for_key_name) - await callback_query.message.answer( + await callback_query.message.edit_text( text="🔑 Введите имя ключа для поиска:", - reply_markup=build_admin_back_kb("users_editor") + reply_markup=build_admin_back_kb() ) @@ -79,11 +79,11 @@ async def handle_user_data_input( state: FSMContext, session: Any ): - kb = build_admin_back_kb("users_editor") + kb = build_admin_back_kb() if not message.text: await message.reply( - text="💢 Пожалуйста, отправьте текстовое сообщение.", + text="🚫 Пожалуйста, отправьте текстовое сообщение.", reply_markup=kb ) return @@ -101,11 +101,10 @@ async def handle_user_data_input( ) if not user: - await message.answer( - text="🔍 Пользователь с указанным username не найден. 🚫", + await message.reply( + text="🚫 Пользователь с указанным Username не найден!", reply_markup=kb, ) - await state.clear() return tg_id = user["tg_id"] @@ -113,23 +112,6 @@ async def handle_user_data_input( await process_user_search(message, state, session, tg_id) -@router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_send_message"), - IsAdminFilter(), -) -async def handle_send_message( - callback_query: types.CallbackQuery, - callback_data: AdminUserEditorCallback, - state: FSMContext -): - tg_id = callback_data.data - await callback_query.message.answer( - "✉️ Введите текст сообщения, которое вы хотите отправить пользователю." - ) - await state.update_data(target_tg_id=tg_id) - await state.set_state(UserEditorState.waiting_for_message_text) - - @router.message( UserEditorState.waiting_for_message_text, IsAdminFilter() @@ -140,22 +122,46 @@ async def handle_message_text_input( bot: Bot ): data = await state.get_data() - target_tg_id = data.get("target_tg_id") - - if not target_tg_id: - await message.answer("🚫 Ошибка: ID пользователя не найден.") - await state.clear() - return + tg_id = data.get("tg_id") try: - await bot.send_message(chat_id=target_tg_id, text=message.text) - await message.answer("✅ Сообщение успешно отправлено.") + await 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(f"❌ Не удалось отправить сообщение: {e}") + await message.answer( + text=f"❌ Не удалось отправить сообщение: {e}", + reply_markup=build_editor_kb(tg_id) + ) await state.clear() +@router.callback_query( + AdminUserEditorCallback.filter(F.action == "users_send_message"), + IsAdminFilter(), +) +async def handle_send_message( + 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) + ) + + await state.update_data(tg_id=tg_id) + await state.set_state(UserEditorState.waiting_for_message_text) + + @router.callback_query( AdminUserEditorCallback.filter(F.action == "users_trial_restore"), IsAdminFilter(), @@ -165,11 +171,11 @@ async def handle_restore_trial( callback_data: AdminUserEditorCallback, session: Any ): - tg_id = int(callback_data.data) + tg_id = callback_data.tg_id await restore_trial(tg_id, session) - await callback_query.message.answer( - text="✅ Триал успешно восстановлен.", - reply_markup=build_admin_back_kb("admin") + await callback_query.message.edit_text( + text="✅ Триал успешно восстановлен!", + reply_markup=build_editor_kb(tg_id) ) @@ -182,11 +188,10 @@ async def process_balance_change( callback_data: AdminUserEditorCallback, state: FSMContext ): - tg_id = int(callback_data.data) - await state.update_data(tg_id=tg_id) - await callback_query.message.answer( + await state.update_data(tg_id=callback_data.tg_id) + await callback_query.message.edit_text( text="💸 Введите новую сумму баланса:", - reply_markup=build_admin_back_kb("users_editor") + reply_markup=build_editor_kb(callback_data.tg_id) ) await state.set_state(UserEditorState.waiting_for_new_balance) @@ -200,16 +205,17 @@ async def handle_new_balance_input( state: FSMContext, session: Any ): + user_data = await state.get_data() + tg_id = user_data.get("tg_id") + if not message.text.isdigit() or int(message.text) < 0: - await message.answer( + await message.edit_text( text="❌ Пожалуйста, введите корректную сумму для изменения баланса.", - reply_markup=build_admin_back_kb("users_editor"), + reply_markup=build_editor_kb(tg_id), ) return new_balance = int(message.text) - user_data = await state.get_data() - tg_id = user_data.get("tg_id") await session.execute( "UPDATE connections SET balance = $1 WHERE tg_id = $2", @@ -217,9 +223,9 @@ async def handle_new_balance_input( tg_id, ) - await message.answer( + await message.edit_text( text=f"✅ Баланс успешно изменен на {new_balance}.", - reply_markup=build_admin_back_kb("admin") + reply_markup=build_admin_back_kb() ) await state.clear() @@ -237,21 +243,21 @@ async def process_key_edit( key_details = await get_key_details(email, session) if not key_details: - await callback_query.message.answer( - text="🔍 Информация о ключе не найдена. 🚫", - reply_markup=build_admin_back_kb("users_editor"), + await callback_query.message.edit_text( + text="🚫 Информация о ключе не найдена.", + reply_markup=build_editor_kb(callback_data.tg_id), ) return - response_message = ( + text = ( f"🔑 Ключ: {key_details['key']}\n" f"⏰ Дата истечения: {key_details['expiry_date']}\n" f"💰 Баланс пользователя: {key_details['balance']}\n" f"🌐 Кластер: {key_details['server_name']}" ) - await callback_query.message.answer( - text=response_message, + await callback_query.message.edit_text( + text=text, reply_markup=build_key_edit_kb(key_details, email) ) @@ -269,22 +275,22 @@ async def handle_key_name_input( key_details = await get_key_details(key_name, session) if not key_details: - await message.answer( + await message.edit_text( text="🚫 Пользователь с указанным именем ключа не найден.", - reply_markup=build_admin_back_kb("users_editor") + reply_markup=build_admin_back_kb() ) await state.clear() return - response_message = ( + text = ( f"🔑 Ключ: {key_details['key']}\n" f"⏰ Дата истечения: {key_details['expiry_date']}\n" f"💰 Баланс пользователя: {key_details['balance']}\n" f"🌐 Сервер: {key_details['server_name']}" ) - await message.answer( - text=response_message, + await message.edit_text( + text=text, reply_markup=build_key_edit_kb(key_details, key_name) ) await state.clear() @@ -300,10 +306,10 @@ async def prompt_expiry_change( state: FSMContext ): email = callback_data.data - await callback_query.message.answer( + await callback_query.message.edit_text( text=f"⏳ Введите новое время истечения для ключа {email} в формате YYYY-MM-DD HH:MM:SS:" ) - await state.update_data(email=email) + await state.update_data(tg_id=callback_data.tg_id, email=email) await state.set_state(UserEditorState.waiting_for_expiry_time) @@ -319,36 +325,29 @@ async def handle_expiry_time_input( user_data = await state.get_data() email = user_data.get("email") - if not email: - await message.answer( - text="📧 Email не найден в состоянии. 🚫", - reply_markup=build_admin_back_kb("users_editor") - ) - await state.clear() - return - try: - expiry_time_str = message.text expiry_time = int( - datetime.strptime(expiry_time_str, "%Y-%m-%d %H:%M:%S").timestamp() * 1000 + datetime.strptime(message.text, "%Y-%m-%d %H:%M:%S").timestamp() * 1000 ) client_id = await get_client_id_by_email(email) + if client_id is None: - await message.answer( - text=f"🚫 Клиент с email {email} не найден. 🔍", - reply_markup=build_admin_back_kb("users_editor"), + await message.edit_text( + text=f"🚫 Клиент с Email {email} не найден. 🔍", + reply_markup=build_admin_back_kb(), ) await state.clear() return - record = await session.fetchrow( + server_id = await session.fetchrow( "SELECT server_id FROM keys WHERE client_id = $1", client_id ) - if not record: - await message.answer( + + if not server_id: + await message.edit_text( text="🚫 Клиент не найден в базе данных. 🔍", - reply_markup=build_admin_back_kb("users_editor"), + reply_markup=build_admin_back_kb(), ) await state.clear() return @@ -372,19 +371,19 @@ async def handle_expiry_time_input( await asyncio.gather(*tasks) await update_key_on_all_servers() - await update_key_expiry(client_id, expiry_time) response_message = f"✅ Время истечения ключа для клиента {client_id} ({email}) успешно обновлено на всех серверах." - await message.answer( + await message.edit_text( text=response_message, - reply_markup=build_admin_back_kb("admin") + reply_markup=build_admin_back_kb() ) except ValueError: - await message.answer( + tg_id = user_data.get("tg_id") + await message.edit_text( text="❌ Пожалуйста, используйте формат: YYYY-MM-DD HH:MM:SS.", - reply_markup=build_admin_back_kb("users_editor"), + reply_markup=build_editor_kb(tg_id), ) except Exception as e: logger.error(e) @@ -406,15 +405,15 @@ async def process_callback_delete_key( ) if client_id is None: - await callback_query.message.answer( - text="🔍 Ключ не найден. 🚫", - reply_markup=build_admin_back_kb("users_editor") + await callback_query.message.edit_text( + text="🚫 Ключ не найден!", + reply_markup=build_editor_kb(callback_data.tg_id) ) return - await callback_query.message.answer( - text="❓ Вы уверены, что хотите удалить ключ?", - reply_markup=build_key_delete_kb(client_id), + await callback_query.message.edit_text( + text="❓ Вы уверены, что хотите удалить ключ?", + reply_markup=build_key_delete_kb(callback_data.tg_id, client_id) ) @@ -432,7 +431,7 @@ async def process_callback_confirm_delete( "SELECT email FROM keys WHERE client_id = $1", client_id ) - kb = build_admin_back_kb("users_editor") + kb = build_editor_kb(callback_data.tg_id) if record: clusters = await get_servers_from_db() @@ -449,12 +448,12 @@ async def process_callback_confirm_delete( await delete_key_from_servers(record["email"], client_id) await delete_key_from_db(client_id, session) - await callback_query.message.answer( + await callback_query.message.edit_text( text="✅ Ключ успешно удален.", reply_markup=kb ) else: - await callback_query.message.answer( + await callback_query.message.edit_text( text="🚫 Ключ не найден или уже удален.", reply_markup=kb ) @@ -464,12 +463,27 @@ async def process_callback_confirm_delete( AdminUserEditorCallback.filter(F.action == "users_delete_user"), IsAdminFilter() ) +async def confirm_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) + ) + + +@router.callback_query( + AdminUserEditorCallback.filter(F.action == "users_delete_user_confirm"), + IsAdminFilter() +) async def delete_user( callback_query: types.CallbackQuery, callback_data: AdminUserEditorCallback, session: Any ): - tg_id = int(callback_data.data) + tg_id = callback_data.tg_id key_records = await session.fetch("SELECT email, client_id FROM keys WHERE tg_id = $1", tg_id) async def delete_keys_from_servers(): @@ -487,33 +501,43 @@ async def delete_user( try: await delete_user_data(session, tg_id) - await callback_query.message.answer( + await callback_query.message.edit_text( text=f"🗑️ Пользователь с ID {tg_id} был удален.", - reply_markup=build_admin_back_kb("users_editor") + reply_markup=build_editor_kb(callback_data.tg_id) ) except Exception as e: logger.error(f"Ошибка при удалении данных из базы данных для пользователя {tg_id}: {e}") - await callback_query.message.answer( + await callback_query.message.edit_text( text=f"❌ Произошла ошибка при удалении пользователя с ID {tg_id}. Попробуйте снова." ) @router.callback_query( - AdminUserEditorCallback.filter(F.action == "users_delete_user_confirm"), + AdminUserEditorCallback.filter(F.action == "users_editor"), IsAdminFilter() ) -async def confirm_delete_user( +async def handle_users_editor( callback_query: types.CallbackQuery, - callback_data: AdminUserEditorCallback + callback_data: AdminUserEditorCallback, + state: FSMContext, + session: Any ): - tg_id = int(callback_data.data) - await callback_query.message.answer( - text=f"Вы уверены, что хотите удалить пользователя с ID {tg_id}?", - reply_markup=build_user_delete_kb(tg_id) + await process_user_search( + callback_query.message, + state, + session, + callback_data.tg_id, + callback_data.data == "edit" ) -async def process_user_search(message: types.Message, state: FSMContext, session: Any, tg_id: int) -> None: +async def process_user_search( + message: types.Message, + state: FSMContext, + session: Any, + tg_id: int, + edit: bool = False +) -> None: username = await session.fetchval( "SELECT username FROM users WHERE tg_id = $1", tg_id ) @@ -524,7 +548,7 @@ async def process_user_search(message: types.Message, state: FSMContext, session if balance is None: await message.answer( text="🚫 Пользователь с указанным ID не найден!", - reply_markup=build_admin_back_kb("users_editor"), + reply_markup=build_admin_back_kb(), ) return @@ -542,10 +566,16 @@ async def process_user_search(message: types.Message, state: FSMContext, session f"🔑 Ключи (для редактирования нажмите на ключ):" ) - await message.answer( - text=text, - reply_markup=build_user_edit_kb(tg_id, key_records) - ) + if edit: + await message.edit_text( + text=text, + reply_markup=build_user_edit_kb(tg_id, key_records) + ) + else: + await message.answer( + text=text, + reply_markup=build_user_edit_kb(tg_id, key_records) + ) await state.clear()