Add auto unban functionality and update related tests and dependencies
This commit is contained in:
175
helper_bot/utils/auto_unban_scheduler.py
Normal file
175
helper_bot/utils/auto_unban_scheduler.py
Normal file
@@ -0,0 +1,175 @@
|
||||
import asyncio
|
||||
from datetime import datetime, timezone, timedelta
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
|
||||
async def auto_unban_users(self):
|
||||
"""
|
||||
Основная функция автоматического разбана пользователей.
|
||||
Получает список пользователей, у которых истекает срок блокировки сегодня,
|
||||
и удаляет их из черного списка.
|
||||
"""
|
||||
try:
|
||||
logger.info("Запуск автоматического разбана пользователей")
|
||||
|
||||
# Получаем сегодняшнюю дату в формате YYYY-MM-DD
|
||||
moscow_tz = timezone(timedelta(hours=3)) # UTC+3 для Москвы
|
||||
today = datetime.now(moscow_tz).strftime("%Y-%m-%d")
|
||||
|
||||
logger.info(f"Поиск пользователей для разблокировки на дату: {today}")
|
||||
|
||||
# Получаем список пользователей для разблокировки
|
||||
users_to_unban = self.bot_db.get_users_for_unblock_today(today)
|
||||
|
||||
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, username in users_to_unban.items():
|
||||
try:
|
||||
result = self.bot_db.delete_user_blacklist(user_id)
|
||||
if result:
|
||||
success_count += 1
|
||||
logger.info(f"Пользователь {user_id} ({username}) успешно разблокирован")
|
||||
else:
|
||||
failed_count += 1
|
||||
failed_users.append(f"{user_id} ({username})")
|
||||
logger.error(f"Ошибка при разблокировке пользователя {user_id} ({username})")
|
||||
except Exception as e:
|
||||
failed_count += 1
|
||||
failed_users.append(f"{user_id} ({username})")
|
||||
logger.error(f"Исключение при разблокировке пользователя {user_id} ({username}): {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"🤖 <b>Отчет об автоматическом разбане</b>\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 += "✅ <b>Разблокированные пользователи:</b>\n"
|
||||
for user_id, username in all_users.items():
|
||||
if f"{user_id} ({username})" not in failed_users:
|
||||
safe_username = username if username else "Неизвестный пользователь"
|
||||
report += f"• ID: {user_id}, Имя: {safe_username}\n"
|
||||
report += "\n"
|
||||
|
||||
if failed_users:
|
||||
report += "❌ <b>Ошибки при разблокировке:</b>\n"
|
||||
for user in failed_users:
|
||||
report += f"• {user}\n"
|
||||
|
||||
return 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}")
|
||||
|
||||
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"🚨 <b>Ошибка автоматического разбана</b>\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
|
||||
Reference in New Issue
Block a user