From 10df92b643ee4a3e15b39a87be3e9d70b251dbf1 Mon Sep 17 00:00:00 2001 From: Pontoporeia Date: Sun, 5 Jul 2026 13:58:19 +0200 Subject: [PATCH] fix: load autosave-handler.js on about_page edit view, persist contact group deletion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two fixes: 1. about_page edit was missing autosave-handler.js: the first if block (editType === 'page' || 'about_page') overrode $extraJs with only overtype.min.js, making the elseif that added autosave-handler.js unreachable for about_page. Added autosave-handler.js to the first block, removed dead 'about_page' from the elseif. 2. Deleting a contact group (Contacts 3/4/5) only removed the DOM element but never triggered htmx autosave. Dispatched a 'change' event on the form after removal+reindex so the hx-trigger fires. Also expanded autosave-handler.js URL filter to accept apropos.php so the status indicator (Enregistrement/Enregistré) works for contacts saves. --- TODO.md | 2 + app/public/admin/contenus-edit.php | 4 +- .../assets/js/app/admin-contacts-form.js | 2 + app/public/assets/js/app/autosave-handler.js | 4 +- .../assets/js/app/file-upload-filepond.js | 46 ++++++++++--------- app/src/Controllers/ThesisFileHandler.php | 2 +- .../validate-file-fragment-shared.php | 12 ++++- app/src/FilepondHandler.php | 14 +++--- .../partials/form/fichiers-fragment.php | 4 +- .../partials/form/fieldset-files.php | 2 +- 10 files changed, 54 insertions(+), 38 deletions(-) diff --git a/TODO.md b/TODO.md index d1a81b0..91768b3 100644 --- a/TODO.md +++ b/TODO.md @@ -24,3 +24,5 @@ - [x] Dans le formulaire admin, le contact privé ne se sauvegarde pas. - [x] Remove "Rendre le contact visible publiquement sur la fiche du TFE" from admin add/edit forms - [x] Auto-show contact on public TFE page when contact_visible is filled (no checkbox needed) +- [x] Fix file size limits: align all layers (JS/FilepondHandler/ThesisFileHandler/validate-fragment) — video/audio 5 GB, default 500 MB, PDF 100 MB; fix JS fileValidateSizeFilter gate bug that rejected AV files >1 GB despite 8 GB per-ext cap +- [x] Fix: deleting contact groups in apropos form not persisted (no change event after DOM removal, autosave never triggered) diff --git a/app/public/admin/contenus-edit.php b/app/public/admin/contenus-edit.php index c8169cb..fccb7f8 100644 --- a/app/public/admin/contenus-edit.php +++ b/app/public/admin/contenus-edit.php @@ -83,7 +83,7 @@ $extraJsInline = ''; if ($editType === 'page' || $editType === 'about_page') { $initialContent = $page["content"] ?? ""; - $extraJs = ["/assets/js/vendor/overtype.min.js"]; + $extraJs = ["/assets/js/vendor/overtype.min.js", "/assets/js/app/autosave-handler.js"]; $extraJsInline = <<<'JS' var OT = window.OverType.default || window.OverType; var hidden = document.getElementById('content'); @@ -113,7 +113,7 @@ var editor = new OT(document.getElementById('editor'), { } }); JS; -} elseif ($editType === 'apropos' || $editType === 'about_page') { +} elseif ($editType === 'apropos') { $extraJs = ["/assets/js/app/autosave-handler.js"]; } diff --git a/app/public/assets/js/app/admin-contacts-form.js b/app/public/assets/js/app/admin-contacts-form.js index 70967b0..7453301 100644 --- a/app/public/assets/js/app/admin-contacts-form.js +++ b/app/public/assets/js/app/admin-contacts-form.js @@ -65,6 +65,8 @@ if (fieldset) { fieldset.remove(); reindexGroups(); + // Trigger htmx autosave so deletion is persisted + form.dispatchEvent(new Event('change', { bubbles: true })); } }); } diff --git a/app/public/assets/js/app/autosave-handler.js b/app/public/assets/js/app/autosave-handler.js index 487750b..1069358 100644 --- a/app/public/assets/js/app/autosave-handler.js +++ b/app/public/assets/js/app/autosave-handler.js @@ -11,7 +11,7 @@ function handleAutosaveResponse(event) { // HTMX requests (e.g. licence fragment, pill-search) also // reach this handler. We filter by URL to avoid mixing them. const url = event.detail.requestConfig?.path || ""; - if (!url.includes("draft.php")) return; + if (!url.includes("draft.php") && !url.includes("apropos.php")) return; const form = event.target.closest("form"); const status = form ? form.querySelector("[data-autosave-status]") : null; @@ -67,7 +67,7 @@ window.handleAutosaveResponse = handleAutosaveResponse; // Show saving indicator while request is in flight document.body.addEventListener("htmx:beforeRequest", (e) => { const url = e.detail.requestConfig?.path || ""; - if (!url.includes("draft.php")) return; + if (!url.includes("draft.php") && !url.includes("apropos.php")) return; // The autosave request comes from the hidden probe div, so find // the status indicator by searching the closest form. const el = e.target; diff --git a/app/public/assets/js/app/file-upload-filepond.js b/app/public/assets/js/app/file-upload-filepond.js index 6e6799d..c07ec6d 100644 --- a/app/public/assets/js/app/file-upload-filepond.js +++ b/app/public/assets/js/app/file-upload-filepond.js @@ -47,7 +47,7 @@ labelFileTypeNotAllowed: "Format non accepté", fileValidateTypeLabelExpectedTypes: "PDF, Images, Vidéos, Audio, VTT, Archives", - maxFileSize: 1073741824, // 1 GB + maxFileSize: 524288000, // 500 MB labelMaxFileSizeExceeded: "Fichier trop volumineux", labelMaxFileSize: "Taille max: {filesize}", allowMultiple: true, @@ -57,17 +57,17 @@ // parseInt("1GB") = 1 byte inside the plugin). perExtensionMaxSize: { pdf: 104857600, // 100 MB - mp4: 8589934592, // 8 GB - webm: 8589934592, - ogv: 8589934592, - mov: 8589934592, - mp3: 8589934592, - ogg: 8589934592, - oga: 8589934592, - wav: 8589934592, - flac: 8589934592, - aac: 8589934592, - m4a: 8589934592, + mp4: 5368709120, // 5 GB + webm: 5368709120, + ogv: 5368709120, + mov: 5368709120, + mp3: 5368709120, + ogg: 5368709120, + oga: 5368709120, + wav: 5368709120, + flac: 5368709120, + aac: 5368709120, + m4a: 5368709120, }, }, annexe: { @@ -79,7 +79,7 @@ ], labelFileTypeNotAllowed: "Format non accepté", fileValidateTypeLabelExpectedTypes: "PDF, ZIP, TAR, GZ", - maxFileSize: 1073741824, // 1 GB + maxFileSize: 524288000, // 500 MB labelMaxFileSizeExceeded: "Fichier trop volumineux", labelMaxFileSize: "Taille max: {filesize}", allowMultiple: true, @@ -407,21 +407,25 @@ labelButtonRetryItemLoad: "Réessayer", labelButtonProcessItem: "Charger", - // Per-extension size validation via FileValidateSize plugin hook. - // Falls back to beforeAddFile for silent rejection (the plugin shows the error). + // Per-extension size validation: skip the global maxFileSize check + // for files with per-extension caps — beforeAddFile enforces those. + // fileValidateSizeFilter is a gate: return false to skip the + // built-in maxFileSize check; return true to proceed with it. fileValidateSizeFilter: (item) => { - // item may be a raw File/Blob (.name) or a FilePond item wrapper (.filename) var ext = getExt(item.filename || item.name); + // For files with per-extension caps, skip the global check. + // beforeAddFile enforces the per-extension limit. if (ext && perExtMax[ext]) { - return parseSize(perExtMax[ext]); // per-extension cap for this item + return false; } - return parseSize(cfg.maxFileSize); // queue default + // For files without per-extension caps, use the global maxFileSize. + return true; }, - // Fallback: beforeAddFile enforces per-extension limits (silent rejection). + // beforeAddFile: primary per-extension size enforcement. + // For files with per-extension caps, this is the authority. + // The global maxFileSize handles files without per-ext caps. beforeAddFile: (item) => { - // This check is redundant if fileValidateSizeFilter works, - // but serves as a fallback. if (typeof item.file === "undefined") return true; var f = item.file; var ext = getExt(f.name); diff --git a/app/src/Controllers/ThesisFileHandler.php b/app/src/Controllers/ThesisFileHandler.php index e137af9..7455298 100644 --- a/app/src/Controllers/ThesisFileHandler.php +++ b/app/src/Controllers/ThesisFileHandler.php @@ -44,7 +44,7 @@ trait ThesisFileHandler private const MAX_PDF_SIZE = 100 * 1024 * 1024; // 100 MB /** Maximum allowed file size for video/audio files (bytes). */ - private const MAX_AV_SIZE = 2 * 1024 * 1024 * 1024; // 2 GB + private const MAX_AV_SIZE = 5 * 1024 * 1024 * 1024; // 5 GB /** Cover image max size. */ private const MAX_COVER_SIZE = 20 * 1024 * 1024; // 20 MB diff --git a/app/src/Controllers/validate-file-fragment-shared.php b/app/src/Controllers/validate-file-fragment-shared.php index 7004a63..80eb6bf 100644 --- a/app/src/Controllers/validate-file-fragment-shared.php +++ b/app/src/Controllers/validate-file-fragment-shared.php @@ -105,10 +105,10 @@ $constraints = match ($fieldName) { 'mp3', 'ogg', 'oga', 'wav', 'flac', 'aac', 'm4a', 'vtt', 'zip', 'tar', 'gz', 'tgz', ], - 'maxSize' => 500 * 1024 * 1024, // 500 MB + 'maxSize' => 500 * 1024 * 1024, // 500 MB (default, overridden per-type below) 'label' => 'Fichier TFE', 'allowedDesc' => 'PDF, images, vidéos, audio, archives', - 'maxSizeDesc' => '500 MB', + 'maxSizeDesc' => '500 MB (5 GB pour vidéos/audio, 100 MB pour PDF)', ], 'annexes' => [ 'mimes' => [ @@ -182,6 +182,14 @@ foreach ($allFiles as $idx => $f) { continue; } + // Per-type size override: video/audio up to 8 GB + $isAv = preg_match('/^(video|audio)\//', $mimeType) + || in_array($ext, ['mp4','webm','ogv','mov','mp3','ogg','oga','wav','flac','aac','m4a']); + if ($isAv && $effMaxSize < 5 * 1024 * 1024 * 1024) { + $effMaxSize = 5 * 1024 * 1024 * 1024; + $effMaxDesc = '5 GB'; + } + if ($size > $effMaxSize) { $mb = round($size / 1024 / 1024, 1); $errors[] = '✕ ' . htmlspecialchars($f['name']) . ' : fichier trop volumineux (' diff --git a/app/src/FilepondHandler.php b/app/src/FilepondHandler.php index 40007dd..86ede63 100644 --- a/app/src/FilepondHandler.php +++ b/app/src/FilepondHandler.php @@ -54,17 +54,17 @@ class FilepondHandler public const QUEUE_SIZE_LIMITS = [ 'cover' => 20 * 1024 * 1024, // 20 MB 'note_intention' => 100 * 1024 * 1024, // 100 MB - 'tfe' => 1024 * 1024 * 1024, // 1 GB (default for non-AV, non-PDF) - 'video' => 8 * 1024 * 1024 * 1024, // 8 GB - 'audio' => 8 * 1024 * 1024 * 1024, // 8 GB - 'annexe' => 1024 * 1024 * 1024, // 1 GB - 'peertube_video' => 8 * 1024 * 1024 * 1024, // 8 GB - 'peertube_audio' => 8 * 1024 * 1024 * 1024, // 8 GB + 'tfe' => 500 * 1024 * 1024, // 500 MB (default for non-AV, non-PDF) + 'video' => 5 * 1024 * 1024 * 1024, // 5 GB + 'audio' => 5 * 1024 * 1024 * 1024, // 5 GB + 'annexe' => 500 * 1024 * 1024, // 500 MB + 'peertube_video' => 5 * 1024 * 1024 * 1024, // 5 GB + 'peertube_audio' => 5 * 1024 * 1024 * 1024, // 5 GB ]; public const AV_EXTENSIONS = ['mp4', 'webm', 'ogv', 'mov', 'mp3', 'ogg', 'oga', 'wav', 'flac', 'aac', 'm4a']; public const MAX_PDF_SIZE = 100 * 1024 * 1024; // 100 MB - public const MAX_AV_SIZE = 8 * 1024 * 1024 * 1024; // 8 GB + public const MAX_AV_SIZE = 5 * 1024 * 1024 * 1024; // 5 GB // ── Log prefix for distinguishing admin vs partage ─────────────────────── diff --git a/app/templates/partials/form/fichiers-fragment.php b/app/templates/partials/form/fichiers-fragment.php index 934f3f3..aff285e 100644 --- a/app/templates/partials/form/fichiers-fragment.php +++ b/app/templates/partials/form/fichiers-fragment.php @@ -150,7 +150,7 @@ $websiteLabel = htmlspecialchars($_POST['website_label'] ?? ''); Glissez pour réordonner.

- PDF (max 100 MB) · Images (max 1 GB) · Vidéo & Audio (max 8 GB) · VTT · Archives (max 1 GB). + PDF (max 100 MB) · Images (max 500 MB) · Vidéo & Audio (max 5 GB) · VTT · Archives (max 500 MB).
→ PDFs trop lourds ? https://bentopdf.com/

Vidéos et audio hébergés sur PeerTube. @@ -202,7 +202,7 @@ $websiteLabel = htmlspecialchars($_POST['website_label'] ?? ''); data-queue-type="annexe" data-existing-files='' aria-describedby="annexe-files-hint"> - PDF ou archives ZIP/TAR. Max 1 GB. Glissez pour réordonner. + PDF ou archives ZIP/TAR. Max 500 MB. Glissez pour réordonner.