149 lines
6.4 KiB
Python
149 lines
6.4 KiB
Python
import logging
|
|
from aiogram import Router, types, Bot
|
|
from aiogram.filters import Command
|
|
from typing import Optional
|
|
|
|
from config.settings import Settings
|
|
from bot.services.panel_api_service import PanelApiService
|
|
|
|
from db.database import update_sync_status, get_last_sync_status, sync_panel_user_data
|
|
from bot.middlewares.i18n import JsonI18n
|
|
from bot.keyboards.inline.admin_keyboards import get_back_to_admin_panel_keyboard
|
|
|
|
router = Router(name="admin_sync_router")
|
|
|
|
|
|
@router.message(Command("sync"))
|
|
async def sync_command_handler(message: types.Message, bot: Bot,
|
|
settings: Settings, i18n_data: dict,
|
|
panel_service: PanelApiService):
|
|
current_lang = i18n_data.get("current_language",
|
|
getattr(settings, 'DEFAULT_LANGUAGE', 'en'))
|
|
i18n: Optional[JsonI18n] = i18n_data.get("i18n_instance")
|
|
if not i18n:
|
|
logging.error("i18n missing")
|
|
await message.answer("Language error.")
|
|
return
|
|
_ = lambda key, **kwargs: i18n.gettext(current_lang, key, **kwargs)
|
|
|
|
await message.answer(_("sync_started"))
|
|
logging.info("Admin triggered panel sync.")
|
|
|
|
users_processed_count = 0
|
|
users_synced_successfully = 0
|
|
sync_errors = []
|
|
|
|
try:
|
|
panel_users_data = await panel_service.get_all_panel_users()
|
|
|
|
if panel_users_data is None:
|
|
error_msg = "Failed to fetch users from panel or panel API issue."
|
|
sync_errors.append(error_msg)
|
|
await update_sync_status("failed", error_msg)
|
|
await message.answer(_("sync_failed", details=error_msg))
|
|
return
|
|
|
|
if not panel_users_data:
|
|
status_msg = "No users found in the panel to sync."
|
|
await update_sync_status("success", status_msg, 0, 0)
|
|
await message.answer(
|
|
_("sync_completed", status="Success", details=status_msg))
|
|
return
|
|
|
|
total_panel_users = len(panel_users_data)
|
|
logging.info(f"Starting sync for {total_panel_users} panel users.")
|
|
|
|
for panel_user_dict in panel_users_data:
|
|
users_processed_count += 1
|
|
telegram_id_from_panel = panel_user_dict.get('telegramId')
|
|
panel_uuid = panel_user_dict.get('uuid')
|
|
|
|
if not telegram_id_from_panel:
|
|
logging.info(
|
|
f"Panel user {panel_uuid} (username: {panel_user_dict.get('username')}) has no 'telegramId'. Skipping TG ID based sync."
|
|
)
|
|
|
|
continue
|
|
|
|
if not panel_uuid:
|
|
logging.warning(
|
|
f"Panel user (TG ID: {telegram_id_from_panel}) missing 'uuid'. Skipping."
|
|
)
|
|
sync_errors.append(
|
|
f"Panel user data for TG ID {telegram_id_from_panel} missing UUID."
|
|
)
|
|
continue
|
|
|
|
if await sync_panel_user_data(panel_user_dict):
|
|
users_synced_successfully += 1
|
|
else:
|
|
sync_errors.append(
|
|
f"Sync issue for panel user: {panel_uuid} (TG ID: {telegram_id_from_panel})"
|
|
)
|
|
|
|
if users_processed_count % 20 == 0:
|
|
logging.info(
|
|
f"Sync progress: {users_processed_count}/{total_panel_users} users processed."
|
|
)
|
|
|
|
status_msg = f"Panel users checked: {total_panel_users}. Users/Subscriptions synced via TG ID: {users_synced_successfully}."
|
|
if sync_errors:
|
|
status_msg += f" Errors encountered: {len(sync_errors)}. See logs for details."
|
|
error_preview = "\n".join(sync_errors[:3])
|
|
await update_sync_status("partial_success",
|
|
status_msg + " " + error_preview,
|
|
total_panel_users,
|
|
users_synced_successfully)
|
|
await message.answer(
|
|
_("sync_completed",
|
|
status="Partial Success",
|
|
details=status_msg))
|
|
else:
|
|
await update_sync_status("success", status_msg, total_panel_users,
|
|
users_synced_successfully)
|
|
await message.answer(
|
|
_("sync_completed", status="Success", details=status_msg))
|
|
|
|
except Exception as e:
|
|
logging.error(f"Error during /sync command: {e}", exc_info=True)
|
|
error_detail = f"An unexpected error occurred during sync: {str(e)}"
|
|
await update_sync_status("failed", error_detail, users_processed_count,
|
|
users_synced_successfully)
|
|
await message.answer(_("sync_failed", details=error_detail))
|
|
|
|
|
|
@router.message(Command("syncstatus"))
|
|
async def sync_status_command_handler(message: types.Message, i18n_data: dict,
|
|
settings: Settings):
|
|
|
|
current_lang = i18n_data.get("current_language",
|
|
getattr(settings, 'DEFAULT_LANGUAGE', 'en'))
|
|
i18n: Optional[JsonI18n] = i18n_data.get("i18n_instance")
|
|
if not i18n:
|
|
await message.answer("Language error.")
|
|
return
|
|
_ = lambda key, **kwargs: i18n.gettext(current_lang, key, **kwargs)
|
|
status_record = await get_last_sync_status()
|
|
response_text = ""
|
|
if status_record:
|
|
last_time_val = status_record['last_sync_time']
|
|
last_time_str = last_time_val.strftime(
|
|
'%Y-%m-%d %H:%M:%S UTC') if isinstance(
|
|
last_time_val, datetime) else str(last_time_val)
|
|
if isinstance(last_time_str, str) and len(last_time_str) > 19:
|
|
last_time_str = last_time_str[:19]
|
|
details_val = status_record['details']
|
|
details_str = (details_val[:200] +
|
|
"...") if details_val and len(details_val) > 200 else (
|
|
details_val or "N/A")
|
|
response_text = (
|
|
f"<b>{_('admin_stats_last_sync_header')}</b>\n"
|
|
f" {_('admin_stats_sync_time')}: {last_time_str}\n"
|
|
f" {_('admin_stats_sync_status')}: {status_record['status']}\n"
|
|
f" {_('admin_stats_sync_users_processed')}: {status_record['users_processed_from_panel']}\n"
|
|
f" {_('admin_stats_sync_subs_synced')}: {status_record['subscriptions_synced']}\n"
|
|
f" {_('admin_stats_sync_details_label')}: {details_str}")
|
|
else:
|
|
response_text = _("admin_sync_status_never_run")
|
|
await message.answer(response_text, parse_mode="HTML")
|