diff --git a/bot/handlers/admin/promo_codes.py b/bot/handlers/admin/promo_codes.py
index e8e9403..6f2a175 100644
--- a/bot/handlers/admin/promo_codes.py
+++ b/bot/handlers/admin/promo_codes.py
@@ -1140,15 +1140,13 @@ async def create_bulk_promo_codes_final(callback_or_message,
await session.commit()
# Send success message
- codes_text = " ".join(created_codes)
success_text = _(
"admin_bulk_promo_created_success",
- default="✅ Создано {count} промокодов на {days} дней!\n\nДействуют до: {validity}\nМакс. активации: {max_act}\n\nПромокоды:\n{codes}",
+ default="✅ Создано {count} промокодов на {days} дней!\n\nДействуют до: {validity}\nМакс. активации: {max_act}",
count=quantity,
days=bonus_days,
validity=valid_until_str_display,
- max_act=max_activations,
- codes=codes_text[:3500] + "..." if len(codes_text) > 3500 else codes_text
+ max_act=max_activations
)
if hasattr(callback_or_message, 'message'):
@@ -1162,22 +1160,21 @@ async def create_bulk_promo_codes_final(callback_or_message,
parse_mode="HTML"
)
- # Send codes as file if too many
- if len(codes_text) > 3500:
- codes_file_content = "\n".join(created_codes)
- codes_file = types.BufferedInputFile(
- codes_file_content.encode('utf-8'),
- filename=f"bulk_promo_codes_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
- )
-
- await target_message.answer_document(
- codes_file,
- caption=_(
- "admin_bulk_promo_codes_file",
- default="📄 Все созданные промокоды в файле",
- count=quantity
- )
+ # Always send codes as file
+ codes_file_content = "\n".join(created_codes)
+ codes_file = types.BufferedInputFile(
+ codes_file_content.encode('utf-8'),
+ filename=f"bulk_promo_codes_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
+ )
+
+ await target_message.answer_document(
+ codes_file,
+ caption=_(
+ "admin_bulk_promo_codes_file",
+ default="📄 Все созданные промокоды в файле ({count} шт.)",
+ count=quantity
)
+ )
except Exception as e:
logging.error(f"Error creating bulk promo codes: {e}")
diff --git a/bot/handlers/inline_mode.py b/bot/handlers/inline_mode.py
index 2224371..9355b0c 100644
--- a/bot/handlers/inline_mode.py
+++ b/bot/handlers/inline_mode.py
@@ -152,16 +152,14 @@ async def create_user_stats_result(session: AsyncSession, i18n_instance, lang: s
stats_text = _(
"inline_user_stats_message",
- default="👥 Статистика пользователей\n\n"
+ default="📊 Статистика Бота\n👥 Пользователи\n\n"
"📊 Всего: {total}\n"
- "📈 Активных сегодня: {active_today}\n"
"💳 С платной подпиской: {paid}\n"
"🆓 На пробном периоде: {trial}\n"
"😴 Неактивных: {inactive}\n"
"🚫 Заблокированных: {banned}\n"
- "🎁 По реферальной программе: {referral}",
+ "🎁 Привлечено по реферальной программе: {referral}",
total=user_stats['total_users'],
- active_today=user_stats['active_today'],
paid=user_stats['paid_subscriptions'],
trial=user_stats['trial_users'],
inactive=user_stats['inactive_users'],
@@ -173,11 +171,11 @@ async def create_user_stats_result(session: AsyncSession, i18n_instance, lang: s
id="admin_user_stats",
title=_(
"inline_admin_user_stats_title",
- default="👥 Статистика пользователей"
+ default="📊 Статистика пользователей"
),
description=_(
- "inline_stats_description",
- default="Всего: {total}, Активных: {active}",
+ "inline_user_stats_description",
+ default="Всего: {total}, Платных: {active}",
total=user_stats['total_users'],
active=user_stats['paid_subscriptions']
),
@@ -240,53 +238,88 @@ async def create_financial_stats_result(session: AsyncSession, i18n_instance, la
async def create_system_stats_result(session: AsyncSession, i18n_instance, lang: str, settings: Settings) -> Optional[InlineQueryResultArticle]:
- """Create system statistics result with online/offline/expired/limited info"""
+ """Create panel statistics result with system/nodes/bandwidth info"""
_ = lambda key, **kwargs: i18n_instance.gettext(lang, key, **kwargs)
try:
- from datetime import datetime, timezone
- from sqlalchemy import select, func, and_
- from db.models import User, Subscription
+ from bot.services.panel_api_service import PanelApiService
- now = datetime.now(timezone.utc)
-
- # Count active subscriptions (online)
- active_subs_stmt = select(func.count(Subscription.subscription_id)).where(
- and_(
- Subscription.is_active == True,
- Subscription.end_date > now
- )
- )
- active_subs = (await session.execute(active_subs_stmt)).scalar() or 0
-
- # Count expired subscriptions
- expired_subs_stmt = select(func.count(Subscription.subscription_id)).where(
- and_(
- Subscription.is_active == True,
- Subscription.end_date <= now
- )
- )
- expired_subs = (await session.execute(expired_subs_stmt)).scalar() or 0
-
- # Count total users (approximation for "total")
- total_users_stmt = select(func.count(User.user_id))
- total_users = (await session.execute(total_users_stmt)).scalar() or 0
-
- # Offline = users without active subscriptions
- offline_users = total_users - active_subs
-
- stats_text = _(
- "inline_system_stats_message",
- default="🖥 Системная статистика\n\n"
- "🟢 Онлайн: {online}\n"
- "🔴 Офлайн: {offline}\n"
- "⏰ Истекшие: {expired}\n"
- "👥 Всего пользователей: {total}",
- online=active_subs,
- offline=max(0, offline_users),
- expired=expired_subs,
- total=total_users
- )
+ # Get panel stats similar to main statistics
+ async with PanelApiService(settings) as panel_service:
+ system_stats = await panel_service.get_system_stats()
+ bandwidth_stats = await panel_service.get_bandwidth_stats()
+ nodes_stats = await panel_service.get_nodes_statistics()
+
+ if system_stats:
+ users = system_stats.get('users', {})
+ status_counts = users.get('statusCounts', {})
+ online_stats = system_stats.get('onlineStats', {})
+
+ active_users = status_counts.get('ACTIVE', 0)
+ disabled_users = status_counts.get('DISABLED', 0)
+ expired_users = status_counts.get('EXPIRED', 0)
+ limited_users = status_counts.get('LIMITED', 0)
+ total_users = users.get('totalUsers', 0)
+ online_now = online_stats.get('onlineNow', 0)
+
+ # Memory usage
+ memory = system_stats.get('memory', {})
+ memory_usage = 0
+ if memory:
+ memory_total = memory.get('total', 1)
+ memory_used = memory.get('used', 0)
+ memory_usage = (memory_used / memory_total) * 100 if memory_total > 0 else 0
+
+ # Bandwidth
+ week_traffic = "N/A"
+ month_traffic = "N/A"
+ if bandwidth_stats:
+ week_data = bandwidth_stats.get('bandwidthLastSevenDays', {})
+ month_data = bandwidth_stats.get('bandwidthLast30Days', {}) or bandwidth_stats.get('bandwidthLastThirtyDays', {})
+
+ week_traffic = week_data.get('current', 'N/A') if week_data else 'N/A'
+ month_traffic = month_data.get('current', 'N/A') if month_data else 'N/A'
+
+ # Nodes
+ active_nodes = 0
+ total_nodes = 0
+ if nodes_stats and 'lastSevenDays' in nodes_stats:
+ unique_nodes = set()
+ for node_data in nodes_stats.get('lastSevenDays', []):
+ unique_nodes.add(node_data.get('nodeName', ''))
+ total_nodes = len(unique_nodes)
+ active_nodes = total_nodes # Assume all are active
+ elif system_stats and 'nodes' in system_stats:
+ active_nodes = system_stats.get('nodes', {}).get('totalOnline', 0)
+ total_nodes = active_nodes
+
+ stats_text = _(
+ "inline_system_stats_message",
+ default="🖥 Статистика панели\n\n"
+ "🟢 Онлайн: {online}\n"
+ "📊 Активных: {active}\n"
+ "🔴 Отключенных: {disabled}\n"
+ "⏰ Истекшие: {expired}\n"
+ "⚠️ Ограниченные: {limited}\n"
+ "👥 Всего пользователей: {total}\n"
+ "💾 Использование RAM: {memory:.1f}%\n"
+ "📊 Трафик за неделю: {week_traffic}\n"
+ "📊 Трафик за месяц: {month_traffic}\n"
+ "🔗 Активных нод: {active_nodes}/{total_nodes}",
+ online=online_now,
+ active=active_users,
+ disabled=disabled_users,
+ expired=expired_users,
+ limited=limited_users,
+ total=total_users,
+ memory=memory_usage,
+ week_traffic=week_traffic,
+ month_traffic=month_traffic,
+ active_nodes=active_nodes,
+ total_nodes=total_nodes
+ )
+ else:
+ stats_text = _("inline_panel_stats_error", default="❌ Ошибка получения данных с панели")
return InlineQueryResultArticle(
id="admin_system_stats",
@@ -296,9 +329,7 @@ async def create_system_stats_result(session: AsyncSession, i18n_instance, lang:
),
description=_(
"inline_system_description",
- default="Онлайн: {online}, Офлайн: {offline}",
- online=active_subs,
- offline=max(0, offline_users)
+ default="Панель: онлайн, ноды, трафик"
),
input_message_content=InputTextMessageContent(
message_text=stats_text,
@@ -309,6 +340,22 @@ async def create_system_stats_result(session: AsyncSession, i18n_instance, lang:
except Exception as e:
logging.error(f"Error creating system stats result: {e}")
+ # Fallback error message
+ error_text = _("inline_panel_stats_error", default="❌ Ошибка получения данных с панели")
+
+ return InlineQueryResultArticle(
+ id="admin_system_stats",
+ title=_(
+ "inline_admin_system_stats_title",
+ default="🖥 Системная статистика"
+ ),
+ description=_("inline_system_error", default="Ошибка получения данных"),
+ input_message_content=InputTextMessageContent(
+ message_text=error_text,
+ parse_mode="HTML"
+ ),
+ thumbnail_url=settings.INLINE_SYSTEM_STATS_THUMBNAIL_URL
+ )
return None
diff --git a/locales/en.json b/locales/en.json
index 50d6ab8..48ebd31 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -305,7 +305,7 @@
"admin_promo_codes_menu_bulk_create": "📦 Bulk Creation",
"admin_bulk_promo_create_prompt": "📦 Bulk Promo Code Creation\n\nEnter data in format:\nquantity|days|description\n\nExample:\n10|7|Weekly promo",
"admin_bulk_promo_invalid_format": "❌ Invalid format. Use: quantity|days|description",
- "admin_bulk_promo_created_success": "✅ Created {count} promo codes for {days} days!\n\nDescription: {description}\nCodes: {codes}",
+ "admin_bulk_promo_created_success": "✅ Created {count} promo codes for {days} days!",
"admin_logs_export_csv": "📄 Export to CSV",
"admin_logs_csv_export_started": "📄 Starting log export to CSV...",
@@ -425,6 +425,8 @@
"admin_panel_stats_header": "Panel Statistics",
"admin_panel_online_label": "Online",
+ "admin_panel_active_label": "Active",
+ "admin_panel_disabled_label": "Disabled",
"admin_panel_offline_label": "Offline",
"admin_panel_expired_label": "Expired",
"admin_panel_limited_label": "Limited",
diff --git a/locales/ru.json b/locales/ru.json
index 86f83ff..b8fce60 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -305,7 +305,7 @@
"admin_promo_codes_menu_bulk_create": "📦 Массовое создание",
"admin_bulk_promo_create_prompt": "📦 Массовое создание промокодов\n\nВведите данные в формате:\nколичество|дни|описание\n\nПример:\n10|7|Промо на неделю",
"admin_bulk_promo_invalid_format": "❌ Неверный формат. Используйте: количество|дни|описание",
- "admin_bulk_promo_created_success": "✅ Создано {count} промокодов на {days} дней!\n\nОписание: {description}\nПромокоды: {codes}",
+ "admin_bulk_promo_created_success": "✅ Создано {count} промокодов на {days} дней!",
"admin_logs_export_csv": "📄 Экспорт в CSV",
"admin_logs_csv_export_started": "📄 Начинаю экспорт логов в CSV...",
@@ -425,6 +425,8 @@
"admin_panel_stats_header": "Статистика панели",
"admin_panel_online_label": "Онлайн",
+ "admin_panel_active_label": "Активных",
+ "admin_panel_disabled_label": "Отключенных",
"admin_panel_offline_label": "Офлайн",
"admin_panel_expired_label": "Истекшие",
"admin_panel_limited_label": "Ограниченные",