Publier Globinours 1.0.0-rc.3

This commit is contained in:
Alexandre NOEL 2026-09-03 12:39:15 +02:00
commit 9a2b4068da
325 changed files with 38230 additions and 20 deletions

View file

@ -0,0 +1,113 @@
<?php
declare(strict_types=1);
final class PrivacyController
{
private static function admin(): void
{
if (!Auth::is('admin')) {
http_response_code(403);
echo h(t('settings.admin_only'));
exit();
}
}
public static function index(): void
{
self::admin();
$settings = AppSettings::all();
$years = max(1, (int) ($settings['privacy_retention_years'] ?? 5));
render('settings_privacy.php', [
'title' => 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 dun 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();
}
}
}