From 83a76c928d50a8a33d3bb35ae2b2ef8384193eb9 Mon Sep 17 00:00:00 2001 From: Egor Date: Sun, 28 Sep 2025 02:01:57 +0300 Subject: [PATCH] Revert "Handle RemnaWave server removal and expose server user list" --- app/database/crud/server_squad.py | 113 +++------------------------- app/handlers/admin/servers.py | 121 +----------------------------- 2 files changed, 14 insertions(+), 220 deletions(-) diff --git a/app/database/crud/server_squad.py b/app/database/crud/server_squad.py index 15af5746..85f1dc58 100644 --- a/app/database/crud/server_squad.py +++ b/app/database/crud/server_squad.py @@ -1,17 +1,11 @@ import logging from typing import Iterable, List, Optional, Sequence, Tuple -from sqlalchemy import select, func, update, delete, text +from sqlalchemy import select, and_, func, update, delete, text from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload -from app.database.models import ( - PromoGroup, - ServerSquad, - SubscriptionServer, - Subscription, - User, -) +from app.database.models import PromoGroup, ServerSquad, SubscriptionServer, Subscription logger = logging.getLogger(__name__) @@ -234,48 +228,14 @@ async def delete_server_squad(db: AsyncSession, server_id: int) -> bool: return True -async def get_server_users( - db: AsyncSession, - server_id: int, -) -> List[dict]: - - result = await db.execute( - select(User, Subscription, SubscriptionServer) - .join(Subscription, Subscription.user_id == User.id) - .join( - SubscriptionServer, - SubscriptionServer.subscription_id == Subscription.id, - ) - .where(SubscriptionServer.server_squad_id == server_id) - .order_by(User.id) - ) - - users_info: List[dict] = [] - for user, subscription, link in result.all(): - users_info.append( - { - "user_id": user.id, - "telegram_id": user.telegram_id, - "username": user.username, - "first_name": user.first_name, - "subscription_id": subscription.id, - "subscription_status": subscription.status, - "subscription_end_date": subscription.end_date, - "connected_at": link.connected_at, - } - ) - - return users_info - - async def sync_with_remnawave( db: AsyncSession, remnawave_squads: List[dict] ) -> Tuple[int, int, int]: - + created = 0 updated = 0 - removed = 0 + disabled = 0 existing_servers = {} result = await db.execute(select(ServerSquad)) @@ -305,64 +265,15 @@ async def sync_with_remnawave( ) created += 1 - missing_servers = [ - server for uuid, server in existing_servers.items() - if uuid not in remnawave_uuids - ] - - if missing_servers: - missing_ids = [server.id for server in missing_servers] - missing_uuids = [server.squad_uuid for server in missing_servers] - - connections_count_result = await db.execute( - select(func.count(SubscriptionServer.id)).where( - SubscriptionServer.server_squad_id.in_(missing_ids) - ) - ) - removed_connections = connections_count_result.scalar() or 0 - - await db.execute( - delete(SubscriptionServer).where( - SubscriptionServer.server_squad_id.in_(missing_ids) - ) - ) - - if removed_connections: - logger.info( - "🔁 Удалено %s привязок подписок к отсутствующим серверам", - removed_connections, - ) - - subscriptions_result = await db.execute( - select(Subscription).where(Subscription.connected_squads.isnot(None)) - ) - - for subscription in subscriptions_result.scalars().all(): - current_squads = list(subscription.connected_squads or []) - if not current_squads: - continue - - updated_squads = [ - squad_uuid for squad_uuid in current_squads - if squad_uuid not in missing_uuids - ] - - if updated_squads != current_squads: - subscription.connected_squads = updated_squads - - for server in missing_servers: - logger.info( - "🗑️ Удаляем сервер %s (UUID: %s) — отсутствует в RemnaWave", - server.display_name, - server.squad_uuid, - ) - await db.delete(server) - removed += 1 - + for uuid, server in existing_servers.items(): + if uuid not in remnawave_uuids and server.is_available: + server.is_available = False + disabled += 1 + await db.commit() - - logger.info(f"🔄 Синхронизация завершена: +{created} ~{updated} -{removed}") - return created, updated, removed + + logger.info(f"🔄 Синхронизация завершена: +{created} ~{updated} -{disabled}") + return created, updated, disabled def _generate_display_name(original_name: str) -> str: diff --git a/app/handlers/admin/servers.py b/app/handlers/admin/servers.py index 1978236c..9edc3af0 100644 --- a/app/handlers/admin/servers.py +++ b/app/handlers/admin/servers.py @@ -15,7 +15,6 @@ from app.database.crud.server_squad import ( create_server_squad, get_available_server_squads, update_server_squad_promo_groups, - get_server_users, ) from app.database.crud.promo_group import get_promo_groups_with_counts from app.services.remnawave_service import RemnaWaveService @@ -82,11 +81,6 @@ def _build_server_edit_view(server): text="📝 Описание", callback_data=f"admin_server_edit_desc_{server.id}" ), ], - [ - types.InlineKeyboardButton( - text="👥 Пользователи", callback_data=f"admin_server_users_{server.id}" - ), - ], [ types.InlineKeyboardButton( text="❌ Отключить" if server.is_available else "✅ Включить", @@ -282,7 +276,7 @@ async def sync_servers_with_remnawave( ) return - created, updated, removed = await sync_with_remnawave(db, squads) + created, updated, disabled = await sync_with_remnawave(db, squads) await cache.delete_pattern("available_countries*") @@ -292,7 +286,7 @@ async def sync_servers_with_remnawave( 📊 Результаты: • Создано новых серверов: {created} • Обновлено существующих: {updated} -• Удалено отсутствующих: {removed} +• Отключено неактивных: {disabled} • Всего обработано: {len(squads)} ℹ️ Новые серверы созданы как недоступные. @@ -1025,119 +1019,9 @@ async def save_server_promo_groups( reply_markup=keyboard, parse_mode="HTML", ) - await callback.answer("✅ Промогруппы обновлены!") -@admin_required -@error_handler -async def show_server_users( - callback: types.CallbackQuery, - db_user: User, - db: AsyncSession, -): - - server_id = int(callback.data.split('_')[-1]) - server = await get_server_squad_by_id(db, server_id) - - if not server: - await callback.answer("❌ Сервер не найден!", show_alert=True) - return - - users = await get_server_users(db, server_id) - - status_emojis = { - "active": "✅", - "trial": "🧪", - "expired": "⏰", - "disabled": "⛔", - } - status_labels = { - "active": "АКТИВНА", - "trial": "TRIAL", - "expired": "ИСТЕКЛА", - "disabled": "ОТКЛЮЧЕНА", - } - - text_lines = [ - "👥 Пользователи сервера", - "", - f"Сервер: {server.display_name}", - f"UUID: {server.squad_uuid}", - "", - ] - - keyboard_rows = [] - max_buttons = 50 - - if not users: - text_lines.append("На этот сервер пока никто не подключен.") - else: - text_lines.append(f"Всего пользователей: {len(users)}") - text_lines.append("Нажмите на пользователя ниже, чтобы открыть управление.") - text_lines.append("") - - preview_limit = 10 - for user_info in users[:preview_limit]: - name_parts = [] - if user_info.get("username"): - name_parts.append(f"@{user_info['username']}") - if user_info.get("first_name"): - name_parts.append(user_info["first_name"]) - display_name = " ".join(name_parts) or str(user_info["telegram_id"]) - - status = (user_info.get("subscription_status") or "unknown").lower() - status_text = status_labels.get(status, status.upper()) - emoji = status_emojis.get(status, "ℹ️") - - text_lines.append(f"• {display_name} — {emoji} {status_text}") - - if len(users) > preview_limit: - remaining = len(users) - preview_limit - text_lines.append(f"… и ещё {remaining} пользователей") - - for user_info in users[:max_buttons]: - if user_info.get("username"): - label = f"@{user_info['username']}" - elif user_info.get("first_name"): - label = user_info["first_name"] - else: - label = str(user_info["telegram_id"]) - - status = (user_info.get("subscription_status") or "unknown").lower() - emoji = status_emojis.get(status, "ℹ️") - button_text = f"{emoji} {label}"[:64] - - keyboard_rows.append( - [ - types.InlineKeyboardButton( - text=button_text, - callback_data=f"admin_user_manage_{user_info['user_id']}", - ) - ] - ) - - if len(users) > max_buttons: - text_lines.append( - f"⚠️ Показаны первые {max_buttons} пользователей. Используйте фильтры в разделе пользователей для подробностей." - ) - - keyboard_rows.append( - [ - types.InlineKeyboardButton( - text="⬅️ Назад", callback_data=f"admin_server_edit_{server.id}" - ) - ] - ) - - await callback.message.edit_text( - "\n".join(text_lines), - reply_markup=types.InlineKeyboardMarkup(inline_keyboard=keyboard_rows), - parse_mode="HTML", - ) - await callback.answer() - - @admin_required @error_handler async def sync_server_user_counts_handler( @@ -1221,7 +1105,6 @@ def register_handlers(dp: Dispatcher): & ~F.data.contains("promo"), ) dp.callback_query.register(toggle_server_availability, F.data.startswith("admin_server_toggle_")) - dp.callback_query.register(show_server_users, F.data.startswith("admin_server_users_")) dp.callback_query.register(start_server_edit_name, F.data.startswith("admin_server_edit_name_")) dp.callback_query.register(start_server_edit_price, F.data.startswith("admin_server_edit_price_"))