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.
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_<slug> 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.
- 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
- 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
- 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
- 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
- shared repFilterEntry() and config array
- shared repFilterEntry() and $filterColumns config array
- fix single-valued FK fading via full intersection
- 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
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.
- toast-fragment.php: 204 early-exit now also checks flash['warning'];
previously the warning was consumed by consumeFlash() then silently dropped
- partage/index.php: store warning as plain text; htmlspecialchars() applied
once at render time — previously htmlspecialchars() was called inside the
stored string then again at output, producing ' entities etc.
- partage/index.php: flash-warning div gets id + tabindex=-1; inline JS
scrolls it into view and focuses it on DOMContentLoaded
- admin/footer.php: htmx:afterSettle listener focuses .toast--warning after
HTMX injects the toast fragment into #toast-region
- Add DuplicateThesisException (typed, carries existing thesis metadata)
- Add Database::findDuplicateThesis(): matches on year + author + normalised
title (exact, prefix, Levenshtein ≤10% of longer string)
- ThesisCreateController::submit() runs duplicate check before any DB write
and throws DuplicateThesisException on match
- AppLogger::logDuplicate() writes status=duplicate entries to the JSON-lines
log for audit purposes
- App::flash/consumeFlash extended to support 'warning' flash type
- admin/actions/formulaire.php: catches DuplicateThesisException, logs it,
flashes an HTML warning toast with a clickable link to the existing thesis,
and repopulates the form fields
- partage/index.php: same catch block; surfaces a plain-text flash-warning
banner on the student form with identifier, title, and year of the match;
form is repopulated via session
- toast.php: renders toast--warning variant
- admin.css: .toast--warning + link colour rules
- form.css: .flash-warning style for the partage form
- Removed the `vimeo/psalm` dependency and all related files
(`psalm.xml`, `psalm‑baseline.xml`, suppress annotations).
- Added **PHPStan** (v2.1.54) and **PHP‑CS‑Fixer** (v3.95.1) to
`vendor/bin/`.
- Created `phpstan.neon` (level 5, bootstraps `app/bootstrap.php`,
scans `Parsedown.php`).
- Created `phpstan‑baseline.neon` with 10 pre‑existing errors.
- Added `.php‑cs‑fixer.dist.php` (PSR‑12 + PHP80Migration, targets
`app/src` & `app/tests`).
- Added `biome.json` and updated `justfile` to replace the old Psalm
recipes with `phpstan`, `cs‑check`, and `cs‑fix`.
- Updated `.gitignore` to exclude PHPStan and PHP‑CS‑Fixer cache files.
- Updated several JS files (`file‑preview.js`, `file‑upload‑queue.js`)
eand PHP controllers (`MediaController.php`, `SearchController.php`,
`SystemController.php`).
- Minor adjustments to `TODO.md`, `app/src/Database.php`,
`app/src/Parsedown.php`, `app/src/ShareLink.php`, and
`app/src/SmtpRelay.php`.
php -S (built-in dev server) ignores .htaccess and .user.ini entirely.
The POST Content-Length limit was still 8M from /etc/php/php.ini.
Pass upload_max_filesize=512M, post_max_size=520M, memory_limit=256M,
max_execution_time=300, max_input_time=300 directly on the CLI.