import asyncio from datetime import datetime, timedelta, timezone from typing import Optional from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.triggers.cron import CronTrigger from helper_bot.utils.base_dependency_factory import get_global_instance from logs.custom_logger import logger from .metrics import db_query_time, track_errors, track_time class AutoUnbanScheduler: """ Класс для автоматического разбана пользователей по истечении срока блокировки. Запускается ежедневно в 5:00 по московскому времени. """ def __init__(self): self.bdf = get_global_instance() self.bot_db = self.bdf.get_db() self.scheduler = AsyncIOScheduler() self.bot = None # Будет установлен позже def set_bot(self, bot): """Устанавливает экземпляр бота для отправки уведомлений""" self.bot = bot @track_time("auto_unban_users", "auto_unban_scheduler") @track_errors("auto_unban_scheduler", "auto_unban_users") @db_query_time("auto_unban_users", "users", "mixed") async def auto_unban_users(self): """ Основная функция автоматического разбана пользователей. Получает список пользователей, у которых истекает срок блокировки сегодня, и удаляет их из черного списка. """ try: logger.info("Запуск автоматического разбана пользователей") # Получаем текущий UNIX timestamp current_timestamp = int(datetime.now().timestamp()) logger.info(f"Поиск пользователей для разблокировки на timestamp: {current_timestamp}") # Получаем список пользователей для разблокировки users_to_unban = await self.bot_db.get_users_for_unblock_today(current_timestamp) if not users_to_unban: logger.info("Нет пользователей для разблокировки сегодня") return logger.info(f"Найдено {len(users_to_unban)} пользователей для разблокировки") # Список для отслеживания результатов success_count = 0 failed_count = 0 failed_users = [] # Разблокируем каждого пользователя for user_id in users_to_unban: try: result = await self.bot_db.delete_user_blacklist(user_id) if result: success_count += 1 logger.info(f"Пользователь {user_id} успешно разблокирован") else: failed_count += 1 failed_users.append(f"{user_id}") logger.error(f"Ошибка при разблокировке пользователя {user_id}") except Exception as e: failed_count += 1 failed_users.append(f"{user_id}") logger.error(f"Исключение при разблокировке пользователя {user_id}: {e}") # Формируем отчет report = self._generate_report(success_count, failed_count, failed_users, users_to_unban) # Отправляем отчет в лог-канал await self._send_report(report) logger.info(f"Автоматический разбан завершен. Успешно: {success_count}, Ошибок: {failed_count}") except Exception as e: error_msg = f"Критическая ошибка в автоматическом разбане: {e}" logger.error(error_msg) await self._send_error_report(error_msg) def _generate_report(self, success_count: int, failed_count: int, failed_users: list, all_users: dict) -> str: """Генерирует отчет о результатах автоматического разбана""" report = f"🤖 Отчет об автоматическом разбане\n\n" report += f"📅 Дата: {datetime.now().strftime('%d.%m.%Y %H:%M')}\n" report += f"✅ Успешно разблокировано: {success_count}\n" report += f"❌ Ошибок: {failed_count}\n\n" if success_count > 0: report += "✅ Разблокированные пользователи:\n" for user_id in all_users: if str(user_id) not in failed_users: report += f"• ID: {user_id}\n" report += "\n" if failed_users: report += "❌ Ошибки при разблокировке:\n" for user in failed_users: report += f"• {user}\n" return report @track_time("send_report", "auto_unban_scheduler") @track_errors("auto_unban_scheduler", "send_report") async def _send_report(self, report: str): """Отправляет отчет в лог-канал""" try: if self.bot: group_for_logs = self.bdf.settings['Telegram']['group_for_logs'] await self.bot.send_message( chat_id=group_for_logs, text=report, parse_mode='HTML' ) except Exception as e: logger.error(f"Ошибка при отправке отчета: {e}") @track_time("send_error_report", "auto_unban_scheduler") @track_errors("auto_unban_scheduler", "send_error_report") async def _send_error_report(self, error_msg: str): """Отправляет отчет об ошибке в важный лог-канал""" try: if self.bot: important_logs = self.bdf.settings['Telegram']['important_logs'] await self.bot.send_message( chat_id=important_logs, text=f"🚨 Ошибка автоматического разбана\n\n{error_msg}", parse_mode='HTML' ) except Exception as e: logger.error(f"Ошибка при отправке отчета об ошибке: {e}") def start_scheduler(self): """Запускает планировщик задач""" try: # Добавляем задачу на ежедневное выполнение в 5:00 по Москве self.scheduler.add_job( self.auto_unban_users, CronTrigger(hour=5, minute=0, timezone='Europe/Moscow'), id='auto_unban_users', name='Автоматический разбан пользователей', replace_existing=True ) # Запускаем планировщик self.scheduler.start() logger.info("Планировщик автоматического разбана запущен. Задача запланирована на 5:00 по Москве") except Exception as e: logger.error(f"Ошибка при запуске планировщика: {e}") def stop_scheduler(self): """Останавливает планировщик задач""" try: if self.scheduler.running: self.scheduler.shutdown() logger.info("Планировщик автоматического разбана остановлен") except Exception as e: logger.error(f"Ошибка при остановке планировщика: {e}") async def run_manual_unban(self): """Запускает разбан вручную (для тестирования)""" logger.info("Запуск ручного разбана пользователей") await self.auto_unban_users() # Глобальный экземпляр планировщика auto_unban_scheduler = AutoUnbanScheduler() def get_auto_unban_scheduler() -> AutoUnbanScheduler: """Возвращает глобальный экземпляр планировщика""" return auto_unban_scheduler