Commit Graph

114 Commits

Author SHA1 Message Date
Pontoporeia
07370b7221 search: ajout filtres finalité et format, boutons plus compacts et Réinitialiser en neutre 2026-06-10 00:17:00 +02:00
Pontoporeia
3d524226a1 formulaire: correctifs identifiant/année, contact, fichiers optionnels
- Identifiant: mise à jour automatique quand l'année change en back-office (updateThesis + ThesisEditController)
- Contact: hint enrichi (1 seul contact, formatage Instagram/Mastodon)
- Fichiers: TFE rendu optionnel pour Site web/Performance/Installation (note d'intention reste obligatoire)
2026-06-10 00:17:00 +02:00
Pontoporeia
c4664ec2e9 fix: prevent mid-word break in repertoire column headers
Base.css applies word-break: break-word to all elements inside <main>,
causing mid-word breaks in narrow columns. Override in repertoire.css:
- hyphens: none, word-break: normal, overflow-wrap: normal on all h2
- redistribute grid fractions: shrink Orientations (1.2→0.9fr), 
  Étudiantes (1→0.8fr), boost Finalité (0.7→0.9fr, min 7rem)
2026-06-10 00:16:49 +02:00
Pontoporeia
312d9eab0e À propos: contacts flexibles, liens sidebar éditables, grille contacts admin, et bouton supprimer
- Contacts: on peut laisser vide le nom OU le rôle (plus besoin des deux)
- Sidebar: les liens « site de l'erg » et « code source » sont éditables depuis /admin/contenus-edit.php?slug=about
- Admin: les champs Nom/Email/Lien des contacts s'affichent en grille 3 colonnes
- Admin: icône corbeille (admin-icon-btn--delete) pour supprimer un contact, avec réindexation automatique
- Database::getAproposContent() gère maintenant les valeurs string (URLs) en plus des arrays
- Database::saveAproposContent() accepte array|string
2026-06-10 00:16:22 +02:00
Pontoporeia
a1a9a316ca rework tfe.php layout: row1 author above title, row2 meta+synopsis 2-col grid, row3 flex files 2026-06-10 00:16:10 +02:00
Pontoporeia
e0d706c677 tfe.css: tfe-meta-item font-weight 400→700 2026-06-10 00:15:41 +02:00
Pontoporeia
c9fa5943cf repertoire: rep-entry + col h2 step-0, years col step-3 2026-06-10 00:15:41 +02:00
Pontoporeia
ef6bff895a admin nav-logo: grid layout for icon+text horizontal alignment and vertical centering 2026-06-10 00:15:41 +02:00
Pontoporeia
9e272873e1 style: set tfe-meta-item default to font-weight 400 so Accès/Licence values render at regular weight 2026-06-10 00:15:41 +02:00
Pontoporeia
3588f22d7b style: consolidate aria-current nav styles — remove border-radius from base header links, keep global :focus-visible ring, move border-bottom/padding to shared header.css 2026-06-10 00:15:41 +02:00
Pontoporeia
cb2b18e470 style: standardise links to Regular weight (400) with violet accent hover, body to Light (300) 2026-06-10 00:15:41 +02:00
Pontoporeia
3f200dae70 TFE page: replace dl/dt/dd with p/span for metadata, remove underlines, lowercase keywords/languages/formats, inclusive text, editable restriction messages 2026-06-10 00:15:41 +02:00
Pontoporeia
71949425c7 TFE page: remove underlines from all links, lowercase keywords/languages/formats, inclusive writing, prevent keyword mid-word breaks, editable restriction messages in admin 2026-06-10 00:15:41 +02:00
Pontoporeia
9a8f0cad65 fix(répertoire): colonnes différenciées, scrollbars discrètes, fontes conformes maquette, AP entre crochets
- grid-template-columns: années=0.4fr, orientations=1.2fr, AP/finalité/intermédiaires
- scrollbars: WebKit 5px transparent + Firefox scrollbar-width:thin global
- rep-entry: BBBDMSans Regular 398, --step--1
- années: BBBDMSans Medium 498 (semi-bold)
- titres colonnes: Ductus Regular 398, text-secondary, letter-spacing 0.12em
- AP: diminutifs entre crochets (ex: Design et Politique du Multiple [DPM])
- TODO: marquer les 4 correctifs répertoire comme faits
2026-06-10 00:15:33 +02:00
Pontoporeia
df70fba5d4 feat: convert all file inputs to FilePond for standardized uploading
- Add csv_import queue type (storeAsFile, no async upload) for CSV import dialog
- Convert file-field.php partial to FilePond with field-name→queue-type mapping
- Conditionally skip server config for storeAsFile queues in buildFilePondOptions
- Skip FilePond init for inputs inside closed <dialog> elements
- Trigger FilePond init when import dialog opens
- Load FilePond CSS/JS assets on admin index page
2026-06-09 13:12:22 +02:00
Pontoporeia
2bb520bb8c Fix: anchor vendor/ gitignore to root so app/public/assets/js/vendor/ is tracked (htmx, OverType, FilePond) 2026-06-08 10:12:39 +02:00
Pontoporeia
ae66c2baad Integrate Monolog: replace four logging systems with single PSR-3 factory
- Add monolog/monolog dependency (^3.10)  
- Create app/Logger.php central factory with channels: app, admin, error, audit
- Each channel gets RotatingFileHandler (30-day retention) with pass-through LineFormatter
  preserving existing JSON format contracts
- Rewrite AppLogger as thin facade delegating to Logger::get('app')
- Rewrite ErrorHandler::log() to delegate to Logger::get('error')
- Rewrite AdminLogger file output to delegate to Logger::get('admin'), keep DB writes
- Add Monolog file shadow to Audit via Logger::get('audit') (Option A per monolog-plan)
- Log level controlled by LOG_LEVEL env var (defaults: DEBUG in cli-server, WARNING otherwise)
- Graceful NullHandler fallback when log directory is not writable
- Update SystemController LOG_FILES: remove php_error, add app/admin/error/audit
- JSON app logs parsed to readable one-liners in the log viewer
- Remove nginx config tab (parametres + fragment + template + css)
- Friendly empty-state message when app log files don't exist yet (notYet)
- PHP tail fallback when exec() unavailable
- All 228 PHPUnit tests pass, no call sites changed
2026-05-20 12:28:31 +02:00
Pontoporeia
2e75a3b35c Fix beforeunload dialog appearing on edit.php when no changes made 2026-05-19 23:59:07 +02:00
Pontoporeia
42222abe7c Récapitulatif admin: sections → fieldsets, fichiers en table, marges + pas de thumbnails 2026-05-19 23:58:51 +02:00
Pontoporeia
c6199525f9 add sticky thead to index, langues, and mots-clés tables 2026-05-19 23:58:51 +02:00
Pontoporeia
678f9fc804 Index page: remove Mots-clés button, move export to bulk selection, fix ZipArchive error, move DB export to paramètres, sticky thead
- Remove 'Mots-clés' button from toolbar (redundant with admin sidebar tags)
- Replace export dialog with 'Exporter CSV' + 'Exporter fichiers' buttons in bulk selection bar
- Export dispatcher now accepts ?ids=1,2,3 for per-selection export
- All ExportController/Database methods accept optional thesisIds array
- Graceful error message when ZipArchive extension is missing on server
- Move DB export (SQLite download) to paramètres → Maintenance section
- Sticky table column headers (position: sticky, top: 0, z-index: 5) for index page table
2026-05-19 23:58:51 +02:00
Pontoporeia
b484943128 Unnest header.css (native CSS nesting silently broken in browsers without support) 2026-05-19 23:58:51 +02:00
Pontoporeia
2cb8d71fe9 Fix dialog margins, add admin-dialog__body/styles, give trash page horizontal margins 2026-05-19 23:58:51 +02:00
Pontoporeia
7cf020c7bd Refactor CSS architecture per css-methodology-spec.md
Split CSS into named layers: reset → colors → typography → base →
components → utilities. Each component has one unique root class in
its own file. No cross-component overrides.

New files:
- reset.css (modern-normalize base — matches project's prior reset)
- colors.css (all colour variables)
- typography.css (font faces, size/space scale, font-family vars)
- base.css (≤ 5 site-wide rules: layout, headings)
- utilities.css (sr-only, skip-link, reduced-motion)
- style.css (root @import file loading all layers)
- components/{links,focus,forms,tables,dialog,details,media,
  buttons,badges,toasts,pagination,header,search}.css

Existing files:
- variables.css → backward-compat wrapper (imports colors + typography)
- common.css → backward-compat wrapper (imports style.css)
- Page files (admin, public, form, tfe, apropos, repertoire, system,
  file-access) → removed redundant @import url(./variables.css)
- head.php → loads style.css instead of modern-normalize + common.css
- partage pages → load style.css

Fixes vs initial refactoring:
- reset.css: use modern-normalize base (not Tailwind Preflight) to
  avoid border/list/heading regressions from aggressive defaults
- components/search.css: restore !important flags on input styles
  (needed to override forms.css base input selectors)
- acces.php: add toast feedback on password copy button

Cleaned up duplicate status-badge/toast definitions from admin.css
(now live in components/badges.css and components/toast.css).
2026-05-19 16:55:32 +02:00
Pontoporeia
7c30d1c55d Fix relink: close modal + HTMX refresh for immediate pool update
- After relink, always close the modal (even if FilePond input not found,
  e.g. page refreshed by live-reload during the fetch).
- After closing, re-fetch #format-fichiers-block via HTMX from
  /admin/fragments/fichiers.php?_thesis_id=N which loads thesis files
  from DB and re-renders the fragment with pre-populated FilePond pools.
  The afterSwap handler auto-reinitializes FilePond instances.
- Updated admin/fragments/fichiers.php to accept _thesis_id, load
  existing files from DB, build per-queue-type JSON, and render in
  edit mode.
2026-05-19 01:32:34 +02:00
Pontoporeia
b77bc486e5 Fix relink: FilePond addFile API, yellow border, limbo type + await
- Fix addFile argument format: FilePond.addFile() takes (source, options)
  as two separate arguments, not a single {source, options} object.
- Change .filepond--file default border from accent-yellow to accent-green.
  Existing files loaded in edit mode have type 'local' and never reach
  processing-complete state, so they got the yellow border.
- Change relinked file add from type 'local' to 'limbo'. Limbo items
  go through DID_COMPLETE_ITEM_PROCESSING which triggers onprocessfile
  (ensures syncOrderInput runs with serverId available) and renders
  the green checkmark visual.
- Await addFile Promise and close modal in .then() instead of
  immediately, ensuring the item is created before cleanup.
- Remove duplicate modal.close() after the addFile block.
2026-05-19 01:13:17 +02:00
Pontoporeia
27e6abc7e4 feat: file browser + relink for orphaned files + htmx fix + header cleanup + fix relinked FilePond integration + resolve acces.php conflict markers 2026-05-19 00:08:06 +02:00
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
6f7a02244f maintenance: allow /partage through gate, fix fragment routing, add visibility table in admin
Extract shared filepond logic into src/FilepondHandler.php class.
Admin filepond endpoints delegate to the handler after AdminAuth check.
New partage filepond endpoints at /partage/actions/filepond/ verify
share_active session flag + CSRF token, no admin auth required.

JS reads filepond-base meta tag to determine endpoint path:
- Admin pages: /admin/actions/filepond (via head.php isAdmin check)
- Partage form: /partage/actions/filepond (explicit meta)

partage/index.php sets share_active = true on form render, cleans up on
successful submit. Partage process endpoint rate-limited to 30/5min per
session. No nginx changes needed — /partage/ location already handles
PHP without auth_basic.
2026-05-19 00:08:06 +02:00
Pontoporeia
9152b120e8 feat: mandatory auto-generated passwords for share links + admin password copy/regeneration + password gate rate limiting 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
6e7c0c00e3 refactor: merge video/audio FilePond pools into TFE input
- Remove separate video/audio/peertube_video/peertube_audio pools from UI
- TFE pool now accepts all file types including video/audio
- When PeerTube is enabled, video/audio dropped into TFE pool auto-upload
  to PeerTube (process.php detects MIME and uploads immediately)
- PeerTube return IDs now encode type: peertube:video:UUID or peertube:audio:UUID
- load.php returns placeholder SVG for PeerTube files so they appear in FilePond
- Edit mode: all existing files (including PeerTube) shown in TFE FilePond pool
- Remove legacy  video/audio/peertube_* handling from both controllers
- Remove unused vide/audio/peertube_* entries from JS QUEUE_CONFIG
2026-05-19 00:08:06 +02:00
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
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
c3f6e8a033 fix: upload progress bar not visible — collectFileNames checks FilePond instances; remove admin auth from progress poll endpoint 2026-05-19 00:08:06 +02:00
Pontoporeia
206a6427e7 style: unify recap+edit file figure styling — two-column grid dl, vertical spacing, admin-back-btn sizing, standardise file display and delete-to-trash SVG icons 2026-05-19 00:08:06 +02:00
Pontoporeia
230555a4c4 exhaustive recap: all fields, figures for files, PeerTube ID display, same in edit form 2026-05-19 00:08:06 +02:00
Pontoporeia
8bf95f4e14 feat: refactor licence fragment — Libre→CC2r+licence, Interne→opt-in want_license, Interdit→none, add details/summary to license UI 2026-05-19 00:08:06 +02:00
Pontoporeia
927ee2fe2a feat: upload progress bar — fieldset layout, accent colors, file name display, completion animation, 800ms redirect delay; decorelate formats from fichiers; server-side poll via token; bump PeerTube embed audio player 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
83a5a508ea feat: PeerTube integration — alternate audio/video labels, FilePond pools, shared SMTP credentials, channel by name, test button, resumable upload, embed improvements, fix alt labels/curl_close/deprecation 2026-05-19 00:08:06 +02:00
Pontoporeia
be50ac5eb0 fix(production): fix multiple remote server errors from nginx logs
- Fix 413 Request Entity Too Large: bump client_max_body_size to 256M,
  PHP post_max_size/upload_max_filesize to 256M, fastcgi timeouts to 300s
- Fix missing v_smtp_active view: add IF NOT EXISTS to all CREATE VIEW
  statements in schema.sql for idempotent migrates
- Fix bars.svg 404: create animated SVG spinner in app/public/assets/img/
- Fix nginx rate limiting: increase admin zone from 60r/m (1 r/s) to
  300r/m (5 r/s) with burst=30 to handle ~11 concurrent HTMX fragment
  GETs on contenus.php page load
- Add deploy-nginx recipe to justfile for uploading nginx config to server
- Database readonly issue mitigated by existing --chown + deploy-server.sh
  permissions fix
- Add comprehensive PHP/JS debugging logs for settings checkboxes:
  per-field raw POST values in error_log, console.log on htmx:beforeSend,
  htmx:sendError, htmx:afterRequest, toast lifecycle
- Fix toast auto-remove script: use getElementById with unique ID instead
  of querySelector which could remove wrong toast on rapid clicks
2026-05-19 00:08:06 +02:00
Pontoporeia
2bacc78492 import dialog: add Terminé button, fix padding, make success permanent, avoid POST resend
import dialog: add Terminé button, fix padding, make success permanent, avoid POST resend
2026-05-19 00:08:06 +02:00
Pontoporeia
cab65ea4a4 fix: jury-fieldset.php calling old() with wrong signature for partage
jury-fieldset.php called old('jury_promoteur') as a global function,
but the partage context defines old(array $data, string $key) —
passing a string where array is expected caused a TypeError.

Changed jury-fieldset.php to use $oldFn callable (like fieldset-tfe-info.php),
with fallback to global old() when not provided. The add-mode repopulation
block no longer calls the global old() directly.
2026-05-19 00:08:06 +02:00
Pontoporeia
9bcfaf5fd5 Make Auteur(s) and Accès columns sortable alphabetically in admin list 2026-05-19 00:08:06 +02:00
Pontoporeia
406752bc6f Improve recap page + fix CSV import for jury roles
recapitulatif.php (partage):
- Center .thanks-success and add bottom margin/padding
- Display ALL fields: identifier, synopsis, languages, formats,
  jury (all roles), baiu link, license, access type
- Add validation notice asking user to verify info, with
  xamxam@erg.be contact link (email obfuscated)

StudentEmail:
- Add 'Note contextuelle' and license_custom to email recap
- Rename 'Promoteur·ice(s)' to 'Promoteur·ice(s) interne'
- Change email message to ask student to verify info + contact
  for errors

CSV export/import:
- Add 3 new CSV columns: Lecteur·ice(s) interne,
  Lecteur·ice(s) externe, Promoteur·ice(s) ULB
- Export splits supervisors by role/is_external/is_ulb into
  separate columns
- Import inserts supervisors with correct role, is_external,
  and is_ulb flags (was: all treated as generic supervisors)
- Add header matching for short distinguishers (ulb, externe)
  via str_contains fallback
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
7b5f3efe40 feat: add FilePond pools for couverture, note_intention, video, audio; refactor queue config 2026-05-19 00:08:05 +02:00
Pontoporeia
ecb559a18a refactor: decouple format extras from main fichiers block, scope FilePond destroy to individual slots, fix FilePond integration for decoupled extras 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