from datetime import datetime from io import BytesIO from typing import Any from aiogram import F, Router from aiogram.types import CallbackQuery, BufferedInputFile from filters.admin import IsAdminFilter from keyboards.admin.panel_kb import AdminPanelCallback, build_admin_back_kb from keyboards.admin.stats_kb import build_stats_kb from logger import logger router = Router() @router.callback_query( AdminPanelCallback.filter(F.action == "stats"), IsAdminFilter(), ) async def user_stats_menu(callback_query: CallbackQuery, session: Any): try: total_users = await session.fetchval("SELECT COUNT(*) FROM users") total_keys = await session.fetchval("SELECT COUNT(*) FROM keys") total_referrals = await session.fetchval("SELECT COUNT(*) FROM referrals") total_payments_today = await session.fetchval( "SELECT COALESCE(SUM(amount), 0) FROM payments WHERE created_at >= CURRENT_DATE" ) total_payments_week = await session.fetchval( "SELECT COALESCE(SUM(amount), 0) FROM payments WHERE created_at >= date_trunc('week', CURRENT_DATE)" ) total_payments_month = await session.fetchval( "SELECT COALESCE(SUM(amount), 0) FROM payments WHERE created_at >= date_trunc('month', CURRENT_DATE)" ) total_payments_all_time = await session.fetchval( "SELECT COALESCE(SUM(amount), 0) FROM payments" ) registrations_today = await session.fetchval( "SELECT COUNT(*) FROM users WHERE created_at >= CURRENT_DATE" ) registrations_week = await session.fetchval( "SELECT COUNT(*) FROM users WHERE created_at >= date_trunc('week', CURRENT_DATE)" ) registrations_month = await session.fetchval( "SELECT COUNT(*) FROM users WHERE created_at >= date_trunc('month', CURRENT_DATE)" ) users_updated_today = await session.fetchval( "SELECT COUNT(*) FROM users WHERE updated_at >= CURRENT_DATE" ) active_keys = await session.fetchval( "SELECT COUNT(*) FROM keys WHERE expiry_time > $1", int(datetime.utcnow().timestamp() * 1000), ) expired_keys = total_keys - active_keys stats_message = ( f"📊 Подробная статистика проекта:\n\n" f"👥 Пользователи:\n" f" 📅 За день: {registrations_today}\n" f" 📆 За неделю: {registrations_week}\n" f" 📆 За месяц: {registrations_month}\n" f" 🌐 За все время: {total_users}\n\n" f"🌟 Активные пользователи:\n" f" 🌟 Активных сегодня: {users_updated_today}\n\n" f"👥 Рефералы:\n" f" 🤝 Всего привлечено: {total_referrals}\n\n" f"🔑 Ключи:\n" f" 🌈 Всего сгенерировано: {total_keys}\n" f" ✅ Действующих: {active_keys}\n" f" ❌ Просроченных: {expired_keys}\n\n" f"💰 Финансовая статистика:\n" f" 📅 За день: {total_payments_today} ₽\n" f" 📆 За неделю: {total_payments_week} ₽\n" f" 📆 За месяц: {total_payments_month} ₽\n" f" 🏦 За все время: {total_payments_all_time} ₽\n" ) await callback_query.message.edit_text( text=stats_message, reply_markup=build_stats_kb() ) except Exception as e: logger.error(f"Error in user_stats_menu: {e}") @router.callback_query( AdminPanelCallback.filter(F.action == "stats_export_users_csv"), IsAdminFilter(), ) async def export_users_csv(callback_query: CallbackQuery, session: Any): kb = build_admin_back_kb("stats") try: users = await session.fetch( """ SELECT u.tg_id, u.username, u.first_name, u.last_name, u.language_code, u.is_bot, c.balance, c.trial FROM users u LEFT JOIN connections c ON u.tg_id = c.tg_id """ ) if not users: await callback_query.message.edit_text( text="📭 Нет пользователей для экспорта.", reply_markup=kb ) return csv_data = "tg_id,username,first_name,last_name,language_code,is_bot,balance,trial\n" # Заголовки CSV for user in users: csv_data += f"{user['tg_id']},{user['username']},{user['first_name']},{user['last_name']},{user['language_code']},{user['is_bot']},{user['balance']},{user['trial']}\n" file_name = BytesIO(csv_data.encode("utf-8-sig")) file_name.seek(0) file = BufferedInputFile(file_name.getvalue(), filename="users_export.csv") await callback_query.message.answer_document( document=file, caption="📥 Экспорт пользователей в CSV" ) file_name.close() except Exception as e: logger.error(f"Ошибка при экспорте пользователей в CSV: {e}") await callback_query.message.edit_text( text=f"❗ Произошла ошибка при экспорте: {e}", reply_markup=kb ) @router.callback_query( AdminPanelCallback.filter(F.action == "stats_export_payments_csv"), IsAdminFilter(), ) async def export_payments_csv(callback_query: CallbackQuery, session: Any): kb = build_admin_back_kb("stats") try: payments = await session.fetch( """ SELECT u.tg_id, u.username, u.first_name, u.last_name, p.amount, p.payment_system, p.status, p.created_at FROM users u JOIN payments p ON u.tg_id = p.tg_id """ ) if not payments: await callback_query.message.edit_text( text="📭 Нет платежей для экспорта.", reply_markup=kb ) return csv_data = "tg_id,username,first_name,last_name,amount,payment_system,status,created_at\n" # Заголовки CSV for payment in payments: csv_data += f"{payment['tg_id']},{payment['username']},{payment['first_name']},{payment['last_name']},{payment['amount']},{payment['payment_system']},{payment['status']},{payment['created_at']}\n" file_name = BytesIO(csv_data.encode("utf-8-sig")) file_name.seek(0) file = BufferedInputFile(file_name.getvalue(), filename="payments_export.csv") await callback_query.message.answer_document( document=file, caption="📥 Экспорт платежей в CSV" ) file_name.close() except Exception as e: logger.error(f"Ошибка при экспорте платежей в CSV: {e}") await callback_query.message.edit_text( text=f"❗ Произошла ошибка при экспорте: {e}", reply_markup=kb )