authorizeAbility($request, 'audit.view'); $organization = $this->organization($request); $logs = $this->query($request, $organization)->paginate(50)->withQueryString(); return view('qms.audit.index', [ 'logs' => $logs, 'organization' => $organization, 'actions' => config('qms.audit_actions'), 'canExport' => app(QmsPermissions::class)->can($this->member($request), 'audit.export'), ]); } public function export(Request $request): StreamedResponse { $this->authorizeAbility($request, 'audit.export'); $organization = $this->organization($request); $filename = 'queue-audit-'.now()->format('Y-m-d-His').'.csv'; return response()->streamDownload(function () use ($request, $organization) { $handle = fopen('php://output', 'w'); fputcsv($handle, ['Time', 'Action', 'Actor', 'Subject', 'Metadata', 'IP']); $this->query($request, $organization)->chunk(200, function ($logs) use ($handle) { foreach ($logs as $log) { fputcsv($handle, [ $log->created_at?->toDateTimeString(), $log->action, $log->actor_ref ?? '—', $log->subject_type ? class_basename($log->subject_type).' #'.$log->subject_id : '—', json_encode($log->metadata ?? []), $log->ip_address ?? '—', ]); } }); fclose($handle); }, $filename, ['Content-Type' => 'text/csv']); } protected function query(Request $request, $organization) { return AuditLog::owned($this->ownerRef($request)) ->where('organization_id', $organization->id) ->when($request->action, fn ($q, $action) => $q->where('action', $action)) ->when($request->from, fn ($q, $from) => $q->where('created_at', '>=', Carbon::parse($from)->startOfDay())) ->when($request->to, fn ($q, $to) => $q->where('created_at', '<=', Carbon::parse($to)->endOfDay())) ->when($request->q, function ($q, $search) { $q->where(function ($inner) use ($search) { $inner->where('action', 'like', "%{$search}%") ->orWhere('metadata', 'like', "%{$search}%"); }); }) ->orderByDesc('created_at'); } }