""" Simple Task Definitions 簡化的任務定義,避免循環導入 """ from datetime import datetime, date, timedelta from sqlalchemy import and_, or_ from utils.logger import get_logger logger = get_logger(__name__) def send_daily_reminders_task(): """發送每日提醒郵件的實際實作""" from models import db, TodoItem, TodoUserPref from utils.email_service import EmailService from utils.notification_service import NotificationService try: today = date.today() tomorrow = today + timedelta(days=1) # 查找明日到期的待辦事項 due_tomorrow = db.session.query(TodoItem).filter( and_( TodoItem.due_date == tomorrow, TodoItem.status != 'DONE' ) ).all() # 查找已逾期的待辦事項 overdue = db.session.query(TodoItem).filter( and_( TodoItem.due_date < today, TodoItem.status != 'DONE' ) ).all() email_service = EmailService() notification_service = NotificationService() sent_count = 0 # 處理明日到期提醒 for todo in due_tomorrow: recipients = notification_service.get_notification_recipients(todo) for recipient in recipients: try: # 檢查用戶是否啟用郵件提醒 user_pref = TodoUserPref.query.filter_by(ad_account=recipient).first() if not user_pref or not user_pref.email_reminder_enabled: continue if email_service.send_reminder_email(todo, recipient, 'due_tomorrow'): sent_count += 1 except Exception as e: logger.error(f"Failed to send due tomorrow reminder to {recipient}: {str(e)}") # 處理逾期提醒 for todo in overdue: recipients = notification_service.get_notification_recipients(todo) for recipient in recipients: try: # 檢查用戶是否啟用郵件提醒 user_pref = TodoUserPref.query.filter_by(ad_account=recipient).first() if not user_pref or not user_pref.email_reminder_enabled: continue if email_service.send_reminder_email(todo, recipient, 'overdue'): sent_count += 1 except Exception as e: logger.error(f"Failed to send overdue reminder to {recipient}: {str(e)}") # 記錄稽核日誌 from models import TodoAuditLog audit = TodoAuditLog( actor_ad='system', todo_id=None, action='DAILY_REMINDER', detail={ 'due_tomorrow_count': len(due_tomorrow), 'overdue_count': len(overdue), 'emails_sent': sent_count } ) db.session.add(audit) db.session.commit() logger.info(f"Daily reminders sent: {sent_count} emails for {len(due_tomorrow + overdue)} todos") return { 'sent_count': sent_count, 'due_tomorrow': len(due_tomorrow), 'overdue': len(overdue) } except Exception as e: logger.error(f"Daily reminders task failed: {str(e)}") raise def send_weekly_summary_task(): """發送每週摘要報告的實際實作""" from models import db, TodoUserPref from utils.email_service import EmailService from utils.notification_service import NotificationService try: # 取得所有啟用週報的用戶 users = TodoUserPref.query.filter_by(weekly_summary_enabled=True).all() email_service = EmailService() notification_service = NotificationService() sent_count = 0 for user in users: try: # 準備週報資料 digest_data = notification_service.prepare_digest(user.ad_account, 'weekly') if email_service.send_digest_email(user.ad_account, digest_data): sent_count += 1 except Exception as e: logger.error(f"Failed to send weekly summary to {user.ad_account}: {str(e)}") # 記錄稽核日誌 from models import TodoAuditLog audit = TodoAuditLog( actor_ad='system', todo_id=None, action='WEEKLY_SUMMARY', detail={ 'users_count': len(users), 'emails_sent': sent_count } ) db.session.add(audit) db.session.commit() logger.info(f"Weekly summary sent: {sent_count} emails to {len(users)} users") return { 'sent_count': sent_count, 'total_users': len(users) } except Exception as e: logger.error(f"Weekly summary task failed: {str(e)}") raise def cleanup_old_logs_task(): """清理舊的日誌記錄的實際實作""" from models import db, TodoAuditLog try: # 清理30天前的稽核日誌 thirty_days_ago = datetime.utcnow() - timedelta(days=30) deleted_count = TodoAuditLog.query.filter( TodoAuditLog.created_at < thirty_days_ago ).delete() db.session.commit() logger.info(f"Cleaned up {deleted_count} old audit logs") return {'deleted_count': deleted_count} except Exception as e: logger.error(f"Cleanup logs task failed: {str(e)}") raise # 為了與現有代碼兼容,提供簡單的包裝函數 def send_daily_reminders(): """包裝函數,保持與現有代碼兼容""" return send_daily_reminders_task() def send_weekly_summary(): """包裝函數,保持與現有代碼兼容""" return send_weekly_summary_task() def cleanup_old_logs(): """包裝函數,保持與現有代碼兼容""" return cleanup_old_logs_task()