Files
fotospiel-app/app/Services/Audit/SuperAdminAuditLogger.php
Codex Agent 8f13465415
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled
Implement tenant announcements and audit log fixes
2026-01-02 14:19:46 +01:00

133 lines
3.2 KiB
PHP

<?php
namespace App\Services\Audit;
use App\Models\SuperAdminActionLog;
use App\Models\User;
use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class SuperAdminAuditLogger
{
/**
* @param array<string, array<int, string>> $metadata
*/
public function record(
string $action,
?Model $subject = null,
array $metadata = [],
?User $actor = null,
?string $source = null
): ?SuperAdminActionLog {
$actor = $actor ?? Filament::auth()->user();
if (! $this->shouldLog($actor)) {
return null;
}
$metadata = $this->sanitizeMetadata($metadata);
return SuperAdminActionLog::create([
'actor_id' => $actor?->getKey(),
'action' => $action,
'subject_type' => $subject?->getMorphClass(),
'subject_id' => $subject?->getKey(),
'source' => $source,
'metadata' => $metadata ?: null,
'occurred_at' => now(),
]);
}
/**
* @param array<string, array<int, string>> $metadata
*/
public function recordModelMutation(
string $operation,
Model $record,
array $metadata = [],
?string $source = null,
?User $actor = null
): ?SuperAdminActionLog {
if ($operation === 'updated') {
$changed = array_keys($record->getChanges());
if ($changed === []) {
return null;
}
$metadata = self::fieldsMetadata($changed);
}
$action = $this->formatAction($record, $operation);
return $this->record(
$action,
$record,
$metadata,
$actor,
$source
);
}
/**
* @param array<int, string>|array<string, mixed> $data
* @return array<string, array<int, string>>
*/
public static function fieldsMetadata(array $data): array
{
$fields = array_is_list($data) ? $data : array_keys($data);
return ['fields' => array_values(array_unique($fields))];
}
private function shouldLog(?User $actor): bool
{
if (! $actor || $actor->role !== 'super_admin') {
return false;
}
$panel = Filament::getCurrentPanel();
if ($panel) {
return $panel->getId() === 'superadmin';
}
if (app()->runningInConsole()) {
return false;
}
return request()->is('super-admin*');
}
/**
* @param array<string, array<int, string>> $metadata
* @return array<string, array<int, string>>
*/
private function sanitizeMetadata(array $metadata): array
{
$sanitized = [];
foreach ($metadata as $key => $value) {
if (! is_array($value)) {
continue;
}
$values = array_values(array_filter($value, fn ($item) => is_string($item) && $item !== ''));
if ($values === []) {
continue;
}
$sanitized[$key] = $values;
}
return $sanitized;
}
private function formatAction(Model $record, string $operation): string
{
return Str::kebab(class_basename($record)).'.'.$operation;
}
}