init commit
This commit is contained in:
139
app/handlers/schedule.py
Normal file
139
app/handlers/schedule.py
Normal file
@@ -0,0 +1,139 @@
|
||||
"""
|
||||
Обработчик команд для управления расписанием рассылок
|
||||
"""
|
||||
|
||||
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}")
|
||||
Reference in New Issue
Block a user