- 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
Requirements:
- parametres.php toggle: 'restricted_files_enabled' enables/disables the feature
- Public TFE page: when enabled + access_type=Interne, hides files, shows French
restriction message + access request form (metadata/synopsis still visible)
- ERG emails (@erg.school / @erg.be): auto-approve, send 24h access link immediately
- External emails: show justification textarea, create pending request, notify admin
- Admin panel /admin/file-access.php: approve/reject requests with optional notes,
sends access email on approval (linked from admin nav with pending count badge)
Security:
- One-time 24h email tokens (used_at + is_valid=0 on first click)
- Token redeemed via POST /validate-access (GET shows confirmation page only)
- Long-lived 30-day browser session in file_access_sessions table
- Cookie: HttpOnly + Secure + SameSite=Strict
- CSRF on all mutations, rate limiting on request submission
- Audit trail: IP, UA, event, timestamp in file_access_audit
Bug fixes:
- admin/file-access.php: $vars never extract()ed → page was blank
- Template had self-contained head/footer includes (double-include)
- Admin approval URL used $requestId instead of $request['thesis_id']
- App::boot() now starts session so CSRF token works on public pages
- Dispatcher routes /validate-access and /request-access through front controller
- Add v_smtp_active VIEW to schema.sql (was only in migration 012,
causing SmtpRelay::isConfigured() to always return false on fresh installs)
- Change thanks redirect from /partage/thanks.php to /partage/thanks
(nginx 'location ~ \.php$ { deny all }' blocked the .php URL)
- Route /partage/thanks in index.php before slug validation
- Guard App::boot() in thanks.php to avoid double-boot when included
- migration 014: adds Récits et expérimentation (RE), PACS, sets code NS
on Narration Spéculative; applied to both posterg.db and test.db
- importer (admin/index.php): replaced the code-only ap_programs lookup
(SELECT WHERE code=?) and the orientationMap short-code translation with
two resolver closures that handle the real CSV format (full names):
resolveAP(): alias map for L.I.E.N.S., case variants → exact name
match → code match (legacy) → case-insensitive name match
resolveOrientation(): legacy 2-letter code map → alias map for
Installation/Performance, Arts numériques, Design numérique →
exact name match → case-insensitive name match
All 5 AP values and 13 orientation values from the real CSV now
resolve to correct DB IDs. Legacy short-code CSVs (test.db format)
continue to work unchanged.
- repertoire-index.php: add $colHasMatches per-column guard.
Entries in a column are only faded when that column has at least one
matched entry in the current result set. When a dimension has no
matched entries (e.g. no thesis has orientation_id set yet), the
entire column stays fully interactive — all values remain clickable.
This fixes: empty columns, forced single-select, cascade fading.
- Database.php: revert allAp/allOr/allFi to full lookup-table queries
so all known values are always shown (not just ones linked to theses).
- common.css: body is now a flex column; main gets flex:1 + min-height:0;
header-search-wrap gets flex-shrink:0; duplicate html/body blocks merged.
- public.css: removed redundant top-level main block; home-main gets min-height:0.
- repertoire.css: search-main gets min-height:0 for proper flex scroll.
- Add dedicated 'confirmation_email' (type=email, required) field
to student form at end of submission (partage + admin).
- ThesisCreateController now validates it is present and a valid
email; form is rejected if missing/invalid.
- Autofocus mapping for confirmation_email errors.
- StudentEmail uses confirmation_email directly (removed extractEmail
hack that mined email from free-form contact field).
- Remove require_once for config/config.php (file was never deployed — outside app/)
- Inline DB path resolution directly in Database::determineDatabasePath()
- Uses APP_ROOT when defined (bootstrap already loaded), falls back to __DIR__/../
- DB_ENV=test|prod env-var override preserved for tests
- php -S cli-server -> test.db, nginx/fpm -> posterg.db