Commit Graph

220 Commits

Author SHA1 Message Date
Pontoporeia
89b7ab476e Handle SMTP 550 recipient-rejected errors with structured SmtpSendException
- Add SmtpSendException with smtpCode/smtpResponse/isRecipientRejected()
- smtpSend() $expect closure throws SmtpSendException (with code) instead of RuntimeException
- SmtpRelay::send() re-throws SmtpSendException so callers can inspect it
- request-access.php (new): catch 550 → roll back token+approval, return HTTP 422 with FR user message
- request-access.php (resend): catch 550 → HTTP 422 instead of silently claiming success
- StudentEmail::sendConfirmation(): catch SmtpSendException → log+false (submission not aborted)
- admin/actions/access-request.php: catch SmtpSendException post-approval → flash warning (recipient-rejected vs transient)
2026-05-05 11:04:52 +02:00
Pontoporeia
8d115dc965 smtp: enable TLS peer verification, fix envelope injection, fix dot-stuffing 2026-05-05 11:04:52 +02:00
Pontoporeia
33987c9b15 smtp: add notify_email field; fix admin notification sent to no-reply sender 2026-05-05 11:04:52 +02:00
Pontoporeia
bdb68479d5 smtp: typed probe errors with per-field UI highlighting on save 2026-05-05 11:04:52 +02:00
Pontoporeia
b750aca2f5 smtp: probe credentials on save (connect+auth+quit, no message sent) 2026-05-05 11:04:52 +02:00
Pontoporeia
56c8d54435 repertoire: align all column headings to shared baseline row 2026-05-05 11:04:52 +02:00
Pontoporeia
a9e03c4b1c repertoire: fixed-header columns, remove main/index padding, minimal column padding 2026-05-05 11:04:52 +02:00
Pontoporeia
0960afb731 fix: add missing favicon tags to partage/recapitulatif.php 2026-05-05 11:04:52 +02:00
Pontoporeia
9ba60084bf fix: require SmtpRelay.php before StudentEmail.php in partage/index.php 2026-05-05 11:04:52 +02:00
Pontoporeia
cb883ab33f fix: deploy-server.sh migrates posterg.db → xamxam.db and cleans legacy nginx configs 2026-05-05 11:04:52 +02:00
Pontoporeia
ab51bf3a66 fix: deploy-server.sh cleans up legacy posterg configs and prunes old xamxam backups 2026-05-05 11:04:52 +02:00
Pontoporeia
68e30abb56 fix: remove Post-ERG branding → XAMXAM; drop legacy posterg nginx symlink in deploy script; rename posterg.db → xamxam.db 2026-05-05 11:04:52 +02:00
Pontoporeia
c949cf9481 rename posterg → xamxam throughout: nginx conf, scripts, PHP source, docs 2026-05-05 11:04:52 +02:00
Pontoporeia
c27ffafa7e fix: add missing favicon tags to partage/index.php (error, password gate, form) 2026-04-29 21:58:49 +02:00
Pontoporeia
80b7fddea4 fix: partials must not unset caller-owned $formData
fieldset-academic.php, fieldset-metadata.php and fieldset-licence-explanation.php
were each calling unset($formData) (or wrong variable) in their cleanup block,
destroying the variable in the parent renderShareLinkForm() scope.  This caused
an Undefined variable / TypeError on old($formData, ...) for any field rendered
after those partials (e.g. confirmation_email at line 328).

Fix: remove $formData from the unset() calls; fieldset-licence-explanation.php
was also unsetting the wrong name — corrected to unset($n) which is the variable
it actually declares.
2026-04-29 21:56:42 +02:00
Pontoporeia
43702542eb feat(admin): sortable form-help blocks with two-panel UI
- Migration 005: add sort_order column to form_help_blocks
- Database: getAllFormHelpBlocks orders by sort_order; new reorderFormHelpBlocks()
- actions/form-help-reorder.php: HTMX POST handler, CSRF-validated, 204 response
- templates/admin/contenus.php: replace flat table with two-panel layout
  - Left: SortableJS 1.15.2 + htmx drag-and-drop ordered block cards
  - Right: static form structure reference showing fieldsets and their inputs
- admin.css: .fhb-* styles for layout, cards, ghost/chosen/drag states, anchors
- schema.sql: updated form_help_blocks DDL with sort_order column
2026-04-29 21:45:55 +02:00
Pontoporeia
5c39e856a3 fix: pass enabledAccessTypes from ThesisEditController to edit view 2026-04-29 21:34:47 +02:00
Pontoporeia
885150ea45 css: centralise semantic element baseline styles in common.css 2026-04-29 21:33:55 +02:00
Pontoporeia
b5189c0d08 admin: merge acces-etudiante+file-access into acces.php, absorb system.php into parametres.php 2026-04-29 21:18:25 +02:00
Pontoporeia
670a38f30d add form help blocks: DB table, admin editor, live rendering in partage form 2026-04-29 21:08:09 +02:00
Pontoporeia
0437ec8d15 fix: escape apostrophe in FORM_HELP_LABELS string (Database.php:2005) 2026-04-29 21:05:53 +02:00
Pontoporeia
d665cb502d centralise form fieldsets into shared partials; add TODO stubs in partage form 2026-04-29 20:59:35 +02:00
Pontoporeia
18a02a0018 deploy: rename deploy path from /var/www/posterg to /var/www/xamxam 2026-04-28 22:21:09 +02:00
Pontoporeia
cd68e6e9d7 deploy: exclude posterg.db, theses/, covers/ from rsync to avoid overwriting remote data 2026-04-28 22:15:06 +02:00
Pontoporeia
59c4cf055f smtp-test: bypass DB, use POST fields directly for credentials 2026-04-27 21:44:10 +02:00
Pontoporeia
e09b056115 fix: iframe for PDF display, exclude cover files from public loop, no session on media requests 2026-04-27 21:11:58 +02:00
Pontoporeia
46a3c360ec fix: use local storage/ in dev, create upload dirs, gitignore uploads 2026-04-27 21:08:48 +02:00
Pontoporeia
48059c2317 fix: serve logs, formulaire.php error_log path, CSRF debug, undefined $redirect 2026-04-27 21:04:21 +02:00
Pontoporeia
32a7509598 feat: add file display to forms and recap pages
- Live file preview on all file inputs (file-field partial, edit template):
  thumbnails for images, emoji icons for PDF/video/zip/vtt, filename + size
- New file-preview.js wired via $extraJs in add.php / edit.php and direct
  <script> in partage/index.php; $extraJs support added to head.php
- admin/recapitulatif.php: replace plain table with rich file list — image
  thumbnails linked to media.php, type badges, human-readable size, date
- partage/recapitulatif.php: full rewrite — shows thesis metadata + files
  list with same rich display (no media links for student privacy)
- form.css: new sections for .file-preview-list (live preview) and
  .recap-file-list / .recap-dl / .partage-recap (recap pages)
2026-04-27 20:52:27 +02:00
Pontoporeia
aca7e7eef8 rename thanks.php to recapitulatif.php in admin and partage 2026-04-27 20:41:43 +02:00
Pontoporeia
4d88bd8cc5 edit.php: rework Fichiers fieldset layout
- Drop file-field.php partial for cover/banner (it added a second label)
- Inline all three file inputs with admin-file-input wrapper
- Move banner inside the Fichiers fieldset
- Each entry: one label, one input, one small hint — no duplicate labels
- Context-aware hints: 'Laisser vide pour conserver...' when file already exists
2026-04-27 20:38:45 +02:00
Pontoporeia
8e864fc624 admin edit.php: add cover image + thesis file management fields
- Database: add deleteThesisFile() and handleCoverUpload() methods
- ThesisEditController::load(): expose currentFiles + currentCover to view
- ThesisEditController::save(): handle couverture upload/removal,
  per-file deletion (delete_files[]), and new thesis file uploads
- edit.php template: new Fichiers fieldset with cover preview+remove,
  existing files list with delete checkboxes, new file upload input
  (mirrors add.php / partage.php)
2026-04-27 20:33:21 +02:00
Pontoporeia
27e1b6828d Implement TFE file access restriction feature (complete)
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
2026-04-27 20:20:52 +02:00
Théophile Gervreau-Mercier
88b9f341cd Replace Posterg branding with XAMXAM in all user-facing content 2026-04-27 19:30:54 +02:00
Théophile Gervreau-Mercier
7e26351f4b refactor: remove test.db, use only posterg.db for all environments
- Simplified Database.php determineDatabasePath to always use posterg.db
- Removed test.db auto-detection based on php_sapi_name
- Removed test.db targets from justfile (migrate-test removed)
- Removed CreateTestDatabase.php fixture script
- Updated migrate.sh to only init posterg.db
- Updated setup-dev.sh to init posterg.db
- Updated run-tests.php (removed DB_ENV=test env var)
- Updated deploy-db to use posterg.db
- Removed test.db file

refactor: remove empty fixtures directory
2026-04-27 18:07:20 +02:00
Théophile Gervreau-Mercier
780105eec0 Fix storage/cache ignore path and untrack cache files 2026-04-25 19:38:51 +02:00
Pontoporeia
54ef24d21f ignore *.db files, fix thesis identifier to use max seq instead of count, untrack .db files 2026-04-24 23:03:49 +02:00
Pontoporeia
4986fa74f4 add structured logging for admin/partage form submissions + migration system
- AppLogger: JSON-line logger in storage/logs/form-submissions.log
- Logs submissions (admin + partage) with IP, UA, thesis ID, author
- Logs errors with context (post keys, share slug)
- Migration runner (app/migrations/run.php) handles schema drift
- 001_add_objet_column.sql fixes production DB missing 'objet' column
- ThesisCreateController::getIdentifier() helper for logging
2026-04-24 23:03:49 +02:00
Pontoporeia
decb9e2907 fix: replace mb_strlen/mb_substr in student-preview.php (mbstring unavailable) 2026-04-24 23:03:49 +02:00
Pontoporeia
9b4cb52617 fix: replace mb_strtolower with strtolower in admin import (mbstring unavailable in php8.4-fpm) 2026-04-24 23:03:49 +02:00
Pontoporeia
e590d8e035 perf: pre-render student popover cards server-side into <template> tags — zero per-hover requests 2026-04-24 23:03:49 +02:00
Pontoporeia
ede53746ba feat: student name popover preview on /repertoire via htmx 2026-04-24 23:03:49 +02:00
Pontoporeia
d961f9533c feat: add objet field (tfe/thèse/frart) with share-link restriction and site-settings toggles 2026-04-24 23:03:49 +02:00
Pontoporeia
dbaabaf8a0 merge all migrations into schema.sql 2026-04-24 23:03:49 +02:00
Pontoporeia
38031374c1 fix(partage): smtp view missing in schema + thanks redirect broken
- 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
2026-04-24 23:03:49 +02:00
Pontoporeia
95bce2bbad Extract form CSS into form.css; scope system.css to system.php only 2026-04-24 23:03:49 +02:00
Pontoporeia
d82556c596 Unify form CSS: move licence/share-badge styles to admin.css, remove inline style from partage form 2026-04-24 23:03:49 +02:00
Pontoporeia
a3849a8e69 SmtpRelay: replace mail() stub with native socket SMTP client 2026-04-24 23:03:49 +02:00
Pontoporeia
b448d0d40c Lock body scroll: only main/inner elements scroll on admin and public pages 2026-04-24 23:03:49 +02:00
Pontoporeia
5a58eefe66 feat(admin): add SMTP test email button on parametres page 2026-04-24 23:03:49 +02:00