xref: /webtrees/app/Auth.php (revision 5a8afed46297e8105e3e5a33ce37e6a8e88bc79d)
1a25f0a04SGreg Roach<?php
23976b470SGreg Roach
3a25f0a04SGreg Roach/**
4a25f0a04SGreg Roach * webtrees: online genealogy
5d11be702SGreg Roach * Copyright (C) 2023 webtrees development team
6a25f0a04SGreg Roach * This program is free software: you can redistribute it and/or modify
7a25f0a04SGreg Roach * it under the terms of the GNU General Public License as published by
8a25f0a04SGreg Roach * the Free Software Foundation, either version 3 of the License, or
9a25f0a04SGreg Roach * (at your option) any later version.
10a25f0a04SGreg Roach * This program is distributed in the hope that it will be useful,
11a25f0a04SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
12a25f0a04SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13a25f0a04SGreg Roach * GNU General Public License for more details.
14a25f0a04SGreg Roach * You should have received a copy of the GNU General Public License
1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>.
16a25f0a04SGreg Roach */
17fcfa147eSGreg Roach
18e7f56f2aSGreg Roachdeclare(strict_types=1);
19e7f56f2aSGreg Roach
2076692c8bSGreg Roachnamespace Fisharebest\Webtrees;
21a25f0a04SGreg Roach
22e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface;
2381b729d3SGreg Roachuse Fisharebest\Webtrees\Http\Exceptions\HttpAccessDeniedException;
2481b729d3SGreg Roachuse Fisharebest\Webtrees\Http\Exceptions\HttpNotFoundException;
259867b2f0SGreg Roachuse Fisharebest\Webtrees\Module\ModuleInterface;
26e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Services\UserService;
2779529c87SGreg Roach
28d8809d62SGreg Roachuse function is_int;
29d8809d62SGreg Roach
30a25f0a04SGreg Roach/**
3176692c8bSGreg Roach * Authentication.
32a25f0a04SGreg Roach */
33c1010edaSGreg Roachclass Auth
34c1010edaSGreg Roach{
354b9ff166SGreg Roach    // Privacy constants
3616d6367aSGreg Roach    public const PRIV_PRIVATE = 2; // Allows visitors to view the item
3716d6367aSGreg Roach    public const PRIV_USER    = 1; // Allows members to access the item
3816d6367aSGreg Roach    public const PRIV_NONE    = 0; // Allows managers to access the item
3916d6367aSGreg Roach    public const PRIV_HIDE    = -1; // Hide the item to all users
404b9ff166SGreg Roach
41a25f0a04SGreg Roach    /**
42a25f0a04SGreg Roach     * Are we currently logged in?
43a25f0a04SGreg Roach     *
44cbc1590aSGreg Roach     * @return bool
45a25f0a04SGreg Roach     */
468f53f488SRico Sonntag    public static function check(): bool
47c1010edaSGreg Roach    {
484b9ff166SGreg Roach        return self::id() !== null;
49a25f0a04SGreg Roach    }
50a25f0a04SGreg Roach
51a25f0a04SGreg Roach    /**
52a25f0a04SGreg Roach     * Is the specified/current user an administrator?
53a25f0a04SGreg Roach     *
54e5a6b4d4SGreg Roach     * @param UserInterface|null $user
55a25f0a04SGreg Roach     *
56cbc1590aSGreg Roach     * @return bool
57a25f0a04SGreg Roach     */
582c6f1bd5SGreg Roach    public static function isAdmin(UserInterface|null $user = null): bool
59c1010edaSGreg Roach    {
603529c469SGreg Roach        $user ??= self::user();
61a25f0a04SGreg Roach
621fe542e9SGreg Roach        return $user->getPreference(UserInterface::PREF_IS_ADMINISTRATOR) === '1';
63a25f0a04SGreg Roach    }
64a25f0a04SGreg Roach
65a25f0a04SGreg Roach    /**
664b9ff166SGreg Roach     * Is the specified/current user a manager of a tree?
67a25f0a04SGreg Roach     *
6884caa210SGreg Roach     * @param Tree               $tree
69e5a6b4d4SGreg Roach     * @param UserInterface|null $user
70a25f0a04SGreg Roach     *
71cbc1590aSGreg Roach     * @return bool
72a25f0a04SGreg Roach     */
732c6f1bd5SGreg Roach    public static function isManager(Tree $tree, UserInterface|null $user = null): bool
74c1010edaSGreg Roach    {
753529c469SGreg Roach        $user ??= self::user();
76a25f0a04SGreg Roach
771fe542e9SGreg Roach        return self::isAdmin($user) || $tree->getUserPreference($user, UserInterface::PREF_TREE_ROLE) === UserInterface::ROLE_MANAGER;
78a25f0a04SGreg Roach    }
79a25f0a04SGreg Roach
80a25f0a04SGreg Roach    /**
814b9ff166SGreg Roach     * Is the specified/current user a moderator of a tree?
82a25f0a04SGreg Roach     *
8384caa210SGreg Roach     * @param Tree               $tree
84e5a6b4d4SGreg Roach     * @param UserInterface|null $user
85a25f0a04SGreg Roach     *
86cbc1590aSGreg Roach     * @return bool
87a25f0a04SGreg Roach     */
882c6f1bd5SGreg Roach    public static function isModerator(Tree $tree, UserInterface|null $user = null): bool
89c1010edaSGreg Roach    {
903529c469SGreg Roach        $user ??= self::user();
91a25f0a04SGreg Roach
921fe542e9SGreg Roach        return
931fe542e9SGreg Roach            self::isManager($tree, $user) ||
941fe542e9SGreg Roach            $tree->getUserPreference($user, UserInterface::PREF_TREE_ROLE) === UserInterface::ROLE_MODERATOR;
95a25f0a04SGreg Roach    }
96a25f0a04SGreg Roach
97a25f0a04SGreg Roach    /**
984b9ff166SGreg Roach     * Is the specified/current user an editor of a tree?
99a25f0a04SGreg Roach     *
10084caa210SGreg Roach     * @param Tree               $tree
101e5a6b4d4SGreg Roach     * @param UserInterface|null $user
102a25f0a04SGreg Roach     *
103cbc1590aSGreg Roach     * @return bool
104a25f0a04SGreg Roach     */
1052c6f1bd5SGreg Roach    public static function isEditor(Tree $tree, UserInterface|null $user = null): bool
106c1010edaSGreg Roach    {
1073529c469SGreg Roach        $user ??= self::user();
108a25f0a04SGreg Roach
1091fe542e9SGreg Roach        return
1101fe542e9SGreg Roach            self::isModerator($tree, $user) ||
1111fe542e9SGreg Roach            $tree->getUserPreference($user, UserInterface::PREF_TREE_ROLE) === UserInterface::ROLE_EDITOR;
112a25f0a04SGreg Roach    }
113a25f0a04SGreg Roach
114a25f0a04SGreg Roach    /**
1154b9ff166SGreg Roach     * Is the specified/current user a member of a tree?
116a25f0a04SGreg Roach     *
11784caa210SGreg Roach     * @param Tree               $tree
118e5a6b4d4SGreg Roach     * @param UserInterface|null $user
119a25f0a04SGreg Roach     *
120cbc1590aSGreg Roach     * @return bool
121a25f0a04SGreg Roach     */
1222c6f1bd5SGreg Roach    public static function isMember(Tree $tree, UserInterface|null $user = null): bool
123c1010edaSGreg Roach    {
1243529c469SGreg Roach        $user ??= self::user();
125a25f0a04SGreg Roach
1261fe542e9SGreg Roach        return
1271fe542e9SGreg Roach            self::isEditor($tree, $user) ||
1281fe542e9SGreg Roach            $tree->getUserPreference($user, UserInterface::PREF_TREE_ROLE) === UserInterface::ROLE_MEMBER;
129a25f0a04SGreg Roach    }
130a25f0a04SGreg Roach
131a25f0a04SGreg Roach    /**
1324b9ff166SGreg Roach     * What is the specified/current user's access level within a tree?
1334b9ff166SGreg Roach     *
1344b9ff166SGreg Roach     * @param Tree               $tree
135e5a6b4d4SGreg Roach     * @param UserInterface|null $user
1364b9ff166SGreg Roach     *
137cbc1590aSGreg Roach     * @return int
1384b9ff166SGreg Roach     */
1392c6f1bd5SGreg Roach    public static function accessLevel(Tree $tree, UserInterface|null $user = null): int
140c1010edaSGreg Roach    {
1413529c469SGreg Roach        $user ??= self::user();
1424b9ff166SGreg Roach
1434b9ff166SGreg Roach        if (self::isManager($tree, $user)) {
1444b9ff166SGreg Roach            return self::PRIV_NONE;
1454b9ff166SGreg Roach        }
146b2ce94c6SRico Sonntag
147b2ce94c6SRico Sonntag        if (self::isMember($tree, $user)) {
148b2ce94c6SRico Sonntag            return self::PRIV_USER;
149b2ce94c6SRico Sonntag        }
150b2ce94c6SRico Sonntag
151b2ce94c6SRico Sonntag        return self::PRIV_PRIVATE;
1524b9ff166SGreg Roach    }
1534b9ff166SGreg Roach
1544b9ff166SGreg Roach    /**
155a25f0a04SGreg Roach     * The ID of the authenticated user, from the current session.
156a25f0a04SGreg Roach     */
157*1ff45046SGreg Roach    public static function id(): int|null
158c1010edaSGreg Roach    {
159d8809d62SGreg Roach        $wt_user = Session::get('wt_user');
160d8809d62SGreg Roach
161d8809d62SGreg Roach        return is_int($wt_user) ? $wt_user : null;
162a25f0a04SGreg Roach    }
163a25f0a04SGreg Roach
164a25f0a04SGreg Roach    /**
165a25f0a04SGreg Roach     * The authenticated user, from the current session.
166a25f0a04SGreg Roach     *
167e5a6b4d4SGreg Roach     * @return UserInterface
168a25f0a04SGreg Roach     */
169e5a6b4d4SGreg Roach    public static function user(): UserInterface
170c1010edaSGreg Roach    {
171d35568b4SGreg Roach        $user_service = Registry::container()->get(UserService::class);
172b55cbc6bSGreg Roach
173b55cbc6bSGreg Roach        return $user_service->find(self::id()) ?? new GuestUser();
174a25f0a04SGreg Roach    }
175a25f0a04SGreg Roach
176a25f0a04SGreg Roach    /**
177a25f0a04SGreg Roach     * Login directly as an explicit user - for masquerading.
178a25f0a04SGreg Roach     *
179e5a6b4d4SGreg Roach     * @param UserInterface $user
180cb923727SGreg Roach     *
181cb923727SGreg Roach     * @return void
182a25f0a04SGreg Roach     */
183e364afe4SGreg Roach    public static function login(UserInterface $user): void
184c1010edaSGreg Roach    {
18581b729d3SGreg Roach        Session::regenerate();
186895230eeSGreg Roach        Session::put('wt_user', $user->id());
187a25f0a04SGreg Roach    }
188a25f0a04SGreg Roach
189a25f0a04SGreg Roach    /**
190a25f0a04SGreg Roach     * End the session for the current user.
191cb923727SGreg Roach     *
192cb923727SGreg Roach     * @return void
193a25f0a04SGreg Roach     */
194e364afe4SGreg Roach    public static function logout(): void
195c1010edaSGreg Roach    {
19631bc7874SGreg Roach        Session::regenerate(true);
197a25f0a04SGreg Roach    }
198e539f5c6SGreg Roach
199e539f5c6SGreg Roach    /**
200ac19d600SGreg Roach     * @template T of ModuleInterface
201ac19d600SGreg Roach     *
2029867b2f0SGreg Roach     * @param ModuleInterface $module
203ac19d600SGreg Roach     * @param class-string<T> $interface
2049867b2f0SGreg Roach     * @param Tree            $tree
205e5a6b4d4SGreg Roach     * @param UserInterface   $user
2069867b2f0SGreg Roach     *
2079867b2f0SGreg Roach     * @return void
2089867b2f0SGreg Roach     */
209ef483801SGreg Roach    public static function checkComponentAccess(ModuleInterface $module, string $interface, Tree $tree, UserInterface $user): void
2109867b2f0SGreg Roach    {
211ef483801SGreg Roach        if ($module->accessLevel($tree, $interface) < self::accessLevel($tree, $user)) {
212d501c45dSGreg Roach            throw new HttpAccessDeniedException();
2139867b2f0SGreg Roach        }
2149867b2f0SGreg Roach    }
2159867b2f0SGreg Roach
2169867b2f0SGreg Roach    /**
217e539f5c6SGreg Roach     * @param Family|null $family
218ffc0a61fSGreg Roach     * @param bool        $edit
219e539f5c6SGreg Roach     *
220ddeb3354SGreg Roach     * @return Family
22181b729d3SGreg Roach     * @throws HttpNotFoundException
22281b729d3SGreg Roach     * @throws HttpAccessDeniedException
223e539f5c6SGreg Roach     */
224*1ff45046SGreg Roach    public static function checkFamilyAccess(Family|null $family, bool $edit = false): Family
225e539f5c6SGreg Roach    {
22681b729d3SGreg Roach        $message = I18N::translate('This family does not exist or you do not have permission to view it.');
22781b729d3SGreg Roach
228e539f5c6SGreg Roach        if ($family === null) {
22981b729d3SGreg Roach            throw new HttpNotFoundException($message);
230e539f5c6SGreg Roach        }
231e539f5c6SGreg Roach
2323c3fd0a5SGreg Roach        if ($edit && $family->canEdit()) {
2338091bfd1SGreg Roach            $family->lock();
2348091bfd1SGreg Roach
235ddeb3354SGreg Roach            return $family;
236e539f5c6SGreg Roach        }
237e539f5c6SGreg Roach
2383c3fd0a5SGreg Roach        if ($family->canShow()) {
2393c3fd0a5SGreg Roach            return $family;
2403c3fd0a5SGreg Roach        }
2413c3fd0a5SGreg Roach
24281b729d3SGreg Roach        throw new HttpAccessDeniedException($message);
2433c3fd0a5SGreg Roach    }
2443c3fd0a5SGreg Roach
245e539f5c6SGreg Roach    /**
2461635452cSGreg Roach     * @param Header|null $header
2471635452cSGreg Roach     * @param bool        $edit
2481635452cSGreg Roach     *
2491635452cSGreg Roach     * @return Header
25081b729d3SGreg Roach     * @throws HttpNotFoundException
25181b729d3SGreg Roach     * @throws HttpAccessDeniedException
2521635452cSGreg Roach     */
253*1ff45046SGreg Roach    public static function checkHeaderAccess(Header|null $header, bool $edit = false): Header
2541635452cSGreg Roach    {
25581b729d3SGreg Roach        $message = I18N::translate('This record does not exist or you do not have permission to view it.');
25681b729d3SGreg Roach
2571635452cSGreg Roach        if ($header === null) {
25881b729d3SGreg Roach            throw new HttpNotFoundException($message);
2591635452cSGreg Roach        }
2601635452cSGreg Roach
2611635452cSGreg Roach        if ($edit && $header->canEdit()) {
2628091bfd1SGreg Roach            $header->lock();
2638091bfd1SGreg Roach
2641635452cSGreg Roach            return $header;
2651635452cSGreg Roach        }
2661635452cSGreg Roach
2671635452cSGreg Roach        if ($header->canShow()) {
2681635452cSGreg Roach            return $header;
2691635452cSGreg Roach        }
2701635452cSGreg Roach
27181b729d3SGreg Roach        throw new HttpAccessDeniedException($message);
2721635452cSGreg Roach    }
2731635452cSGreg Roach
2741635452cSGreg Roach    /**
275e539f5c6SGreg Roach     * @param Individual|null $individual
276ffc0a61fSGreg Roach     * @param bool            $edit
2773c3fd0a5SGreg Roach     * @param bool            $chart For some charts, we can show private records
278e539f5c6SGreg Roach     *
279ddeb3354SGreg Roach     * @return Individual
28081b729d3SGreg Roach     * @throws HttpNotFoundException
28181b729d3SGreg Roach     * @throws HttpAccessDeniedException
282e539f5c6SGreg Roach     */
283*1ff45046SGreg Roach    public static function checkIndividualAccess(Individual|null $individual, bool $edit = false, bool $chart = false): Individual
284e539f5c6SGreg Roach    {
28581b729d3SGreg Roach        $message = I18N::translate('This individual does not exist or you do not have permission to view it.');
28681b729d3SGreg Roach
287e539f5c6SGreg Roach        if ($individual === null) {
28881b729d3SGreg Roach            throw new HttpNotFoundException($message);
289e539f5c6SGreg Roach        }
290e539f5c6SGreg Roach
2913c3fd0a5SGreg Roach        if ($edit && $individual->canEdit()) {
2928091bfd1SGreg Roach            $individual->lock();
2938091bfd1SGreg Roach
294ddeb3354SGreg Roach            return $individual;
295e539f5c6SGreg Roach        }
296e539f5c6SGreg Roach
2973c3fd0a5SGreg Roach        if ($chart && $individual->tree()->getPreference('SHOW_PRIVATE_RELATIONSHIPS') === '1') {
2983c3fd0a5SGreg Roach            return $individual;
2993c3fd0a5SGreg Roach        }
3003c3fd0a5SGreg Roach
3013c3fd0a5SGreg Roach        if ($individual->canShow()) {
3023c3fd0a5SGreg Roach            return $individual;
3033c3fd0a5SGreg Roach        }
3043c3fd0a5SGreg Roach
30581b729d3SGreg Roach        throw new HttpAccessDeniedException($message);
3063c3fd0a5SGreg Roach    }
3073c3fd0a5SGreg Roach
308e539f5c6SGreg Roach    /**
309e8ded2caSGreg Roach     * @param Location|null $location
310e8ded2caSGreg Roach     * @param bool          $edit
311e8ded2caSGreg Roach     *
312e8ded2caSGreg Roach     * @return Location
31381b729d3SGreg Roach     * @throws HttpNotFoundException
31481b729d3SGreg Roach     * @throws HttpAccessDeniedException
315e8ded2caSGreg Roach     */
316*1ff45046SGreg Roach    public static function checkLocationAccess(Location|null $location, bool $edit = false): Location
317e8ded2caSGreg Roach    {
31881b729d3SGreg Roach        $message = I18N::translate('This record does not exist or you do not have permission to view it.');
31981b729d3SGreg Roach
320e8ded2caSGreg Roach        if ($location === null) {
32181b729d3SGreg Roach            throw new HttpNotFoundException($message);
322e8ded2caSGreg Roach        }
323e8ded2caSGreg Roach
324e8ded2caSGreg Roach        if ($edit && $location->canEdit()) {
325e8ded2caSGreg Roach            $location->lock();
326e8ded2caSGreg Roach
327e8ded2caSGreg Roach            return $location;
328e8ded2caSGreg Roach        }
329e8ded2caSGreg Roach
330e8ded2caSGreg Roach        if ($location->canShow()) {
331e8ded2caSGreg Roach            return $location;
332e8ded2caSGreg Roach        }
333e8ded2caSGreg Roach
33481b729d3SGreg Roach        throw new HttpAccessDeniedException($message);
335e8ded2caSGreg Roach    }
336e8ded2caSGreg Roach
337e8ded2caSGreg Roach    /**
338e539f5c6SGreg Roach     * @param Media|null $media
339ffc0a61fSGreg Roach     * @param bool       $edit
340e539f5c6SGreg Roach     *
341ddeb3354SGreg Roach     * @return Media
34281b729d3SGreg Roach     * @throws HttpNotFoundException
34381b729d3SGreg Roach     * @throws HttpAccessDeniedException
344e539f5c6SGreg Roach     */
345*1ff45046SGreg Roach    public static function checkMediaAccess(Media|null $media, bool $edit = false): Media
346e539f5c6SGreg Roach    {
34781b729d3SGreg Roach        $message = I18N::translate('This media object does not exist or you do not have permission to view it.');
34881b729d3SGreg Roach
349e539f5c6SGreg Roach        if ($media === null) {
35081b729d3SGreg Roach            throw new HttpNotFoundException($message);
351e539f5c6SGreg Roach        }
352e539f5c6SGreg Roach
3533c3fd0a5SGreg Roach        if ($edit && $media->canEdit()) {
3548091bfd1SGreg Roach            $media->lock();
3558091bfd1SGreg Roach
356ddeb3354SGreg Roach            return $media;
357e539f5c6SGreg Roach        }
358e539f5c6SGreg Roach
3593c3fd0a5SGreg Roach        if ($media->canShow()) {
3603c3fd0a5SGreg Roach            return $media;
3613c3fd0a5SGreg Roach        }
3623c3fd0a5SGreg Roach
36381b729d3SGreg Roach        throw new HttpAccessDeniedException($message);
3643c3fd0a5SGreg Roach    }
3653c3fd0a5SGreg Roach
366e539f5c6SGreg Roach    /**
367e539f5c6SGreg Roach     * @param Note|null $note
368ffc0a61fSGreg Roach     * @param bool      $edit
369e539f5c6SGreg Roach     *
370ddeb3354SGreg Roach     * @return Note
37181b729d3SGreg Roach     * @throws HttpNotFoundException
37281b729d3SGreg Roach     * @throws HttpAccessDeniedException
373e539f5c6SGreg Roach     */
374*1ff45046SGreg Roach    public static function checkNoteAccess(Note|null $note, bool $edit = false): Note
375e539f5c6SGreg Roach    {
37681b729d3SGreg Roach        $message = I18N::translate('This note does not exist or you do not have permission to view it.');
37781b729d3SGreg Roach
378e539f5c6SGreg Roach        if ($note === null) {
37981b729d3SGreg Roach            throw new HttpNotFoundException($message);
380e539f5c6SGreg Roach        }
381e539f5c6SGreg Roach
3823c3fd0a5SGreg Roach        if ($edit && $note->canEdit()) {
3838091bfd1SGreg Roach            $note->lock();
3848091bfd1SGreg Roach
385ddeb3354SGreg Roach            return $note;
386e539f5c6SGreg Roach        }
387e539f5c6SGreg Roach
3883c3fd0a5SGreg Roach        if ($note->canShow()) {
3893c3fd0a5SGreg Roach            return $note;
3903c3fd0a5SGreg Roach        }
3913c3fd0a5SGreg Roach
39281b729d3SGreg Roach        throw new HttpAccessDeniedException($message);
3933c3fd0a5SGreg Roach    }
3943c3fd0a5SGreg Roach
395e539f5c6SGreg Roach    /**
396701f5d18SGreg Roach     * @param SharedNote|null $shared_note
397701f5d18SGreg Roach     * @param bool            $edit
398701f5d18SGreg Roach     *
399701f5d18SGreg Roach     * @return SharedNote
400701f5d18SGreg Roach     * @throws HttpNotFoundException
401701f5d18SGreg Roach     * @throws HttpAccessDeniedException
402701f5d18SGreg Roach     */
403*1ff45046SGreg Roach    public static function checkSharedNoteAccess(SharedNote|null $shared_note, bool $edit = false): SharedNote
404701f5d18SGreg Roach    {
405701f5d18SGreg Roach        $message = I18N::translate('This note does not exist or you do not have permission to view it.');
406701f5d18SGreg Roach
407701f5d18SGreg Roach        if ($shared_note === null) {
408701f5d18SGreg Roach            throw new HttpNotFoundException($message);
409701f5d18SGreg Roach        }
410701f5d18SGreg Roach
411701f5d18SGreg Roach        if ($edit && $shared_note->canEdit()) {
412701f5d18SGreg Roach            $shared_note->lock();
413701f5d18SGreg Roach
414701f5d18SGreg Roach            return $shared_note;
415701f5d18SGreg Roach        }
416701f5d18SGreg Roach
417701f5d18SGreg Roach        if ($shared_note->canShow()) {
418701f5d18SGreg Roach            return $shared_note;
419701f5d18SGreg Roach        }
420701f5d18SGreg Roach
421701f5d18SGreg Roach        throw new HttpAccessDeniedException($message);
422701f5d18SGreg Roach    }
423701f5d18SGreg Roach
424701f5d18SGreg Roach    /**
425e539f5c6SGreg Roach     * @param GedcomRecord|null $record
426ffc0a61fSGreg Roach     * @param bool              $edit
427e539f5c6SGreg Roach     *
428ddeb3354SGreg Roach     * @return GedcomRecord
42981b729d3SGreg Roach     * @throws HttpNotFoundException
43081b729d3SGreg Roach     * @throws HttpAccessDeniedException
431e539f5c6SGreg Roach     */
432*1ff45046SGreg Roach    public static function checkRecordAccess(GedcomRecord|null $record, bool $edit = false): GedcomRecord
433e539f5c6SGreg Roach    {
43481b729d3SGreg Roach        $message = I18N::translate('This record does not exist or you do not have permission to view it.');
43581b729d3SGreg Roach
436e539f5c6SGreg Roach        if ($record === null) {
43781b729d3SGreg Roach            throw new HttpNotFoundException($message);
438e539f5c6SGreg Roach        }
439e539f5c6SGreg Roach
4403c3fd0a5SGreg Roach        if ($edit && $record->canEdit()) {
4418091bfd1SGreg Roach            $record->lock();
4428091bfd1SGreg Roach
443ddeb3354SGreg Roach            return $record;
444e539f5c6SGreg Roach        }
445e539f5c6SGreg Roach
4463c3fd0a5SGreg Roach        if ($record->canShow()) {
4473c3fd0a5SGreg Roach            return $record;
4483c3fd0a5SGreg Roach        }
4493c3fd0a5SGreg Roach
45081b729d3SGreg Roach        throw new HttpAccessDeniedException($message);
4513c3fd0a5SGreg Roach    }
4523c3fd0a5SGreg Roach
453e539f5c6SGreg Roach    /**
454e539f5c6SGreg Roach     * @param Repository|null $repository
455ffc0a61fSGreg Roach     * @param bool            $edit
456e539f5c6SGreg Roach     *
457ddeb3354SGreg Roach     * @return Repository
45881b729d3SGreg Roach     * @throws HttpNotFoundException
45981b729d3SGreg Roach     * @throws HttpAccessDeniedException
460e539f5c6SGreg Roach     */
461*1ff45046SGreg Roach    public static function checkRepositoryAccess(Repository|null $repository, bool $edit = false): Repository
462e539f5c6SGreg Roach    {
46381b729d3SGreg Roach        $message = I18N::translate('This repository does not exist or you do not have permission to view it.');
46481b729d3SGreg Roach
465e539f5c6SGreg Roach        if ($repository === null) {
46681b729d3SGreg Roach            throw new HttpNotFoundException($message);
467e539f5c6SGreg Roach        }
468e539f5c6SGreg Roach
4693c3fd0a5SGreg Roach        if ($edit && $repository->canEdit()) {
4708091bfd1SGreg Roach            $repository->lock();
4718091bfd1SGreg Roach
472ddeb3354SGreg Roach            return $repository;
473e539f5c6SGreg Roach        }
474e539f5c6SGreg Roach
4753c3fd0a5SGreg Roach        if ($repository->canShow()) {
4763c3fd0a5SGreg Roach            return $repository;
4773c3fd0a5SGreg Roach        }
4783c3fd0a5SGreg Roach
47981b729d3SGreg Roach        throw new HttpAccessDeniedException($message);
4803c3fd0a5SGreg Roach    }
4813c3fd0a5SGreg Roach
482e539f5c6SGreg Roach    /**
483e539f5c6SGreg Roach     * @param Source|null $source
484ffc0a61fSGreg Roach     * @param bool        $edit
485e539f5c6SGreg Roach     *
486ddeb3354SGreg Roach     * @return Source
48781b729d3SGreg Roach     * @throws HttpNotFoundException
48881b729d3SGreg Roach     * @throws HttpAccessDeniedException
489e539f5c6SGreg Roach     */
490*1ff45046SGreg Roach    public static function checkSourceAccess(Source|null $source, bool $edit = false): Source
491e539f5c6SGreg Roach    {
49281b729d3SGreg Roach        $message = I18N::translate('This source does not exist or you do not have permission to view it.');
49381b729d3SGreg Roach
494e539f5c6SGreg Roach        if ($source === null) {
49581b729d3SGreg Roach            throw new HttpNotFoundException($message);
496e539f5c6SGreg Roach        }
497e539f5c6SGreg Roach
4983c3fd0a5SGreg Roach        if ($edit && $source->canEdit()) {
4998091bfd1SGreg Roach            $source->lock();
5008091bfd1SGreg Roach
501ddeb3354SGreg Roach            return $source;
502e539f5c6SGreg Roach        }
503ffc0a61fSGreg Roach
5043c3fd0a5SGreg Roach        if ($source->canShow()) {
5053c3fd0a5SGreg Roach            return $source;
5063c3fd0a5SGreg Roach        }
5073c3fd0a5SGreg Roach
50881b729d3SGreg Roach        throw new HttpAccessDeniedException($message);
5093c3fd0a5SGreg Roach    }
5103c3fd0a5SGreg Roach
511b1089081SGreg Roach    /**
512ffc0a61fSGreg Roach     * @param Submitter|null $submitter
513ffc0a61fSGreg Roach     * @param bool           $edit
514ffc0a61fSGreg Roach     *
515ffc0a61fSGreg Roach     * @return Submitter
516b1089081SGreg Roach     * @throws HttpNotFoundException
517b1089081SGreg Roach     * @throws HttpAccessDeniedException
518ffc0a61fSGreg Roach     */
519*1ff45046SGreg Roach    public static function checkSubmitterAccess(Submitter|null $submitter, bool $edit = false): Submitter
520ffc0a61fSGreg Roach    {
52181b729d3SGreg Roach        $message = I18N::translate('This record does not exist or you do not have permission to view it.');
52281b729d3SGreg Roach
523ffc0a61fSGreg Roach        if ($submitter === null) {
52481b729d3SGreg Roach            throw new HttpNotFoundException($message);
525ffc0a61fSGreg Roach        }
526ffc0a61fSGreg Roach
5273c3fd0a5SGreg Roach        if ($edit && $submitter->canEdit()) {
5288091bfd1SGreg Roach            $submitter->lock();
5298091bfd1SGreg Roach
530ffc0a61fSGreg Roach            return $submitter;
531ffc0a61fSGreg Roach        }
5323c3fd0a5SGreg Roach
5333c3fd0a5SGreg Roach        if ($submitter->canShow()) {
5343c3fd0a5SGreg Roach            return $submitter;
5353c3fd0a5SGreg Roach        }
5363c3fd0a5SGreg Roach
53781b729d3SGreg Roach        throw new HttpAccessDeniedException($message);
5383c3fd0a5SGreg Roach    }
5391635452cSGreg Roach
540b1089081SGreg Roach    /**
5411635452cSGreg Roach     * @param Submission|null $submission
5421635452cSGreg Roach     * @param bool            $edit
5431635452cSGreg Roach     *
5441635452cSGreg Roach     * @return Submission
54581b729d3SGreg Roach     * @throws HttpNotFoundException
54681b729d3SGreg Roach     * @throws HttpAccessDeniedException
5471635452cSGreg Roach     */
548*1ff45046SGreg Roach    public static function checkSubmissionAccess(Submission|null $submission, bool $edit = false): Submission
5491635452cSGreg Roach    {
55081b729d3SGreg Roach        $message = I18N::translate('This record does not exist or you do not have permission to view it.');
55181b729d3SGreg Roach
5521635452cSGreg Roach        if ($submission === null) {
55381b729d3SGreg Roach            throw new HttpNotFoundException($message);
5541635452cSGreg Roach        }
5551635452cSGreg Roach
5561635452cSGreg Roach        if ($edit && $submission->canEdit()) {
5578091bfd1SGreg Roach            $submission->lock();
5588091bfd1SGreg Roach
5591635452cSGreg Roach            return $submission;
5601635452cSGreg Roach        }
5611635452cSGreg Roach
5621635452cSGreg Roach        if ($submission->canShow()) {
5631635452cSGreg Roach            return $submission;
5641635452cSGreg Roach        }
5651635452cSGreg Roach
56681b729d3SGreg Roach        throw new HttpAccessDeniedException($message);
5671635452cSGreg Roach    }
568870365fbSGreg Roach
569870365fbSGreg Roach    /**
5705416d6ddSGreg Roach     * @param Tree          $tree
5715416d6ddSGreg Roach     * @param UserInterface $user
5725416d6ddSGreg Roach     *
5735416d6ddSGreg Roach     * @return bool
5745416d6ddSGreg Roach     */
5755416d6ddSGreg Roach    public static function canUploadMedia(Tree $tree, UserInterface $user): bool
5765416d6ddSGreg Roach    {
5775416d6ddSGreg Roach        return
578be410956SGreg Roach            self::isEditor($tree, $user) &&
579be410956SGreg Roach            self::accessLevel($tree, $user) <= (int) $tree->getPreference('MEDIA_UPLOAD');
5805416d6ddSGreg Roach    }
5815416d6ddSGreg Roach
5825416d6ddSGreg Roach    /**
583870365fbSGreg Roach     * @return array<int,string>
584870365fbSGreg Roach     */
585870365fbSGreg Roach    public static function accessLevelNames(): array
586870365fbSGreg Roach    {
587870365fbSGreg Roach        return [
588d823340dSGreg Roach            self::PRIV_PRIVATE => I18N::translate('Show to visitors'),
589d823340dSGreg Roach            self::PRIV_USER    => I18N::translate('Show to members'),
590d823340dSGreg Roach            self::PRIV_NONE    => I18N::translate('Show to managers'),
591d823340dSGreg Roach            self::PRIV_HIDE    => I18N::translate('Hide from everyone'),
592870365fbSGreg Roach        ];
593870365fbSGreg Roach    }
594138139c2SGreg Roach
595138139c2SGreg Roach    /**
596138139c2SGreg Roach     * @return array<string,string>
597138139c2SGreg Roach     */
598138139c2SGreg Roach    public static function privacyRuleNames(): array
599138139c2SGreg Roach    {
600138139c2SGreg Roach        return [
601138139c2SGreg Roach            'none'         => I18N::translate('Show to visitors'),
602138139c2SGreg Roach            'privacy'      => I18N::translate('Show to members'),
603138139c2SGreg Roach            'confidential' => I18N::translate('Show to managers'),
604138139c2SGreg Roach            'hidden'       => I18N::translate('Hide from everyone'),
605138139c2SGreg Roach        ];
606138139c2SGreg Roach    }
607a25f0a04SGreg Roach}
608