addMinutes(5), function (): ?HomepageAnnouncement { return HomepageAnnouncement::query() ->published() ->active() ->visibleNow() ->forPlacement(HomepageAnnouncement::PLACEMENT_HOMEPAGE_AFTER_FEATURED) ->orderByDesc('priority') ->orderByDesc('starts_at') ->first(); }); } public function clearActiveCache(): void { Cache::forget(self::ACTIVE_CACHE_KEY); } /** * @param array $attributes * @return array */ public function sanitizeAttributes(array $attributes): array { foreach (['primary_link_url', 'secondary_link_url'] as $key) { $attributes[$key] = $this->sanitizer->sanitizeCustomUrl($attributes[$key] ?? null); } $attributes['content_html'] = $this->sanitizer->sanitizeHtml($attributes['content_html'] ?? null); return $attributes; } public function toHomepagePayload(?HomepageAnnouncement $announcement): ?array { if (! $announcement) { return null; } return [ 'id' => (int) $announcement->id, 'dismiss_version' => max(1, (int) $announcement->dismiss_version), 'title' => (string) $announcement->title, 'subtitle' => $announcement->subtitle, 'badge_text' => $announcement->badge_text, 'content_html' => $announcement->content_html, 'gradient_preset' => $announcement->gradient_preset, 'theme_preset' => $announcement->theme_preset, 'background_image_url' => $this->resolveBackgroundImageUrl($announcement->background_image), 'is_dismissible' => (bool) $announcement->is_dismissible, 'overlay_opacity' => (int) ($announcement->overlay_opacity ?? 55), 'primary_link' => $this->buildLinkPayload($announcement, 'primary'), 'secondary_link' => $this->buildLinkPayload($announcement, 'secondary'), ]; } /** * @param array $attributes */ public function previewPayload(array $attributes): ?array { $announcement = new HomepageAnnouncement(); $announcement->forceFill($this->sanitizeAttributes($attributes)); $announcement->id = 0; return $this->toHomepagePayload($announcement); } private function buildLinkPayload(HomepageAnnouncement $announcement, string $prefix): ?array { $label = trim((string) $announcement->getAttribute($prefix . '_link_label')); if ($label === '') { return null; } $url = $this->resolveLinkUrl($announcement, $prefix); if ($url === null) { return null; } return [ 'label' => $label, 'url' => $url, ]; } private function resolveLinkUrl(HomepageAnnouncement $announcement, string $prefix): ?string { $type = (string) ($announcement->getAttribute($prefix . '_link_type') ?? HomepageAnnouncement::LINK_TYPE_NONE); $url = $this->sanitizer->sanitizeCustomUrl($announcement->getAttribute($prefix . '_link_url')); $targetId = (int) ($announcement->getAttribute($prefix . '_link_target_id') ?? 0); return match ($type) { HomepageAnnouncement::LINK_TYPE_NONE => null, HomepageAnnouncement::LINK_TYPE_CUSTOM_URL => $url, HomepageAnnouncement::LINK_TYPE_EXPLORE => Route::has('explore.index') ? route('explore.index') : ($url ?? '/explore'), HomepageAnnouncement::LINK_TYPE_UPLOAD => Route::has('upload') ? route('upload') : ($url ?? '/upload'), HomepageAnnouncement::LINK_TYPE_NEWS => $this->newsUrl($targetId) ?? $url, HomepageAnnouncement::LINK_TYPE_WORLD => $this->worldUrl($targetId) ?? $url, HomepageAnnouncement::LINK_TYPE_COLLECTION => $this->collectionUrl($targetId) ?? $url, HomepageAnnouncement::LINK_TYPE_GROUP => $this->groupUrl($targetId) ?? $url, HomepageAnnouncement::LINK_TYPE_PROFILE => $this->profileUrl($targetId) ?? $url, HomepageAnnouncement::LINK_TYPE_ARTWORK => $this->artworkUrl($targetId) ?? $url, default => $url, }; } private function resolveBackgroundImageUrl(?string $backgroundImage): ?string { $backgroundImage = trim((string) $backgroundImage); if ($backgroundImage === '') { return null; } if (str_starts_with($backgroundImage, 'http://') || str_starts_with($backgroundImage, 'https://') || str_starts_with($backgroundImage, '/')) { return $backgroundImage; } return Storage::disk('public')->url($backgroundImage); } private function artworkUrl(int $artworkId): ?string { if ($artworkId < 1) { return null; } $artwork = Artwork::query()->find($artworkId); if (! $artwork) { return null; } return null; } private function newsUrl(int $articleId): ?string { if ($articleId < 1) { return null; } $article = NewsArticle::query()->find($articleId); if (! $article) { return null; } return route('news.show', ['slug' => $article->slug]); } private function worldUrl(int $worldId): ?string { if ($worldId < 1) { return null; } $world = World::query()->find($worldId); if (! $world) { return null; } if (method_exists($world, 'publicUrl')) { return $world->publicUrl(); } return route('worlds.show', ['world' => $world->slug]); } private function collectionUrl(int $collectionId): ?string { if ($collectionId < 1) { return null; } $collection = Collection::query()->with('user')->find($collectionId); if (! $collection || ! $collection->user?->username) { return null; } return route('profile.collections.show', [ 'username' => strtolower((string) $collection->user->username), 'slug' => $collection->slug, ]); } private function groupUrl(int $groupId): ?string { if ($groupId < 1) { return null; } $group = Group::query()->find($groupId); if (! $group) { return null; } return route('groups.show', ['group' => $group]); } private function profileUrl(int $userId): ?string { if ($userId < 1) { return null; } $user = User::query()->find($userId); if (! $user?->username) { return null; } return route('profile.show', ['username' => strtolower((string) $user->username)]); } }