import re import unicodedata from pathlib import Path from app.core.config import settings from app.models.notes import NoteItem def _slugify(text: str, max_len: int = 50) -> str: text = unicodedata.normalize("NFD", text) text = "".join(c for c in text if unicodedata.category(c) != "Mn") text = text.lower() text = re.sub(r"[^\w\s-]", "", text) text = re.sub(r"[\s_-]+", "-", text) return text.strip("-")[:max_len] def _note_filename(note: NoteItem) -> str: date = note.created_at.strftime("%Y-%m-%d") raw = note.title or note.content[:40] slug = _slugify(raw) or "sans-titre" short_id = str(note.id)[:8] return f"{date}_{slug}_{short_id}.md" def _render(note: NoteItem) -> str: lines = ["---"] lines.append(f"id: {note.id}") if note.title: lines.append(f'title: "{note.title}"') if note.category: lines.append(f"category: {note.category}") if note.tags: tags_str = ", ".join(f'"{t}"' for t in note.tags) lines.append(f"tags: [{tags_str}]") lines.append(f"created_at: {note.created_at.isoformat()}") if note.gps_lat is not None and note.gps_lon is not None: lines.append(f'gps: "{note.gps_lat}, {note.gps_lon}"') lines.append("---") lines.append("") lines.append(note.content) images = [a for a in note.attachments if a.file_type == "image" and a.file_path] audios = [a for a in note.attachments if a.file_type == "audio" and a.file_path] if images or audios: lines.append("") lines.append("## Pièces jointes") lines.append("") for att in images: # file_path est relatif à UPLOAD_DIR, ex: "images/originals/uuid.webp" rel = f"../uploads/{att.file_path}" name = att.original_name or "image" lines.append(f"![{name}]({rel})") for att in audios: rel = f"../uploads/{att.file_path}" name = att.original_name or "audio" lines.append(f"[{name}]({rel})") return "\n".join(lines) + "\n" def save_note_markdown(note: NoteItem) -> None: notes_dir = settings.notes_md_path notes_dir.mkdir(parents=True, exist_ok=True) short_id = str(note.id)[:8] # Supprime l'ancienne version (titre peut avoir changé) for old in notes_dir.glob(f"*_{short_id}.md"): old.unlink() (notes_dir / _note_filename(note)).write_text(_render(note), encoding="utf-8") def delete_note_markdown(note_id: str) -> None: notes_dir = settings.notes_md_path if not notes_dir.exists(): return short_id = note_id[:8] for f in notes_dir.glob(f"*_{short_id}.md"): f.unlink()