from aiogram import F, Router, types from aiogram.types import CallbackQuery from sqlalchemy.ext.asyncio import AsyncSession from panels.remnawave_runtime import ( invalidate_remnawave_profile, resolve_remnawave_api_url, with_remnawave_api, ) from filters.admin import IsAdminFilter from .keyboard import AdminUserEditorCallback, build_editor_kb, build_hwid_menu_kb from .utils import resolve_admin_key router = Router() @router.callback_query( AdminUserEditorCallback.filter(F.action == "users_hwid_menu"), IsAdminFilter(), ) async def handle_hwid_menu( callback_query: CallbackQuery, callback_data: AdminUserEditorCallback, session: AsyncSession, ): key_ref = str(callback_data.data) tg_id = callback_data.tg_id key_obj = await resolve_admin_key(session, tg_id, key_ref) if not key_obj: await callback_query.message.edit_text("🚫 Не удалось найти ключ.", reply_markup=build_editor_kb(tg_id)) return client_id = key_obj.client_id remna_api_url = await resolve_remnawave_api_url(session, "", fallback_any=True) if not remna_api_url: await callback_query.message.edit_text( "🚫 Нет доступного сервера Remnawave.", reply_markup=build_editor_kb(tg_id), ) return async def _fetch_info_and_devices(api): user_info = await api.get_user_by_uuid(client_id) devices = await api.get_user_hwid_devices(client_id) return user_info, devices result = await with_remnawave_api(session, "", _fetch_info_and_devices, fallback_any=True, timeout_sec=8.0) if result is None: await callback_query.message.edit_text("❌ Ошибка авторизации в Remnawave.") return user_info, devices = result status_emoji = "🟢" status_text = "Онлайн" online_at_str = "—" first_connected_str = "—" last_node_uuid = "—" if not user_info: status_emoji = "⚪️" status_text = "Не найден" else: is_online = bool(user_info.get("isOnline")) status_emoji = "🟢" if is_online else "⚪️" status_text = "Онлайн" if is_online else "Офлайн" online_at = user_info.get("onlineAt") if online_at: online_at_str = online_at[:19].replace("T", " ") first_connected_at = user_info.get("firstConnectedAt") if first_connected_at: first_connected_str = first_connected_at[:19].replace("T", " ") last_node_uuid_val = user_info.get("lastConnectedNodeUuid") if last_node_uuid_val: last_node_uuid = last_node_uuid_val if not devices: text = ( "💻 HWID устройства\n\n" f"{status_emoji} Статус: {status_text}\n" f"└ 🕓 Онлайн был: {online_at_str}\n" f"└ 🚀 Первое подключение: {first_connected_str}\n" f"└ 🛰 Нода последнего подключения: {last_node_uuid}\n\n" "🔌 Нет привязанных устройств." ) else: text = ( "💻 HWID устройства\n\n" f"{status_emoji} Статус: {status_text}\n" f"└ 🕓 Онлайн был: {online_at_str}\n" f"└ 🚀 Первое подключение: {first_connected_str}\n" f"└ 🛰 Нода последнего подключения: {last_node_uuid}\n\n" f"🔗 Привязано устройств: {len(devices)}\n\n" ) for idx, device in enumerate(devices, 1): created = device.get("createdAt", "")[:19].replace("T", " ") updated = device.get("updatedAt", "")[:19].replace("T", " ") text += ( f"{idx}. {device.get('hwid')}\n" f"└ 📱 Модель: {device.get('deviceModel') or '—'}\n" f"└ 🧠 Платформа: {device.get('platform') or '—'} / {device.get('osVersion') or '—'}\n" f"└ 🌐 User-Agent: {device.get('userAgent') or '—'}\n" f"└ 🕓 Создано: {created}\n" f"└ 🔄 Обновлено: {updated}\n\n" ) await callback_query.message.edit_text(text, reply_markup=build_hwid_menu_kb(key_ref, tg_id)) @router.callback_query( AdminUserEditorCallback.filter(F.action == "users_hwid_reset"), IsAdminFilter(), ) async def handle_hwid_reset( callback_query: CallbackQuery, callback_data: AdminUserEditorCallback, session: AsyncSession, ): key_ref = str(callback_data.data) tg_id = callback_data.tg_id key_obj = await resolve_admin_key(session, tg_id, key_ref) if not key_obj: await callback_query.message.edit_text("🚫 Не удалось найти ключ.", reply_markup=build_editor_kb(tg_id)) return client_id = key_obj.client_id remna_api_url = await resolve_remnawave_api_url(session, "", fallback_any=True) if not remna_api_url: await callback_query.message.edit_text( "🚫 Нет доступного сервера Remnawave.", reply_markup=build_editor_kb(tg_id), ) return async def _reset_devices(api): devices = await api.get_user_hwid_devices(client_id) if not devices: return 0, 0 deleted = 0 for device in devices: if await api.delete_user_hwid_device(client_id, device["hwid"]): deleted += 1 return len(devices), deleted reset_result = await with_remnawave_api(session, "", _reset_devices, fallback_any=True, timeout_sec=12.0) if reset_result is None: await callback_query.message.edit_text("❌ Ошибка авторизации в Remnawave.") return total, deleted = reset_result await invalidate_remnawave_profile( session, "", str(client_id), fallback_any=True, ) if total == 0: await callback_query.message.edit_text( "ℹ️ У пользователя нет привязанных устройств.", reply_markup=build_editor_kb(tg_id, True), ) return await callback_query.message.edit_text( f"✅ Удалено HWID-устройств: {deleted} из {total}.", reply_markup=build_editor_kb(tg_id, True), )