From 8342e8fe354df45aa0fcafd7fa91e3d869b231ec Mon Sep 17 00:00:00 2001 From: gy9vin Date: Sun, 4 Jan 2026 21:21:05 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D1=83=D1=87=D0=BD=D0=BE=D0=B9=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BF=D1=83=D1=81=D0=BA=20=D0=BC=D0=BE=D0=BD=D0=B8=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=D0=B0=20=D1=82=D1=80=D0=B0=D1=84?= =?UTF-8?q?=D0=B8=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ручная проверка в админке (monitoring.py): - Новая кнопка "📊 Проверка трафика" в меню мониторинга - Проверяет всех юзеров с активной подпиской - Показывает результат: сколько проверено, сколько превышений - Отправляет уведомления админам при превышении --- app/handlers/admin/monitoring.py | 106 +++++++++++++++++++++++++++++-- app/keyboards/admin.py | 16 +++-- 2 files changed, 112 insertions(+), 10 deletions(-) diff --git a/app/handlers/admin/monitoring.py b/app/handlers/admin/monitoring.py index 5f8a4320..fff926ae 100644 --- a/app/handlers/admin/monitoring.py +++ b/app/handlers/admin/monitoring.py @@ -11,6 +11,10 @@ from app.config import settings from app.database.database import get_db from app.services.monitoring_service import monitoring_service from app.services.nalogo_queue_service import nalogo_queue_service +from app.services.traffic_monitoring_service import ( + traffic_monitoring_service, + traffic_monitoring_scheduler, +) from app.utils.decorators import admin_required from app.utils.pagination import paginate_list from app.keyboards.admin import get_monitoring_keyboard, get_admin_main_keyboard @@ -737,10 +741,10 @@ async def stop_monitoring_callback(callback: CallbackQuery): async def force_check_callback(callback: CallbackQuery): try: await callback.answer("⏳ Выполняем проверку подписок...") - + async for db in get_db(): results = await monitoring_service.force_check_subscriptions(db) - + text = f""" ✅ Принудительная проверка завершена @@ -753,20 +757,112 @@ async def force_check_callback(callback: CallbackQuery): Нажмите "Назад" для возврата в меню мониторинга. """ - + from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton keyboard = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text="⬅️ Назад", callback_data="admin_monitoring")] ]) - + await callback.message.edit_text(text, parse_mode="HTML", reply_markup=keyboard) break - + except Exception as e: logger.error(f"Ошибка принудительной проверки: {e}") await callback.answer(f"❌ Ошибка проверки: {str(e)}", show_alert=True) +@router.callback_query(F.data == "admin_mon_traffic_check") +@admin_required +async def traffic_check_callback(callback: CallbackQuery): + """Ручная проверка трафика всех пользователей.""" + try: + # Проверяем, включен ли мониторинг трафика + if not traffic_monitoring_scheduler.is_enabled(): + await callback.answer( + "⚠️ Мониторинг трафика отключен в настройках\n" + "Включите TRAFFIC_MONITORING_ENABLED=true в .env", + show_alert=True + ) + return + + await callback.answer("⏳ Запускаем проверку трафика...") + + # Устанавливаем бота, если не установлен + if not traffic_monitoring_scheduler.bot: + traffic_monitoring_scheduler.set_bot(callback.bot) + + checked_count = 0 + exceeded_count = 0 + exceeded_users = [] + + async for db in get_db(): + from app.database.crud.user import get_users_with_active_subscriptions + + users = await get_users_with_active_subscriptions(db) + + for user in users: + if user.remnawave_uuid: + is_exceeded, traffic_info = await traffic_monitoring_service.check_user_traffic_threshold( + db, + user.remnawave_uuid, + user.telegram_id + ) + checked_count += 1 + + if is_exceeded: + exceeded_count += 1 + total_gb = traffic_info.get('total_gb', 0) + exceeded_users.append({ + 'telegram_id': user.telegram_id, + 'name': user.full_name or str(user.telegram_id), + 'traffic_gb': total_gb + }) + + # Отправляем уведомление админам + if traffic_monitoring_scheduler._should_send_notification(user.remnawave_uuid): + await traffic_monitoring_service.process_suspicious_traffic( + db, + user.remnawave_uuid, + traffic_info, + callback.bot + ) + traffic_monitoring_scheduler._record_notification(user.remnawave_uuid) + + break + + threshold_gb = settings.TRAFFIC_THRESHOLD_GB_PER_DAY + + text = f""" +📊 Проверка трафика завершена + +🔍 Результаты: +• Проверено пользователей: {checked_count} +• Превышений порога: {exceeded_count} +• Порог: {threshold_gb} ГБ/сутки + +🕐 Время проверки: {datetime.now().strftime('%H:%M:%S')} +""" + + if exceeded_users: + text += "\n⚠️ Пользователи с превышением:\n" + for u in exceeded_users[:10]: + text += f"• {u['name']}: {u['traffic_gb']:.1f} ГБ\n" + if len(exceeded_users) > 10: + text += f"... и ещё {len(exceeded_users) - 10}\n" + + from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="🔄 Повторить", callback_data="admin_mon_traffic_check")], + [InlineKeyboardButton(text="⬅️ Назад", callback_data="admin_monitoring")] + ]) + + await callback.message.edit_text(text, parse_mode="HTML", reply_markup=keyboard) + + except Exception as e: + logger.error(f"Ошибка проверки трафика: {e}") + await callback.answer(f"❌ Ошибка: {str(e)}", show_alert=True) + + @router.callback_query(F.data.startswith("admin_mon_logs")) @admin_required async def monitoring_logs_callback(callback: CallbackQuery): diff --git a/app/keyboards/admin.py b/app/keyboards/admin.py index afc12b52..628e0d36 100644 --- a/app/keyboards/admin.py +++ b/app/keyboards/admin.py @@ -1705,22 +1705,28 @@ def get_monitoring_keyboard(language: str = "ru") -> InlineKeyboardMarkup: ], [ InlineKeyboardButton( - text=_t(texts, "ADMIN_MONITORING_FORCE_CHECK", "🔄 Принудительная проверка"), + text=_t(texts, "ADMIN_MONITORING_FORCE_CHECK", "🔄 Проверка подписок"), callback_data="admin_mon_force_check" ), + InlineKeyboardButton( + text=_t(texts, "ADMIN_MONITORING_TRAFFIC_CHECK", "📊 Проверка трафика"), + callback_data="admin_mon_traffic_check" + ) + ], + [ InlineKeyboardButton( text=_t(texts, "ADMIN_MONITORING_LOGS", "📋 Логи"), callback_data="admin_mon_logs" + ), + InlineKeyboardButton( + text=_t(texts, "ADMIN_MONITORING_STATISTICS", "📈 Статистика"), + callback_data="admin_mon_statistics" ) ], [ InlineKeyboardButton( text=_t(texts, "ADMIN_MONITORING_TEST_NOTIFICATIONS", "🧪 Тест уведомлений"), callback_data="admin_mon_test_notifications" - ), - InlineKeyboardButton( - text=_t(texts, "ADMIN_MONITORING_STATISTICS", "📊 Статистика"), - callback_data="admin_mon_statistics" ) ], [