129 lines
4.3 KiB
Python
129 lines
4.3 KiB
Python
import logging
|
|
from datetime import datetime, timedelta
|
|
from apscheduler.schedulers.background import BackgroundScheduler
|
|
from apscheduler.triggers.cron import CronTrigger
|
|
from sqlalchemy.orm import Session
|
|
from app.db.session import SessionLocal
|
|
from app.models.task import Task, TaskStatus
|
|
from app.models.user import User
|
|
from app.services.whatsapp_service import send_task_reminder, send_task_overdue
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SchedulerService:
|
|
def __init__(self):
|
|
self.scheduler = BackgroundScheduler()
|
|
self.scheduler.start()
|
|
self._setup_jobs()
|
|
|
|
def _setup_jobs(self):
|
|
self.scheduler.add_job(
|
|
func=self.send_reminders,
|
|
trigger=CronTrigger(hour=9, minute=0), # Daily at 9 AM
|
|
id='daily_reminders',
|
|
name='Send daily task reminders',
|
|
replace_existing=True
|
|
)
|
|
|
|
self.scheduler.add_job(
|
|
func=self.check_overdue_tasks,
|
|
trigger=CronTrigger(hour=18, minute=0), # Daily at 6 PM
|
|
id='overdue_check',
|
|
name='Check for overdue tasks',
|
|
replace_existing=True
|
|
)
|
|
|
|
def send_reminders(self):
|
|
logger.info("Starting daily reminder job")
|
|
db: Session = SessionLocal()
|
|
|
|
try:
|
|
# Get tasks scheduled for today that haven't been reminded
|
|
today = datetime.utcnow().date()
|
|
tomorrow = today + timedelta(days=1)
|
|
|
|
tasks = db.query(Task).join(User).filter(
|
|
Task.status.in_([TaskStatus.PENDING, TaskStatus.IN_PROGRESS]),
|
|
Task.scheduled_at >= datetime.combine(today, datetime.min.time()),
|
|
Task.scheduled_at < datetime.combine(tomorrow, datetime.min.time()),
|
|
Task.whatsapp_reminder_sent == False,
|
|
User.whatsapp_number.isnot(None)
|
|
).all()
|
|
|
|
sent_count = 0
|
|
for task in tasks:
|
|
if send_task_reminder(task.owner.whatsapp_number, task):
|
|
task.whatsapp_reminder_sent = True
|
|
sent_count += 1
|
|
|
|
db.commit()
|
|
logger.info(f"Sent {sent_count} reminders")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error in reminder job: {str(e)}")
|
|
db.rollback()
|
|
finally:
|
|
db.close()
|
|
|
|
def check_overdue_tasks(self):
|
|
logger.info("Starting overdue task check")
|
|
db: Session = SessionLocal()
|
|
|
|
try:
|
|
now = datetime.utcnow()
|
|
overdue_tasks = db.query(Task).join(User).filter(
|
|
Task.status.in_([TaskStatus.PENDING, TaskStatus.IN_PROGRESS]),
|
|
Task.due_date < now,
|
|
User.whatsapp_number.isnot(None)
|
|
).all()
|
|
|
|
sent_count = 0
|
|
for task in overdue_tasks:
|
|
if send_task_overdue(task.owner.whatsapp_number, task):
|
|
sent_count += 1
|
|
|
|
logger.info(f"Sent {sent_count} overdue notifications")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error in overdue check job: {str(e)}")
|
|
finally:
|
|
db.close()
|
|
|
|
def schedule_task_reminder(self, task_id: int, remind_at: datetime):
|
|
job_id = f"task_reminder_{task_id}"
|
|
|
|
self.scheduler.add_job(
|
|
func=self._send_individual_reminder,
|
|
trigger='date',
|
|
run_date=remind_at,
|
|
args=[task_id],
|
|
id=job_id,
|
|
name=f'Reminder for task {task_id}',
|
|
replace_existing=True
|
|
)
|
|
|
|
def _send_individual_reminder(self, task_id: int):
|
|
db: Session = SessionLocal()
|
|
|
|
try:
|
|
task = db.query(Task).join(User).filter(
|
|
Task.id == task_id,
|
|
User.whatsapp_number.isnot(None)
|
|
).first()
|
|
|
|
if task and task.status in [TaskStatus.PENDING, TaskStatus.IN_PROGRESS]:
|
|
send_task_reminder(task.owner.whatsapp_number, task)
|
|
task.whatsapp_reminder_sent = True
|
|
db.commit()
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error sending individual reminder for task {task_id}: {str(e)}")
|
|
finally:
|
|
db.close()
|
|
|
|
def shutdown(self):
|
|
self.scheduler.shutdown()
|
|
|
|
|
|
scheduler_service = SchedulerService() |