172 lines
5.7 KiB
PHP
172 lines
5.7 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Resources\FindingResource\Pages;
|
|
|
|
use App\Filament\Resources\FindingResource;
|
|
use App\Models\Finding;
|
|
use App\Models\Tenant;
|
|
use App\Models\User;
|
|
use Filament\Actions;
|
|
use Filament\Forms\Components\TextInput;
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Resources\Pages\ListRecords;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Facades\Gate;
|
|
|
|
class ListFindings extends ListRecords
|
|
{
|
|
protected static string $resource = FindingResource::class;
|
|
|
|
protected function getHeaderActions(): array
|
|
{
|
|
return [
|
|
Actions\Action::make('acknowledge_all_matching')
|
|
->label('Acknowledge all matching')
|
|
->icon('heroicon-o-check')
|
|
->color('gray')
|
|
->requiresConfirmation()
|
|
->authorize(function (): bool {
|
|
$tenant = Tenant::current();
|
|
$user = auth()->user();
|
|
|
|
if (! $tenant || ! $user instanceof User) {
|
|
return false;
|
|
}
|
|
|
|
$probe = new Finding(['tenant_id' => $tenant->getKey()]);
|
|
|
|
return $user->can('update', $probe);
|
|
})
|
|
->visible(fn (): bool => $this->getStatusFilterValue() === Finding::STATUS_NEW)
|
|
->modalDescription(function (): string {
|
|
$count = $this->getAllMatchingCount();
|
|
|
|
return "You are about to acknowledge {$count} finding".($count === 1 ? '' : 's').' matching the current filters.';
|
|
})
|
|
->form(function (): array {
|
|
$count = $this->getAllMatchingCount();
|
|
|
|
if ($count <= 100) {
|
|
return [];
|
|
}
|
|
|
|
return [
|
|
TextInput::make('confirmation')
|
|
->label('Type ACKNOWLEDGE to confirm')
|
|
->required()
|
|
->in(['ACKNOWLEDGE'])
|
|
->validationMessages([
|
|
'in' => 'Please type ACKNOWLEDGE to confirm.',
|
|
]),
|
|
];
|
|
})
|
|
->action(function (array $data): void {
|
|
$tenant = Tenant::current();
|
|
$user = auth()->user();
|
|
|
|
if (! $tenant || ! $user instanceof User) {
|
|
return;
|
|
}
|
|
|
|
$query = $this->buildAllMatchingQuery();
|
|
$count = (clone $query)->count();
|
|
|
|
if ($count === 0) {
|
|
Notification::make()
|
|
->title('No matching findings')
|
|
->body('There are no new findings matching the current filters.')
|
|
->warning()
|
|
->send();
|
|
|
|
return;
|
|
}
|
|
|
|
$firstRecord = (clone $query)->first();
|
|
if ($firstRecord instanceof Finding) {
|
|
Gate::authorize('update', $firstRecord);
|
|
}
|
|
|
|
$updated = $query->update([
|
|
'status' => Finding::STATUS_ACKNOWLEDGED,
|
|
'acknowledged_at' => now(),
|
|
'acknowledged_by_user_id' => $user->getKey(),
|
|
]);
|
|
|
|
$this->deselectAllTableRecords();
|
|
$this->resetPage();
|
|
|
|
Notification::make()
|
|
->title('Bulk acknowledge completed')
|
|
->body("Acknowledged {$updated} finding".($updated === 1 ? '' : 's').'.')
|
|
->success()
|
|
->send();
|
|
}),
|
|
];
|
|
}
|
|
|
|
protected function buildAllMatchingQuery(): Builder
|
|
{
|
|
$tenant = Tenant::current();
|
|
|
|
$query = Finding::query();
|
|
|
|
if (! $tenant) {
|
|
return $query->whereRaw('1 = 0');
|
|
}
|
|
|
|
$query->where('tenant_id', $tenant->getKey());
|
|
|
|
$query->where('status', Finding::STATUS_NEW);
|
|
|
|
$findingType = $this->getFindingTypeFilterValue();
|
|
if (is_string($findingType) && $findingType !== '') {
|
|
$query->where('finding_type', $findingType);
|
|
}
|
|
|
|
$scopeKeyState = $this->getTableFilterState('scope_key') ?? [];
|
|
$scopeKey = Arr::get($scopeKeyState, 'scope_key');
|
|
if (is_string($scopeKey) && $scopeKey !== '') {
|
|
$query->where('scope_key', $scopeKey);
|
|
}
|
|
|
|
$runIdsState = $this->getTableFilterState('run_ids') ?? [];
|
|
$baselineRunId = Arr::get($runIdsState, 'baseline_run_id');
|
|
if (is_numeric($baselineRunId)) {
|
|
$query->where('baseline_run_id', (int) $baselineRunId);
|
|
}
|
|
|
|
$currentRunId = Arr::get($runIdsState, 'current_run_id');
|
|
if (is_numeric($currentRunId)) {
|
|
$query->where('current_run_id', (int) $currentRunId);
|
|
}
|
|
|
|
return $query;
|
|
}
|
|
|
|
protected function getAllMatchingCount(): int
|
|
{
|
|
return (int) $this->buildAllMatchingQuery()->count();
|
|
}
|
|
|
|
protected function getStatusFilterValue(): string
|
|
{
|
|
$state = $this->getTableFilterState('status') ?? [];
|
|
$value = Arr::get($state, 'value');
|
|
|
|
return is_string($value) && $value !== ''
|
|
? $value
|
|
: Finding::STATUS_NEW;
|
|
}
|
|
|
|
protected function getFindingTypeFilterValue(): string
|
|
{
|
|
$state = $this->getTableFilterState('finding_type') ?? [];
|
|
$value = Arr::get($state, 'value');
|
|
|
|
return is_string($value) && $value !== ''
|
|
? $value
|
|
: Finding::FINDING_TYPE_DRIFT;
|
|
}
|
|
}
|