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

4.1 KiB

TFE Access Restriction Feature

Admin Edit Form — File Management

  • Add cover image upload/preview/remove to edit.php
  • Add existing thesis files listing with per-file delete checkboxes
  • Add new thesis files upload field (PDF, JPG, PNG, MP4, ZIP, VTT)
  • Add deleteThesisFile() and handleCoverUpload() to Database.php
  • Update ThesisEditController::save() to handle cover, file deletion, new uploads
  • Update ThesisEditController::load() to expose currentFiles + currentCover
  • Rework Fichiers fieldset layout: inline file inputs (no partial double-label), banner moved inside fieldset, one label per field

Overview

Add access restriction for TFE attached files based on user email domain, with admin validation workflow.

Implementation Plan

1. Database Changes

  • Add restricted_files_enabled setting to site_settings table
  • Create file_access_requests table
    • id, thesis_id, email, justification, status (pending/approved/rejected), admin_notes, created_at, approved_at, approved_by_admin_id
  • Create file_access_tokens table (short-lived, one-time email links, 24h)
    • id, request_id, token (unique), expires_at, used_at (one-time mark)
  • Create file_access_sessions table (long-lived browser sessions, 30 days)
    • id, request_id, session_token, expires_at, is_valid
  • Create file_access_audit table (IP, UA, timestamp on redemption)

2. Configuration

  • Add restricted_files_enabled checkbox in parametres.php (Formulaire section)
  • Update settings.php action handler to persist the setting

3. Public TFE View (tfe.php) - Restricted Access UI

  • TfeController checks restricted flag + access_type_id=2 + cookie session
  • French text: "Accès restreint — Les fichiers attachés à ce TFE sont réservés aux utilisateurs autorisés."
  • Request form: email input + conditional justification textarea (non-ERG only)
  • JS: shows/hides justification textarea based on email domain (@erg.school / @erg.be)
  • Form submits via fetch POST to /request-access.php with CSRF token
  • Metadata, title, authors, synopsis all remain visible regardless of restriction

4. Email Flow

  • @erg.school / @erg.be → auto-approve, generate 24h one-time token, send email immediately
  • External email → create pending request, notify admin by email
  • Admin approves → generate 24h token, send email to requester
  • Email contains link to GET /validate-access (confirmation page) → POST to redeem

5. Secure Token Redemption

  • One-time email token (24h, marked used_at on first click, is_valid=0)
  • GET /validate-access → shows confirmation page (no side effects)
  • POST /validate-access → redeems token (CSRF required), creates browser session cookie
  • Cookie: HttpOnly; Secure; SameSite=Strict; 30 days
  • Session stored in file_access_sessions (separate from one-time email token)
  • TfeController checks file_access_sessions via hasValidCookieAccess()
  • Audit trail: IP, User-Agent, timestamp in file_access_audit on every redemption attempt

6. Admin Panel - Access Requests Management

  • Admin page: /admin/file-access.php (linked from admin nav with pending badge)
  • List pending/approved/rejected requests with tab filters and pagination
  • Approve dialog (with optional note) → sends 24h access email
  • Reject dialog (with optional note)
  • Bug fix: $vars was never extract()ed — page was blank
  • Bug fix: template included head.php/header.php/footer.php itself (double-include)
  • Bug fix: admin approval URL used $requestId instead of $request['thesis_id']

7. Security

  • One-time use tokens (used_at + is_valid=0)
  • POST-based redemption (token in hidden form field, not URL action)
  • 256-bit random tokens, rate limiting on request submission (3/10min per IP)
  • HttpOnly cookie + SameSite=Strict
  • CSRF on all mutations
  • Audit trail (IP, UA, event, timestamp)
  • Short-lived email links (24h), long-lived browser sessions (30 days)
  • App::boot() starts session for all public requests (CSRF token available everywhere)