t('privacy.title'), 'settings' => $settings, 'review' => PrivacyService::retentionReview($years), 'accesses' => PrivacyService::accessLog(), 'saved' => isset($_GET['saved']), 'error' => (string) ($_GET['error'] ?? ''), ]); } public static function save(): void { self::admin(); self::postOnly(); $values = []; foreach ( [ 'privacy_retention_years' => 5, 'privacy_retention_adopter_years' => 5, 'privacy_retention_foster_years' => 5, 'privacy_retention_volunteer_years' => 5, ] as $key => $default ) { $values[$key] = (string) max(1, min(30, (int) ($_POST[$key] ?? $default))); } $values['privacy_access_log_months'] = (string) max( 1, min(120, (int) ($_POST['privacy_access_log_months'] ?? 24)), ); AppSettings::save($values, Auth::id()); AuditService::log( 'privacy_settings_saved', '/settings/privacy/save', 'Politique de conservation modifiée', null, null, $values, ); header('Location: /settings/privacy?saved=1'); exit(); } public static function export(): void { self::admin(); $id = (int) ($_GET['id'] ?? 0); try { $path = PrivacyService::exportContact($id); PrivacyService::logAccess('contact_export', $id, null, 'contact-' . $id . '.zip', 'download'); AuditService::log( 'contact_exported', '/settings/privacy/export', 'Export RGPD d’un contact', 'contact', $id, ); header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename="contact-' . $id . '-globinours.zip"'); header('Content-Length: ' . filesize($path)); header('Cache-Control: private,no-store'); readfile($path); @unlink($path); } catch (RuntimeException $e) { http_response_code(404); echo h($e->getMessage()); } catch (Throwable $e) { http_response_code(500); echo h(SecurityService::publicError($e)); } } public static function anonymize(): void { self::admin(); self::postOnly(); $id = (int) ($_POST['id'] ?? 0); try { if (!isset($_POST['confirm_reviewed'])) { throw new RuntimeException(t('privacy.review_required')); } PrivacyService::anonymize($id, (string) ($_POST['reason'] ?? '')); header('Location: /settings/privacy?saved=1'); } catch (Throwable $e) { header('Location: /settings/privacy?error=' . rawurlencode($e->getMessage())); } exit(); } private static function postOnly(): void { if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { http_response_code(405); header('Allow: POST'); exit(); } } }