- Add snooze.py handler: prompts user for snooze minutes and schedules a one-shot job with a cancel button (cancel_snooze_<id>) - Refactor callback.py: support compound action prefix parsing for cancel_snooze_*, switch snooze action to prompt-based flow - Add snooze_action_keyboard() in keyboards.py; update snooze button label - Register handle_snooze_input in group=1 to avoid ConversationHandler conflict - Filter completed once-type reminders from get_user_reminders() - Fix DateTrigger: compare and localize once_time in UTC consistently Co-Authored-By: claude-sonnet-4-6 <noreply@anthropic.com>
73 lines
2.5 KiB
Python
73 lines
2.5 KiB
Python
from datetime import datetime, timedelta, timezone
|
|
|
|
import pytz
|
|
from telegram import Update
|
|
from telegram.ext import ContextTypes
|
|
|
|
from bot.models.database import Session
|
|
from bot.models.reminder import Reminder
|
|
from bot.utils.keyboards import snooze_action_keyboard
|
|
|
|
|
|
async def handle_snooze_input(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
"""Handle user input for snooze minutes."""
|
|
if "snooze_reminder_id" not in context.user_data:
|
|
return
|
|
|
|
reminder_id = context.user_data.pop("snooze_reminder_id")
|
|
chat_id = context.user_data.pop("snooze_chat_id", None)
|
|
|
|
try:
|
|
minutes = int(update.message.text.strip())
|
|
if minutes <= 0 or minutes > 1440:
|
|
await update.message.reply_text("请输入 1-1440 之间的分钟数。")
|
|
return
|
|
except ValueError:
|
|
await update.message.reply_text("请输入有效的数字。")
|
|
return
|
|
|
|
session = Session()
|
|
try:
|
|
reminder = session.get(Reminder, reminder_id)
|
|
if reminder is None:
|
|
await update.message.reply_text("提醒不存在或已被删除。")
|
|
return
|
|
|
|
snooze_time_utc = datetime.now(timezone.utc) + timedelta(minutes=minutes)
|
|
|
|
# For once-type reminders, update the once_time and reschedule
|
|
if reminder.reminder_type == "once":
|
|
reminder.once_time = snooze_time_utc
|
|
reminder.is_active = True
|
|
session.commit()
|
|
|
|
# Reschedule using APScheduler
|
|
from bot.scheduler.job_manager import add_reminder_job
|
|
add_reminder_job(reminder_id)
|
|
else:
|
|
# For recurring reminders, use temporary job_queue
|
|
from bot.scheduler.executor import execute_reminder
|
|
_rid = reminder_id
|
|
|
|
async def snooze_callback(ctx):
|
|
await execute_reminder(_rid, ctx.bot)
|
|
|
|
context.job_queue.run_once(
|
|
snooze_callback,
|
|
when=snooze_time_utc,
|
|
name=f"snooze_{reminder_id}",
|
|
)
|
|
|
|
tz = pytz.timezone("Asia/Shanghai")
|
|
display_time = snooze_time_utc.astimezone(tz).strftime("%Y-%m-%d %H:%M")
|
|
|
|
# Only show cancel button for recurring reminders (once-type uses DB now)
|
|
keyboard = None if reminder.reminder_type == "once" else snooze_action_keyboard(reminder_id)
|
|
|
|
await update.message.reply_text(
|
|
f"⏰ 已延期 {minutes} 分钟\n将在 {display_time} 再次提醒:{reminder.title}",
|
|
reply_markup=keyboard,
|
|
)
|
|
finally:
|
|
Session.remove()
|