105 lines
4.3 KiB
Python
105 lines
4.3 KiB
Python
"""NAS folder structure per client and project — geen alles-op-een-hoop."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import re
|
|
from pathlib import Path
|
|
from typing import Any, Optional
|
|
|
|
from app.db import execute, fetch_one
|
|
|
|
NAS_ROOT = Path(os.getenv("NAS_CLIENTS_ROOT", "/data/nas-clients"))
|
|
|
|
PROJECT_SUBDIRS = ("photos", "documents", "packaging", "exports", "briefs")
|
|
|
|
PROJECT_TYPES = [
|
|
{"id": "packaging", "label_nl": "Verpakking & label", "label_en": "Packaging & label", "icon": "📦", "nas_sub": "packaging"},
|
|
{"id": "retail_listing", "label_nl": "Retail listing / schap", "label_en": "Retail listing", "icon": "🏪", "nas_sub": "documents"},
|
|
{"id": "recipe", "label_nl": "Recept & productontwikkeling", "label_en": "Recipe & R&D", "icon": "🍱", "nas_sub": "briefs"},
|
|
{"id": "marketing", "label_nl": "Marketing campagne", "label_en": "Marketing campaign", "icon": "📣", "nas_sub": "exports"},
|
|
{"id": "halal", "label_nl": "Halal certificering", "label_en": "Halal certification", "icon": "☪️", "nas_sub": "documents"},
|
|
{"id": "sourcing", "label_nl": "Sourcing & import", "label_en": "Sourcing & import", "icon": "🚢", "nas_sub": "documents"},
|
|
{"id": "crm", "label_nl": "Klant & partnership", "label_en": "Client & partnership", "icon": "🤝", "nas_sub": "documents"},
|
|
{"id": "research", "label_nl": "Marktonderzoek", "label_en": "Market research", "icon": "🔬", "nas_sub": "briefs"},
|
|
{"id": "general", "label_nl": "Algemeen project", "label_en": "General project", "icon": "📁", "nas_sub": "documents"},
|
|
]
|
|
|
|
|
|
def slugify(name: str, max_len: int = 48) -> str:
|
|
s = re.sub(r"[^a-zA-Z0-9]+", "-", (name or "project").strip().lower()).strip("-")
|
|
return (s[:max_len] or "project")
|
|
|
|
|
|
def _write_meta(path: Path, data: dict[str, Any]) -> None:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
|
|
|
|
def ensure_client_folder(client_id: int, client_name: str) -> str:
|
|
"""Maak NAS-map per klant: clients/{slug}/ met submappen."""
|
|
slug = slugify(client_name)
|
|
root = NAS_ROOT / slug
|
|
for sub in ("projects", "photos", "documents", "inbox"):
|
|
(root / sub).mkdir(parents=True, exist_ok=True)
|
|
meta = {
|
|
"client_id": client_id,
|
|
"client_name": client_name,
|
|
"slug": slug,
|
|
"structure": ["projects", "photos", "documents", "inbox"],
|
|
}
|
|
_write_meta(root / "client.json", meta)
|
|
rel = str(root)
|
|
execute("UPDATE clients SET nas_folder = %s WHERE id = %s", (rel, client_id))
|
|
return rel
|
|
|
|
|
|
def ensure_project_folder(
|
|
project_id: int,
|
|
project_name: str,
|
|
client_id: Optional[int],
|
|
client_name: Optional[str],
|
|
project_type: str = "general",
|
|
) -> dict[str, Any]:
|
|
"""Projectmap onder klant: clients/{client}/projects/{project}/"""
|
|
client_root: Path | None = None
|
|
if client_id and client_name:
|
|
row = fetch_one("SELECT nas_folder FROM clients WHERE id = %s", (client_id,))
|
|
if row and row.get("nas_folder"):
|
|
client_root = Path(row["nas_folder"])
|
|
else:
|
|
client_root = Path(ensure_client_folder(client_id, client_name))
|
|
else:
|
|
client_root = NAS_ROOT / "_geen-klant"
|
|
client_root.mkdir(parents=True, exist_ok=True)
|
|
|
|
proj_slug = f"{project_id}-{slugify(project_name)}"
|
|
proj_root = client_root / "projects" / proj_slug
|
|
for sub in PROJECT_SUBDIRS:
|
|
(proj_root / sub).mkdir(parents=True, exist_ok=True)
|
|
|
|
type_info = next((t for t in PROJECT_TYPES if t["id"] == project_type), PROJECT_TYPES[-1])
|
|
_write_meta(
|
|
proj_root / "project.json",
|
|
{
|
|
"project_id": project_id,
|
|
"name": project_name,
|
|
"client_id": client_id,
|
|
"project_type": project_type,
|
|
"folders": list(PROJECT_SUBDIRS),
|
|
"primary_sub": type_info.get("nas_sub", "documents"),
|
|
},
|
|
)
|
|
|
|
nas_path = str(proj_root)
|
|
client_rel = str(client_root)
|
|
execute(
|
|
"""UPDATE cockpit_projects SET nas_path = %s, nas_client_root = %s, updated_at = NOW() WHERE id = %s""",
|
|
(nas_path, client_rel, project_id),
|
|
)
|
|
return {"nas_path": nas_path, "nas_client_root": client_rel, "project_slug": proj_slug}
|
|
|
|
|
|
def list_types() -> list[dict[str, Any]]:
|
|
return list(PROJECT_TYPES)
|