/** * Baut eine Download-URL für ein im Backend gespeichertes Upload-File. * * Geht über `GET /api/files/download?path=...` – der Backend-Controller * macht einen Per-File-Ownership-Check (Pfad → Resource → canAccessCustomer * / canAccessContract). Damit kann auch ein eingeloggter User keine * fremden Dateien abrufen, selbst wenn er den Pfad kennen würde. * * und window.open senden keinen Authorization-Header, daher * Token als Query-Parameter (auth-Middleware akzeptiert `?token=`). * * Trade-off: Tokens in URLs können in Logs/Referrer landen. Eine * sauberere Lösung mit kurzlebigen Download-Tokens (signierte URLs) * wäre v1.1-Item. */ import { getAccessToken } from '../services/api'; /** * Kurzform für Inline-Vorschau: identisch zu `fileUrl(path, { inline: true })`. * Verwenden für „Anzeigen"-Links / target="_blank"-Vorschauen. Default- * `fileUrl(path)` bleibt für Downloads (Content-Disposition: attachment). */ export function viewUrl(path: string | null | undefined): string { return fileUrl(path, { inline: true }); } export function fileUrl(path: string | null | undefined, opts?: { inline?: boolean }): string { if (!path) return ''; const token = getAccessToken(); const normalizedPath = path.startsWith('/') ? path : '/' + path; // `?disposition=inline` schaltet die Anzeige im Browser-Tab ein, // der Backend-Controller bleibt aber nur dann inline, wenn die // Datei tatsächlich ein safe Type (PDF/PNG/JPEG/GIF/WebP) ist – // sonst fällt's auf attachment zurück. Default attachment. const dispParam = opts?.inline ? '&disposition=inline' : ''; const base = `/api/files/download?path=${encodeURIComponent(normalizedPath)}${dispParam}`; if (!token) return base; return `${base}&token=${encodeURIComponent(token)}`; }