Implement superadmin audit log for mutations
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled

This commit is contained in:
Codex Agent
2026-01-02 11:57:49 +01:00
parent 8b4950c79d
commit 412ecbe691
82 changed files with 1766 additions and 192 deletions

View File

@@ -6,6 +6,7 @@ use App\Filament\Blog\Resources\CategoryResource\Pages;
use App\Filament\Blog\Traits\HasContentEditor;
use App\Filament\Clusters\RareAdmin\RareAdminCluster;
use App\Models\BlogCategory;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
@@ -24,6 +25,7 @@ use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Str;
@@ -116,38 +118,25 @@ class CategoryResource extends Resource
$data['description_de'] = $descArray['de'] ?? '';
$data['description_en'] = $descArray['en'] ?? '';
\Illuminate\Support\Facades\Log::info('BeforeFill Description Extraction:', [
'descJson' => $descJson,
'descArray' => $descArray,
'description_de' => $data['description_de'],
'description_en' => $data['description_en'],
]);
return $data;
}
public static function mutateFormDataBeforeCreate(array $data): array
{
\Illuminate\Support\Facades\Log::info('mutateFormDataBeforeCreate Input Data:', ['data' => $data]);
$nameData = [
'de' => $data['name_de'] ?? '',
'en' => $data['name_en'] ?? '',
];
$data['name'] = json_encode($nameData);
\Illuminate\Support\Facades\Log::info('mutateFormDataBeforeCreate Name JSON:', ['name' => $nameData]);
$descData = [
'de' => $data['description_de'] ?? '',
'en' => $data['description_en'] ?? '',
];
$data['description'] = json_encode($descData);
\Illuminate\Support\Facades\Log::info('mutateFormDataBeforeCreate Description JSON:', ['description' => $descData]);
unset($data['name_de'], $data['name_en'], $data['description_de'], $data['description_en']);
\Illuminate\Support\Facades\Log::info('mutateFormDataBeforeCreate Final Data:', $data);
return $data;
}
@@ -185,11 +174,28 @@ class CategoryResource extends Resource
//
])
->actions([
EditAction::make(),
EditAction::make()
->after(fn (array $data, BlogCategory $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]),
]);
}

View File

@@ -3,9 +3,9 @@
namespace App\Filament\Blog\Resources\CategoryResource\Pages;
use App\Filament\Blog\Resources\CategoryResource;
use Filament\Resources\Pages\CreateRecord;
use App\Filament\Resources\Pages\AuditedCreateRecord;
class CreateCategory extends CreateRecord
class CreateCategory extends AuditedCreateRecord
{
protected static string $resource = CategoryResource::class;
@@ -30,4 +30,4 @@ class CreateCategory extends CreateRecord
$this->record = static::getResource()::getModel()::create($data);
}
}
}

View File

@@ -3,17 +3,23 @@
namespace App\Filament\Blog\Resources\CategoryResource\Pages;
use App\Filament\Blog\Resources\CategoryResource;
use App\Filament\Resources\Pages\AuditedEditRecord;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditCategory extends EditRecord
class EditCategory extends AuditedEditRecord
{
protected static string $resource = CategoryResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
Actions\DeleteAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
];
}
@@ -24,7 +30,7 @@ class EditCategory extends EditRecord
'description_de' => 'nullable|string',
'name_en' => 'nullable|string|max:255',
'description_en' => 'nullable|string',
'slug' => 'required|string|max:255|unique:blog_categories,slug,' . $this->record->id,
'slug' => 'required|string|max:255|unique:blog_categories,slug,'.$this->record->id,
'is_visible' => 'boolean',
];
}
@@ -40,12 +46,13 @@ class EditCategory extends EditRecord
public function save(bool $shouldRedirect = true, bool $shouldSendSavedNotification = true): void
{
$state = $this->form->getState();
\Illuminate\Support\Facades\Log::info('EditCategory Save - Full State:', $state);
$data = $state['data'] ?? $state;
$data = \App\Filament\Blog\Resources\CategoryResource::mutateFormDataBeforeSave($data);
$this->record->update($data);
parent::afterSave();
}
}
}

View File

@@ -7,6 +7,7 @@ use App\Filament\Blog\Traits\HasContentEditor;
use App\Filament\Clusters\RareAdmin\RareAdminCluster;
use App\Models\BlogCategory;
use App\Models\BlogPost;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction;
@@ -29,6 +30,7 @@ use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\TernaryFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Str;
@@ -243,11 +245,27 @@ class PostResource extends Resource
->actions([
DeleteAction::make()
->icon('heroicon-o-trash')
->label(''),
->label('')
->after(fn (BlogPost $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]),
]);
}

View File

@@ -3,9 +3,9 @@
namespace App\Filament\Blog\Resources\PostResource\Pages;
use App\Filament\Blog\Resources\PostResource;
use Filament\Resources\Pages\CreateRecord;
use App\Filament\Resources\Pages\AuditedCreateRecord;
class CreatePost extends CreateRecord
class CreatePost extends AuditedCreateRecord
{
protected static string $resource = PostResource::class;
}
}

View File

@@ -3,10 +3,11 @@
namespace App\Filament\Blog\Resources\PostResource\Pages;
use App\Filament\Blog\Resources\PostResource;
use App\Filament\Resources\Pages\AuditedEditRecord;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditPost extends EditRecord
class EditPost extends AuditedEditRecord
{
protected static string $resource = PostResource::class;
@@ -14,7 +15,12 @@ class EditPost extends EditRecord
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\DeleteAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
];
}

View File

@@ -3,11 +3,12 @@
namespace App\Filament\Clusters\DailyOps\Resources\Photos\Pages;
use App\Filament\Clusters\DailyOps\Resources\Photos\PhotoResource;
use App\Filament\Resources\Pages\AuditedEditRecord;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\DeleteAction;
use Filament\Actions\ViewAction;
use Filament\Resources\Pages\EditRecord;
class EditPhoto extends EditRecord
class EditPhoto extends AuditedEditRecord
{
protected static string $resource = PhotoResource::class;
@@ -15,7 +16,12 @@ class EditPhoto extends EditRecord
{
return [
ViewAction::make(),
DeleteAction::make(),
DeleteAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
];
}
}

View File

@@ -5,6 +5,7 @@ namespace App\Filament\Clusters\DailyOps\Resources\Photos\Tables;
use App\Models\Event;
use App\Models\Photo;
use App\Models\Tenant;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\Action;
use Filament\Actions\BulkAction;
use Filament\Actions\BulkActionGroup;
@@ -208,6 +209,18 @@ class PhotosTable
'moderated_at' => now(),
'moderated_by' => Filament::auth()->id(),
]);
app(SuperAdminAuditLogger::class)->record(
'photo.'.$status,
$record,
SuperAdminAuditLogger::fieldsMetadata([
'status',
'moderation_notes',
'moderated_at',
'moderated_by',
]),
source: self::class
);
}
private static function applyModerationToRecords(Collection $records, string $status, ?string $notes): int
@@ -215,7 +228,7 @@ class PhotosTable
$moderatedAt = now();
$moderatedBy = Filament::auth()->id();
return Photo::query()
$updated = Photo::query()
->whereIn('id', $records->pluck('id'))
->where('status', 'pending')
->update([
@@ -224,6 +237,24 @@ class PhotosTable
'moderated_at' => $moderatedAt,
'moderated_by' => $moderatedBy,
]);
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->record(
'photo.'.$status,
$record,
SuperAdminAuditLogger::fieldsMetadata([
'status',
'moderation_notes',
'moderated_at',
'moderated_by',
]),
source: self::class
);
}
return $updated;
}
private static function statusLabels(): array

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Filament\Clusters\RareAdmin\Resources\SuperAdminActionLogs\Pages;
use App\Filament\Clusters\RareAdmin\Resources\SuperAdminActionLogs\SuperAdminActionLogResource;
use Filament\Resources\Pages\ManageRecords;
class ManageSuperAdminActionLogs extends ManageRecords
{
protected static string $resource = SuperAdminActionLogResource::class;
protected function getHeaderActions(): array
{
return [];
}
}

View File

@@ -0,0 +1,123 @@
<?php
namespace App\Filament\Clusters\RareAdmin\Resources\SuperAdminActionLogs;
use App\Filament\Clusters\RareAdmin\RareAdminCluster;
use App\Filament\Clusters\RareAdmin\Resources\SuperAdminActionLogs\Pages\ManageSuperAdminActionLogs;
use App\Models\SuperAdminActionLog;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use UnitEnum;
class SuperAdminActionLogResource extends Resource
{
protected static ?string $model = SuperAdminActionLog::class;
protected static ?string $cluster = RareAdminCluster::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedClipboardDocumentList;
protected static ?int $navigationSort = 95;
protected static ?string $recordTitleAttribute = 'action';
public static function getNavigationGroup(): UnitEnum|string|null
{
return __('admin.nav.infrastructure');
}
public static function getNavigationLabel(): string
{
return 'Audit log';
}
public static function canCreate(): bool
{
return false;
}
public static function canEdit($record): bool
{
return false;
}
public static function canDelete($record): bool
{
return false;
}
public static function canDeleteAny(): bool
{
return false;
}
public static function form(Schema $schema): Schema
{
return $schema
->components([
//
]);
}
public static function table(Table $table): Table
{
return $table
->recordTitleAttribute('action')
->columns([
TextColumn::make('action')
->badge()
->searchable()
->sortable(),
TextColumn::make('actor.fullName')
->label('Actor')
->sortable()
->searchable(),
TextColumn::make('subject_type')
->label('Subject')
->formatStateUsing(fn (?string $state) => $state ? class_basename($state) : '—')
->searchable()
->toggleable(),
TextColumn::make('subject_id')
->label('Subject ID')
->sortable()
->toggleable(),
TextColumn::make('metadata')
->label('Fields')
->formatStateUsing(function ($state): string {
if (! is_array($state)) {
return '—';
}
$fields = $state['fields'] ?? [];
return $fields ? implode(', ', $fields) : '—';
})
->toggleable(isToggledHiddenByDefault: true)
->wrap(),
TextColumn::make('source')
->label('Source')
->limit(40)
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('occurred_at')
->label('Timestamp')
->dateTime()
->sortable(),
])
->filters([
//
])
->recordActions([])
->toolbarActions([]);
}
public static function getPages(): array
{
return [
'index' => ManageSuperAdminActionLogs::route('/'),
];
}
}

View File

@@ -3,15 +3,17 @@
namespace App\Filament\Resources\Coupons\Pages;
use App\Filament\Resources\Coupons\CouponResource;
use App\Filament\Resources\Pages\AuditedCreateRecord;
use App\Jobs\SyncCouponToPaddle;
use Filament\Resources\Pages\CreateRecord;
class CreateCoupon extends CreateRecord
class CreateCoupon extends AuditedCreateRecord
{
protected static string $resource = CouponResource::class;
protected function afterCreate(): void
{
parent::afterCreate();
SyncCouponToPaddle::dispatch($this->record);
}
}

View File

@@ -3,14 +3,15 @@
namespace App\Filament\Resources\Coupons\Pages;
use App\Filament\Resources\Coupons\CouponResource;
use App\Filament\Resources\Pages\AuditedEditRecord;
use App\Jobs\SyncCouponToPaddle;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\DeleteAction;
use Filament\Actions\ForceDeleteAction;
use Filament\Actions\RestoreAction;
use Filament\Actions\ViewAction;
use Filament\Resources\Pages\EditRecord;
class EditCoupon extends EditRecord
class EditCoupon extends AuditedEditRecord
{
protected static string $resource = CouponResource::class;
@@ -19,14 +20,34 @@ class EditCoupon extends EditRecord
return [
ViewAction::make(),
DeleteAction::make()
->after(fn ($record) => SyncCouponToPaddle::dispatch($record, true)),
ForceDeleteAction::make(),
RestoreAction::make(),
->after(function ($record): void {
app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
);
SyncCouponToPaddle::dispatch($record, true);
}),
ForceDeleteAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'force_deleted',
$record,
source: static::class
)),
RestoreAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'restored',
$record,
source: static::class
)),
];
}
protected function afterSave(): void
{
parent::afterSave();
SyncCouponToPaddle::dispatch($this->record);
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Filament\Resources\Coupons\Pages;
use App\Filament\Resources\Coupons\CouponResource;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord;
@@ -13,7 +14,13 @@ class ViewCoupon extends ViewRecord
protected function getHeaderActions(): array
{
return [
EditAction::make(),
EditAction::make()
->after(fn (array $data, $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
];
}
}

View File

@@ -5,6 +5,7 @@ namespace App\Filament\Resources\Coupons\Tables;
use App\Enums\CouponStatus;
use App\Enums\CouponType;
use App\Jobs\SyncCouponToPaddle;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\Action;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
@@ -18,6 +19,7 @@ use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\TernaryFilter;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Str;
class CouponsTable
@@ -95,7 +97,13 @@ class CouponsTable
])
->recordActions([
ViewAction::make(),
EditAction::make(),
EditAction::make()
->after(fn (array $data, $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
Action::make('sync')
->label(__('Sync to Paddle'))
->icon('heroicon-m-arrow-path')
@@ -104,9 +112,42 @@ class CouponsTable
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
ForceDeleteBulkAction::make(),
RestoreBulkAction::make(),
DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
ForceDeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'force_deleted',
$record,
source: static::class
);
}
}),
RestoreBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'restored',
$record,
source: static::class
);
}
}),
]),
]);
}

View File

@@ -5,6 +5,7 @@ namespace App\Filament\Resources;
use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster;
use App\Filament\Resources\EmotionResource\Pages;
use App\Models\Emotion;
use App\Services\Audit\SuperAdminAuditLogger;
use BackedEnum;
use Filament\Actions;
use Filament\Forms\Components\MarkdownEditor;
@@ -17,6 +18,7 @@ use Filament\Schemas\Components\Tabs\Tab as SchemaTab;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
use UnitEnum;
class EmotionResource extends Resource
@@ -116,10 +118,27 @@ class EmotionResource extends Resource
])
->filters([])
->actions([
Actions\EditAction::make(),
Actions\EditAction::make()
->after(fn (array $data, Emotion $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
])
->bulkActions([
Actions\DeleteBulkAction::make(),
Actions\DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]);
}

View File

@@ -3,6 +3,7 @@
namespace App\Filament\Resources\EmotionResource\Pages;
use App\Filament\Resources\EmotionResource;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\ManageRecords;
@@ -13,7 +14,13 @@ class ManageEmotions extends ManageRecords
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
Actions\CreateAction::make()
->after(fn (array $data, $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'created',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
Actions\Action::make('import')
->label(__('admin.common.import_csv'))
->icon('heroicon-o-arrow-up-tray')

View File

@@ -6,6 +6,7 @@ use App\Exports\EventPurchaseExporter;
use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster;
use App\Filament\Resources\EventPurchaseResource\Pages;
use App\Models\EventPurchase;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\Action;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
@@ -23,6 +24,7 @@ use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\TernaryFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Log;
class EventPurchaseResource extends Resource
@@ -174,11 +176,29 @@ class EventPurchaseResource extends Resource
->action(function (EventPurchase $record) {
$record->update(['refunded_at' => now()]);
Log::info('Refund processed for purchase ID: '.$record->id);
app(SuperAdminAuditLogger::class)->record(
'event_purchase.refunded',
$record,
SuperAdminAuditLogger::fieldsMetadata(['refunded_at']),
source: static::class
);
}),
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
ExportBulkAction::make()
->label('Export CSV')
->exporter(EventPurchaseExporter::class),

View File

@@ -3,9 +3,9 @@
namespace App\Filament\Resources\EventPurchaseResource\Pages;
use App\Filament\Resources\EventPurchaseResource;
use Filament\Resources\Pages\CreateRecord;
use App\Filament\Resources\Pages\AuditedCreateRecord;
class CreateEventPurchase extends CreateRecord
class CreateEventPurchase extends AuditedCreateRecord
{
protected static string $resource = EventPurchaseResource::class;
}
}

View File

@@ -3,10 +3,11 @@
namespace App\Filament\Resources\EventPurchaseResource\Pages;
use App\Filament\Resources\EventPurchaseResource;
use App\Filament\Resources\Pages\AuditedEditRecord;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditEventPurchase extends EditRecord
class EditEventPurchase extends AuditedEditRecord
{
protected static string $resource = EventPurchaseResource::class;
@@ -14,7 +15,12 @@ class EditEventPurchase extends EditRecord
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\DeleteAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
];
}
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Filament\Resources\EventPurchaseResource\Pages;
use App\Filament\Resources\EventPurchaseResource;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
@@ -13,7 +14,13 @@ class ViewEventPurchase extends ViewRecord
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
Actions\EditAction::make()
->after(fn (array $data, $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
];
}
}
}

View File

@@ -9,6 +9,7 @@ use App\Models\Event;
use App\Models\EventJoinTokenEvent;
use App\Models\EventType;
use App\Models\Tenant;
use App\Services\Audit\SuperAdminAuditLogger;
use App\Support\JoinTokenLayoutRegistry;
use BackedEnum;
use Carbon\Carbon;
@@ -22,6 +23,7 @@ use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
use UnitEnum;
class EventResource extends Resource
@@ -133,11 +135,26 @@ class EventResource extends Resource
])
->filters([])
->actions([
Actions\EditAction::make(),
Actions\EditAction::make()
->after(fn (array $data, Event $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
Actions\Action::make('toggle')
->label(__('admin.events.actions.toggle_active'))
->icon('heroicon-o-power')
->action(fn ($record) => $record->update(['is_active' => ! $record->is_active])),
->action(function (Event $record): void {
$record->update(['is_active' => ! $record->is_active]);
app(SuperAdminAuditLogger::class)->record(
'event.toggled',
$record,
SuperAdminAuditLogger::fieldsMetadata(['is_active']),
source: static::class
);
}),
Actions\Action::make('download_photos')
->label(__('admin.events.actions.download_photos'))
->icon('heroicon-o-arrow-down-tray')
@@ -243,7 +260,18 @@ class EventResource extends Resource
}),
])
->bulkActions([
Actions\DeleteBulkAction::make(),
Actions\DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]);
}

View File

@@ -3,9 +3,9 @@
namespace App\Filament\Resources\EventResource\Pages;
use App\Filament\Resources\EventResource;
use Filament\Resources\Pages\CreateRecord;
use App\Filament\Resources\Pages\AuditedCreateRecord;
class CreateEvent extends CreateRecord
class CreateEvent extends AuditedCreateRecord
{
protected static string $resource = EventResource::class;
}

View File

@@ -3,9 +3,9 @@
namespace App\Filament\Resources\EventResource\Pages;
use App\Filament\Resources\EventResource;
use Filament\Resources\Pages\EditRecord;
use App\Filament\Resources\Pages\AuditedEditRecord;
class EditEvent extends EditRecord
class EditEvent extends AuditedEditRecord
{
protected static string $resource = EventResource::class;
}

View File

@@ -3,21 +3,21 @@
namespace App\Filament\Resources\EventResource\RelationManagers;
use App\Models\EventPackage;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\CreateAction;
use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Forms;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
@@ -93,15 +93,43 @@ class EventPackagesRelationManager extends RelationManager
])
->filters([])
->headerActions([
CreateAction::make(),
CreateAction::make()
->after(fn (array $data, EventPackage $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'created',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
])
->actions([
EditAction::make(),
DeleteAction::make(),
EditAction::make()
->after(fn (array $data, EventPackage $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
DeleteAction::make()
->after(fn (EventPackage $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]),
]);
}

View File

@@ -5,6 +5,7 @@ namespace App\Filament\Resources;
use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster;
use App\Filament\Resources\EventTypeResource\Pages;
use App\Models\EventType;
use App\Services\Audit\SuperAdminAuditLogger;
use BackedEnum;
use Filament\Actions;
use Filament\Forms\Components\KeyValue;
@@ -16,6 +17,7 @@ use Filament\Schemas\Components\Tabs\Tab as SchemaTab;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
use UnitEnum;
class EventTypeResource extends Resource
@@ -104,10 +106,27 @@ class EventTypeResource extends Resource
])
->filters([])
->actions([
Actions\EditAction::make(),
Actions\EditAction::make()
->after(fn (array $data, EventType $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
])
->bulkActions([
Actions\DeleteBulkAction::make(),
Actions\DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]);
}

View File

@@ -3,6 +3,7 @@
namespace App\Filament\Resources\EventTypeResource\Pages;
use App\Filament\Resources\EventTypeResource;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\ManageRecords;
@@ -13,7 +14,13 @@ class ManageEventTypes extends ManageRecords
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
Actions\CreateAction::make()
->after(fn (array $data, $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'created',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
];
}
}

View File

@@ -5,6 +5,7 @@ namespace App\Filament\Resources;
use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster;
use App\Filament\Resources\GiftVoucherResource\Pages;
use App\Models\GiftVoucher;
use App\Services\Audit\SuperAdminAuditLogger;
use App\Services\GiftVouchers\GiftVoucherService;
use BackedEnum;
use Carbon\Carbon;
@@ -97,6 +98,13 @@ class GiftVoucherResource extends Resource
->visible(fn (GiftVoucher $record): bool => $record->canBeRefunded())
->action(function (GiftVoucher $record, GiftVoucherService $service): void {
$service->refund($record, 'customer_request');
app(SuperAdminAuditLogger::class)->record(
'gift_voucher.refunded',
$record,
SuperAdminAuditLogger::fieldsMetadata(['status', 'refunded_at']),
source: static::class
);
})
->successNotificationTitle('Gutschein erstattet'),
Action::make('resend')
@@ -118,6 +126,13 @@ class GiftVoucherResource extends Resource
$record,
Carbon::parse($data['recipient_delivery_scheduled_at'])
);
app(SuperAdminAuditLogger::class)->record(
'gift_voucher.delivery_scheduled',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
source: static::class
);
})
->visible(fn (GiftVoucher $record): bool => ! empty($record->recipient_email)),
Action::make('mark_redeemed')
@@ -136,6 +151,13 @@ class GiftVoucherResource extends Resource
'manual_marked' => true,
]),
])->save();
app(SuperAdminAuditLogger::class)->record(
'gift_voucher.marked_redeemed',
$record,
SuperAdminAuditLogger::fieldsMetadata(['status', 'redeemed_at', 'metadata']),
source: static::class
);
})
->successNotificationTitle('Als eingelöst markiert'),
]);

View File

@@ -3,11 +3,12 @@
namespace App\Filament\Resources\GiftVoucherResource\Pages;
use App\Filament\Resources\GiftVoucherResource;
use App\Services\Audit\SuperAdminAuditLogger;
use App\Services\GiftVouchers\GiftVoucherService;
use Filament\Actions\Action;
use Filament\Resources\Pages\ListRecords;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Pages\ListRecords;
use Illuminate\Support\Str;
class ListGiftVouchers extends ListRecords
@@ -62,7 +63,20 @@ class ListGiftVouchers extends ListRecords
],
];
$service->issueFromPaddle($payload);
$voucher = $service->issueFromPaddle($payload);
app(SuperAdminAuditLogger::class)->recordModelMutation(
'issued',
$voucher,
SuperAdminAuditLogger::fieldsMetadata([
'amount',
'currency',
'status',
'expires_at',
'coupon_id',
]),
source: static::class
);
})
->modalHeading('Geschenkgutschein ausstellen'),
];

View File

@@ -5,6 +5,7 @@ namespace App\Filament\Resources;
use App\Filament\Clusters\RareAdmin\RareAdminCluster;
use App\Filament\Resources\LegalPageResource\Pages;
use App\Models\LegalPage;
use App\Services\Audit\SuperAdminAuditLogger;
use BackedEnum;
use Filament\Actions;
use Filament\Forms\Components\DatePicker;
@@ -18,6 +19,7 @@ use Filament\Schemas\Components\Tabs\Tab as SchemaTab;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
use UnitEnum;
class LegalPageResource extends Resource
@@ -99,10 +101,27 @@ class LegalPageResource extends Resource
])
->filters([])
->actions([
Actions\EditAction::make(),
Actions\EditAction::make()
->after(fn (array $data, LegalPage $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
])
->bulkActions([
Actions\DeleteBulkAction::make(),
Actions\DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]);
}

View File

@@ -3,9 +3,9 @@
namespace App\Filament\Resources\LegalPageResource\Pages;
use App\Filament\Resources\LegalPageResource;
use Filament\Resources\Pages\EditRecord;
use App\Filament\Resources\Pages\AuditedEditRecord;
class EditLegalPage extends EditRecord
class EditLegalPage extends AuditedEditRecord
{
protected static string $resource = LegalPageResource::class;
}

View File

@@ -5,6 +5,7 @@ namespace App\Filament\Resources;
use App\Filament\Clusters\RareAdmin\RareAdminCluster;
use App\Filament\Resources\MediaStorageTargetResource\Pages;
use App\Models\MediaStorageTarget;
use App\Services\Audit\SuperAdminAuditLogger;
use BackedEnum;
use Filament\Actions;
use Filament\Forms\Components\KeyValue;
@@ -15,6 +16,7 @@ use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
use UnitEnum;
class MediaStorageTargetResource extends Resource
@@ -115,10 +117,27 @@ class MediaStorageTargetResource extends Resource
])
->filters([])
->actions([
Actions\EditAction::make(),
Actions\EditAction::make()
->after(fn (array $data, MediaStorageTarget $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
])
->bulkActions([
Actions\DeleteBulkAction::make(),
Actions\DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]);
}

View File

@@ -3,10 +3,9 @@
namespace App\Filament\Resources\MediaStorageTargetResource\Pages;
use App\Filament\Resources\MediaStorageTargetResource;
use Filament\Resources\Pages\CreateRecord;
use App\Filament\Resources\Pages\AuditedCreateRecord;
class CreateMediaStorageTarget extends CreateRecord
class CreateMediaStorageTarget extends AuditedCreateRecord
{
protected static string $resource = MediaStorageTargetResource::class;
}

View File

@@ -3,18 +3,23 @@
namespace App\Filament\Resources\MediaStorageTargetResource\Pages;
use App\Filament\Resources\MediaStorageTargetResource;
use App\Filament\Resources\Pages\AuditedEditRecord;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditMediaStorageTarget extends EditRecord
class EditMediaStorageTarget extends AuditedEditRecord
{
protected static string $resource = MediaStorageTargetResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
Actions\DeleteAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
];
}
}

View File

@@ -6,6 +6,7 @@ use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster;
use App\Filament\Resources\PackageAddonResource\Pages;
use App\Jobs\SyncPackageAddonToPaddle;
use App\Models\PackageAddon;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
@@ -17,6 +18,7 @@ use Filament\Tables;
use Filament\Tables\Columns\BadgeColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
class PackageAddonResource extends Resource
{
@@ -130,11 +132,28 @@ class PackageAddonResource extends Resource
->body('Das Add-on wird im Hintergrund mit Paddle abgeglichen.')
->send();
}),
Actions\EditAction::make(),
Actions\EditAction::make()
->after(fn (array $data, PackageAddon $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
])
->bulkActions([
Actions\BulkActionGroup::make([
Actions\DeleteBulkAction::make(),
Actions\DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]),
]);
}

View File

@@ -3,9 +3,9 @@
namespace App\Filament\Resources\PackageAddonResource\Pages;
use App\Filament\Resources\PackageAddonResource;
use Filament\Resources\Pages\CreateRecord;
use App\Filament\Resources\Pages\AuditedCreateRecord;
class CreatePackageAddon extends CreateRecord
class CreatePackageAddon extends AuditedCreateRecord
{
protected static string $resource = PackageAddonResource::class;
}

View File

@@ -3,9 +3,9 @@
namespace App\Filament\Resources\PackageAddonResource\Pages;
use App\Filament\Resources\PackageAddonResource;
use Filament\Resources\Pages\EditRecord;
use App\Filament\Resources\Pages\AuditedEditRecord;
class EditPackageAddon extends EditRecord
class EditPackageAddon extends AuditedEditRecord
{
protected static string $resource = PackageAddonResource::class;

View File

@@ -7,6 +7,7 @@ use App\Filament\Resources\PackageResource\Pages;
use App\Jobs\PullPackageFromPaddle;
use App\Jobs\SyncPackageToPaddle;
use App\Models\Package;
use App\Services\Audit\SuperAdminAuditLogger;
use BackedEnum;
use Filament\Actions;
use Filament\Actions\BulkActionGroup;
@@ -37,6 +38,7 @@ use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Str;
use Illuminate\Validation\Rules\Unique;
@@ -319,20 +321,75 @@ class PackageResource extends Resource
->send();
}),
ViewAction::make(),
EditAction::make(),
EditAction::make()
->after(fn (array $data, Package $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
DeleteAction::make()
->visible(fn (Package $record) => ! $record->trashed()),
->visible(fn (Package $record) => ! $record->trashed())
->after(fn (Package $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
RestoreAction::make()
->visible(fn (Package $record) => $record->trashed()),
->visible(fn (Package $record) => $record->trashed())
->after(fn (Package $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'restored',
$record,
source: static::class
)),
ForceDeleteAction::make()
->visible(fn (Package $record) => $record->trashed())
->requiresConfirmation(),
->requiresConfirmation()
->after(fn (Package $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'force_deleted',
$record,
source: static::class
)),
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
RestoreBulkAction::make(),
ForceDeleteBulkAction::make()->requiresConfirmation(),
DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
RestoreBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'restored',
$record,
source: static::class
);
}
}),
ForceDeleteBulkAction::make()
->requiresConfirmation()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'force_deleted',
$record,
source: static::class
);
}
}),
]),
]);
}

View File

@@ -3,9 +3,9 @@
namespace App\Filament\Resources\PackageResource\Pages;
use App\Filament\Resources\PackageResource;
use Filament\Resources\Pages\CreateRecord;
use App\Filament\Resources\Pages\AuditedCreateRecord;
class CreatePackage extends CreateRecord
class CreatePackage extends AuditedCreateRecord
{
protected static string $resource = PackageResource::class;
}

View File

@@ -3,10 +3,11 @@
namespace App\Filament\Resources\PackageResource\Pages;
use App\Filament\Resources\PackageResource;
use App\Filament\Resources\Pages\AuditedEditRecord;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditPackage extends EditRecord
class EditPackage extends AuditedEditRecord
{
protected static string $resource = PackageResource::class;
@@ -14,7 +15,12 @@ class EditPackage extends EditRecord
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\DeleteAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Pages;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Resources\Pages\CreateRecord;
class AuditedCreateRecord extends CreateRecord
{
protected function afterCreate(): void
{
app(SuperAdminAuditLogger::class)->recordModelMutation(
'created',
$this->record,
SuperAdminAuditLogger::fieldsMetadata($this->form->getState()),
static::class
);
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Filament\Resources\Pages;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Resources\Pages\EditRecord;
class AuditedEditRecord extends EditRecord
{
protected function afterSave(): void
{
$changed = array_keys($this->record->getChanges());
if ($changed === []) {
return;
}
app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$this->record,
SuperAdminAuditLogger::fieldsMetadata($changed ?: $this->form->getState()),
static::class
);
}
}

View File

@@ -6,6 +6,7 @@ use App\Filament\Clusters\DailyOps\DailyOpsCluster;
use App\Filament\Resources\PhotoResource\Pages;
use App\Models\Event;
use App\Models\Photo;
use App\Services\Audit\SuperAdminAuditLogger;
use BackedEnum;
use Filament\Actions;
use Filament\Forms\Components\FileUpload;
@@ -16,6 +17,7 @@ use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
use UnitEnum;
class PhotoResource extends Resource
@@ -78,29 +80,95 @@ class PhotoResource extends Resource
])
->filters([])
->actions([
Actions\EditAction::make(),
Actions\EditAction::make()
->after(fn (array $data, Photo $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
Actions\Action::make('feature')
->label(__('admin.photos.actions.feature'))
->visible(fn (Photo $record) => ! $record->is_featured)
->action(fn (Photo $record) => $record->update(['is_featured' => true]))
->action(function (Photo $record): void {
$record->update(['is_featured' => true]);
app(SuperAdminAuditLogger::class)->record(
'photo.featured',
$record,
SuperAdminAuditLogger::fieldsMetadata(['is_featured']),
source: static::class
);
})
->icon('heroicon-o-star'),
Actions\Action::make('unfeature')
->label(__('admin.photos.actions.unfeature'))
->visible(fn (Photo $record) => $record->is_featured)
->action(fn (Photo $record) => $record->update(['is_featured' => false]))
->action(function (Photo $record): void {
$record->update(['is_featured' => false]);
app(SuperAdminAuditLogger::class)->record(
'photo.unfeatured',
$record,
SuperAdminAuditLogger::fieldsMetadata(['is_featured']),
source: static::class
);
})
->icon('heroicon-o-star'),
Actions\DeleteAction::make(),
Actions\DeleteAction::make()
->after(fn (Photo $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
])
->bulkActions([
Actions\BulkAction::make('feature')
->label(__('admin.photos.actions.feature_selected'))
->icon('heroicon-o-star')
->action(fn ($records) => $records->each->update(['is_featured' => true])),
->action(function ($records): void {
$records->each->update(['is_featured' => true]);
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->record(
'photo.featured',
$record,
SuperAdminAuditLogger::fieldsMetadata(['is_featured']),
source: static::class
);
}
}),
Actions\BulkAction::make('unfeature')
->label(__('admin.photos.actions.unfeature_selected'))
->icon('heroicon-o-star')
->action(fn ($records) => $records->each->update(['is_featured' => false])),
Actions\DeleteBulkAction::make(),
->action(function ($records): void {
$records->each->update(['is_featured' => false]);
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->record(
'photo.unfeatured',
$record,
SuperAdminAuditLogger::fieldsMetadata(['is_featured']),
source: static::class
);
}
}),
Actions\DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]);
}

View File

@@ -2,10 +2,10 @@
namespace App\Filament\Resources\PhotoResource\Pages;
use App\Filament\Resources\Pages\AuditedEditRecord;
use App\Filament\Resources\PhotoResource;
use Filament\Resources\Pages\EditRecord;
class EditPhoto extends EditRecord
class EditPhoto extends AuditedEditRecord
{
protected static string $resource = PhotoResource::class;
}

View File

@@ -2,10 +2,10 @@
namespace App\Filament\Resources\PhotoboothSettings\Pages;
use App\Filament\Resources\Pages\AuditedEditRecord;
use App\Filament\Resources\PhotoboothSettings\PhotoboothSettingResource;
use Filament\Resources\Pages\EditRecord;
class EditPhotoboothSetting extends EditRecord
class EditPhotoboothSetting extends AuditedEditRecord
{
protected static string $resource = PhotoboothSettingResource::class;

View File

@@ -2,6 +2,7 @@
namespace App\Filament\Resources\PhotoboothSettings\Tables;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\EditAction;
use Filament\Tables;
use Filament\Tables\Table;
@@ -29,7 +30,13 @@ class PhotoboothSettingsTable
->label(__('Aktualisiert')),
])
->recordActions([
EditAction::make(),
EditAction::make()
->after(fn (array $data, $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
])
->headerActions([])
->bulkActions([]);

View File

@@ -7,6 +7,7 @@ use App\Filament\Resources\PurchaseResource\Pages;
use App\Models\PackagePurchase;
use App\Notifications\Customer\RefundReceipt;
use App\Notifications\Ops\RefundProcessed;
use App\Services\Audit\SuperAdminAuditLogger;
use App\Services\Paddle\PaddleTransactionService;
use BackedEnum;
use Filament\Actions\Action;
@@ -27,6 +28,7 @@ use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
@@ -178,7 +180,13 @@ class PurchaseResource extends Resource
])
->actions([
ViewAction::make(),
EditAction::make(),
EditAction::make()
->after(fn (array $data, PackagePurchase $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
Action::make('refund')
->label('Refund')
->color('danger')
@@ -234,11 +242,29 @@ class PurchaseResource extends Resource
if ($opsEmail) {
Notification::route('mail', $opsEmail)->notify(new RefundProcessed($record, $refundSuccess, $reason, $errorMessage));
}
app(SuperAdminAuditLogger::class)->record(
'purchase.refunded',
$record,
SuperAdminAuditLogger::fieldsMetadata(['refunded', 'metadata']),
source: static::class
);
}),
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]),
])
->emptyStateHeading('No Purchases Found')

View File

@@ -2,10 +2,10 @@
namespace App\Filament\Resources\PurchaseResource\Pages;
use App\Filament\Resources\Pages\AuditedCreateRecord;
use App\Filament\Resources\PurchaseResource;
use Filament\Resources\Pages\CreateRecord;
class CreatePurchase extends CreateRecord
class CreatePurchase extends AuditedCreateRecord
{
protected static string $resource = PurchaseResource::class;
}
}

View File

@@ -2,11 +2,12 @@
namespace App\Filament\Resources\PurchaseResource\Pages;
use App\Filament\Resources\Pages\AuditedEditRecord;
use App\Filament\Resources\PurchaseResource;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditPurchase extends EditRecord
class EditPurchase extends AuditedEditRecord
{
protected static string $resource = PurchaseResource::class;
@@ -14,7 +15,12 @@ class EditPurchase extends EditRecord
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\DeleteAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
];
}
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Filament\Resources\PurchaseResource\Pages;
use App\Filament\Resources\PurchaseResource;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
@@ -13,8 +14,19 @@ class ViewPurchase extends ViewRecord
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
Actions\DeleteAction::make(),
Actions\EditAction::make()
->after(fn (array $data, $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
Actions\DeleteAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
Actions\Action::make('refund')
->label('Refund')
->color('danger')
@@ -24,6 +36,13 @@ class ViewPurchase extends ViewRecord
->action(function ($record) {
$record->update(['refunded' => true]);
// TODO: Call Paddle API for actual refund
app(SuperAdminAuditLogger::class)->record(
'purchase.refunded',
$record,
SuperAdminAuditLogger::fieldsMetadata(['refunded']),
source: static::class
);
}),
];
}

View File

@@ -5,6 +5,7 @@ namespace App\Filament\Resources;
use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster;
use App\Filament\Resources\TaskResource\Pages;
use App\Models\Task;
use App\Services\Audit\SuperAdminAuditLogger;
use BackedEnum;
use Filament\Actions;
use Filament\Forms\Components\MarkdownEditor;
@@ -17,6 +18,7 @@ use Filament\Schemas\Components\Tabs\Tab as SchemaTab;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
use UnitEnum;
class TaskResource extends Resource
@@ -163,11 +165,33 @@ class TaskResource extends Resource
])
->filters([])
->actions([
Actions\EditAction::make(),
Actions\DeleteAction::make(),
Actions\EditAction::make()
->after(fn (array $data, Task $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
Actions\DeleteAction::make()
->after(fn (Task $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
])
->bulkActions([
Actions\DeleteBulkAction::make(),
Actions\DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]);
}

View File

@@ -4,6 +4,7 @@ namespace App\Filament\Resources\TaskResource\Pages;
use App\Filament\Resources\TaskResource;
use App\Models\Task;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Form;
use Filament\Notifications\Notification;
@@ -14,7 +15,9 @@ use Illuminate\Support\Facades\Storage;
class ImportTasks extends Page
{
protected static string $resource = TaskResource::class;
protected string $view = 'filament.resources.task-resource.pages.import-tasks';
protected ?string $heading = null;
public ?string $file = null;
@@ -35,8 +38,9 @@ class ImportTasks extends Page
$this->validate();
$path = $this->form->getState()['file'] ?? null;
if (!$path || !Storage::disk('public')->exists($path)) {
if (! $path || ! Storage::disk('public')->exists($path)) {
Notification::make()->danger()->title(__('admin.notifications.file_not_found'))->send();
return;
}
@@ -58,14 +62,14 @@ class ImportTasks extends Page
private function importTasksCsv(string $file): array
{
$handle = fopen($file, 'r');
if (!$handle) {
if (! $handle) {
return [0, 0];
}
$ok = 0;
$fail = 0;
$headers = fgetcsv($handle, 0, ',');
if (!$headers) {
if (! $headers) {
return [0, 0];
}
@@ -87,7 +91,7 @@ class ImportTasks extends Page
$emotionId = DB::table('emotions')->where('name->en', $emotionNameEn)->value('id');
}
if (!$emotionId) {
if (! $emotionId) {
throw new \Exception('Emotion not found.');
}
@@ -97,7 +101,7 @@ class ImportTasks extends Page
$eventTypeId = DB::table('event_types')->where('slug', $eventTypeSlug)->value('id');
}
Task::create([
$task = Task::create([
'emotion_id' => $emotionId,
'event_type_id' => $eventTypeId,
'title' => [
@@ -113,10 +117,17 @@ class ImportTasks extends Page
'de' => $row[$map['example_text_de']] ?? null,
'en' => $row[$map['example_text_en']] ?? null,
],
'sort_order' => (int)($row[$map['sort_order']] ?? 0),
'is_active' => (int)($row[$map['is_active']] ?? 1) ? 1 : 0,
'sort_order' => (int) ($row[$map['sort_order']] ?? 0),
'is_active' => (int) ($row[$map['is_active']] ?? 1) ? 1 : 0,
]);
app(SuperAdminAuditLogger::class)->recordModelMutation(
'created',
$task,
SuperAdminAuditLogger::fieldsMetadata($task->getChanges()),
source: static::class
);
$ok++;
});
} catch (\Throwable $e) {
@@ -125,6 +136,7 @@ class ImportTasks extends Page
}
fclose($handle);
return [$ok, $fail];
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Filament\Resources\TaskResource\Pages;
use App\Filament\Resources\TaskResource;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\ManageRecords;
@@ -13,7 +14,13 @@ class ManageTasks extends ManageRecords
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
Actions\CreateAction::make()
->after(fn (array $data, $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'created',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
Actions\Action::make('import')
->label(__('admin.common.import_csv'))
->icon('heroicon-o-arrow-up-tray')

View File

@@ -3,6 +3,7 @@
namespace App\Filament\Resources\TenantFeedbackResource\Pages;
use App\Filament\Resources\TenantFeedbackResource;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\ViewRecord;
@@ -13,7 +14,12 @@ class ViewTenantFeedback extends ViewRecord
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
DeleteAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
];
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Filament\Resources\TenantFeedbackResource\Tables;
use App\Models\TenantFeedback;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\Action;
use Filament\Actions\BulkAction;
use Filament\Actions\BulkActionGroup;
@@ -182,11 +183,23 @@ class TenantFeedbackTable
'moderated_at' => now(),
'moderated_by' => Filament::auth()->id(),
]);
app(SuperAdminAuditLogger::class)->record(
'tenant_feedback.'.$status,
$record,
SuperAdminAuditLogger::fieldsMetadata([
'status',
'moderation_notes',
'moderated_at',
'moderated_by',
]),
source: self::class
);
}
private static function applyModerationToRecords(Collection $records, string $status, ?string $notes): int
{
return TenantFeedback::query()
$updated = TenantFeedback::query()
->whereIn('id', $records->pluck('id'))
->update([
'status' => $status,
@@ -194,6 +207,24 @@ class TenantFeedbackTable
'moderated_at' => now(),
'moderated_by' => Filament::auth()->id(),
]);
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->record(
'tenant_feedback.'.$status,
$record,
SuperAdminAuditLogger::fieldsMetadata([
'status',
'moderation_notes',
'moderated_at',
'moderated_by',
]),
source: self::class
);
}
return $updated;
}
private static function statusLabels(): array

View File

@@ -5,6 +5,7 @@ namespace App\Filament\Resources;
use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster;
use App\Filament\Resources\TenantPackageResource\Pages;
use App\Models\TenantPackage;
use App\Services\Audit\SuperAdminAuditLogger;
use BackedEnum;
use Filament\Actions\ActionGroup;
use Filament\Actions\BulkActionGroup;
@@ -20,6 +21,7 @@ use Filament\Schemas\Schema;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
class TenantPackageResource extends Resource
{
@@ -68,13 +70,35 @@ class TenantPackageResource extends Resource
->actions([
ActionGroup::make([
ViewAction::make(),
EditAction::make(),
DeleteAction::make(),
EditAction::make()
->after(fn (array $data, TenantPackage $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
DeleteAction::make()
->after(fn (TenantPackage $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
]),
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]),
]);
}

View File

@@ -2,10 +2,10 @@
namespace App\Filament\Resources\TenantPackageResource\Pages;
use App\Filament\Resources\Pages\AuditedCreateRecord;
use App\Filament\Resources\TenantPackageResource;
use Filament\Resources\Pages\CreateRecord;
class CreateTenantPackage extends CreateRecord
class CreateTenantPackage extends AuditedCreateRecord
{
protected static string $resource = TenantPackageResource::class;
}

View File

@@ -2,11 +2,12 @@
namespace App\Filament\Resources\TenantPackageResource\Pages;
use App\Filament\Resources\Pages\AuditedEditRecord;
use App\Filament\Resources\TenantPackageResource;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditTenantPackage extends EditRecord
class EditTenantPackage extends AuditedEditRecord
{
protected static string $resource = TenantPackageResource::class;
@@ -14,7 +15,12 @@ class EditTenantPackage extends EditRecord
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\DeleteAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
];
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Filament\Resources\TenantPackageResource\Pages;
use App\Filament\Resources\TenantPackageResource;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
@@ -13,8 +14,19 @@ class ViewTenantPackage extends ViewRecord
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
Actions\DeleteAction::make(),
Actions\EditAction::make()
->after(fn (array $data, $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
Actions\DeleteAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
];
}
}

View File

@@ -10,6 +10,7 @@ use App\Filament\Resources\TenantResource\Schemas\TenantInfolist;
use App\Jobs\AnonymizeAccount;
use App\Models\Tenant;
use App\Notifications\InactiveTenantDeletionWarning;
use App\Services\Audit\SuperAdminAuditLogger;
use App\Services\Tenant\TenantLifecycleLogger;
use BackedEnum;
use Carbon\Carbon;
@@ -27,6 +28,7 @@ use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Notification as NotificationFacade;
use Illuminate\Support\Facades\Route;
use UnitEnum;
@@ -180,7 +182,13 @@ class TenantResource extends Resource
])
->filters([])
->actions([
Actions\EditAction::make(),
Actions\EditAction::make()
->after(fn (array $data, Tenant $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
Actions\Action::make('add_package')
->label('Package hinzufügen')
->icon('heroicon-o-plus')
@@ -213,6 +221,13 @@ class TenantResource extends Resource
'price' => 0,
'metadata' => ['reason' => $data['reason'] ?? 'manual assignment'],
]);
app(SuperAdminAuditLogger::class)->record(
'tenant.package_added',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
source: static::class
);
}),
Actions\Action::make('export')
->label('Daten exportieren')
@@ -225,7 +240,18 @@ class TenantResource extends Resource
->icon('heroicon-o-shield-exclamation'),
])
->bulkActions([
Actions\DeleteBulkAction::make(),
Actions\DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]);
}
@@ -269,6 +295,13 @@ class TenantResource extends Resource
actor: Filament::auth()->user()
);
app(SuperAdminAuditLogger::class)->record(
'tenant.activated',
$record,
SuperAdminAuditLogger::fieldsMetadata(['is_active']),
source: static::class
);
return $updated;
}),
Actions\Action::make('deactivate')
@@ -287,6 +320,13 @@ class TenantResource extends Resource
actor: Filament::auth()->user()
);
app(SuperAdminAuditLogger::class)->record(
'tenant.deactivated',
$record,
SuperAdminAuditLogger::fieldsMetadata(['is_active']),
source: static::class
);
return $updated;
}),
Actions\Action::make('suspend')
@@ -305,6 +345,13 @@ class TenantResource extends Resource
actor: Filament::auth()->user()
);
app(SuperAdminAuditLogger::class)->record(
'tenant.suspended',
$record,
SuperAdminAuditLogger::fieldsMetadata(['is_suspended']),
source: static::class
);
return $updated;
}),
Actions\Action::make('unsuspend')
@@ -322,6 +369,13 @@ class TenantResource extends Resource
actor: Filament::auth()->user()
);
app(SuperAdminAuditLogger::class)->record(
'tenant.unsuspended',
$record,
SuperAdminAuditLogger::fieldsMetadata(['is_suspended']),
source: static::class
);
return $updated;
}),
Actions\Action::make('schedule_deletion')
@@ -374,6 +428,13 @@ class TenantResource extends Resource
],
Filament::auth()->user()
);
app(SuperAdminAuditLogger::class)->record(
'tenant.deletion_scheduled',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
source: static::class
);
})
->successNotificationTitle(__('admin.tenants.actions.schedule_deletion_success')),
Actions\Action::make('cancel_deletion')
@@ -398,6 +459,13 @@ class TenantResource extends Resource
],
Filament::auth()->user()
);
app(SuperAdminAuditLogger::class)->record(
'tenant.deletion_cancelled',
$record,
SuperAdminAuditLogger::fieldsMetadata(['pending_deletion_at', 'deletion_warning_sent_at']),
source: static::class
);
})
->successNotificationTitle(__('admin.tenants.actions.cancel_deletion_success')),
Actions\Action::make('anonymize_now')
@@ -415,6 +483,13 @@ class TenantResource extends Resource
'anonymize_requested',
actor: Filament::auth()->user()
);
app(SuperAdminAuditLogger::class)->record(
'tenant.anonymize_requested',
$record,
SuperAdminAuditLogger::fieldsMetadata([]),
source: static::class
);
})
->successNotificationTitle(__('admin.tenants.actions.anonymize_success')),
];
@@ -472,6 +547,13 @@ class TenantResource extends Resource
],
Filament::auth()->user()
);
app(SuperAdminAuditLogger::class)->record(
'tenant.limits_updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
source: static::class
);
}),
Actions\Action::make('update_subscription_expires_at')
->label(__('admin.tenants.actions.update_subscription_expires_at'))
@@ -508,6 +590,13 @@ class TenantResource extends Resource
],
Filament::auth()->user()
);
app(SuperAdminAuditLogger::class)->record(
'tenant.subscription_expires_at_updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
source: static::class
);
}),
Actions\Action::make('set_grace_period')
->label(__('admin.tenants.actions.set_grace_period'))
@@ -537,6 +626,13 @@ class TenantResource extends Resource
],
Filament::auth()->user()
);
app(SuperAdminAuditLogger::class)->record(
'tenant.grace_period_set',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
source: static::class
);
}),
Actions\Action::make('clear_grace_period')
->label(__('admin.tenants.actions.clear_grace_period'))
@@ -560,6 +656,13 @@ class TenantResource extends Resource
],
Filament::auth()->user()
);
app(SuperAdminAuditLogger::class)->record(
'tenant.grace_period_cleared',
$record,
SuperAdminAuditLogger::fieldsMetadata(['grace_period_ends_at']),
source: static::class
);
}),
];
}

View File

@@ -2,10 +2,10 @@
namespace App\Filament\Resources\TenantResource\Pages;
use App\Filament\Resources\Pages\AuditedEditRecord;
use App\Filament\Resources\TenantResource;
use Filament\Resources\Pages\EditRecord;
class EditTenant extends EditRecord
class EditTenant extends AuditedEditRecord
{
protected static string $resource = TenantResource::class;

View File

@@ -3,6 +3,7 @@
namespace App\Filament\Resources\TenantResource\Pages;
use App\Filament\Resources\TenantResource;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
@@ -23,7 +24,13 @@ class ViewTenant extends ViewRecord
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
Actions\EditAction::make()
->after(fn (array $data, $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
...TenantResource::lifecycleActions(),
];
}

View File

@@ -4,6 +4,7 @@ namespace App\Filament\Resources\TenantResource\Pages;
use App\Filament\Resources\TenantResource;
use App\Filament\Resources\TenantResource\Schemas\TenantLifecycleInfolist;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
use Filament\Schemas\Schema;
@@ -25,7 +26,13 @@ class ViewTenantLifecycle extends ViewRecord
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
Actions\EditAction::make()
->after(fn (array $data, $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
Actions\ActionGroup::make(TenantResource::lifecycleActions())
->label(__('admin.tenants.actions.lifecycle'))
->icon('heroicon-o-shield-exclamation'),

View File

@@ -2,6 +2,7 @@
namespace App\Filament\Resources\TenantResource\RelationManagers;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\ViewAction;
@@ -15,6 +16,7 @@ use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
class PackagePurchasesRelationManager extends RelationManager
{
@@ -130,7 +132,18 @@ class PackagePurchasesRelationManager extends RelationManager
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]),
]);
}

View File

@@ -2,22 +2,19 @@
namespace App\Filament\Resources\TenantResource\RelationManagers;
use Filament\Forms;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;
use Filament\Schemas\Schema;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\ViewAction;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\Collection;
class PurchasesRelationManager extends RelationManager
{
@@ -77,7 +74,7 @@ class PurchasesRelationManager extends RelationManager
->columns([
TextColumn::make('package_id')
->badge()
->color(fn (string $state): string => match($state) {
->color(fn (string $state): string => match ($state) {
'starter_pack' => 'info',
'pro_pack' => 'success',
'lifetime_unlimited' => 'danger',
@@ -92,7 +89,7 @@ class PurchasesRelationManager extends RelationManager
->money('EUR'),
TextColumn::make('platform')
->badge()
->color(fn (string $state): string => match($state) {
->color(fn (string $state): string => match ($state) {
'ios' => 'info',
'android' => 'success',
'web' => 'warning',
@@ -123,10 +120,19 @@ class PurchasesRelationManager extends RelationManager
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]),
]);
}
}

View File

@@ -2,6 +2,8 @@
namespace App\Filament\Resources\TenantResource\RelationManagers;
use App\Models\TenantPackage;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions\Action;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
@@ -17,6 +19,7 @@ use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
class TenantPackagesRelationManager extends RelationManager
{
@@ -92,22 +95,57 @@ class TenantPackagesRelationManager extends RelationManager
])
->headerActions([])
->actions([
EditAction::make(),
EditAction::make()
->after(fn (array $data, TenantPackage $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
Action::make('activate')
->label('Aktivieren')
->icon('heroicon-o-check-circle')
->color('success')
->action(fn ($record) => $record->update(['active' => true])),
->action(function (TenantPackage $record): void {
$record->update(['active' => true]);
app(SuperAdminAuditLogger::class)->record(
'tenant_package.activated',
$record,
SuperAdminAuditLogger::fieldsMetadata(['active']),
source: static::class
);
}),
Action::make('deactivate')
->label('Deaktivieren')
->icon('heroicon-o-x-circle')
->color('danger')
->requiresConfirmation()
->action(fn ($record) => $record->update(['active' => false])),
->action(function (TenantPackage $record): void {
$record->update(['active' => false]);
app(SuperAdminAuditLogger::class)->record(
'tenant_package.deactivated',
$record,
SuperAdminAuditLogger::fieldsMetadata(['active']),
source: static::class
);
}),
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]),
]);
}

View File

@@ -5,6 +5,7 @@ namespace App\Filament\Resources;
use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster;
use App\Filament\Resources\UserResource\Pages;
use App\Models\User;
use App\Services\Audit\SuperAdminAuditLogger;
use BackedEnum;
use Filament\Actions\ActionGroup;
use Filament\Actions\BulkActionGroup;
@@ -19,6 +20,7 @@ use Filament\Schemas\Schema;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
class UserResource extends Resource
{
@@ -98,12 +100,29 @@ class UserResource extends Resource
->actions([
ActionGroup::make([
ViewAction::make(),
EditAction::make(),
EditAction::make()
->after(fn (array $data, User $record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'updated',
$record,
SuperAdminAuditLogger::fieldsMetadata($data),
static::class
)),
]),
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
DeleteBulkAction::make()
->after(function (Collection $records): void {
$logger = app(SuperAdminAuditLogger::class);
foreach ($records as $record) {
$logger->recordModelMutation(
'deleted',
$record,
source: static::class
);
}
}),
]),
]);
}

View File

@@ -2,11 +2,11 @@
namespace App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\Pages\AuditedCreateRecord;
use App\Filament\Resources\UserResource;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Support\Facades\Hash;
class CreateUser extends CreateRecord
class CreateUser extends AuditedCreateRecord
{
protected static string $resource = UserResource::class;

View File

@@ -2,19 +2,25 @@
namespace App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\Pages\AuditedEditRecord;
use App\Filament\Resources\UserResource;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
use Illuminate\Support\Facades\Hash;
class EditUser extends EditRecord
class EditUser extends AuditedEditRecord
{
protected static string $resource = UserResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
Actions\DeleteAction::make()
->after(fn ($record) => app(SuperAdminAuditLogger::class)->recordModelMutation(
'deleted',
$record,
source: static::class
)),
];
}

View File

@@ -4,6 +4,7 @@ namespace App\Filament\SuperAdmin\Pages;
use App\Filament\Clusters\RareAdmin\RareAdminCluster;
use App\Models\GuestPolicySetting;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Forms;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
@@ -163,6 +164,26 @@ class GuestPolicySettingsPage extends Page
$settings->guest_notification_ttl_hours = $this->guest_notification_ttl_hours;
$settings->save();
app(SuperAdminAuditLogger::class)->record(
'guest_policy.updated',
$settings,
SuperAdminAuditLogger::fieldsMetadata([
'guest_downloads_enabled',
'guest_sharing_enabled',
'guest_upload_visibility',
'per_device_upload_limit',
'join_token_failure_limit',
'join_token_failure_decay_minutes',
'join_token_access_limit',
'join_token_access_decay_minutes',
'join_token_download_limit',
'join_token_download_decay_minutes',
'share_link_ttl_hours',
'guest_notification_ttl_hours',
]),
source: static::class
);
Notification::make()
->title(__('admin.guest_policy.notifications.saved'))
->success()

View File

@@ -4,6 +4,7 @@ namespace App\Filament\SuperAdmin\Pages;
use App\Filament\Clusters\RareAdmin\RareAdminCluster;
use App\Models\WatermarkSetting;
use App\Services\Audit\SuperAdminAuditLogger;
use Filament\Forms;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
@@ -128,6 +129,21 @@ class WatermarkSettingsPage extends Page
$settings->offset_y = $this->offset_y;
$settings->save();
app(SuperAdminAuditLogger::class)->record(
'watermark_settings.updated',
$settings,
SuperAdminAuditLogger::fieldsMetadata([
'asset',
'position',
'opacity',
'scale',
'padding',
'offset_x',
'offset_y',
]),
source: static::class
);
Notification::make()
->title('Wasserzeichen aktualisiert')
->success()