Files
xamxam/TODO.md
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

15 KiB

XAMXAM TODO

Merge apropos editables into À propos page + remove charte + source code URL

  • actions/apropos.php — only contacts; removed credits, erg_url
  • actions/page.php — remove charte from allowed slugs
  • contenus.php (front controller) — filter pages to only show about + licenses
  • templates/admin/contenus.php — restored "Pages statiques" table
  • contenus-edit.php (front controller) — about slug loads contacts for unified edit
  • templates/admin/contenus-edit.phpabout_page type: Markdown editor + contacts on one page
  • templates/admin/apropos-groups-form.php — reusable partial for contacts
  • Database.php — simplified getAproposContent/saveAproposContent (contacts-only JSON)
  • storage/schema.sql — removed credits, erg_url; only contacts remains
  • AboutController.php — removed credits, sourceCode DB loading
  • templates/public/about.php — hardcoded source code URL, hardcoded credits HTML
  • apropos.css.apropos-toc-source styles

Duplicate TFE submission prevention (fixes)

  • DuplicateThesisException — typed exception carrying existing thesis metadata
  • Database::findDuplicateThesis() — year + author + normalised-title matching (exact, prefix, Levenshtein ≤10%)
  • ThesisCreateController::submit() — calls duplicate check before any DB write, throws DuplicateThesisException
  • AppLogger::logDuplicate() — dedicated log action (status: duplicate) for audit trail
  • App::flash/consumeFlash — extended to support warning type alongside error/success
  • admin/actions/formulaire.php — catches DuplicateThesisException separately; logs it; flashes HTML warning with link to existing thesis; repopulates form
  • partage/index.php — same catch block; plain-text warning (no admin link) surfaced on the student form via flash-warning banner; form repopulated
  • toast.php — renders toast--warning block
  • admin.css.toast--warning style + link colour
  • form.css.flash-warning style (partage form)

Admin audit logging

  • AdminLogger class — JSON-lines to /var/log/xamxam.log (prod) or storage/logs/admin.log (dev), mirrors to admin_audit_log DB table
  • admin_audit_log DB table — created in schema + migrated
  • share_links.is_archived column — archive replaces delete; stats preserved
  • ShareLink::archive() — new method; toggleActive returns new state; listActive() / listArchived() split; validateLink blocks archived slugs
  • actions/acces-etudiante.php — delete→archive, all actions logged (create, toggle, set_password, archive)
  • actions/publish.php — publish/unpublish logged
  • actions/delete.php — delete / bulk-delete / delete-all logged
  • actions/visibility.php — visibility changes logged
  • actions/export-csv.php — CSV export logged
  • actions/export-db.php — DB export logged
  • actions/edit.php — TFE edit logged
  • actions/formulaire.php — TFE add from admin logged
  • actions/tag.php — rename/merge/delete logged
  • actions/page.php — static page edits logged
  • actions/apropos.php — à-propos edits logged
  • actions/form-help.php — form structure edits logged
  • actions/access-request.php — approve/reject logged
  • actions/maintenance.php — maintenance on/off logged
  • actions/settings.php — formulaire toggles, objet types, SMTP update logged
  • actions/smtp-test.php — SMTP test logged
  • templates/admin/acces.php — archive button, archived links collapsible section
  • scripts/setup-server.sh — provision /var/log/xamxam.log with correct ownership

Multi-author support

  • ThesisCreateController::validateAndSanitise() — comma-split auteurice, sort alphabetically, build author entries array
  • Database::createThesis() — removed hardcoded author_id insert; authors linked via setThesisAuthors() instead
  • ThesisEditController::save() — authors sorted alphabetically before setThesisAuthors()
  • Database::findDuplicateThesis() — accepts array of author names, matches any shared author via IN + DISTINCT
  • File folder naming — slug generated from all authors alphabetically sorted (both create and edit)
  • v_theses_full GROUP_CONCAT — ORDER BY a.name ASC for deterministic alphabetical display
  • Migration 012_author_view_order.sql — rebuilds view with alphabetical author ordering

Fix remote 500s and broken TFE pages (post-deploy)

  • migrations/pending/008_share_links_is_archived.sqlALTER TABLE share_links ADD COLUMN is_archived (missing on remote; breaks acces.php)
  • migrations/pending/009_admin_audit_log.sqlCREATE TABLE admin_audit_log (missing on remote)
  • migrations/pending/010_smtp_notify_email.sqlALTER TABLE smtp_settings ADD COLUMN notify_email (missing on remote; breaks parametres.php via SmtpRelay::getSettings())
  • migrations/pending/011_thesis_files_sort_and_label.sqlALTER TABLE thesis_files ADD COLUMN sort_order / display_label (missing on remote; breaks every public TFE detail page)
  • justfile — added deploy-migrate recipe: SSHes to remote and runs php migrations/run.php

Replace browser dialogs with <dialog> modals

  • admin/index.phpalert() (no selection) → <dialog id="no-selection-dialog">; confirm() bulk publish/unpublish → <dialog id="bulk-confirm-dialog">; confirm() bulk delete → <dialog id="bulk-delete-dialog">; confirm() single delete → <dialog id="delete-thesis-dialog">; inline confirm() on Dépublier button removed (no confirmation needed for reversible action)
  • admin/tags.phpconfirm() merge → <dialog id="merge-tag-dialog">; confirm() delete → <dialog id="delete-tag-dialog">
  • admin/acces-etudiante.phpconfirm() delete link → <dialog id="delete-link-dialog">
  • admin/acces.phpconfirm() archive link → <dialog id="archive-link-dialog">
  • admin/parametres.phpconfirm() enable maintenance → <dialog id="enable-maintenance-dialog">; confirm() delete all TFE → <dialog id="delete-all-tfe-dialog">; admin password confirm() kept with TODO comment
  • admin/account.php — admin password confirm() kept with TODO comment
  • admin.css — added .admin-dialog--sm, .admin-dialog__alert, .admin-dialog__footer styles

Fix 403 on HTMX tab requests in parametres.php

  • AdminAuth::requireLogin() — now sets $_SESSION[SESSION_KEY] when accepting nginx Basic Auth credentials (was returning early without marking the session)
  • AdminAuth::isAuthenticated() — now falls back to PHP_AUTH_PW verification (same logic as requireLogin) so HTMX requests to system-fragment.php authenticate even before a session exists

Duplicate warning display fixes

  • toast-fragment.php — 204 guard now also checks warning; warning was silently discarded before
  • partage/index.php — warning stored as plain text (no pre-escaping); htmlspecialchars() applied once at render; was double-encoded before
  • partage/index.phpflash-warning div gets id + tabindex=-1; inline JS scrolls and focuses it on load
  • admin/footer.phphtmx:afterSettle listener focuses .toast--warning after HTMX injects the toast fragment

Sticky save/cancel buttons on edit page

  • templates/admin/edit.php — moved .admin-form-footer from bottom to top-right, right after <h1>
  • admin.css — added .admin-form-footer--sticky variant with position:sticky; top:0; justify-content:flex-end

Fix CSV importer column shift and data repair

  • Pad rows to expected column count to avoid offset warnings from short rows
  • Distinguish $yearRaw !== '' before intval() to handle empty-year rows correctly
  • Improve missing-field error message: lists which fields are missing, includes identifier/title snippet
  • Derive year from identifier when year column is empty
  • Auto-detect column-shifted CSV: when orientation/finality columns are empty but synopsis/context match known orientation/finality names, remap on import
  • Migration 013_fix_csv_column_shift.sql: move orientation from synopsis→orientation_id, finality from context_note→finality_id for already-imported theses
  • Migration 013_fix_remarks_keywords.php: move keywords from remarks→tags+thesis_tags for already-imported theses

Standardise répertoire filter column rendering

  • Centralise filter column rendering into a shared repFilterEntry() function
  • Define $filterColumns config array as single source of truth for the 5 filter columns
  • All columns (years, ap, or, fi, kw) now share identical fade/select/HTMX logic via the same code path
  • Fix single-valued FK columns (years, ap, or, fi): matched entries now use full intersection so clicking one entry correctly fades others with zero results
  • Fix column ordering: students between finalité and mots-clés

Standardise buttons with .btn base class

  • Create .btn base class in common.css: border-radius: 10px; padding: var(--space-xs) + background + cursor
  • Add .btn--primary (accent bg), .btn--secondary (--bg bg + border), .btn--sm, .btn--lg, .btn--danger, .btn--warning, .btn--success, .btn--ghost, .btn--muted, .btn--blue, .btn--yellow, .btn--green, .btn--red modifiers
  • Replace old button definitions in admin.css, form.css, tfe.css, file-access.css, system.css with empty alias comments
  • Update all PHP templates to use new .btn classes (btn btn--primary, btn btn--secondary, btn btn--danger, etc.)
  • Update border-radius on pagination buttons to 10px for consistency
  • Exclude storage/maintenance.flag from rsync deploy and git

Admin file export system

  • ExportController: add getAllThesisFiles(), buildExportManifest(), createExportZip() — gathers all thesis files, creates zip with files/ + manifest.json
  • admin/actions/export-files.php — thin dispatcher, streams zip, logs audit
  • AdminLogger::logFilesExport() — audit log entry for file exports
  • templates/admin/index.php — add "Exporter fichiers" button next to CSV export button
  • Database::getAllThesisFilesForExport() — query all thesis_files + identifier
  • docs/export.md — documentation en français pour administrateurs : fonctionnement, contenu du ZIP, procédure de restauration complète et partielle

Validate & refactor TFE form fields (new spec)

  • Schema: add exemplaire_baiu and exemplaire_erg boolean columns to theses

  • Schema: add jury_promoteur_ulb boolean column to thesis_supervisors

  • Schema: persist cc4r checkbox in theses table

  • Schema: update v_theses_full view to include new columns + jury split (interne/externe/ULB)

  • Admin edit form: add jury_points, remarks, exemplaire_baiu, exemplaire_erg fields (Backoffice fieldset)

  • Admin edit form: add promoteur_ulb checkbox in jury fieldset

  • Admin edit form: reorder fields to match spec layout

  • Public TFE fiche: split lecteur·ice(s) into interne/externe

  • Public TFE fiche: add promoteur·ice ULB display

  • ThesisEditController: handle new fields in save()

  • ThesisCreateController: handle CC4r + is_ulb in jury methods

  • Database::updateThesis: include new columns (remarks, jury_points, exemplaire_baiu, exemplaire_erg, cc4r)

  • Database::setThesisJury: include is_ulb column

  • Database::getThesisJury: include is_ulb in SELECT

  • StudentEmail: use new jury_lecteurs_internes/externes and jury_promoteurs_ulb columns

  • Recapitulatif: show promoteur·ice ULB and lecteur·ices interne/externe

  • Migration: 014_tfe_form_fields.sql — ALTER + view rebuild

  • Fix Call to undefined function old() in admin edit page — define old() in app/public/admin/edit.php (was only in add.php)

  • Add Note contextuelle and Backoffice fieldsets to admin add form (matching edit form)

  • Database::createThesis() — add context_note, remarks, jury_points, exemplaire_baiu, exemplaire_erg, cc4r columns

  • ThesisCreateController::validateAndSanitise() — handle new admin-only fields

  • ThesisCreateController::submit() — pass new fields to createThesis()

  • Replace admin E-mail de confirmation fieldset with Contact interne in Backoffice section (add + edit)

  • Remove confirmation email sending from add/edit (admin never sent; student partage unchanged)

Refactor form structure per spec (student vs admin)

  • Remove jury_president field from student-facing forms (edit keeps it as optional)
  • Jury: split into promoteur·ice interne, promoteur·ice ULB, lecteur·ice interne, lecteur·ice externe — each with +add button
  • AP filtering: student form hides PACS; admin form shows all APs
  • Language: add "autre" text field alongside predefined checkboxes
  • Duration: split into pages field + minutes field + annexes checkbox
  • Licence: removed from métadonnées fieldset, now only in degrés d'ouverture section
  • Degrés d'ouverture: généralités FIRST, then radio choice (Libre/Interne/Interdit), then licence dropdown + custom text + CC2r
  • CC4r → CC2r rename in form UI + cc2r POST name
  • Licence: custom licence text field added (license_custom DB column)
  • Généralités text editable via form help block (fieldset_generalites)
  • Libre option: hidden in student form when disabled in settings; always shown in admin
  • Contact: contact_visible field always present in TFE info; admin gets contact_public checkbox separately
  • Email confirmation: mandatory in student form, optional in admin
  • Fichiers: cover image hint updated to 4:3 ratio
  • All three form pages (admin add, admin edit, partage) updated
  • Controllers updated: collectJuryMembers, validateAndSanitise, buildFileSizeInfo, license_custom, cc2rcc4r mapping

Fix form field required states & missing fields per spec

  • Admin add: add contact_public checkbox (matching edit form)
  • Admin add + partage + admin edit: formats checkbox-list $required = true
  • All forms: jury promoteur·ice interne required attribute
  • All forms: jury lecteur·ice interne required attribute (at least one)
  • All forms: jury lecteur·ice externe required attribute (at least one)
  • All forms: licence select $required = true
  • Admin edit: add "E-mail de confirmation" fieldset
  • Partage: contact always visible (POST handler defaults showContact to true when no contact_public key present)
  • Partage: filter PACS from AP programs dropdown
  • Verify no duplicate asterisks on any field
  • Admin add: contact_public POST handling in ThesisCreateController for admin submissions
  • Server-side validation: formats required, jury members required, licence required (ThesisCreateController + ThesisEditController)
  • Autofocus mappings for new validation errors (format, jury, licence)