All checks were successful
Deploy bericht / deploy (push) Successful in 1s
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]
46 lines
1.7 KiB
PHP
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));
|