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"{_('admin_stats_last_sync_header')}\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")