Files
xamxam/TODO.md
Pontoporeia 41629398d3 Extract ThesisEditController from admin/edit.php and actions/edit.php
src/ThesisEditController.php (285 lines) centralises all data-fetching and
mutation logic for the thesis-edit workflow:

  load(int $thesisId): array
    Fetches the thesis row, current language/format/jury selections, and all
    lookup tables (orientations, AP programmes, finality types, languages,
    formats, licences, access types) in one call.  Returns a flat view-variable
    array that the dispatcher extracts directly.

  save(int $thesisId, array $post, array $files): void
    Runs the full edit inside a transaction: thesis metadata, authors, jury,
    languages, formats, tags.  Banner upload/removal is handled outside the
    transaction (filesystem op).  Rolls back and re-throws on any failure.

  static autofocusFieldForError(string $msg): ?string
    Centralises the WCAG 3.3.1 exception-message → field-name mapping that
    was previously duplicated inline in actions/edit.php.

Dispatcher changes:
  admin/edit.php      191 → 162 lines  (pure view + ThesisEditController::create() + load())
  actions/edit.php    153 →  53 lines  (CSRF guard + ThesisEditController::save() call)

Follows the same pattern as SearchController and SystemController.
2026-04-06 15:33:08 +02:00

71 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TODO
Pending tasks have been split into topic files under [`todo/`](todo/README.md):
| File | Topic |
|------|-------|
| [todo/01-css-semantic-refactor.md](todo/01-css-semantic-refactor.md) | CSS class audit, semantic HTML (public + admin), inline style extraction, favicon |
| [todo/02-php-components.md](todo/02-php-components.md) | Form field partials, shared UI partials, controller extraction, backend maintenance |
| [todo/03-system-cache.md](todo/03-system-cache.md) | `system_cache` table, `SystemCache` class, `system.php` refactor |
| [todo/04-accessibility.md](todo/04-accessibility.md) | WCAG 2.1 AA - remaining failures grouped by success criterion |
## Recently completed (this session)
- [x] `src/ThesisEditController.php` — extracted all data-fetching and mutation logic from `admin/edit.php` and `admin/actions/edit.php` into a dedicated controller class; `load(int $thesisId): array` fetches the thesis row, current language/format/jury selections, and all lookup tables for the view; `save(int $thesisId, array $post, array $files): void` validates and persists thesis metadata, authors, jury, languages, formats, tags, and banner in a transaction with proper rollback on error; static `autofocusFieldForError(string $msg): ?string` centralises WCAG 3.3.1 field-name mapping; `admin/edit.php` reduced 191→162 lines (pure dispatcher + view template); `actions/edit.php` reduced 153→53 lines (CSRF guard + one controller call)
- [x] `src/SystemController.php` — extracted all data-fetching logic from `admin/system.php` and `admin/system-fragment.php` into a dedicated controller class; centralises: system status checks (nginx, php-fpm, HTTP ping, SQLite DB, storage dir, maintenance flag) with 2-min TTL caching, PHP environment info (1-hour TTL), disk usage (5-min TTL), log file reading (`readLogTail`), nginx config reading, and the shared CSS-class classifier methods (`logLineClass`, `nginxLineClass`, `statusLabel`, `statusClass`, `humanBytes`, `diskColor`); `system.php` reduced 582→282 lines; `system-fragment.php` reduced 213→137 lines with all `frag_*`-prefixed duplicated helpers removed; both files now purely dispatch to the controller and render view templates
- [x] `src/SearchController.php` — extracted all data-fetching logic from `public/search.php` into a dedicated controller class; `SearchController::create()` handles rate-limit enforcement (429 response + exit) and returns a ready instance; `handle()` sanitises GET params, runs all DB queries (`searchTheses`, `countSearchResults`, `getAvailableYears`, `getAllOrientations`, `getAllAPPrograms`, `getUsedTags`, `getPublishedAuthors`), builds the alphabetical author map, assembles OG/meta tags, and returns a flat view-variable array; `public/search.php` reduced from 285 lines to 162 lines (pure dispatcher + view template)
- [x] `admin/system.php` + `assets/js/system.js` + `assets/css/system.css` — extracted the large `$extraJsInline` heredoc (≈130 lines) into a static `public/assets/js/system.js` loaded via `$extraJs`; replaced 4 inline `style=` attributes with named CSS modifier classes (`srv-section-title--compact`, `srv-section-title--sub`, `php-grid--flush`, `log-toolbar label` rule); only the dynamic `--disk-pct`/`--disk-color` CSS custom properties remain inline because they carry PHP runtime values
- [x] `src/App.php` — removed dead legacy flash key fallback chains from `consumeFlash()`: the `error`, `admin_error`, `edit_error`, `form_error`, `success`, `admin_success`, `edit_success` session keys were never written by any code; all callers already use `App::flash()``_flash_error` / `_flash_success`. Method is now 4 lines instead of 18.
- [x] `admin/import.php` + `admin.css` — extracted all 4 remaining inline `style=` attributes from `import.php` into named CSS classes (`admin-error-list`, `admin-file-hint`, `admin-import-results`, `admin-import-results__title`) in the Import page section of `admin.css`. No more inline styles in `import.php`.
- [x] WCAG 3.3.1 `autofocus` on first invalid field — `App::flashAutofocus()` / `consumeAutofocus()` added; `actions/formulaire.php` maps exception messages → field names and stores the autofocus hint in `$_SESSION['_flash_autofocus']`; `actions/edit.php` does the same; `add.php` consumes it via a `withAutofocus()` helper and injects `autofocus => true` into `$attrs` for `text-field.php` / `select-field.php` includes; `edit.php` uses inline ternary for the same; `text-field.php` and `select-field.php` partials now support boolean `true` values in `$attrs` (emit bare attribute names for `autofocus`, `required`, etc.)
- [x] `config/apropos.php` — extracted hardcoded contacts (Laurent Leprince, Xavier Gorgol, Brigitte Ledune) and credits into a config array (`contacts[]`, `credits[]`, `erg_url`); `public/apropos.php` now loops over the config with `htmlspecialchars` instead of embedding names/emails in HTML
- [x] `todo/02-php-components.md` — audited and marked 8 stale items as already done: all 5 form field partials (`text-field`, `select-field`, `checkbox-list`, `file-field`, `jury-fieldset`), `admin-alert.php`/`flash-messages.php` consolidation, `RateLimit` cache dir placement, and `apropos.php` contacts extraction
- [x] WCAG 4.1.2 `<video>` captions — `tfe.php` now emits `<track kind="captions">` for each MP4 when a `.vtt` sidecar exists (N-th VTT paired with N-th video). `formulaire.php` accepts `.vtt` uploads (`file_type='caption'`, MIME normalised). `media.php` serves `text/vtt` with correct headers and visibility gating. Admin `add.php` file-field hint documents the `.vtt` upload convention.
- [x] `admin/edit.php` — WCAG 4.1.2: removed `mb_strimwidth` truncation from `$accessOptions` mapping; access type `<select>` options now include full description text (`name — description`) so the accessible name is unambiguous for screen readers
- [x] `public/assets/favicon.svg` — created public favicon: brand-purple (`#9557b5`) rounded square with white "P" lettermark; distinct from `admin_favicon.svg` (archive-restore icon in `#c104fc`)
- [x] `templates/head.php` — favicon `<link>` now selects `favicon.svg` (public) vs `admin_favicon.svg` (admin) based on `$isAdmin`; closes `todo/01-css-semantic-refactor.md` favicon task
- [x] `todo/04-accessibility.md` — marked WCAG 3.1.1 lang audit and WCAG 4.1.2 select truncation items as done
- [x] `todo/01-css-semantic-refactor.md` — marked favicon task as done
- [x] `admin.css` - added `[aria-current="page"]` rule for admin nav links (`border-bottom: 2px solid currentColor; padding-bottom: 1px`) fixing WCAG 1.4.1 (active nav link had no non-colour indicator)
- [x] `admin.css` - fixed undefined `--admin-purple` variable in pagination hover; replaced with `--accent-primary` (same `#9557b5` value)
- [x] `todo/01-css-semantic-refactor.md` - audited all CSS/HTML refactor tasks; marked ~15 items as already-done (`.admin-main`, `.admin-page-title`, `.admin-form-row`, `.admin-label`, `.admin-input/select/textarea`, `.admin-table`, `.admin-fieldset`, `tfe.css` class replacements, `search.css` selector, `login.php`/`edit.php` inline styles, `admin-alert` replacement, form partial hints)
- [x] `todo/04-accessibility.md` - marked WCAG 1.4.1 admin nav and `--admin-purple` audit items as completed
- [x] `admin/index.php` - server-side pagination (25/page); `Database::getThesesListCount()` added; `getThesesList()` extended with `$limit`/`$offset`; `access_type` JOIN added to query (was missing); result-count meta line added; `.pagination-wrap` + `.pagination-btn` + `.pagination-info` styles added to `admin.css`
- [x] `checkbox-list.php` - replaced `<div class="admin-checkbox-list">` with `<fieldset class="admin-checkbox-group"><legend class="sr-only">...</legend><ul>` (WCAG 1.3.1 fix)
- [x] `admin.css` - replaced `.admin-checkbox-list` with `.admin-body fieldset.admin-checkbox-group > ul` semantic selectors; added `span.admin-row-label` as visible label column counterpart
- [x] `login.php` - wrapped content in `<main id="main-content">` landmark
- [x] `account.php` - `<div class="admin-account-status">``<dl>`; `__row` divs kept; `__label` spans → `<dt>`; `admin-danger-zone__description` div → `<p>`
- [x] `index.php` - maintenance bar `<div>``<aside role="status" aria-label="Statut du site">`
- [x] `add.php` / `edit.php` - `autocomplete="name"` on author field, `autocomplete="email"` on contact field
- [x] `tags.php` - all inline `style=` attributes removed; sizing/spacing moved to CSS (`.admin-input--inline`, `.admin-select--inline`, `.admin-inline-form + .admin-inline-form`, `.admin-tags-count`)
- [x] Marked already-done items in todo files: stats `<dl>`, `thanks.php` `<section>`, `scope="col"` on both tables, `tfe.php` inline styles, `role="alert"` on flash messages
- [x] `admin-submit-wrap``admin-form-footer` rename: updated all 6 admin templates (`add.php`, `edit.php`, `login.php`, `account.php`, `import.php`, `pages-edit.php`) and all 8 CSS selectors in `admin.css` (`.admin-form > div:not(...)` exclusion guards, `.admin-login-box` overrides). Closes `todo/01-css-semantic-refactor.md` submit-wrap task.
- [x] Marked `status-badge.php` partial and WCAG 1.3.1 status-badge items as already-done in `todo/02-php-components.md` and `todo/04-accessibility.md` (partial + CSS were fully implemented; TODO had not been updated)
- [x] `public/index.php` — WCAG 2.4.4: home page cards now append `<span class="sr-only">, YEAR</span>` to each cards `<p>` link text so screen readers get unique link names when two theses share the same title
- [x] `todo/04-accessibility.md` — WCAG 2.4.3: marked back-link focus-order item as already done (`tfe-back-link` is already the first DOM element in `.tfe-left`, before `<h1>`)
- [x] `jury-fieldset.php` — WCAG 3.3.2: replaced bare `<label>Lecteur·ices :</label>` with `<fieldset class="admin-jury-lecteurs"><legend>Lecteur·ices</legend>` so the lecteur group has a proper programmatic label
- [x] `jury-fieldset.php` — WCAG 4.1.2: all "Externe" checkboxes (promoteur + each lecteur row, static + dynamically added via JS) now carry `aria-label="[Role] — externe"` providing group context without visible redundancy
- [x] `jury-fieldset.php` — WCAG 2.1.1: jury remove buttons verified to have descriptive `aria-label="Supprimer le lecteur·ice N"` on all rows (static + dynamic)
- [x] `admin.css` — added `.admin-body fieldset fieldset.admin-jury-lecteurs` rule: strips border/background on the nested lecteur fieldset so it renders as a visual sub-group, not a double-bordered card
- [x] `todo/04-accessibility.md` — WCAG 1.4.4 + 1.4.12 audited and marked done: all font-sizes are `rem`; no `overflow:hidden` on essential text content