check()) { session(['url.intended' => request()->url()]); return redirect(LaravelLocalization::localizeUrl('/login')); } $postId = PostTranslation::where('slug', $slug)->value('post_id'); $post = $postId ? Post::with(['poll', 'category.translations'])->find($postId) : null; if (!$post || !$post->poll) { return view('posts.not_found'); } // Poll admins may preview unpublished polls and drafts; for everyone else a draft does // not exist yet, even when its post already has a publication date (security audit R3) $preview = Poll::viewerIsPollAdmin(); if ($post->poll->status === Poll::STATUS_DRAFT && !$preview) { return view('posts.not_found'); } $published = function ($query) use ($preview) { if (!$preview) { $query->whereDate('from', '<=', now()) ->where(fn ($q) => $q->whereDate('till', '>', now())->orWhereNull('till')); } }; // The current language, otherwise any published language $translation = $post->translations()->where('locale', App::getLocale())->where($published)->first() ?? $post->translations()->where($published)->first(); if (!$translation) { return view('posts.not_found'); } // Another of the user's profiles may take part while the active one may not: right after // logging in to this poll (a one-time session marker set by LoginResponse) with only one // such profile, switch to it straight away (its own login flow, password for banks and // admins); otherwise offer them on the page. $justLoggedIn = session()->pull('poll_switch_after_login') === '/' . ltrim(request()->path(), '/'); $switchProfiles = $this->switchProfiles($post->poll, request()->url()); if ($justLoggedIn && count($switchProfiles) === 1) { return redirect($switchProfiles[0]['url']); } $media = $post->getFirstMedia('posts'); $category = $post->category?->translations->firstWhere('locale', App::getLocale())?->name ?? $post->category?->translations->first()?->name; $update = Carbon::parse($translation->updated_at)->isoFormat('LL'); return view('polls.show', compact('post', 'translation', 'media', 'category', 'update', 'switchProfiles')); } /** * The logged-in user's other profiles that may take part when the active profile may not, * each with the direct login link of that profile that returns to this poll. * * @return array */ private function switchProfiles(Poll $poll, string $pollUrl): array { $user = Auth::guard('web')->user(); $active = getActiveProfile(); if (!$user instanceof User || !$active || !$poll->isOpen() || $poll->isTargetedAt($active, $user)) { return []; } $user->loadMissing(['organizations', 'banksManaged', 'admins']); $routes = [ User::class => ['user.direct-login', 'userId'], Organization::class => ['organization.direct-login', 'organizationId'], Bank::class => ['bank.direct-login', 'bankId'], Admin::class => ['admin.direct-login', 'adminId'], ]; $profiles = collect([$user])->concat($user->organizations)->concat($user->banksManaged)->concat($user->admins) ->reject(fn (Model $profile) => $profile->is($active)) ->filter(fn (Model $profile) => $poll->isTargetedAt($profile, $user)); return $profiles->map(function (Model $profile) use ($routes, $pollUrl) { [$route, $parameter] = $routes[get_class($profile)]; return [ 'name' => $profile->name, 'type' => class_basename($profile), 'url' => route($route, [$parameter => $profile->getKey()]) . '?intended=' . urlencode($pollUrl), ]; })->values()->all(); } }