['width' => 1080, 'height' => 1080, 'format' => 'webp'], NovaCardExport::TYPE_HIRES => ['width' => 2160, 'height' => 2160, 'format' => 'webp'], NovaCardExport::TYPE_SQUARE => ['width' => 1080, 'height' => 1080, 'format' => 'webp'], NovaCardExport::TYPE_STORY => ['width' => 1080, 'height' => 1920, 'format' => 'webp'], NovaCardExport::TYPE_WALLPAPER => ['width' => 2560, 'height' => 1440, 'format' => 'webp'], NovaCardExport::TYPE_OG => ['width' => 1200, 'height' => 630, 'format' => 'jpg'], ]; public function requestExport(User $user, NovaCard $card, string $exportType, array $options = []): NovaCardExport { if (! $card->allow_export && ! $card->isOwnedBy($user)) { abort(403, 'This card does not allow exports.'); } $spec = self::EXPORT_SPECS[$exportType] ?? self::EXPORT_SPECS[NovaCardExport::TYPE_PREVIEW]; // Reuse a recent pending/ready non-expired export for the same type. $existing = NovaCardExport::query() ->where('card_id', $card->id) ->where('user_id', $user->id) ->where('export_type', $exportType) ->whereIn('status', [NovaCardExport::STATUS_READY, NovaCardExport::STATUS_PENDING, NovaCardExport::STATUS_PROCESSING]) ->where('expires_at', '>', now()) ->orderByDesc('created_at') ->first(); if ($existing !== null) { return $existing; } $export = NovaCardExport::query()->create([ 'card_id' => $card->id, 'user_id' => $user->id, 'export_type' => $exportType, 'status' => NovaCardExport::STATUS_PENDING, 'width' => $spec['width'], 'height' => $spec['height'], 'format' => $spec['format'], 'options_json' => $options, 'expires_at' => now()->addMinutes(self::EXPORT_TTL_MINUTES), ]); GenerateNovaCardExportJob::dispatch($export->id) ->onQueue((string) config('nova_cards.render.queue', 'default')); return $export->refresh(); } public function getStatus(NovaCardExport $export): array { return [ 'id' => (int) $export->id, 'export_type' => (string) $export->export_type, 'status' => (string) $export->status, 'output_url' => $export->isReady() && ! $export->isExpired() ? $export->outputUrl() : null, 'width' => $export->width, 'height' => $export->height, 'format' => (string) $export->format, 'ready_at' => optional($export->ready_at)?->toISOString(), 'expires_at' => optional($export->expires_at)?->toISOString(), ]; } public function cleanupExpired(): int { $exports = NovaCardExport::query() ->where('expires_at', '<', now()) ->whereNotNull('output_path') ->get(); $count = 0; foreach ($exports as $export) { $disk = Storage::disk((string) config('nova_cards.storage.public_disk', 'public')); if ($export->output_path && $disk->exists($export->output_path)) { $disk->delete($export->output_path); } $export->delete(); $count++; } return $count; } }