From 116817e2de417a0d552f0c03b8c860d6a930f5b0 Mon Sep 17 00:00:00 2001 From: andre Date: Fri, 25 Sep 2026 23:43:41 +0100 Subject: [PATCH] =?UTF-8?q?feat(backoffice):=20exporta=C3=A7=C3=A3o=20CSV?= =?UTF-8?q?=20nas=20listagens,=20com=20audit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Novo helper csv_export() (config/functions.php): CSV Excel-friendly (BOM UTF-8 + ';') e cada exportação fica no audit_log (RGPD: exportar dados pessoais tem de ser rastreável). Botão "Exportar CSV" em todas as listagens do backoffice: equipa, eventos, galerias, ginásios, horário, mensalidades, modalidades, horário de funcionamento e lixeira (pedidos de inscrição e aulas experimentais já tinham). Fecha a metade "exportação com permissões e audit" do item 6.9 (a única parte que o relatório considera ganho real à escala atual). Co-Authored-By: Claude Fable 5 --- config/functions.php | 21 +++++++++++++++++++++ views/admin/events/index.php | 13 ++++++++++++- views/admin/galerias/index.php | 10 ++++++++++ views/admin/gyms/index.php | 14 +++++++++++++- views/admin/horario/index.php | 10 ++++++++++ views/admin/memberships/index.php | 10 ++++++++++ views/admin/modalidades/index.php | 10 ++++++++++ views/admin/team/index.php | 10 ++++++++++ views/admin/trash/index.php | 14 +++++++++++++- views/admin/work_hours/index.php | 14 +++++++++++++- 10 files changed, 122 insertions(+), 4 deletions(-) diff --git a/config/functions.php b/config/functions.php index 1ad6cc0..26a22b7 100644 --- a/config/functions.php +++ b/config/functions.php @@ -100,6 +100,27 @@ function format_date_pt(string $date): string { return (new DateTime($date))->format('d/m/Y'); } +// ─── CSV export (backoffice listings) ──────────────────────────────────────── +// Excel-friendly CSV (UTF-8 BOM + ';'). Every export is recorded in the audit +// log — RGPD requires personal-data exports to be traceable. +function csv_export(string $type, string $filename, string $summary, array $header, array $rows): void { + audit('export.' . $type, [ + 'target_type' => $type, + 'target_label' => 'CSV (' . count($rows) . ' registos)', + 'summary' => $summary, + ]); + header('Content-Type: text/csv; charset=utf-8'); + header('Content-Disposition: attachment; filename="' . $filename . '-' . date('Y-m-d') . '.csv"'); + $out = fopen('php://output', 'w'); + fwrite($out, "\xEF\xBB\xBF"); + fputcsv($out, $header, ';', '"', ''); + foreach ($rows as $row) { + fputcsv($out, $row, ';', '"', ''); + } + fclose($out); + exit; +} + // ─── Email template loader ──────────────────────────────────────────────────── // {{placeholder}} HTML bodies under templates/emails/. Built locally, delivered // by id.andmore.pt via the enqueue_email()/flush_message() façade. diff --git a/views/admin/events/index.php b/views/admin/events/index.php index bf59357..8a14491 100644 --- a/views/admin/events/index.php +++ b/views/admin/events/index.php @@ -15,6 +15,14 @@ if (isset($_POST['delete']) && is_numeric($_POST['delete'])) { $items = db_events_list($pdo, true); // include soft-deleted so they can be restored +if (isset($_GET['csv'])) { + $rows = []; + foreach ($items as $item) { + $rows[] = [$item['title'], $item['summary'] ?? '', format_date_pt((string) $item['publish_from']), format_date_pt((string) $item['publish_until']), events_status($item), db_event_leads_count($pdo, (int) $item['e_id'])]; + } + csv_export('event', 'eventos', 'Exportação CSV de eventos', ['Evento', 'Resumo', 'Início', 'Fim', 'Estado', 'Leads'], $rows); +} + // Status badge styling + label (PT). $badge = [ 'active' => ['bg-success', 'Ativo'], @@ -30,7 +38,10 @@ include __DIR__ . '/../../../includes/header.php';
diff --git a/views/admin/galerias/index.php b/views/admin/galerias/index.php index ee9b4d1..5aaeb43 100644 --- a/views/admin/galerias/index.php +++ b/views/admin/galerias/index.php @@ -26,6 +26,15 @@ if (isset($_POST['optimize_all'])) { } $galleries = db_gallery_list($pdo); + +if (isset($_GET['csv'])) { + $rows = []; + foreach ($galleries as $g) { + $rows[] = [$g['name']]; + } + csv_export('gallery', 'galerias', 'Exportação CSV de galerias', ['Nome'], $rows); +} + $page_title = 'Galerias'; include __DIR__ . '/../../../includes/header.php'; ?> @@ -33,6 +42,7 @@ include __DIR__ . '/../../../includes/header.php';

Galerias

+ Exportar CSV