chore: run lint and prettifier
This commit is contained in:
+120
-105
@@ -1,27 +1,26 @@
|
||||
import logging
|
||||
from aiogram import Router, F, types
|
||||
from typing import Optional, Dict, List
|
||||
from datetime import datetime
|
||||
import html
|
||||
import logging
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from aiogram import Router, types
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from config.settings import Settings
|
||||
|
||||
from db.dal import user_dal, payment_dal, panel_sync_dal
|
||||
from db.models import Payment, PanelSyncStatus
|
||||
from bot.services.panel_api_service import PanelApiService
|
||||
|
||||
from bot.keyboards.inline.admin_keyboards import (
|
||||
get_back_to_admin_panel_keyboard,
|
||||
get_back_to_user_management_keyboard,
|
||||
)
|
||||
from bot.middlewares.i18n import JsonI18n
|
||||
from bot.services.panel_api_service import PanelApiService
|
||||
from config.settings import Settings
|
||||
from db.dal import panel_sync_dal, payment_dal, user_dal
|
||||
from db.models import PanelSyncStatus, Payment
|
||||
|
||||
router = Router(name="admin_statistics_router")
|
||||
|
||||
|
||||
def _format_rating_user_label(user_row: Dict[str, object],
|
||||
bot_username: Optional[str] = None) -> str:
|
||||
def _format_rating_user_label(
|
||||
user_row: Dict[str, object], bot_username: Optional[str] = None
|
||||
) -> str:
|
||||
user_id = int(user_row.get("user_id", 0) or 0)
|
||||
username = user_row.get("username")
|
||||
first_name = user_row.get("first_name")
|
||||
@@ -49,9 +48,9 @@ def _format_rating_user_label(user_row: Dict[str, object],
|
||||
return " ".join(parts)
|
||||
|
||||
|
||||
async def show_statistics_handler(callback: types.CallbackQuery,
|
||||
i18n_data: dict, settings: Settings,
|
||||
session: AsyncSession):
|
||||
async def show_statistics_handler(
|
||||
callback: types.CallbackQuery, i18n_data: dict, settings: Settings, session: AsyncSession
|
||||
):
|
||||
current_lang = i18n_data.get("current_language", settings.DEFAULT_LANGUAGE)
|
||||
i18n: Optional[JsonI18n] = i18n_data.get("i18n_instance")
|
||||
if not i18n or not callback.message:
|
||||
@@ -65,10 +64,8 @@ async def show_statistics_handler(callback: types.CallbackQuery,
|
||||
|
||||
# Enhanced user statistics
|
||||
user_stats = await user_dal.get_enhanced_user_statistics(session)
|
||||
|
||||
stats_text_parts.append(
|
||||
f"\n<b>👥 {_('admin_enhanced_users_stats_header')}</b>"
|
||||
)
|
||||
|
||||
stats_text_parts.append(f"\n<b>👥 {_('admin_enhanced_users_stats_header')}</b>")
|
||||
stats_text_parts.append(
|
||||
f"📊 {_('admin_user_stats_total_label')}: <b>{user_stats['total_users']}</b>"
|
||||
)
|
||||
@@ -88,82 +85,102 @@ async def show_statistics_handler(callback: types.CallbackQuery,
|
||||
stats_text_parts.append(
|
||||
f"🎁 {_('admin_user_stats_referral_label')}: <b>{user_stats['referral_users']}</b>"
|
||||
)
|
||||
|
||||
|
||||
# Panel Statistics - moved above financial
|
||||
stats_text_parts.append(f"\n<b>🖥 {_('admin_panel_stats_header')}</b>")
|
||||
|
||||
|
||||
try:
|
||||
async with PanelApiService(settings) as panel_service:
|
||||
# Get system stats
|
||||
system_stats = await panel_service.get_system_stats()
|
||||
bandwidth_stats = await panel_service.get_bandwidth_stats()
|
||||
nodes_stats = await panel_service.get_nodes_statistics()
|
||||
|
||||
logging.info(f"Panel stats response: system={system_stats}, bandwidth={bandwidth_stats}, nodes={nodes_stats}")
|
||||
|
||||
|
||||
logging.info(
|
||||
f"Panel stats response: system={system_stats}, bandwidth={bandwidth_stats}, nodes={nodes_stats}"
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
stats_text_parts.append(f"🟢 {_('admin_panel_online_label')}: <b>{online_now}</b>")
|
||||
stats_text_parts.append(f"📊 {_('admin_panel_active_label')}: <b>{active_users}</b>")
|
||||
stats_text_parts.append(f"🔴 {_('admin_panel_disabled_label')}: <b>{disabled_users}</b>")
|
||||
stats_text_parts.append(f"⏰ {_('admin_panel_expired_label')}: <b>{expired_users}</b>")
|
||||
stats_text_parts.append(f"⚠️ {_('admin_panel_limited_label')}: <b>{limited_users}</b>")
|
||||
stats_text_parts.append(f"👥 {_('admin_panel_total_users_label')}: <b>{total_users}</b>")
|
||||
|
||||
stats_text_parts.append(
|
||||
f"📊 {_('admin_panel_active_label')}: <b>{active_users}</b>"
|
||||
)
|
||||
stats_text_parts.append(
|
||||
f"🔴 {_('admin_panel_disabled_label')}: <b>{disabled_users}</b>"
|
||||
)
|
||||
stats_text_parts.append(
|
||||
f"⏰ {_('admin_panel_expired_label')}: <b>{expired_users}</b>"
|
||||
)
|
||||
stats_text_parts.append(
|
||||
f"⚠️ {_('admin_panel_limited_label')}: <b>{limited_users}</b>"
|
||||
)
|
||||
stats_text_parts.append(
|
||||
f"👥 {_('admin_panel_total_users_label')}: <b>{total_users}</b>"
|
||||
)
|
||||
|
||||
# System resources
|
||||
memory = system_stats.get('memory', {})
|
||||
memory = system_stats.get("memory", {})
|
||||
if memory:
|
||||
memory_total = memory.get('total', 1)
|
||||
memory_used = memory.get('used', 0)
|
||||
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
|
||||
stats_text_parts.append(f"💾 {_('admin_panel_memory_usage_label')}: <b>{memory_usage:.1f}%</b>")
|
||||
stats_text_parts.append(
|
||||
f"💾 {_('admin_panel_memory_usage_label')}: <b>{memory_usage:.1f}%</b>"
|
||||
)
|
||||
else:
|
||||
stats_text_parts.append(f"⚠️ {_('admin_panel_system_stats_error')}")
|
||||
|
||||
|
||||
# Bandwidth stats
|
||||
if bandwidth_stats:
|
||||
week_traffic = bandwidth_stats.get('bandwidthLastSevenDays', {})
|
||||
month_traffic = bandwidth_stats.get('bandwidthLast30Days', {})
|
||||
week_traffic = bandwidth_stats.get("bandwidthLastSevenDays", {})
|
||||
month_traffic = bandwidth_stats.get("bandwidthLast30Days", {})
|
||||
# Fallback to the actual key name from API if the above doesn't exist
|
||||
if not month_traffic:
|
||||
month_traffic = bandwidth_stats.get('bandwidthLastThirtyDays', {})
|
||||
|
||||
month_traffic = bandwidth_stats.get("bandwidthLastThirtyDays", {})
|
||||
|
||||
if week_traffic:
|
||||
week_total = week_traffic.get('current', '0 B')
|
||||
stats_text_parts.append(f"📊 {_('admin_panel_traffic_week_label')}: <b>{week_total}</b>")
|
||||
|
||||
week_total = week_traffic.get("current", "0 B")
|
||||
stats_text_parts.append(
|
||||
f"📊 {_('admin_panel_traffic_week_label')}: <b>{week_total}</b>"
|
||||
)
|
||||
|
||||
if month_traffic:
|
||||
month_total = month_traffic.get('current', '0 B')
|
||||
stats_text_parts.append(f"📊 {_('admin_panel_traffic_month_label')}: <b>{month_total}</b>")
|
||||
month_total = month_traffic.get("current", "0 B")
|
||||
stats_text_parts.append(
|
||||
f"📊 {_('admin_panel_traffic_month_label')}: <b>{month_total}</b>"
|
||||
)
|
||||
else:
|
||||
stats_text_parts.append(f"⚠️ {_('admin_panel_bandwidth_stats_error')}")
|
||||
|
||||
# Nodes stats
|
||||
if nodes_stats and 'lastSevenDays' in nodes_stats:
|
||||
last_seven_days = nodes_stats.get('lastSevenDays', [])
|
||||
|
||||
# Nodes stats
|
||||
if nodes_stats and "lastSevenDays" in nodes_stats:
|
||||
last_seven_days = nodes_stats.get("lastSevenDays", [])
|
||||
# Get unique node names from the data
|
||||
unique_nodes = set()
|
||||
for node_data in last_seven_days:
|
||||
unique_nodes.add(node_data.get('nodeName', ''))
|
||||
unique_nodes.add(node_data.get("nodeName", ""))
|
||||
total_nodes_count = len(unique_nodes)
|
||||
# Assume all nodes are active since we don't have status info
|
||||
stats_text_parts.append(f"🔗 {_('admin_panel_nodes_label')}: <b>{total_nodes_count}/{total_nodes_count}</b>")
|
||||
stats_text_parts.append(
|
||||
f"🔗 {_('admin_panel_nodes_label')}: <b>{total_nodes_count}/{total_nodes_count}</b>"
|
||||
)
|
||||
else:
|
||||
# Use nodes total from system stats as fallback
|
||||
nodes_info = system_stats.get('nodes', {}) if system_stats else {}
|
||||
total_online = nodes_info.get('totalOnline', 0)
|
||||
nodes_info = system_stats.get("nodes", {}) if system_stats else {}
|
||||
total_online = nodes_info.get("totalOnline", 0)
|
||||
stats_text_parts.append(f"🔗 {_('admin_panel_nodes_label')}: <b>{total_online}</b>")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to fetch panel statistics: {e}", exc_info=True)
|
||||
stats_text_parts.append(f"❌ {_('admin_panel_stats_fetch_error')}")
|
||||
@@ -171,10 +188,8 @@ async def show_statistics_handler(callback: types.CallbackQuery,
|
||||
|
||||
# Financial statistics
|
||||
financial_stats = await payment_dal.get_financial_statistics(session)
|
||||
|
||||
stats_text_parts.append(
|
||||
f"\n<b>💰 {_('admin_financial_stats_header')}</b>"
|
||||
)
|
||||
|
||||
stats_text_parts.append(f"\n<b>💰 {_('admin_financial_stats_header')}</b>")
|
||||
stats_text_parts.append(
|
||||
f"📅 {_('admin_financial_today_label')}: <b>{financial_stats['today_revenue']:.2f} RUB</b> ({financial_stats['today_payments_count']} {_('admin_financial_payments_label')})"
|
||||
)
|
||||
@@ -188,12 +203,11 @@ async def show_statistics_handler(callback: types.CallbackQuery,
|
||||
f"🏆 {_('admin_financial_all_time_label')}: <b>{financial_stats['all_time_revenue']:.2f} RUB</b>"
|
||||
)
|
||||
|
||||
last_payments_models: List[
|
||||
Payment] = await payment_dal.get_recent_payment_logs_with_user(session,
|
||||
limit=5)
|
||||
last_payments_models: List[Payment] = await payment_dal.get_recent_payment_logs_with_user(
|
||||
session, limit=5
|
||||
)
|
||||
if last_payments_models:
|
||||
stats_text_parts.append(
|
||||
f"\n<b>{_('admin_stats_recent_payments_header')}</b>")
|
||||
stats_text_parts.append(f"\n<b>{_('admin_stats_recent_payments_header')}</b>")
|
||||
for payment in last_payments_models:
|
||||
pending_statuses = [
|
||||
"pending",
|
||||
@@ -217,45 +231,45 @@ async def show_statistics_handler(callback: types.CallbackQuery,
|
||||
elif payment.user and payment.user.first_name:
|
||||
user_info += f" ({payment.user.first_name})"
|
||||
|
||||
payment_date_str = payment.created_at.strftime(
|
||||
'%Y-%m-%d') if payment.created_at else "N/A"
|
||||
payment_date_str = (
|
||||
payment.created_at.strftime("%Y-%m-%d") if payment.created_at else "N/A"
|
||||
)
|
||||
|
||||
stats_text_parts.append(
|
||||
_("admin_stats_payment_item",
|
||||
status_emoji=status_emoji,
|
||||
amount=payment.amount,
|
||||
currency=payment.currency,
|
||||
user_info=user_info,
|
||||
p_status=payment.status,
|
||||
p_date=payment_date_str))
|
||||
_(
|
||||
"admin_stats_payment_item",
|
||||
status_emoji=status_emoji,
|
||||
amount=payment.amount,
|
||||
currency=payment.currency,
|
||||
user_info=user_info,
|
||||
p_status=payment.status,
|
||||
p_date=payment_date_str,
|
||||
)
|
||||
)
|
||||
else:
|
||||
stats_text_parts.append(f"\n{_('admin_stats_no_payments_found')}")
|
||||
|
||||
sync_status_model: Optional[
|
||||
PanelSyncStatus] = await panel_sync_dal.get_panel_sync_status(session)
|
||||
sync_status_model: Optional[PanelSyncStatus] = await panel_sync_dal.get_panel_sync_status(
|
||||
session
|
||||
)
|
||||
if sync_status_model and sync_status_model.status != "never_run":
|
||||
stats_text_parts.append(
|
||||
f"\n<b>{_('admin_stats_last_sync_header')}</b>")
|
||||
stats_text_parts.append(f"\n<b>{_('admin_stats_last_sync_header')}</b>")
|
||||
|
||||
sync_time_val = sync_status_model.last_sync_time
|
||||
sync_time_str = sync_time_val.strftime(
|
||||
'%Y-%m-%d %H:%M:%S UTC') if sync_time_val else "N/A"
|
||||
sync_time_str = sync_time_val.strftime("%Y-%m-%d %H:%M:%S UTC") if sync_time_val else "N/A"
|
||||
|
||||
details_val = sync_status_model.details
|
||||
details_str = details_val or "N/A"
|
||||
|
||||
stats_text_parts.append(
|
||||
f" {_('admin_stats_sync_time')}: {sync_time_str}")
|
||||
stats_text_parts.append(
|
||||
f" {_('admin_stats_sync_status')}: {sync_status_model.status}")
|
||||
stats_text_parts.append(f" {_('admin_stats_sync_time')}: {sync_time_str}")
|
||||
stats_text_parts.append(f" {_('admin_stats_sync_status')}: {sync_status_model.status}")
|
||||
stats_text_parts.append(
|
||||
f" {_('admin_stats_sync_users_processed')}: {sync_status_model.users_processed_from_panel}"
|
||||
)
|
||||
stats_text_parts.append(
|
||||
f" {_('admin_stats_sync_subs_synced')}: {sync_status_model.subscriptions_synced}"
|
||||
)
|
||||
stats_text_parts.append(
|
||||
f" {_('admin_stats_sync_details_label')}: {details_str}")
|
||||
stats_text_parts.append(f" {_('admin_stats_sync_details_label')}: {details_str}")
|
||||
else:
|
||||
stats_text_parts.append(f"\n{_('admin_sync_status_never_run')}")
|
||||
|
||||
@@ -265,28 +279,30 @@ async def show_statistics_handler(callback: types.CallbackQuery,
|
||||
await callback.message.edit_text(
|
||||
final_text,
|
||||
reply_markup=get_back_to_admin_panel_keyboard(current_lang, i18n),
|
||||
parse_mode="HTML")
|
||||
parse_mode="HTML",
|
||||
)
|
||||
except Exception as e_edit:
|
||||
logging.error(f"Error editing message for statistics: {e_edit}",
|
||||
exc_info=True)
|
||||
logging.error(f"Error editing message for statistics: {e_edit}", exc_info=True)
|
||||
|
||||
max_chunk_size = 4000
|
||||
for i in range(0, len(final_text), max_chunk_size):
|
||||
chunk = final_text[i:i + max_chunk_size]
|
||||
chunk = final_text[i : i + max_chunk_size]
|
||||
is_last_chunk = (i + max_chunk_size) >= len(final_text)
|
||||
try:
|
||||
await callback.message.answer(
|
||||
chunk,
|
||||
reply_markup=get_back_to_admin_panel_keyboard(
|
||||
current_lang, i18n) if is_last_chunk else None,
|
||||
parse_mode="HTML")
|
||||
reply_markup=get_back_to_admin_panel_keyboard(current_lang, i18n)
|
||||
if is_last_chunk
|
||||
else None,
|
||||
parse_mode="HTML",
|
||||
)
|
||||
except Exception as e_chunk:
|
||||
logging.error(f"Failed to send statistics chunk: {e_chunk}")
|
||||
if i == 0:
|
||||
await callback.message.answer(
|
||||
_("error_displaying_statistics"),
|
||||
reply_markup=get_back_to_admin_panel_keyboard(
|
||||
current_lang, i18n))
|
||||
reply_markup=get_back_to_admin_panel_keyboard(current_lang, i18n),
|
||||
)
|
||||
break
|
||||
|
||||
|
||||
@@ -311,8 +327,7 @@ async def show_user_ratings_handler(
|
||||
me = await callback.bot.get_me()
|
||||
bot_username = me.username
|
||||
except Exception as e_get_me:
|
||||
logging.warning("Failed to resolve bot username for ratings links: %s",
|
||||
e_get_me)
|
||||
logging.warning("Failed to resolve bot username for ratings links: %s", e_get_me)
|
||||
|
||||
traffic_top = await user_dal.get_top_users_by_traffic_used(session, limit=top_limit)
|
||||
lifetime_traffic_top = await user_dal.get_top_users_by_lifetime_traffic_used(
|
||||
|
||||
Reference in New Issue
Block a user