Snapshot of main at 9f39a6e1e (2026-11-02)
This commit is contained in:
commit
6ccf1792d7
2580 files changed
+1040202
No files matched your search
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Admin;
|
||||
use App\Models\Bank;
|
||||
use App\Models\Organization;
|
||||
use App\Models\Poll;
|
||||
use App\Models\Post;
|
||||
use App\Models\PostTranslation;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
|
||||
|
||||
/**
|
||||
* Dedicated page of a poll: its post (title, image, intro, text) with the poll form below.
|
||||
*/
|
||||
class PollController extends Controller
|
||||
{
|
||||
public function show(string $slug)
|
||||
{
|
||||
// Polls are for logged-in profiles only. The route requires a login already; this is a
|
||||
// safety net should the route ever be moved out of its protected group.
|
||||
if (!Auth::guard('web')->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<int, array{name: string, type: string, url: string}>
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user