bericht/ajax/delete_attachment.php
Eduard Wisch a7bf3929a4
All checks were successful
Deploy bericht / deploy (push) Successful in 1s
feat: Phase 1.6 + 1.1 + 1.2 — verknüpfte Sicht, PDF-Vorschau, Anhänge löschen
Phase 1.6 Verknüpfte Sicht Auftrag↔Rechnung:
- Bericht::fetchLinkedForElement liest llx_element_element-Verknüpfungen
- linkToElement/unlinkFromElement n:m-API
- Bericht-Übersicht zeigt drei Sektionen: direkt zugeordnet,
  zusätzlich verknüpft, aus verknüpften Aufträgen (read-only)
- 'Übernehmen'-Button erstellt llx_element_element-Eintrag
- 'Lösen'-Button entfernt Verknüpfung
- generate_pdf legt das fertige PDF auch unter den verknüpften
  Elementen ab + ECM-Eintrag

Phase 1.1 Live-PDF-Vorschau:
- Neuer Endpoint ajax/preview_pdf.php — wie generate_pdf, aber:
  schreibt nicht in ECM, ändert nicht den Status, streamt direkt
- 👁️ Vorschau-Button im Editor öffnet Modal mit iframe (PDF.js
  Viewer des Browsers)
- bericht_burn_annotations und bericht_render_cover_internal in
  lib/bericht.lib.php verschoben (gemeinsam genutzt)
- ESC-Key + Backdrop-Click schließen das Modal

Phase 1.2 Anhänge löschen:
- Neuer Endpoint ajax/delete_attachment.php mit Path-Whitelist
  (nur facture/, commande/, propal/), löscht Datei + thumbs +
  llx_ecm_files-Eintrag
- 🗑️-Button in jeder Anhang-Zeile, Confirm-Dialog mit
  Quell-Auftrag/Rechnung im Text
- Inline-Remove ohne Page-Reload

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
2026-04-08 22:13:46 +02:00

46 lines
1.7 KiB
PHP

<?php
/* Löscht eine Datei aus dem Anhang-Verzeichnis eines Parent-Objekts.
* Sicherheits-Whitelist: nur Pfade unter facture/, commande/, propal/.
* Bereinigt zugehörigen llx_ecm_files-Eintrag.
*
* POST: relpath, token
*/
require_once __DIR__.'/_inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
global $db, $user;
if (!$user->hasRight('bericht', 'write')) bericht_ajax_fail('Permission denied', 403);
$relpath = (string) ($_POST['relpath'] ?? '');
if (empty($relpath)) bericht_ajax_fail('relpath fehlt');
// Whitelist-Prüfung: nur unter den drei erlaubten Element-Verzeichnissen
if (!preg_match('#^(facture|commande|propal)/[^/]+/[^/]+$#', $relpath)) {
bericht_ajax_fail('Pfad nicht erlaubt: ' . $relpath, 403);
}
$full = bericht_resolve_data_path($relpath);
if (!$full || !file_exists($full)) bericht_ajax_fail('Datei nicht gefunden', 404);
// Datei löschen
if (!@unlink($full)) bericht_ajax_fail('Löschen fehlgeschlagen');
// Thumbs ebenfalls löschen (Dolibarr legt _mini/_small unter thumbs/ ab)
$dir = dirname($full);
$base = pathinfo($full, PATHINFO_FILENAME);
$ext = pathinfo($full, PATHINFO_EXTENSION);
foreach (array('_mini', '_small') as $suffix) {
$thumb = $dir.'/thumbs/'.$base.$suffix.'.'.$ext;
if (file_exists($thumb)) @unlink($thumb);
$thumb_png = $dir.'/thumbs/'.$base.$suffix.'.png';
if (file_exists($thumb_png)) @unlink($thumb_png);
}
// ECM-Eintrag bereinigen
$relpath_dir = dirname($relpath);
$filename = basename($relpath);
$db->query("DELETE FROM ".$db->prefix()."ecm_files"
." WHERE filepath = '".$db->escape($relpath_dir)."'"
." AND filename = '".$db->escape($filename)."'");
bericht_ajax_ok(array('deleted' => $relpath));