72d3075466cc | 2026-06-29 17:27
---
a790ddc02ad0 | 2026-06-24 14:57
Fix admin login heading: prevent 'Administration' from hyphenating or overflowing box
---
21f16ee093ec | 2026-06-24 14:49
chore: move #rep-polish to Completed, investigate #tighten-csp blockers
---
eb706214ce16 | 2026-06-24 14:45
feat: scroll-position memory on repertoire HTMX swaps + swap transition polish
- Add repertoire-scroll-restore.js: snapshots scrollTop of each column
before htmx:beforeSwap, restores after htmx:afterSwap (keyed by data-col)
- Add subtle opacity transition on #repertoire-index during htmx-swapping
- Tighten rep-indicator opacity transition to 0.1s for snappier feedback
- Import new module in public-entry.js
---
e0cf9f8f5746 | 2026-06-24 14:26
chore: update TODO — mark icon-color-verify and 3 security tasks complete
---
0062b296782e | 2026-06-24 14:17
Fix security issues from audit: gate partage fragments on share_active session, add CSRF to retry-email POST, remove dead App::verifyCsrf()
---
84869ad96811 | 2026-06-24 14:15
Fix open redirect in tag.php + language.php: reject protocol-relative URLs (//evil.com) by also checking for // prefix
---
6ecd3d4540ef | 2026-06-24 13:21
Fix biome lint errors: remove duplicate CSS properties, apply safe auto-fixes
CSS:
- Remove duplicate 'background' fallbacks in base.css, header.css, search.css
(solid color declared before gradient — gradient always wins)
- Remove duplicate 'padding' in admin.css .admin-import-log
JS (biome --write safe fixes applied):
- function() → arrow functions in all IIFEs and callbacks
- forEach/callback → arrow functions
- evaluePtrn → parseInt(x, 10) in admin-contacts-form.js
- Cleaned label text in build.mjs lint step
Remaining warnings are intentional: !important overrides, descending
specificity (admin.css cascade), noUnusedVariables (functions exported
to window/onclick), useTemplate style preference.
---
82d3dcb084b7 | 2026-06-24 13:18
Fix repertoire column scrolling + admin TOC duplication
- repertoire.css: add min-height: 0 to column
scroll containers so
grid 1fr row shrinks below content and overflow-y: auto activates
- admin-toc.js: add __adminTocBuilt guard + nav.children check to prevent
double population when loaded both via admin.min.js and direct
at the end of the #format-fichiers-block fragment.
- Removed hx-preserve wrappers — they prevented re-render after
format/annexes toggles changed visible inputs.
- This also fixes .zip removal from TFE accept and jury repopulation
array crash from the previous commit.
refactor: simplify file-upload-queue.js, remove file-preview.js
- file-upload-queue.js rewritten from ~250 lines to ~120 lines:
no more DataTransfer machinery, no IIFE wrapper, uses .onchange
instead of addEventListener for simpler HTMX re-init.
- window.XamxamInitFileUploads is the function itself (not an IIFE export).
- Merged file-preview.js functionality into file-upload-queue.js
(single-file .data-preview handling). Deleted file-preview.js.
- fichiers-fragment.php inline script calls XamxamInitFileUploads()
after every HTMX swap (same as before).
debug: add console.log to file-upload-queue.js for file input behavior
Adds logging at key points to diagnose why only one file is displayed:
- XamxamInitFileUploads called
- TFE queue picker init (id, multiple attribute state)
- onchange event (files count, names)
- fileArray post-concat length
- Single-file preview bindings (id, multiple attribute)
Remove after debug session.
---
8f4f9d00b457 | 2026-05-08 17:03
Refactor: Form improvements and cleanup: note contextuel, annexes, fichiers
1. fix: form improvements — multiple promoteurices, asterisks, contact dedup, bentopdf
- Multiple promoteurice (interne + ULB): both fieldsets now support dynamic
add/remove rows (same pattern as lecteurs). field names changed to arrays
(jury_promoteur[], jury_promoteur_ulb_name[]). Controllers accept both
scalar and array forms for backwards compat.
- ULB promoteurice: when finality=Approfondi, asterisk appears on legend
and first ULB input is marked required (JS toggle). Non-Approfondi hides
the fieldset and clears values.
- Contact visibility duplication: removed redundant contact_public checkbox
from admin add/edit forms (showContact=false). The 'mail' field in
fieldset-tfe-info already serves this purpose.
- Asterisk fixes: website URL field now has asterisk+required when Site web
format selected. Video/audio already had correct required handling.
- bentopdf link: clearer full URL 'https://bentopdf.com/' in both
fichiers-fragment.php and form.php (edit mode)
2. refactor: merge Note contextuelle into Backoffice, add Lien BAIU, reorder fields
Backoffice fieldset now contains in order:
1. Note contextuelle (was standalone fieldset)
2. Points du jury
3. Remarques
4. Lien BAIU (moved from Métadonnées complémentaires)
5. Exemplaire physique BAIU
6. Exemplaire physique ERG
7. Contact interne
Métadonnées complémentaires now only has: pages, minutes, annexes checkbox.
Removed dead showContextNote variable from form.php, add.php, edit.php.
Controller baiu_link still mapped to input name "lien" (no migration needed).
3. refactor: move annexes checkbox from Métadonnées into Fichiers fieldset
- Removed 'Ce TFE comporte des annexes' checkbox from
fieldset-metadata.php.
- Added annexes checkbox + conditional file input to
fichiers-fragment.php. When checked, an HTMX swap reveals
the 'annexes' file input (multiple, PDF or ZIP/TAR, max 500 MB).
- form.php seeds ['has_annexes'] for initial fragment render.
- Métadonnées complémentaires now only contains pages + minutes.
---
03c5fd217eaa | 2026-05-08 16:48
feat: dual upload system — direct file storage + PeerTube API integration
Adds a parallel PeerTube upload system behind a feature flag (disabled by default
until upload quota is granted). When disabled, the existing direct file upload
path works unchanged.
Files:
- src/PeerTubeService.php — credential storage (encrypted), OAuth2 token
retrieval, multipart upload to /api/v1/videos/upload
- migrations/021_peertube_settings.sql — peertube_settings singleton table
+ peertube_upload_enabled site_setting (default 0)
- admin/actions/settings.php — peertube section handler
- admin/parametres.php / templates/admin/parametres.php — PeerTube UI section
- partage/fichiers-fragment.php — shows file inputs when enabled, TODO notice otherwise
- ThesisCreateController / ThesisEditController — handlePeerTubeUpload()
- tfe.php — PeerTube iframe embed detection
- AdminLogger — logPeerTubeUpdate()
---
11e61226e2aa | 2026-05-08 16:35
fix: justfile shebang recipes indentation (spaces → tabs)
---
e6829994b6d1 | 2026-05-08 13:03
Refactor + feat: unify format/fichiers HTMX fragment, reorder format types, add file constraints, fix admin auth
* **Unified Format + Fichiers into a single HTMX fragment**
* Introduced `app/public/partage/fichiers-fragment.php` as shared dynamic block returning both format checkboxes and adaptive “Fichiers” fieldset
* Logic adapts inputs based on selected formats:
* no selection / upload formats → standard file inputs
* “Site web” → URL fields only
* “Site web + upload” → file inputs + URL sub-fieldset
* Added admin wrapper: `app/public/admin/fichiers-fragment.php` (gated via `admin_mode=1`)
* Added `app/public/admin/format-website-fragment.php` for edit-mode website URL toggling
* Wired route `/partage/fichiers-fragment` in `app/public/partage/index.php`
* Refactored `form.php` (add/edit partage) to use single `#format-fichiers-block` instead of separate fragments
* Edit mode format checkboxes now target `format-website-fragment.php` → `#edit-website-url-fieldset`
* Added `$hxInclude` support in `checkbox-list.php` for configurable HTMX includes
* **Format system migration + ordering**
* Migration `020_format_types_sort_and_rename.sql`:
* added `sort_order` column to `format_types`
* inserted new format **Image**
* defined ordering: Écriture · Image · Audio · Vidéo · Site web · Performance · Objet éditorial · Installation · Autre
* `Database.php`: format queries now use `ORDER BY sort_order, id`
* `fichiers-fragment.php`:
* uses ordered format list
* resolves Image/Vidéo/Audio by name
* introduces `$hasImage` flag
* preserves `admin_mode` across HTMX requests
* **File constraints and UX updates**
* Enforced **100 MB PDF limit**
* `ThesisCreateController`: `MAX_PDF_SIZE = 100MB` for PDFs only
* `ThesisEditController`: same PDF-specific constraint applied
* Other file types remain capped at 500 MB
* Updated UI hints in `fichiers-fragment.php` and edit form:
* explicitly mention 100 MB PDF limit
* added reference to `bentopdf.com` for compression guidance
* `file-field.php`: added `$hintRaw` to allow HTML rendering in hints
* **Admin authentication fix**
* Fixed missing auth in admin fragments
* Added `require_once AdminAuth.php`
* Replaced direct usage with `AdminAuth::requireLogin()`
* Applied consistent pattern with existing fragment authentication approach
* **Migrations included**
* `019_add_ecriture_format.sql`
* `020_format_types_sort_and_rename.sql`
* **Files affected**
* Controllers: `ThesisCreateController`, `ThesisEditController`
* DB layer: `Database.php`
* Public fragments: `partage/fichiers-fragment.php`, `admin/fichiers-fragment.php`, `admin/format-website-fragment.php`
* Templates: `form.php`, `checkbox-list.php`, `file-field.php`
* Routing: `partage/index.php`
* Misc: `TODO.md`
This consolidates format normalization, HTMX UI simplification, file validation rules, and admin stability fixes into a single coherent system update.
---
7e35bba5304c | 2026-05-08 12:48
Encrypt SMTP password at rest with AES-256-GCM
---
95fcbc919a44 | 2026-05-08 12:40
Remove required from all admin add/edit form inputs
- Skip required-field validation for orientation/ap/finality/licence/jury in admin add+edit
---
5735ccbc3878 | 2026-05-08 11:30
Fix issues with nginx access to pages
- fix: 403 on /language-autre-fragment.php — add explicit nginx location block
The nginx catch-all blocked direct access
to all PHP files except /index.php and files inside /admin/.
language-autre-fragment.php lives at the public root and is POSTed to by
HTMX from both the admin edit form and the partage form. Added an explicit
fastcgi block so it is executed
rather than denied.
- fix: replace .php-suffixed public URLs blocked by nginx catch-all
Audit of all client-facing PHP URL references against nginx routing:
- fetch('/request-access.php') in tfe.php -> '/request-access'
(clean URL already routed by Dispatcher)
- /media.php?path= in form.php (x2) and admin/recapitulatif.php -> /media?path=
(nginx only has location = /media, no location for /media.php)
All these .php-suffixed URLs hit the nginx catch-all
location ~ \.php$ { deny all; }
which takes precedence over location / { try_files ... } for regex matches.
---
6ba13e00eabd | 2026-05-08 10:56
test: add ShareLinkTest + PureLogicTest (TDD), fix coverMap undefined in SearchController
---
15d54fa19ee3 | 2026-05-08 10:55
add Néerlandais language option and make language_autre conditionally required
---
f3d961556260 | 2026-05-08 10:46
merge banners into covers: remove banner field, migrate files, add covers to search/home/repertoire cards
---
e3896811c416 | 2026-05-07 23:45
Fix migrations and deploy issues + errors + linting
- scan both pending/ and applied/ dirs so remote catch-up works
- fix remote 500s: run.php handles per-statement errors so VIEW rebuilds run after duplicate columns; replace mb_strimwidth with substr (no mbstring extension on server)
- add missing migration: 015_license_custom.sql (column existed in schema.sql but was never migrated)
- remote: fgetcsv enclosure single-char + AdminLogger permission-denied
guard + deploy always migrates
- fix admin-filters wrapping: restore flex-wrap, flex-basis on
inputs/selects, shrink-protect buttons
- fix phpstan: remove redundant ?? [] after isset guard in
ThesisEditController
- biome: exclude vendored min.js via includes patterns;
lint whole js dir; modernise beforeunload-guard.js
---
bdd95341b09c | 2026-05-07 22:48
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.
---
ac0008df6cc5 | 2026-05-07 21:24
Add website-type TFE support: URLs stored as thesis_files rows, HTMX-toggle on Site web format
---
9dc7ea98f252 | 2026-05-07 20:58
fix: password-protected share links never load form after password entry
The main GET handler in partage/index.php always showed the password gate
for links with password_hash set, even after successful verification. The
session flag share_verified_ was being set by requirePasswordGate()
but never checked when deciding whether to re-show the gate.
Added a check: if the session flag is already set, skip the gate and
render the form directly.
Also added error_log() calls throughout the password flow to help
diagnose future issues.
---
03121d6b7ef5 | 2026-05-07 20:52
form: add spacing between elements inside fieldsets
- common.css: fieldset > *:not(:last-child) gets margin-bottom: var(--space-xs)
- admin.css: .param-form fieldset > * zeroes margin to avoid double-spacing with flex gap
---
d9dd4bdbc777 | 2026-05-07 20:42
Edit Email confirmation styling
---
696259afae08 | 2026-05-07 19:54
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)
---
51f9f56e0995 | 2026-05-07 19:40
Replace span with a link + href in about.php for credits
---
e0c748d8e7b0 | 2026-05-07 18:44
Refactor about.php
- Hardcode source code URL and credits in about template, remove from DB/admin interface; only contacts remains editable
- Merge apropos editables into one À propos section, remove charte, add editable source code URL
---
24d68dda598e | 2026-05-07 17:52
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
---
dce0e0b30194 | 2026-05-07 17:30
schema: validate against new TFE field spec
- add exemplaire_baiu, exemplaire_erg, cc4r, remarks;
- add is_ulb to jury;
- split jury_lecteurs into interne/externe in view;
- refactor admin edit form with backoffice fields;
- update public fiche to show promoteur ULB and split lecteurs
---
7793b6f86d4f | 2026-05-07 16:28
add file export system for admins
- ExportController: getAllThesisFiles(), buildExportManifest(), createExportZip()
builds a ZIP archive with manifest.json + files/ mirror of storage/theses/
- Database: getAllThesisFilesForExport() queries all thesis_files + identifier
- AdminLogger: logFilesExport() audit log entry
- admin/actions/export-files.php: thin dispatcher, streams zip with headers
- templates/admin/index.php: 'Exporter fichiers' button next to CSV export
---
821369f00468 | 2026-05-07 12:27
exclude maintenance.flag from rsync deploy and git
---
3f87d71e389e | 2026-05-05 18:54
Fix: CSV importer and imported data
- pad rows, distinguish empty year, better error diagnostics
- derive year from identifier when year column is empty
- fix remaining 18 theses: Installation/Performance (slash→dash) orientation alias
- csv importer: use column-name-based header detection instead of hardcoded positions
---
b063312642c5 | 2026-05-05 18:27
centralise repertoire filter column rendering
- shared repFilterEntry() and config array
- shared repFilterEntry() and $filterColumns config array
- fix single-valued FK fading via full intersection
---
bca707ee9687 | 2026-05-05 11:34
standardise buttons: .btn base class (border-radius 10px, padding var(--space-xs))
---
b58445f71c84 | 2026-05-05 11:09
sticky save/cancel buttons at top-right of admin edit page
---
95066de7b4d3 | 2026-05-05 10:31
standardise multi-author support across all forms
- ThesisCreateController: comma-split auteurice, sort alphabetically,
use setThesisAuthors() instead of hardcoded createThesis() author_id
- Database::createThesis(): removed author_id param and hardcoded insert
- Database::findDuplicateThesis(): accepts array of author names, matches
any shared author via IN + DISTINCT
- ThesisEditController::save(): sort authors alphabetically on save
- File folder naming: slug from all authors alphabetically sorted
- v_theses_full GROUP_CONCAT: ORDER BY a.name ASC for deterministic display
- Migration 012_author_view_order.sql: rebuilds view with alphabetical order
---
125c501f4080 | 2026-05-04 18:33
Fix 403 on HTMX fragment requests: AdminAuth Basic Auth sets session key
---
37111eaac452 | 2026-05-04 18:19
fix: add missing remote DB migrations and deploy-migrate recipe
Four ALTER TABLE / CREATE TABLE statements were applied locally but never
deployed to the remote production database, causing:
- acces.php → 500: share_links.is_archived missing (ShareLink::listActive/listArchived)
- parametres.php → 500: smtp_settings.notify_email missing (SmtpRelay::getSettings)
- /tfe?id=N → redirect-to-home: thesis_files.sort_order missing (getThesisFiles ORDER BY)
- admin_audit_log table missing (AdminLogger::insertDb, best-effort but noisy)
Adds four pending migrations (008–011) covering all missing schema changes.
Adds 'deploy-migrate' just recipe to run migrations on the remote after deploy.
---
ae6d9b86b32a | 2026-05-04 17:52
Replace browser alert/confirm dialogs with