trim((string) $request->query('status', 'all')), 'engine' => trim((string) $request->query('engine', 'all')), 'mode' => trim((string) $request->query('mode', 'all')), 'scale' => trim((string) $request->query('scale', 'all')), 'user' => trim((string) $request->query('user', '')), 'date_from' => trim((string) $request->query('date_from', '')), 'date_to' => trim((string) $request->query('date_to', '')), ]; $jobs = EnhanceJob::query() ->with(['user:id,name,username', 'artwork:id,title,slug']) ->when($filters['status'] !== '' && $filters['status'] !== 'all', fn ($query) => $query->where('status', $filters['status'])) ->when($filters['engine'] !== '' && $filters['engine'] !== 'all', fn ($query) => $query->where('engine', $filters['engine'])) ->when($filters['mode'] !== '' && $filters['mode'] !== 'all', fn ($query) => $query->where('mode', $filters['mode'])) ->when($filters['scale'] !== '' && $filters['scale'] !== 'all', fn ($query) => $query->where('scale', (int) $filters['scale'])) ->when($filters['user'] !== '', function ($query) use ($filters): void { $query->whereHas('user', function ($userQuery) use ($filters): void { $userQuery ->where('name', 'like', '%' . $filters['user'] . '%') ->orWhere('username', 'like', '%' . $filters['user'] . '%'); }); }) ->when($filters['date_from'] !== '', fn ($query) => $query->whereDate('created_at', '>=', $filters['date_from'])) ->when($filters['date_to'] !== '', fn ($query) => $query->whereDate('created_at', '<=', $filters['date_to'])) ->latest('id') ->paginate(20) ->withQueryString() ->through(fn (EnhanceJob $job): array => $this->serializeJob($job)); return Inertia::render('Moderation/Enhance/Index', [ 'title' => 'Enhance Jobs', 'jobs' => $jobs, 'filters' => $filters, 'options' => [ 'statuses' => ['all', 'pending', 'queued', 'processing', 'completed', 'failed', 'cancelled', 'expired'], 'engines' => ['all', 'stub', 'external_worker'], 'modes' => array_merge(['all'], (array) config('enhance.allowed_modes', [])), 'scales' => array_merge(['all'], array_map('intval', (array) config('enhance.allowed_scales', []))), ], 'indexUrl' => route('admin.enhance.index'), 'enhanceConfig' => $this->enhanceService->frontendConfig(), ])->rootView('moderation'); } public function show(EnhanceJob $enhanceJob): Response { $enhanceJob->loadMissing(['user:id,name,username', 'artwork:id,title,slug']); return Inertia::render('Moderation/Enhance/Show', [ 'title' => 'Enhance Job #' . $enhanceJob->id, 'job' => $this->serializeJob($enhanceJob, true), 'indexUrl' => route('admin.enhance.index'), 'enhanceConfig' => $this->enhanceService->frontendConfig(), ])->rootView('moderation'); } public function retry(EnhanceJob $enhanceJob): RedirectResponse { $this->authorize('retry', $enhanceJob); $job = $this->enhanceService->retry($enhanceJob); return redirect() ->route('admin.enhance.show', ['enhanceJob' => $job]) ->with('success', 'Enhance job queued again.'); } public function markFailed(Request $request, EnhanceJob $enhanceJob): RedirectResponse { $this->authorize('markFailed', $enhanceJob); $job = $this->enhanceService->markFailedByModerator($enhanceJob, $request->user()); return redirect() ->route('admin.enhance.show', ['enhanceJob' => $job]) ->with('success', 'Enhance job marked as failed.'); } public function destroy(EnhanceJob $enhanceJob): RedirectResponse { $this->authorize('delete', $enhanceJob); $this->enhanceService->delete($enhanceJob); return redirect() ->route('admin.enhance.index') ->with('success', 'Enhance job deleted.'); } private function serializeJob(EnhanceJob $job, bool $detailed = false): array { return [ 'id' => $job->id, 'status' => (string) $job->status, 'engine' => (string) $job->engine, 'mode' => (string) $job->mode, 'scale' => (int) $job->scale, 'source_url' => $job->sourceUrl(), 'output_url' => $job->outputUrl(), 'preview_url' => $job->previewUrl(), 'input_width' => (int) ($job->input_width ?? 0), 'input_height' => (int) ($job->input_height ?? 0), 'input_filesize' => (int) ($job->input_filesize ?? 0), 'input_mime' => $job->input_mime, 'output_width' => (int) ($job->output_width ?? 0), 'output_height' => (int) ($job->output_height ?? 0), 'output_filesize' => (int) ($job->output_filesize ?? 0), 'output_mime' => $job->output_mime, 'processing_seconds' => $job->processing_seconds, 'error_message' => $job->error_message, 'metadata' => $job->metadata ?? [], 'created_at' => optional($job->created_at)?->toIso8601String(), 'queued_at' => optional($job->queued_at)?->toIso8601String(), 'started_at' => optional($job->started_at)?->toIso8601String(), 'finished_at' => optional($job->finished_at)?->toIso8601String(), 'expires_at' => optional($job->expires_at)?->toIso8601String(), 'user' => $job->user ? [ 'id' => $job->user->id, 'name' => $job->user->name, 'username' => $job->user->username, ] : null, 'artwork' => $job->artwork ? [ 'id' => $job->artwork->id, 'title' => $job->artwork->title, 'slug' => $job->artwork->slug, 'url' => route('art.show', ['id' => $job->artwork->id, 'slug' => $job->artwork->slug]), ] : null, 'show_url' => route('admin.enhance.show', ['enhanceJob' => $job]), 'download_url' => $job->outputUrl(), 'retry_url' => route('admin.enhance.retry', ['enhanceJob' => $job]), 'mark_failed_url' => route('admin.enhance.mark-failed', ['enhanceJob' => $job]), 'delete_url' => route('admin.enhance.destroy', ['enhanceJob' => $job]), 'can_retry' => $job->status === EnhanceJob::STATUS_FAILED, 'can_mark_failed' => in_array($job->status, [EnhanceJob::STATUS_PENDING, EnhanceJob::STATUS_QUEUED, EnhanceJob::STATUS_PROCESSING], true), 'detailed' => $detailed, ]; } }