140 lines
6.2 KiB
Python
140 lines
6.2 KiB
Python
"""
|
||
Обработчик команд для управления расписанием рассылок
|
||
"""
|
||
|
||
import logging
|
||
from telegram import Update
|
||
from telegram.ext import ContextTypes
|
||
from app.scheduler import broadcast_scheduler, schedule_broadcast, cancel_broadcast, list_broadcasts
|
||
from app.database.repository import MessageRepository
|
||
from app.database import AsyncSessionLocal
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
async def schedule_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||
"""Команда для управления расписанием"""
|
||
|
||
if not update.message:
|
||
return
|
||
|
||
user_id = update.message.from_user.id
|
||
|
||
# Только администратор может управлять расписанием
|
||
# (это нужно добавить в конфигурацию)
|
||
|
||
try:
|
||
# /schedule list - показать все расписания
|
||
if context.args and context.args[0] == 'list':
|
||
schedules = await list_broadcasts()
|
||
|
||
if not schedules:
|
||
await update.message.reply_text("📋 Нет активных расписаний")
|
||
return
|
||
|
||
text = "📅 Активные расписания:\n\n"
|
||
for idx, sched in enumerate(schedules, 1):
|
||
text += f"{idx}. {sched['name']}\n"
|
||
text += f" ID: `{sched['id']}`\n"
|
||
text += f" Расписание: {sched['trigger']}\n"
|
||
text += f" Следующее выполнение: {sched['next_run_time']}\n\n"
|
||
|
||
await update.message.reply_text(text, parse_mode='Markdown')
|
||
|
||
# /schedule add message_id group_id cron_expr
|
||
elif context.args and context.args[0] == 'add':
|
||
if len(context.args) < 4:
|
||
await update.message.reply_text(
|
||
"❌ Использование: /schedule add <message_id> <group_id> <cron_expr>\n\n"
|
||
"Пример: /schedule add 1 10 '0 9 * * *'\n\n"
|
||
"Cron формат: minute hour day month day_of_week\n"
|
||
"0 9 * * * - ежедневно в 9:00 UTC"
|
||
)
|
||
return
|
||
|
||
try:
|
||
message_id = int(context.args[1])
|
||
group_id = int(context.args[2])
|
||
cron_expr = ' '.join(context.args[3:])
|
||
|
||
# Проверить, что сообщение существует
|
||
async with AsyncSessionLocal() as session:
|
||
message_repo = MessageRepository(session)
|
||
message = await message_repo.get_by_id(message_id)
|
||
if not message:
|
||
await update.message.reply_text(f"❌ Сообщение с ID {message_id} не найдено")
|
||
return
|
||
|
||
job_id = await schedule_broadcast(
|
||
message_id=message_id,
|
||
group_ids=[group_id],
|
||
cron_expr=cron_expr
|
||
)
|
||
|
||
await update.message.reply_text(
|
||
f"✅ Расписание создано!\n\n"
|
||
f"ID: `{job_id}`\n"
|
||
f"Сообщение: {message_id}\n"
|
||
f"Группа: {group_id}\n"
|
||
f"Расписание: {cron_expr}"
|
||
)
|
||
|
||
except ValueError as e:
|
||
await update.message.reply_text(f"❌ Ошибка: {e}")
|
||
except Exception as e:
|
||
logger.error(f"Ошибка при создании расписания: {e}")
|
||
await update.message.reply_text(f"❌ Ошибка: {e}")
|
||
|
||
# /schedule remove job_id
|
||
elif context.args and context.args[0] == 'remove':
|
||
if len(context.args) < 2:
|
||
await update.message.reply_text(
|
||
"❌ Использование: /schedule remove <job_id>"
|
||
)
|
||
return
|
||
|
||
job_id = context.args[1]
|
||
success = await cancel_broadcast(job_id)
|
||
|
||
if success:
|
||
await update.message.reply_text(f"✅ Расписание удалено: {job_id}")
|
||
else:
|
||
await update.message.reply_text(f"❌ Расписание не найдено: {job_id}")
|
||
|
||
else:
|
||
await update.message.reply_text(
|
||
"📅 Управление расписанием\n\n"
|
||
"Команды:\n"
|
||
"/schedule list - показать все расписания\n"
|
||
"/schedule add <msg_id> <group_id> <cron> - добавить расписание\n"
|
||
"/schedule remove <job_id> - удалить расписание\n\n"
|
||
"Примеры cron:\n"
|
||
"0 9 * * * - ежедневно в 9:00 UTC\n"
|
||
"0 9 * * MON - по понедельникам в 9:00\n"
|
||
"*/30 * * * * - каждые 30 минут"
|
||
)
|
||
|
||
except Exception as e:
|
||
logger.error(f"Ошибка в команде schedule: {e}")
|
||
await update.message.reply_text(f"❌ Ошибка: {e}")
|
||
|
||
|
||
async def initialize_scheduler(context: ContextTypes.DEFAULT_TYPE):
|
||
"""Инициализировать планировщик при запуске бота"""
|
||
try:
|
||
await broadcast_scheduler.initialize()
|
||
broadcast_scheduler.start()
|
||
await broadcast_scheduler.add_maintenance_schedules()
|
||
logger.info("✅ Планировщик инициализирован и запущен")
|
||
except Exception as e:
|
||
logger.error(f"❌ Ошибка при инициализации планировщика: {e}")
|
||
|
||
|
||
async def shutdown_scheduler(context: ContextTypes.DEFAULT_TYPE):
|
||
"""Завершить планировщик при остановке бота"""
|
||
try:
|
||
await broadcast_scheduler.shutdown()
|
||
logger.info("✅ Планировщик завершен")
|
||
except Exception as e:
|
||
logger.error(f"❌ Ошибка при завершении планировщика: {e}")
|