diff --git a/modules/audit/i18n/default_de.json b/modules/audit/i18n/default_de.json index 165c72b..778a710 100644 --- a/modules/audit/i18n/default_de.json +++ b/modules/audit/i18n/default_de.json @@ -68,5 +68,6 @@ "Lifecycle risks (7d)": "Lifecycle-Risiken (7d)", "Top lifecycle reason codes (7d)": "Top-Lifecycle-Fehlercodes (7d)", "Recent lifecycle risks (7d)": "Aktuelle Lifecycle-Risiken (7d)", - "Audit & logs": "Audit & Protokolle" + "Audit & logs": "Audit & Protokolle", + "Actor email": "Akteur-E-Mail" } diff --git a/modules/audit/i18n/default_en.json b/modules/audit/i18n/default_en.json index f6ce003..466b665 100644 --- a/modules/audit/i18n/default_en.json +++ b/modules/audit/i18n/default_en.json @@ -68,5 +68,6 @@ "Lifecycle risks (7d)": "Lifecycle risks (7d)", "Top lifecycle reason codes (7d)": "Top lifecycle reason codes (7d)", "Recent lifecycle risks (7d)": "Recent lifecycle risks (7d)", - "Audit & logs": "Audit & logs" + "Audit & logs": "Audit & logs", + "Actor email": "Actor email" } diff --git a/modules/audit/module.php b/modules/audit/module.php index 36a90c9..fd9c39a 100644 --- a/modules/audit/module.php +++ b/modules/audit/module.php @@ -24,6 +24,7 @@ return [ ['path' => 'admin/system-audit', 'target' => 'audit/system-audit/index'], ['path' => 'admin/system-audit/view', 'target' => 'audit/system-audit/view'], ['path' => 'admin/system-audit/data', 'target' => 'audit/system-audit/data'], + ['path' => 'admin/system-audit/export', 'target' => 'audit/system-audit/export'], ['path' => 'admin/system-audit/purge', 'target' => 'audit/system-audit/purge'], // Import audit pages ['path' => 'admin/import-audit', 'target' => 'audit/import-audit/index'], diff --git a/modules/audit/pages/audit/system-audit/export().php b/modules/audit/pages/audit/system-audit/export().php new file mode 100644 index 0000000..aeb4651 --- /dev/null +++ b/modules/audit/pages/audit/system-audit/export().php @@ -0,0 +1,57 @@ +query('limit'), 5000); +$filters['offset'] = 0; + +$result = app(SystemAuditService::class)->listPaged($filters); + +$resolveOutcomeLabel = static function (string $raw): string { + $outcome = SystemAuditOutcome::normalizeOr($raw, SystemAuditOutcome::Success); + return (string) t($outcome->labelToken()); +}; + +$resolveChannelLabel = static function (string $raw): string { + $channel = SystemAuditChannel::normalizeOr($raw, SystemAuditChannel::Web); + return strtoupper($channel->labelToken()); +}; + +$resolveActor = static function (array $row): string { + $name = trim((string) ($row['actor_user_display_name'] ?? '')); + if ($name !== '') { + return $name; + } + $email = trim((string) ($row['actor_user_email'] ?? '')); + return $email !== '' ? $email : ''; +}; + +$columns = [ + new ExportColumn(t('ID'), static fn (array $r): string => (string) ($r['id'] ?? '')), + new ExportColumn(t('Created'), static fn (array $r): string => (string) dt((string) ($r['created_at'] ?? ''), 'Y-m-d H:i:s')), + new ExportColumn(t('Event'), static fn (array $r): string => (string) ($r['event_type'] ?? '')), + new ExportColumn(t('Status'), static fn (array $r): string => $resolveOutcomeLabel((string) ($r['outcome'] ?? ''))), + new ExportColumn(t('Channel'), static fn (array $r): string => $resolveChannelLabel((string) ($r['channel'] ?? ''))), + new ExportColumn(t('Actor'), static fn (array $r): string => $resolveActor($r)), + new ExportColumn(t('Actor email'), static fn (array $r): string => (string) ($r['actor_user_email'] ?? '')), + new ExportColumn(t('Target type'), static fn (array $r): string => (string) ($r['target_type'] ?? '')), + new ExportColumn(t('Target UUID'), static fn (array $r): string => (string) ($r['target_uuid'] ?? '')), + new ExportColumn(t('Request ID'), static fn (array $r): string => (string) ($r['request_id'] ?? '')), + new ExportColumn(t('Error code'), static fn (array $r): string => (string) ($r['error_code'] ?? '')), +]; + +$filename = 'system-audit-' . date('Ymd-His') . '.csv'; + +exportSendCsv($filename, (array) ($result['rows'] ?? []), $columns, exportResolveFlavor($request)); diff --git a/modules/audit/pages/audit/system-audit/index(default).phtml b/modules/audit/pages/audit/system-audit/index(default).phtml index 064feb1..1d7d4b2 100644 --- a/modules/audit/pages/audit/system-audit/index(default).phtml +++ b/modules/audit/pages/audit/system-audit/index(default).phtml @@ -15,6 +15,7 @@ $searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null; $listTitle = t('System audit logs'); ob_start(); ?> + $clientFilterSchema, 'filterChipMeta' => $filterChipMeta, 'gridLang' => $gridLang, + 'exportUrl' => lurl('admin/system-audit/export'), 'labels' => [ 'created' => t('Created'), 'status' => t('Status'), diff --git a/modules/audit/web/js/pages/admin-system-audit-index.js b/modules/audit/web/js/pages/admin-system-audit-index.js index 13cf8a6..aea8f71 100644 --- a/modules/audit/web/js/pages/admin-system-audit-index.js +++ b/modules/audit/web/js/pages/admin-system-audit-index.js @@ -1,5 +1,6 @@ import { createListPageModule } from '/js/core/app-list-page-module.js'; import { withCurrentListReturn } from '/js/pages/app-list-utils.js'; +import { initListExport } from '/js/core/app-list-export.js'; createListPageModule({ configId: 'admin-system-audit-index', @@ -97,6 +98,10 @@ createListPageModule({ }, }) || {}; + if (gridConfig && config.exportUrl) { + initListExport({ gridConfig, exportUrl: config.exportUrl }); + } + return gridConfig; }, });