mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
Fix FilePond: maxFileSize as bytes + temp files survive page reload
1. maxFileSize bug: FileValidateSize plugin overrides core's maxFileSize
setter. Core uses toBytes('1GB') = 1073741824, but plugin registers
maxFileSize as [null, Type.INT] which calls toInt('1GB') = 1.
Fix: all maxFileSize and perExtensionMaxSize values as raw bytes.
Also fix option name: fileValidateSizeFilterItem → fileValidateSizeFilter.
2. Temp file persistence: files uploaded via FilePond went to
tmp/filepond/ and vanished from the UI on page reload because
data-existing-files only included DB-persisted files.
Fix: session-track temp file_ids in handleProcess, inject via
getSessionTempFiles() into data-existing-files, teach handleLoad
to stream temp files from disk, and route JS remove → revert for hex IDs.
This commit is contained in:
@@ -45,6 +45,14 @@ if ($thesisId) {
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// Include session temp files so uploads survive page reload
|
||||
require_once APP_ROOT . '/src/FilepondHandler.php';
|
||||
$tempFiles = FilepondHandler::getSessionTempFiles($queueType);
|
||||
foreach ($tempFiles as $tf) {
|
||||
$result[] = $tf;
|
||||
}
|
||||
|
||||
return $result;
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* The server returns a file_id stored as item.serverId.
|
||||
* 4. Form submit sends only file_ids (tiny payload), not the files themselves.
|
||||
* 5. Type + size validation: via native FilePond options + FileValidateType/Size plugins
|
||||
* plus fileValidateSizeFilterItem for per-extension size caps.
|
||||
* plus fileValidateSizeFilter for per-extension size caps.
|
||||
* 6. Order serialization: hidden inputs track file order using serverId (not filename).
|
||||
* 7. HTMX cleanup: generic destroyFilePondsIn(target) for all swaps, not just known IDs.
|
||||
* 8. Edit mode: loads existing files via data-existing-files JSON + server.load.
|
||||
@@ -47,24 +47,27 @@
|
||||
labelFileTypeNotAllowed: "Format non accepté",
|
||||
fileValidateTypeLabelExpectedTypes:
|
||||
"PDF, Images, Vidéos, Audio, VTT, Archives",
|
||||
maxFileSize: "1GB",
|
||||
maxFileSize: 1073741824, // 1 GB
|
||||
labelMaxFileSizeExceeded: "Fichier trop volumineux",
|
||||
labelMaxFileSize: "Taille max: {filesize}",
|
||||
allowMultiple: true,
|
||||
// Per-extension size limits: certain types get higher caps.
|
||||
// Values in bytes; FileValidateSize plugin reads maxFileSize as INT,
|
||||
// so numeric literals are required (string suffixes like "1GB" become
|
||||
// parseInt("1GB") = 1 byte inside the plugin).
|
||||
perExtensionMaxSize: {
|
||||
pdf: "100MB",
|
||||
mp4: "8GB",
|
||||
webm: "8GB",
|
||||
ogv: "8GB",
|
||||
mov: "8GB",
|
||||
mp3: "8GB",
|
||||
ogg: "8GB",
|
||||
oga: "8GB",
|
||||
wav: "8GB",
|
||||
flac: "8GB",
|
||||
aac: "8GB",
|
||||
m4a: "8GB",
|
||||
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,
|
||||
},
|
||||
},
|
||||
annexe: {
|
||||
@@ -76,7 +79,7 @@
|
||||
],
|
||||
labelFileTypeNotAllowed: "Format non accepté",
|
||||
fileValidateTypeLabelExpectedTypes: "PDF, ZIP, TAR, GZ",
|
||||
maxFileSize: "1GB",
|
||||
maxFileSize: 1073741824, // 1 GB
|
||||
labelMaxFileSizeExceeded: "Fichier trop volumineux",
|
||||
labelMaxFileSize: "Taille max: {filesize}",
|
||||
allowMultiple: true,
|
||||
@@ -85,7 +88,7 @@
|
||||
acceptedFileTypes: ["image/jpeg", "image/png", "image/webp"],
|
||||
labelFileTypeNotAllowed: "Seulement JPG, PNG ou WEBP",
|
||||
fileValidateTypeLabelExpectedTypes: "JPG, PNG, WEBP",
|
||||
maxFileSize: "20MB",
|
||||
maxFileSize: 20971520, // 20 MB
|
||||
labelMaxFileSizeExceeded: "Fichier trop volumineux",
|
||||
labelMaxFileSize: "Taille max: {filesize}",
|
||||
allowMultiple: false,
|
||||
@@ -94,7 +97,7 @@
|
||||
acceptedFileTypes: ["application/pdf"],
|
||||
labelFileTypeNotAllowed: "Seulement PDF",
|
||||
fileValidateTypeLabelExpectedTypes: "PDF",
|
||||
maxFileSize: "100MB",
|
||||
maxFileSize: 104857600, // 100 MB
|
||||
labelMaxFileSizeExceeded: "Fichier trop volumineux",
|
||||
labelMaxFileSize: "Taille max: {filesize}",
|
||||
allowMultiple: false,
|
||||
@@ -103,7 +106,7 @@
|
||||
acceptedFileTypes: ["text/csv"],
|
||||
labelFileTypeNotAllowed: "Seulement CSV",
|
||||
fileValidateTypeLabelExpectedTypes: "CSV",
|
||||
maxFileSize: "50MB",
|
||||
maxFileSize: 52428800, // 50 MB
|
||||
labelMaxFileSizeExceeded: "Fichier trop volumineux",
|
||||
labelMaxFileSize: "Taille max: {filesize}",
|
||||
allowMultiple: false,
|
||||
@@ -119,6 +122,8 @@
|
||||
* Parse a size string like "500MB" or "2GB" to bytes.
|
||||
*/
|
||||
function parseSize(str) {
|
||||
// Already a number (bytes) — pass through
|
||||
if (typeof str === 'number') return str;
|
||||
var m = str.match(/^(\d+(?:\.\d+)?)\s*(B|KB|MB|GB|TB)$/i);
|
||||
if (!m) return 0;
|
||||
var val = parseFloat(m[1]);
|
||||
@@ -277,7 +282,25 @@
|
||||
// FilePond appends the source value (db_id) automatically
|
||||
|
||||
remove: (source, load, error) => {
|
||||
console.log(`[filepond] remove called | db_id=${source}`);
|
||||
console.log(`[filepond] remove called | id=${source}`);
|
||||
// Hex IDs (32 chars) → temp files → use revert endpoint
|
||||
if (/^[a-f0-9]{32}$/.test(source)) {
|
||||
fetch(`${base}/revert.php`, {
|
||||
method: "DELETE",
|
||||
headers: { "X-CSRF-Token": csrfToken },
|
||||
body: source,
|
||||
})
|
||||
.then((r) => {
|
||||
console.log("[filepond] revert (from remove) response | ok=" + r.ok + " | status=" + r.status);
|
||||
r.ok ? load() : error("Erreur suppression");
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("[filepond] revert (from remove) fetch error", e);
|
||||
error("Erreur réseau");
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Numeric IDs → DB files → use remove endpoint
|
||||
fetch(`${base}/remove.php`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
@@ -341,10 +364,9 @@
|
||||
labelButtonRetryItemLoad: "Réessayer",
|
||||
labelButtonProcessItem: "Charger",
|
||||
|
||||
// ── Per-extension size validation ──────────────────────────────
|
||||
// Uses fileValidateSizeFilterItem if the FileValidateSize plugin supports it.
|
||||
// Per-extension size validation via FileValidateSize plugin hook.
|
||||
// Falls back to beforeAddFile for silent rejection (the plugin shows the error).
|
||||
fileValidateSizeFilterItem: (item) => {
|
||||
fileValidateSizeFilter: (item) => {
|
||||
var ext = getExt(item.filename);
|
||||
if (ext && perExtMax[ext]) {
|
||||
return parseSize(perExtMax[ext]); // per-extension cap for this item
|
||||
@@ -352,10 +374,9 @@
|
||||
return parseSize(cfg.maxFileSize); // queue default
|
||||
},
|
||||
|
||||
// Fallback: if fileValidateSizeFilterItem is not available,
|
||||
// beforeAddFile enforces per-extension limits (silent rejection).
|
||||
// Fallback: beforeAddFile enforces per-extension limits (silent rejection).
|
||||
beforeAddFile: (item) => {
|
||||
// This check is redundant if fileValidateSizeFilterItem works,
|
||||
// This check is redundant if fileValidateSizeFilter works,
|
||||
// but serves as a fallback.
|
||||
if (typeof item.file === "undefined") return true;
|
||||
var f = item.file;
|
||||
|
||||
Reference in New Issue
Block a user