Files
xamxam/app/templates/head.php
Pontoporeia 2e9ebfc684 filepond: implement async server-ID upload architecture with nested queue support + PeerTube integration
Replace `storeAsFile:true` with a full async FilePond round-trip pipeline using opaque server-side file IDs.

* Added 4 new PHP endpoints under `/admin/actions/filepond/`:

  * `process.php` — upload/process single file and return opaque `file_id`
  * `revert.php` — delete pending tmp uploads before form submit
  * `load.php` — stream existing files by DB ID for FilePond preload
  * `remove.php` — soft-delete `thesis_files` rows
* `process.php` improvements:

  * accept arbitrary FilePond field names instead of hardcoded `file`
  * support PHP-nested multi-file queue inputs (`queue_file[tfe][]`)
  * explicit unwrapping of nested `$_FILES` structures
  * add `audio/mp3` to audio + `peertube_audio` MIME whitelists
  * immediate upload of `peertube_*` files to PeerTube, returning `peertube:{uuid}` IDs
  * extensive `error_log()` instrumentation for request, CSRF, MIME, upload, and save stages
* `revert.php` now accepts `peertube:` IDs without local cleanup
* `ThesisFileHandler`:

  * add `handleFilePondQueueFiles()` + `handleFilePondSingleFile()`
  * process async uploads from `storage/tmp/filepond/` via opaque `file_id`
  * inline handling of `peertube:{uuid}` IDs with direct `thesis_files` insertion
  * remove obsolete deferred PeerTube queue-processing flow
* `ThesisCreateController` + `ThesisEditController`:

  * gate async path behind `filepond_mode=1`
  * preserve legacy multipart flow as fallback
* `file-upload-filepond.js`:

  * remove `storeAsFile:true`
  * add `buildServerConfig()` for async endpoint wiring
  * fix `syncOrderInput()` to use `serverId`
  * add `onprocessfile` hook
  * add `fileValidateSizeFilterItem` for per-extension size caps
  * preload existing uploads via `data-existing-files` + `server.load`
  * replace static `INPUT_ID_TO_TYPE` map with `data-queue-type`
  * add extensive `console.log()` debugging across upload pipeline stages
* `upload-progress.js`:

  * block form submission while uploads are pending
  * update `collectFileNames()` to read processed FilePond items
* Templates/layout:

  * add `data-queue-type`
  * add `data-existing-files`
  * add global CSRF meta tag outside admin-only context
  * add `filepond_mode` hidden input
  * add CSRF token/meta support for partage pages
  * move website URL field below file upload block
* `.gitignore`: exclude `storage/tmp/` from version control
2026-05-19 00:08:06 +02:00

89 lines
4.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<?php
// Admin: append suffix to title and prepend admin.css
if (!empty($isAdmin)) {
$pageTitle = isset($pageTitle) ? $pageTitle . ' Admin' : 'Admin';
$extraCss = array_merge(['/assets/css/admin.css'], $extraCss ?? []);
}
?>
<title><?= htmlspecialchars($pageTitle ?? 'XAMXAM') ?></title>
<?php if (empty($isAdmin)): ?>
<?php if (!empty($metaDescription)): ?>
<meta name="description" content="<?= htmlspecialchars($metaDescription) ?>">
<?php endif; ?>
<?php
// Open Graph / Twitter Card tags — populated per-page via $ogTags array.
// Keys: type, title, description, url, image, image_alt, site_name, article_author, article_published_time
if (!empty($ogTags)):
$ogType = $ogTags['type'] ?? 'website';
$ogTitle = $ogTags['title'] ?? ($pageTitle ?? 'XAMXAM');
$ogDescription = $ogTags['description'] ?? ($metaDescription ?? '');
$ogUrl = $ogTags['url'] ?? '';
$ogImage = $ogTags['image'] ?? '';
$ogImageAlt = $ogTags['image_alt'] ?? $ogTitle;
$ogSiteName = $ogTags['site_name'] ?? 'XAMXAM ERG';
?>
<meta property="og:type" content="<?= htmlspecialchars($ogType) ?>">
<meta property="og:site_name" content="<?= htmlspecialchars($ogSiteName) ?>">
<meta property="og:title" content="<?= htmlspecialchars($ogTitle) ?>">
<?php if (!empty($ogDescription)): ?>
<meta property="og:description" content="<?= htmlspecialchars($ogDescription) ?>">
<?php endif; ?>
<?php if (!empty($ogUrl)): ?>
<meta property="og:url" content="<?= htmlspecialchars($ogUrl) ?>">
<?php endif; ?>
<?php if (!empty($ogImage)): ?>
<meta property="og:image" content="<?= htmlspecialchars($ogImage) ?>">
<meta property="og:image:alt" content="<?= htmlspecialchars($ogImageAlt) ?>">
<?php endif; ?>
<?php if (!empty($ogTags['article_author'])): ?>
<meta property="article:author" content="<?= htmlspecialchars($ogTags['article_author']) ?>">
<?php endif; ?>
<?php if (!empty($ogTags['article_published_time'])): ?>
<meta property="article:published_time" content="<?= htmlspecialchars($ogTags['article_published_time']) ?>">
<?php endif; ?>
<meta name="twitter:card" content="<?= !empty($ogImage) ? 'summary_large_image' : 'summary' ?>">
<meta name="twitter:title" content="<?= htmlspecialchars($ogTitle) ?>">
<?php if (!empty($ogDescription)): ?>
<meta name="twitter:description" content="<?= htmlspecialchars($ogDescription) ?>">
<?php endif; ?>
<?php if (!empty($ogImage)): ?>
<meta name="twitter:image" content="<?= htmlspecialchars($ogImage) ?>">
<meta name="twitter:image:alt" content="<?= htmlspecialchars($ogImageAlt) ?>">
<?php endif; ?>
<?php endif; ?>
<?php endif; ?>
<link rel="apple-touch-icon" sizes="152x152" href="/assets/favicon/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="167x167" href="/assets/favicon/apple-touch-icon-167x167.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicon/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon/favicon-16x16.png">
<link rel="shortcut icon" href="/assets/favicon/favicon.ico">
<meta name="theme-color" content="#ffffff">
<?php if (!empty($_SESSION['csrf_token'])): ?>
<meta name="csrf-token" content="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
<?php endif; ?>
<link rel="stylesheet" href="<?= App::assetV('/assets/css/modern-normalize.min.css') ?>">
<link rel="stylesheet" href="<?= App::assetV('/assets/css/common.css') ?>">
<?php foreach ($extraCss ?? [] as $css): ?>
<link rel="stylesheet" href="<?= App::assetV($css) ?>">
<?php endforeach; ?>
<?php foreach ($extraJs ?? [] as $js): ?>
<script src="<?= App::assetV($js) ?>" defer></script>
<?php endforeach; ?>
<?php if (php_sapi_name() === 'cli-server'): ?>
<script>
(function poll(){
fetch('/live-reload').then(r=>r.json()).then(d=>{
if(d.changed) location.reload(); else setTimeout(poll,1000);
}).catch(()=>setTimeout(poll,2000));
})();
</script>
<?php endif; ?>
</head>
<body class="<?= htmlspecialchars($bodyClass ?? '') ?>">