Files
TG_autoposter/app/handlers/schedule.py
2025-12-18 05:55:32 +09:00

140 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Обработчик команд для управления расписанием рассылок
"""
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}")