89 lines
3.3 KiB
Python
89 lines
3.3 KiB
Python
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
|