mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-02-26 22:31:44 +00:00
Revert "Handle RemnaWave server removal and expose server user list"
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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(
|
||||
📊 <b>Результаты:</b>
|
||||
• Создано новых серверов: {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 = [
|
||||
"👥 <b>Пользователи сервера</b>",
|
||||
"",
|
||||
f"Сервер: {server.display_name}",
|
||||
f"UUID: <code>{server.squad_uuid}</code>",
|
||||
"",
|
||||
]
|
||||
|
||||
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_"))
|
||||
|
||||
Reference in New Issue
Block a user