import os import json from typing import List, Optional, Dict, Any from datetime import datetime from modules.email.draft import EmailDraft class DraftHandler: """ Gestionnaire de brouillons (fichiers JSON). Répertoire: Data/email_drafts """ def __init__(self, base_dir: Optional[str] = None): base_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) self.base_dir = base_dir or os.path.join(base_root, "Data", "email_drafts") os.makedirs(self.base_dir, exist_ok=True) def _draft_path(self, draft_id: str) -> str: return os.path.join(self.base_dir, f"{draft_id}.json") def add_draft(self, draft: EmailDraft) -> str: path = self._draft_path(draft.id) with open(path, "w", encoding="utf-8") as f: json.dump(draft.to_dict(), f, ensure_ascii=False, indent=2) return draft.id def get_draft(self, draft_id: str) -> Optional[EmailDraft]: path = self._draft_path(draft_id) if not os.path.exists(path): return None with open(path, "r", encoding="utf-8") as f: return EmailDraft.from_dict(json.load(f)) def update_draft(self, draft: EmailDraft) -> bool: path = self._draft_path(draft.id) if not os.path.exists(path): return False with open(path, "w", encoding="utf-8") as f: json.dump(draft.to_dict(), f, ensure_ascii=False, indent=2) return True def delete_draft(self, draft_id: str) -> bool: path = self._draft_path(draft_id) if os.path.exists(path): try: os.remove(path) return True except Exception: return False return False def list_drafts(self, status: Optional[str] = None) -> List[EmailDraft]: drafts: List[EmailDraft] = [] for filename in os.listdir(self.base_dir): if filename.endswith(".json"): try: with open(os.path.join(self.base_dir, filename), "r", encoding="utf-8") as f: data = json.load(f) d = EmailDraft.from_dict(data) if status is None or d.status == status: drafts.append(d) except Exception: continue # Tri: plus récents d'abord drafts.sort(key=lambda d: d.created_at or "", reverse=True) return drafts def list_pending(self) -> List[EmailDraft]: return self.list_drafts(status="draft") def mark_sent(self, draft_id: str, success: bool, error_message: Optional[str] = None) -> bool: d = self.get_draft(draft_id) if not d: return False d.status = "sent" if success else "failed" d.sent_at = datetime.utcnow().isoformat() d.error_message = None if success else (error_message or "Unknown error") return self.update_draft(d) def find_existing_for_task(self, task_id: str) -> Optional[EmailDraft]: """ Évite les doublons: si un draft 'draft' existe déjà pour cette tâche, le renvoie. Les brouillons 'failed' ne bloquent pas la régénération. """ for d in self.list_drafts(): if d.task_id == task_id and d.status == "draft": return d return None