Commit Graph

19 Commits

Author SHA1 Message Date
Pontoporeia
79eddf5d5a feat: fix file deletion on save + trash policy + documents/ prefix + relink browser
1. note_intention: Delete old file only when a genuinely new upload arrives
   (32-char hex file_id), not when the FilePond pool preserves an existing
   file by sending its DB integer ID.  Previously the DB integer ID
   triggered $hasNewNote=true, which deleted the existing note_intention
   from disk+DB, then handleFilePondSingleFile couldn't re-process it
   because the regex requires a hex pattern.  Same fix applied to cover.

2. All file deletions now use deleteThesisFileToTrash() which renames
   files to tmp/_trash/ instead of unlinking.  The trash preserves
   original filenames prefixed with DB id for traceability.  Skips
   website URLs and PeerTube refs (no disk file).

3. Storage prefix changed from theses/ to documents/ to reflect that
   the folder holds all document types (determined by file_type in DB).
   MediaController visibility gate supports both prefixes for backward
   compat with existing files.

4. File browser + relink feature for orphaned files:
   - /admin/fragments/file-browser.php — HTMX tree browser for
     storage/documents/ and storage/theses/
   - /admin/actions/filepond/relink.php — POST endpoint that inserts
     a thesis_files row pointing to existing on-disk file
   - Per-pool "📂 Relier" buttons (edit mode only)
   - JS: XamxamOpenFileBrowser / XamxamRelinkFile with FilePond integration
   - CSS: .relink-modal dialog + .file-browser tree styles
2026-05-19 00:08:06 +02:00
Pontoporeia
8bb0b3a1f2 refactor: unify FilePond edit previews + clean upload UI and shared fragments
* Move shared `fichiers-fragment.php` from `partage/` to `templates/partials/form/`
  and update all include/require references
* `.gitignore`: exclude SQLite WAL/SHM journal files
* FilePond UI:

  * change uploaded file block border state from yellow to green
  * restyle image previews to use site light-theme colors
* Edit mode:

  * remove custom existing-file preview list implementation
  * preload existing files directly into FilePond pools
  * include `cover` and `note_intention` assets in FilePond-managed state
* Remove obsolete upload progress bar UI and related JS includes
* Remove deprecated `Écriture` + `Image` format types from upload flow/configuration
2026-05-19 00:08:06 +02:00
Pontoporeia
b56d073210 refactor: extract inline JS into app/ modules, remove dead overtype-webcomponent
- Remove overtype-webcomponent.min.js (zero references)
- Extract copyLogContent + fallbackCopy + HTMX tab-updater → app/admin-logs.js
  (removes duplicate from both system.php and parametres.php)
- Extract copyUrl → app/clipboard.js (shared by acces.php)
- Extract tag/language pill-search logic → app/pill-search.js
  Generalized with data-pill-search attributes, auto-inits via
  DOMContentLoaded + htmx:afterSwap
- Extract access-request form handler → app/access-request.js
  (was inline in templates/public/tfe.php)

Files created: admin-logs.js, clipboard.js, pill-search.js, access-request.js
Files modified: 9 templates/controllers to drop inline scripts and
  reference external JS files
2026-05-19 00:08:06 +02:00
Pontoporeia
cdec3e96a6 fix PeerTube upload: final working solution — simple multipart POST with CURLFile; iterated through Google-resumable PATCH protocol debugging (HTTP version negotiation, chunk body encoding, off-by-one fixes) before settling on simpler POST approach 2026-05-19 00:08:06 +02:00
Pontoporeia
8db7b6e9eb feat: FilePond production hardening — extension-based validation, server-side size limits (2GB), annexe validation, drop accept attributes, FilePond file styling 2026-05-19 00:08:05 +02:00
Pontoporeia
1aff5ff46d Replace custom file-upload-queue.js with FilePond
- Delete file-upload-queue.js (495 lines of custom queue logic)
- Delete sortable.min.js dependency
- Add file-upload-filepond.js: thin wrapper that upgrades .tfe-file-picker
  inputs to FilePond instances with storeAsFile:true for native multipart
  form submission (no form-submit interception needed)
- Update fichiers-fragment.php: replace queue container <ul> elements
  and empty-state <p> with bare <input> elements that FilePond upgrades;
  change name attributes to queue_file[tfe][] etc. for PHP compatibility
- Update add.php, edit.php, partage/index.php: swap JS/CSS refs
- Clean up form.css: remove .fq-* and .tfe-file-queue custom styles,
  add FilePond theme overrides matching xamxam design tokens
- Update dead-code fieldset-files.php for consistency

Server-side stays unchanged: PHP receives ['queue_file']['tfe'][]
exactly as before through native multipart submission.
2026-05-19 00:08:05 +02:00
Pontoporeia
13d26ded66 Replace HTMX+PHP file upload queues with client-side JS
Drops the session-backed HTMX incremental upload system in favour of a
single JS module that manages `File` objects client-side and injects
them into `FormData` on submit.

Key changes:

* `file-upload-queue.js`: client-side queues with validation, reorder
  (SortableJS), removal, dirty-state tracking, and fetch-based submit
  with manual redirect handling
* `fichiers-fragment.php`: empty queue containers for JS-managed queues;
  HTMX format switching still works with queue rehydration after swap;
  annexe uploads now support multiple files
* Form UI cleanup: moved existing files and cover preview into the
  `Fichiers` fieldset (edit mode); removed redundant queue labels while
  keeping labels for single-file inputs (`couverture`,
  `note d'intention`); added delete buttons for existing files
* `ThesisFileHandler.php`: added
  `handleTfeQueueFiles()`/`handleAnnexeQueueFiles()` reading from
  `$_FILES['queue_file']`; introduced `extractFilesSubArray()` for
  nested upload arrays; removed session-based queue handling
* `ThesisCreateController.php` &
  `ThesisEditController.php`: switched to extracted
  `['queue_file']` uploads
* `beforeunload-guard.js`: now also watches
  `window.__xamxamDirty`
* Deleted obsolete PHP upload/remove/reorder queue endpoints for
  `partage` and `admin`
* Cleaned up route dispatch in `partage/index.php`
* Misc form and styling updates in templates/CSS
* Added `docs/cms-migration-plan.html`
2026-05-19 00:08:05 +02:00
Pontoporeia
ca7707cd47 refactor: session-based incremental TFE upload via HTMX, drop SortableJS
Replace the client-side FileArray + Sortable drag-to-reorder with a
server-side session-based upload flow:

- New endpoints: /partage/upload-tfe-file, /partage/remove-tfe-file
  (and /admin/ variants) — single-file incremental upload via HTMX
  multipart/form-data with progress bar support
- Session storage: uploaded files go to STORAGE_ROOT/uploads/{session_id}/
  with metadata in $_SESSION['tfe_uploads']
- file-upload-queue.js reduced to single-file previews only (couverture,
  note_intention, annexes thumbnails)
- ThesisFileHandler gains handleTfeFilesFromSession + writeTfeFileFromSrc
  + cleanupSessionUploads for final commit from session temp
- Sortable.min.js removed from all script tags; drag handles and ghost
  CSS removed
- No file_orders[]/file_labels[] hidden field injection needed
- Upload queue survives page refresh (server-owned list)

This eliminates the SortableJS dependency entirely while keeping the
same UX: pick files, see them in a queue, remove individual files.
2026-05-19 00:08:05 +02:00
Pontoporeia
8a4b2541fb Fix: email clearing in findOrCreateAuthor, htmlspecialchars(null) crash in old(), dead contact_interne field, access_type_id radio clearing
- findOrCreateAuthor: always update email column (pass null when empty/falsy) so clearing an email actually persists
- admin/add.php & admin/edit.php old(): add null guard before htmlspecialchars, cast to string
- jury-fieldset.php: guard against old() returning array for scalar-checked jury_lecteur keys
- formulaire.php: only suppress display_errors in production (not cli-server dev mode)
- Removed dead contact_interne field from backoffice form (no DB column, never saved)
- Removed dead contactInterne validation from ThesisCreateController
- Added "— Non défini" radio option for access_type_id in admin mode for clearing
- Fixed strict int-vs-string comparison breaking radio button checked detection
2026-05-19 00:08:05 +02:00
Pontoporeia
6cc0e407f3 Error tests, FK violations fix
- ErrorHandler tests: 77 assertions covering FK extraction, normalization, dedup, edge cases. Fix FK table map for child tables.
- Fix FK violation: (int)null → 0 in createThesis for orientation/ap/finality/license FK columns. Add FK value logging to updateThesis.
- Add CURRENT_ISSUES.md with summary of FK violation, dev debugging, and tag dedup status for next conversation
2026-05-19 00:08:05 +02:00
Pontoporeia
21c2b55bfb style: normalize headers, overtype editor rounded corners, remove duplicate cover preview, thesis-add-header grid layout, subtitle below header with top gradient 2026-05-19 00:08:05 +02:00
Pontoporeia
bdd95341b0 Extract shared TFE form partial — single source of truth for add/edit/partage
Created templates/partials/form/form.php as the unified form template driven by
$mode ('add'|'edit'|'partage') and boolean flags for optional sections.

The three calling templates (templates/admin/add.php, templates/admin/edit.php,
partage/index.php renderShareLinkForm) now only set variables then include the
shared partial. ~200 lines of duplicated fieldset HTML eliminated.
2026-05-07 23:39:41 +02:00
Pontoporeia
696259afae Fix form field required states & missing fields per spec
- Admin add: add contact_public checkbox (matching edit form)
- All forms: formats checkbox-list now required
- All forms: jury promoteur·ice interne required, lecteur·ice interne/externe required
- All forms: licence select now required
- Admin edit: add E-mail de confirmation fieldset
- Partage: contact always visible when provided (no contact_public field)
- Partage: filter PACS from AP programs dropdown
- Server-side validation: formats, jury, licence required (create + edit controllers)
- Autofocus mappings for new validation errors
- No duplicate asterisks — verified across all rendered fields
- fix: add missing old() function in admin edit controller
- refactor: move admin email field to Backoffice as Contact interne, never send email
- Untrack admin.log (covered by .gitignore)
2026-05-07 23:39:41 +02:00
Pontoporeia
24d68dda59 refactor form structure per new spec + fix
- split jury into interne/externe/ULB,
- remove president from student form,
- add language_autre,
- split duration into pages+minutes+annexes,
- move licence to degrés d'ouverture with CC2r,
- add license_custom,
- filter PACS from student AP list,
- editable généralités help block,
- Libre toggle per settings

Fix:
- missing comma after cc4r column in schema.sql
- remove duplicate form footer from partage template
- remove couverture from student files fieldset; add promoteur ULB conditional disable via JS on Approfondi
- promoteur ULB: remove 'si applicable', make required when visible
2026-05-07 19:43:43 +02:00
Pontoporeia
a83dc1c74e feat: multi-type file upload with sort order, labels, and expanded MIME support
- DB migration 007: add sort_order + display_label to thesis_files
- Database: getThesisFiles ordered by sort_order; insertThesisFile accepts label/order;
  new reorderThesisFiles() and updateThesisFileLabel() methods
- ThesisCreateController + ThesisEditController: expand allowed MIME/exts to include
  audio (mp3/ogg/wav/flac/aac/m4a), video (webm/mov/ogv), image (gif/webp),
  archives (tar/gz), any-ext via octet-stream; max size raised to 500 MB;
  accept file_labels[] and file_orders[] POST fields; detectFileType() helper
- MediaController: expanded MIME allowlist; HTTP Range support for audio/video;
  force-download for unknown types; inline for known displayable types
- fieldset-files.php: sortable queue UI with SortableJS, per-file labels, 500 MB hint
- templates/admin/edit.php: existing files as sortable list with drag handles,
  type icons, label inputs, delete checkboxes, hidden sort-order fields
- file-upload-queue.js: new JS replacing file-preview.js — sortable new-file queue,
  per-file labels, hidden order fields on submit, backward-compat legacy preview
- tfe.php: renders audio (<audio>), all video formats, images, PDF, and
  download-only 'other' files; reads display_label; sorted by sort_order
- tfe.css + form.css: styles for audio player, download files, sortable queue,
  drag handles, file type badges, label inputs
- .htaccess + .user.ini: upload_max_filesize=512M / post_max_size=520M
2026-05-05 11:04:52 +02:00
Pontoporeia
32a7509598 feat: add file display to forms and recap pages
- Live file preview on all file inputs (file-field partial, edit template):
  thumbnails for images, emoji icons for PDF/video/zip/vtt, filename + size
- New file-preview.js wired via $extraJs in add.php / edit.php and direct
  <script> in partage/index.php; $extraJs support added to head.php
- admin/recapitulatif.php: replace plain table with rich file list — image
  thumbnails linked to media.php, type badges, human-readable size, date
- partage/recapitulatif.php: full rewrite — shows thesis metadata + files
  list with same rich display (no media links for student privacy)
- form.css: new sections for .file-preview-list (live preview) and
  .recap-file-list / .recap-dl / .partage-recap (recap pages)
2026-04-27 20:52:27 +02:00
Pontoporeia
95bce2bbad Extract form CSS into form.css; scope system.css to system.php only 2026-04-24 23:03:49 +02:00
Pontoporeia
4839b568de Separate admin views from controllers — move HTML to templates/admin/
All admin pages refactored to thin controllers + pure view templates, mirroring
the public-page pattern:

Controllers (public/admin/*.php): auth, data loading, include template
Views (templates/admin/*.php): pure HTML/PHP output
Fragment partials (templates/admin/partials/): toast, system-log-panel, system-nginx-config-panel

Pages migrated: login, tags, contenus, contenus-edit, account, acces-etudiante,
thanks, add, edit, parametres, system, index

Fragment endpoints refactored: system-fragment.php, toast-fragment.php
Skipped (pure redirects): logout, logs, status, import
2026-04-24 23:03:49 +02:00
Pontoporeia
75f808bee4 feat: extract MediaController, wire into Dispatcher, delete media.php 2026-04-20 12:32:00 +02:00