Migrating to Postgres from sqlite3

This commit is contained in:
machka
2025-05-20 18:41:32 +00:00
parent ac2f83c061
commit a56d804b58
38 changed files with 5017 additions and 4389 deletions
+68 -58
View File
@@ -1,10 +1,14 @@
import logging
from aiogram import Router, F, types
from typing import Optional, Dict
from typing import Optional, Dict, List
from datetime import datetime
from sqlalchemy.ext.asyncio import AsyncSession
from config.settings import Settings
from db.database import get_user_count_stats, get_payment_logs, get_message_logs_db, get_last_sync_status
from db.dal import user_dal, payment_dal, panel_sync_dal
from db.models import Payment, PanelSyncStatus
from bot.keyboards.inline.admin_keyboards import get_back_to_admin_panel_keyboard
from bot.middlewares.i18n import JsonI18n
@@ -12,67 +16,69 @@ router = Router(name="admin_statistics_router")
async def show_statistics_handler(callback: types.CallbackQuery,
i18n_data: dict, settings: Settings):
current_lang = i18n_data.get("current_language",
getattr(settings, 'DEFAULT_LANGUAGE', 'en'))
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:
logging.error("i18n missing in show_statistics_handler")
await callback.answer("Language service error.", show_alert=True)
if not i18n or not callback.message:
await callback.answer("Error displaying statistics.", show_alert=True)
return
_ = lambda key, **kwargs: i18n.gettext(current_lang, key, **kwargs)
await callback.answer()
stats_text_parts = [f"<b>{_('admin_stats_header')}</b>"]
user_stats = await get_user_count_stats()
user_stats_dict = await user_dal.get_user_count_stats_dal(session)
stats_text_parts.append(
_("admin_stats_users",
total_users=user_stats.get("total_users", 0),
banned_users=user_stats.get("banned_users", 0),
active_subs=user_stats.get("users_with_active_subscriptions", 0)))
total_users=user_stats_dict.get("total_users", 0),
banned_users=user_stats_dict.get("banned_users", 0),
active_subs=user_stats_dict.get("users_with_active_subscriptions",
0)))
last_payments = await get_payment_logs(limit=5)
if last_payments:
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>")
for payment in last_payments:
status_emoji = "" if payment['status'] == 'succeeded' else (
"" if payment['status'] == 'pending' else "")
user_info = f"User {payment['user_id']}" + (
f" (@{payment['username']})" if payment['username'] else "")
payment_date_str = payment['created_at']
if isinstance(payment_date_str,
str) and len(payment_date_str) > 10:
payment_date_str = payment_date_str[:10]
for payment in last_payments_models:
status_emoji = "" if payment.status == 'succeeded' else (
"" if payment.status == 'pending'
or payment.status == 'pending_yookassa' else "")
user_info = f"User {payment.user_id}"
if payment.user and payment.user.username:
user_info += f" (@{payment.user.username})"
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"
stats_text_parts.append(
_("admin_stats_payment_item",
status_emoji=status_emoji,
amount=payment['amount'],
currency=payment['currency'],
amount=payment.amount,
currency=payment.currency,
user_info=user_info,
p_status=payment['status'],
p_status=payment.status,
p_date=payment_date_str))
else:
stats_text_parts.append(f"\n{_('admin_stats_no_payments_found')}")
sync_status = await get_last_sync_status()
if sync_status:
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>")
sync_time_val = sync_status['last_sync_time']
sync_time_str = "N/A"
if isinstance(sync_time_val, datetime):
sync_time_str = sync_time_val.strftime('%Y-%m-%d %H:%M:%S UTC')
elif isinstance(sync_time_val, str):
sync_time_str = sync_time_val[:19] if len(
sync_time_val) > 19 else sync_time_val
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"
details_val = sync_status['details']
details_val = sync_status_model.details
details_str = (details_val[:100] +
"...") if details_val and len(details_val) > 100 else (
details_val or "N/A")
@@ -80,12 +86,12 @@ async def show_statistics_handler(callback: types.CallbackQuery,
stats_text_parts.append(
f" {_('admin_stats_sync_time')}: {sync_time_str}")
stats_text_parts.append(
f" {_('admin_stats_sync_status')}: {sync_status['status']}")
f" {_('admin_stats_sync_status')}: {sync_status_model.status}")
stats_text_parts.append(
f" {_('admin_stats_sync_users_processed')}: {sync_status['users_processed_from_panel']}"
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['subscriptions_synced']}"
f" {_('admin_stats_sync_subs_synced')}: {sync_status_model.subscriptions_synced}"
)
stats_text_parts.append(
f" {_('admin_stats_sync_details_label')}: {details_str}")
@@ -94,26 +100,30 @@ async def show_statistics_handler(callback: types.CallbackQuery,
final_text = "\n".join(stats_text_parts)
if callback.message:
try:
await callback.message.edit_text(
final_text,
reply_markup=get_back_to_admin_panel_keyboard(
current_lang, i18n),
parse_mode="HTML")
except Exception as e:
logging.error(f"Error editing message for statistics: {e}",
exc_info=True)
try:
await callback.message.edit_text(
final_text,
reply_markup=get_back_to_admin_panel_keyboard(current_lang, i18n),
parse_mode="HTML")
except Exception as e_edit:
logging.error(f"Error editing message for statistics: {e_edit}",
exc_info=True)
for chunk in [
final_text[i:i + 4000]
for i in range(0, len(final_text), 4000)
]:
max_chunk_size = 4000
for i in range(0, len(final_text), 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 chunk == final_text[-len(chunk):] else None,
current_lang, i18n) if is_last_chunk else None,
parse_mode="HTML")
else:
logging.error("Cannot send statistics, callback.message is None.")
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))
break