diff --git a/backup.py b/backup.py index a4d79675..ccee564c 100644 --- a/backup.py +++ b/backup.py @@ -92,3 +92,8 @@ def _cleanup_old_backups(): logger.info("Старые бэкапы удалены.") except subprocess.CalledProcessError as e: logger.error(f"Ошибка при удалении старых бэкапов: {e}") + + +async def create_backup_and_send_to_admins(xui): + await xui.login() + await xui.database.export() diff --git a/handlers/admin/admin_servers.py b/handlers/admin/admin_servers.py index f8654e86..ae511623 100644 --- a/handlers/admin/admin_servers.py +++ b/handlers/admin/admin_servers.py @@ -1,11 +1,13 @@ -from aiogram import F, Router, types +from aiogram import Bot, F, Router, types from aiogram.fsm.context import FSMContext from aiogram.fsm.state import State, StatesGroup from aiogram.types import InlineKeyboardButton from aiogram.utils.keyboard import InlineKeyboardBuilder import asyncpg +from py3xui import AsyncApi -from config import DATABASE_URL +from backup import create_backup_and_send_to_admins +from config import ADMIN_PASSWORD, ADMIN_USERNAME, DATABASE_URL from database import check_unique_server_name, get_servers_from_db from filters.admin import IsAdminFilter @@ -259,6 +261,8 @@ async def handle_manage_cluster(callback_query: types.CallbackQuery, state: FSMC builder = InlineKeyboardBuilder() + builder.row(InlineKeyboardButton(text="💾 Создать бэкап кластера", callback_data=f"backup_cluster|{cluster_name}")) + for server in cluster_servers: builder.row( InlineKeyboardButton( @@ -361,3 +365,30 @@ async def handle_add_server(callback_query: types.CallbackQuery, state: FSMConte ) await state.set_state(UserEditorState.waiting_for_server_name) + + +@router.callback_query(F.data.startswith("backup_cluster|"), IsAdminFilter()) +async def handle_backup_cluster(callback_query: types.CallbackQuery): + cluster_name = callback_query.data.split("|")[1] + + servers = await get_servers_from_db() + cluster_servers = servers.get(cluster_name, []) + + for server in cluster_servers: + xui = AsyncApi( + server["api_url"], + username=ADMIN_USERNAME, + password=ADMIN_PASSWORD, + ) + await create_backup_and_send_to_admins(xui) + + builder = InlineKeyboardBuilder() + builder.row(InlineKeyboardButton(text="🔙 Назад", callback_data="servers_editor")) + + await callback_query.message.answer( + f"Бэкап для кластера {cluster_name} был успешно создан и отправлен администраторам!\n\n" + f"🔔 Бэкапы отправлены в боты панелей.", + parse_mode="HTML", + reply_markup=builder.as_markup(), + ) + await callback_query.answer() diff --git a/handlers/profile.py b/handlers/profile.py index f93bf35a..005aecf1 100644 --- a/handlers/profile.py +++ b/handlers/profile.py @@ -22,7 +22,7 @@ async def process_callback_view_profile(callback_query: types.CallbackQuery, sta if balance is None: balance = 0 - profile_message = profile_message_send(username, chat_id, balance, key_count) + profile_message = profile_message_send(username, chat_id, int(balance), key_count) if key_count == 0: profile_message += "\n
🔧 Нажмите кнопку ➕ Устройство, чтобы настроить VPN-подключение"