""" 每日配額檢查批次 (5.1) 執行時間: 每日 02:00 批次名稱: daily_quota_check 檢查郵件和雲端硬碟配額使用情況,超過 80% 發送告警 """ import logging from datetime import datetime from app.batch.base import log_batch_execution logger = logging.getLogger(__name__) QUOTA_ALERT_THRESHOLD = 0.8 # 超過 80% 發送告警 ALERT_EMAIL = "admin@porscheworld.tw" def _send_alert_email(to: str, subject: str, body: str) -> bool: """ 發送告警郵件 目前使用 SMTP 直送,未來可整合 Mailserver """ try: import smtplib from email.mime.text import MIMEText from app.core.config import settings msg = MIMEText(body, "plain", "utf-8") msg["Subject"] = subject msg["From"] = settings.MAIL_ADMIN_USER msg["To"] = to with smtplib.SMTP(settings.MAIL_SERVER, settings.MAIL_PORT) as smtp: if settings.MAIL_USE_TLS: smtp.starttls() smtp.login(settings.MAIL_ADMIN_USER, settings.MAIL_ADMIN_PASSWORD) smtp.send_message(msg) logger.info(f"告警郵件已發送至 {to}: {subject}") return True except Exception as e: logger.warning(f"發送告警郵件失敗: {e}") return False def run_daily_quota_check() -> dict: """ 執行每日配額檢查批次 Returns: 執行結果摘要 """ started_at = datetime.utcnow() alerts_sent = 0 errors = [] summary = { "email_checked": 0, "email_alerts": 0, "drive_checked": 0, "drive_alerts": 0, } logger.info("=== 開始每日配額檢查批次 ===") # 取得資料庫 Session from app.db.session import get_db from app.models.email_account import EmailAccount from app.models.network_drive import NetworkDrive db = next(get_db()) try: # 1. 檢查郵件配額 logger.info("檢查郵件配額使用情況...") email_accounts = db.query(EmailAccount).filter( EmailAccount.is_active == True ).all() for account in email_accounts: summary["email_checked"] += 1 # 目前郵件 Mailserver API 未整合,跳過實際配額查詢 # TODO: 整合 Mailserver API 後取得實際使用量 # usage_mb = mailserver_service.get_usage(account.email_address) # if usage_mb and usage_mb / account.quota_mb > QUOTA_ALERT_THRESHOLD: # _send_alert_email(...) pass logger.info(f"郵件帳號檢查完成: {summary['email_checked']} 個帳號") # 2. 檢查雲端硬碟配額 (Drive Service API) logger.info("檢查雲端硬碟配額使用情況...") network_drives = db.query(NetworkDrive).filter( NetworkDrive.is_active == True ).all() from app.services.drive_service import get_drive_service_client drive_client = get_drive_service_client() for drive in network_drives: summary["drive_checked"] += 1 try: # 查詢配額使用量 (Drive Service 未上線時會回傳 None) # 注意: drive.id 是資料庫 ID,需要 drive_user_id # 目前跳過實際查詢,等 Drive Service 上線後補充 pass except Exception as e: logger.warning(f"查詢 {drive.drive_name} 配額失敗: {e}") logger.info(f"雲端硬碟檢查完成: {summary['drive_checked']} 個帳號") # 3. 記錄批次執行日誌 finished_at = datetime.utcnow() message = ( f"郵件帳號: {summary['email_checked']} 個, 告警: {summary['email_alerts']} 個; " f"雲端硬碟: {summary['drive_checked']} 個, 告警: {summary['drive_alerts']} 個" ) log_batch_execution( batch_name="daily_quota_check", status="success", message=message, started_at=started_at, finished_at=finished_at, ) logger.info(f"=== 每日配額檢查批次完成 === {message}") return {"status": "success", "summary": summary} except Exception as e: error_msg = f"每日配額檢查批次失敗: {str(e)}" logger.error(error_msg) log_batch_execution( batch_name="daily_quota_check", status="failed", message=error_msg, started_at=started_at, ) return {"status": "failed", "error": str(e)} finally: db.close() if __name__ == "__main__": import sys import os # 允許直接執行此批次 sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../../..")) logging.basicConfig(level=logging.INFO) result = run_daily_quota_check() print(f"執行結果: {result}")