authorize('view', $group); abort_unless((int) $challenge->group_id === (int) $group->id, 404); abort_unless($challenge->canBeViewedBy($request->user()), 403); $groupPayload = $this->groups->mapGroupDetail($group, $request->user()); $challengePayload = $this->challenges->detailPayload($challenge, $request->user()); $canonical = route('groups.challenges.show', ['group' => $group, 'challenge' => $challenge]); $description = Str::limit(trim(strip_tags((string) ($challengePayload['summary'] ?? $challengePayload['description'] ?? $groupPayload['headline'] ?? 'Group challenge on Skinbase.'))), 160, '…'); $seo = app(SeoFactory::class)->collectionPage( sprintf('%s — %s — Skinbase', $challenge->title, $group->name), $description, $canonical, $challengePayload['cover_url'] ?? null, )->toArray(); $seo['og_type'] = 'article'; $seo['json_ld'] = [[ '@context' => 'https://schema.org', '@type' => 'CreativeWork', 'name' => (string) $challenge->title, 'description' => $description, 'url' => $canonical, 'image' => $challengePayload['cover_url'] ?? null, 'dateCreated' => $challenge->created_at?->toAtomString(), 'publisher' => ['@type' => 'Organization', 'name' => (string) $group->name], ]]; return Inertia::render('Group/GroupChallengeShow', [ 'group' => $groupPayload, 'challenge' => $challengePayload, 'seo' => $seo, ])->rootView('collections'); } public function attachArtwork(AttachArtworkToGroupChallengeRequest $request, Group $group, GroupChallenge $challenge): RedirectResponse { $this->authorize('view', $group); abort_unless((int) $challenge->group_id === (int) $group->id, 404); abort_unless($challenge->canBeViewedBy($request->user()), 403); $artwork = Artwork::query()->findOrFail((int) $request->validated('artwork_id')); $this->challenges->attachArtwork($challenge, $artwork, $request->user()); return back()->with('success', 'Artwork attached to challenge.'); } }