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='= htmlspecialchars(json_encode($existingFilesJsonForAnnexe ?? []), ENT_QUOTES) ?>'
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.
- Types acceptés : PDF · JPG/PNG/GIF/WEBP · MP4/WebM/MOV (vidéo) · MP3/OGG/WAV/FLAC (audio) · ZIP/TAR (archives). Max 1 GB par fichier.
+ Types acceptés : PDF (max 100 MB) · JPG/PNG/GIF/WEBP (max 500 MB) · MP4/WebM/MOV (vidéo, max 5 GB) · MP3/OGG/WAV/FLAC (audio, max 5 GB) · ZIP/TAR (archives, max 500 MB).
Les fichiers .vtt sont des sous-titres et seront associés automatiquement à la vidéo précédente.