xref: /webtrees/app/Services/UserService.php (revision add3fa4120ca696c713a0d0ac9b9c86f751fe49a)
1e5a6b4d4SGreg Roach<?php
2e5a6b4d4SGreg Roach/**
3e5a6b4d4SGreg Roach * webtrees: online genealogy
4e5a6b4d4SGreg Roach * Copyright (C) 2019 webtrees development team
5e5a6b4d4SGreg Roach * This program is free software: you can redistribute it and/or modify
6e5a6b4d4SGreg Roach * it under the terms of the GNU General Public License as published by
7e5a6b4d4SGreg Roach * the Free Software Foundation, either version 3 of the License, or
8e5a6b4d4SGreg Roach * (at your option) any later version.
9e5a6b4d4SGreg Roach * This program is distributed in the hope that it will be useful,
10e5a6b4d4SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
11e5a6b4d4SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12e5a6b4d4SGreg Roach * GNU General Public License for more details.
13e5a6b4d4SGreg Roach * You should have received a copy of the GNU General Public License
14e5a6b4d4SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>.
15e5a6b4d4SGreg Roach */
16e5a6b4d4SGreg Roachdeclare(strict_types=1);
17e5a6b4d4SGreg Roach
18e5a6b4d4SGreg Roachnamespace Fisharebest\Webtrees\Services;
19e5a6b4d4SGreg Roach
20e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Auth;
2186730b84SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface;
22e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Individual;
2386730b84SGreg Roachuse Fisharebest\Webtrees\Tree;
24e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\User;
25e5a6b4d4SGreg Roachuse Illuminate\Database\Capsule\Manager as DB;
26e5a6b4d4SGreg Roachuse Illuminate\Database\Query\JoinClause;
27e5a6b4d4SGreg Roachuse Illuminate\Support\Collection;
286ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface;
296ccdf4f0SGreg Roachuse function app;
30e5a6b4d4SGreg Roach
31e5a6b4d4SGreg Roach/**
32e5a6b4d4SGreg Roach * Functions for managing users.
33e5a6b4d4SGreg Roach */
34e5a6b4d4SGreg Roachclass UserService
35e5a6b4d4SGreg Roach{
36e5a6b4d4SGreg Roach    /**
37e5a6b4d4SGreg Roach     * Find the user with a specified user_id.
38e5a6b4d4SGreg Roach     *
39e5a6b4d4SGreg Roach     * @param int|null $user_id
40e5a6b4d4SGreg Roach     *
41e5a6b4d4SGreg Roach     * @return User|null
42e5a6b4d4SGreg Roach     */
4325d7fe95SGreg Roach    public function find($user_id): ?User
44e5a6b4d4SGreg Roach    {
450b5fd0a6SGreg Roach        return app('cache.array')->rememberForever(__CLASS__ . $user_id, static function () use ($user_id): ?User {
46e5a6b4d4SGreg Roach            return DB::table('user')
47e5a6b4d4SGreg Roach                ->where('user_id', '=', $user_id)
48e5a6b4d4SGreg Roach                ->get()
49e5a6b4d4SGreg Roach                ->map(User::rowMapper())
50e5a6b4d4SGreg Roach                ->first();
51e5a6b4d4SGreg Roach        });
52e5a6b4d4SGreg Roach    }
53e5a6b4d4SGreg Roach
54e5a6b4d4SGreg Roach    /**
55e5a6b4d4SGreg Roach     * Find the user with a specified email address.
56e5a6b4d4SGreg Roach     *
57e5a6b4d4SGreg Roach     * @param string $email
58e5a6b4d4SGreg Roach     *
59e5a6b4d4SGreg Roach     * @return User|null
60e5a6b4d4SGreg Roach     */
61e364afe4SGreg Roach    public function findByEmail($email): ?User
62e5a6b4d4SGreg Roach    {
63e5a6b4d4SGreg Roach        return DB::table('user')
64e5a6b4d4SGreg Roach            ->where('email', '=', $email)
65e5a6b4d4SGreg Roach            ->get()
66e5a6b4d4SGreg Roach            ->map(User::rowMapper())
67e5a6b4d4SGreg Roach            ->first();
68e5a6b4d4SGreg Roach    }
69e5a6b4d4SGreg Roach
70e5a6b4d4SGreg Roach    /**
71e5a6b4d4SGreg Roach     * Find the user with a specified user_name or email address.
72e5a6b4d4SGreg Roach     *
73e5a6b4d4SGreg Roach     * @param string $identifier
74e5a6b4d4SGreg Roach     *
75e5a6b4d4SGreg Roach     * @return User|null
76e5a6b4d4SGreg Roach     */
77e364afe4SGreg Roach    public function findByIdentifier($identifier): ?User
78e5a6b4d4SGreg Roach    {
79e5a6b4d4SGreg Roach        return DB::table('user')
80e5a6b4d4SGreg Roach            ->where('user_name', '=', $identifier)
81e5a6b4d4SGreg Roach            ->orWhere('email', '=', $identifier)
82e5a6b4d4SGreg Roach            ->get()
83e5a6b4d4SGreg Roach            ->map(User::rowMapper())
84e5a6b4d4SGreg Roach            ->first();
85e5a6b4d4SGreg Roach    }
86e5a6b4d4SGreg Roach
87e5a6b4d4SGreg Roach    /**
88e5a6b4d4SGreg Roach     * Find the user(s) with a specified genealogy record.
89e5a6b4d4SGreg Roach     *
90e5a6b4d4SGreg Roach     * @param Individual $individual
91e5a6b4d4SGreg Roach     *
9254c7f8dfSGreg Roach     * @return Collection
93e5a6b4d4SGreg Roach     */
94e5a6b4d4SGreg Roach    public function findByIndividual(Individual $individual): Collection
95e5a6b4d4SGreg Roach    {
96e5a6b4d4SGreg Roach        return DB::table('user')
97e5a6b4d4SGreg Roach            ->join('user_gedcom_setting', 'user_gedcom_setting.user_id', '=', 'user.user_id')
98e5a6b4d4SGreg Roach            ->where('gedcom_id', '=', $individual->tree()->id())
99e5a6b4d4SGreg Roach            ->where('setting_value', '=', $individual->xref())
100e5a6b4d4SGreg Roach            ->where('setting_name', '=', 'gedcomid')
101e5a6b4d4SGreg Roach            ->select(['user.*'])
102e5a6b4d4SGreg Roach            ->get()
103e5a6b4d4SGreg Roach            ->map(User::rowMapper());
104e5a6b4d4SGreg Roach    }
105e5a6b4d4SGreg Roach
106e5a6b4d4SGreg Roach    /**
107e5a6b4d4SGreg Roach     * Find the user with a specified user_name.
108e5a6b4d4SGreg Roach     *
109e5a6b4d4SGreg Roach     * @param string $user_name
110e5a6b4d4SGreg Roach     *
111e5a6b4d4SGreg Roach     * @return User|null
112e5a6b4d4SGreg Roach     */
113e364afe4SGreg Roach    public function findByUserName($user_name): ?User
114e5a6b4d4SGreg Roach    {
115e5a6b4d4SGreg Roach        return DB::table('user')
116e5a6b4d4SGreg Roach            ->where('user_name', '=', $user_name)
117e5a6b4d4SGreg Roach            ->get()
118e5a6b4d4SGreg Roach            ->map(User::rowMapper())
119e5a6b4d4SGreg Roach            ->first();
120e5a6b4d4SGreg Roach    }
121e5a6b4d4SGreg Roach
122e5a6b4d4SGreg Roach    /**
123e5a6b4d4SGreg Roach     * Get a list of all users.
124e5a6b4d4SGreg Roach     *
12554c7f8dfSGreg Roach     * @return Collection
126e5a6b4d4SGreg Roach     */
127e5a6b4d4SGreg Roach    public function all(): Collection
128e5a6b4d4SGreg Roach    {
129e5a6b4d4SGreg Roach        return DB::table('user')
130e5a6b4d4SGreg Roach            ->where('user_id', '>', 0)
131e5a6b4d4SGreg Roach            ->orderBy('real_name')
132e5a6b4d4SGreg Roach            ->get()
133e5a6b4d4SGreg Roach            ->map(User::rowMapper());
134e5a6b4d4SGreg Roach    }
135e5a6b4d4SGreg Roach
136e5a6b4d4SGreg Roach    /**
137e5a6b4d4SGreg Roach     * Get a list of all administrators.
138e5a6b4d4SGreg Roach     *
13954c7f8dfSGreg Roach     * @return Collection
140e5a6b4d4SGreg Roach     */
141e5a6b4d4SGreg Roach    public function administrators(): Collection
142e5a6b4d4SGreg Roach    {
143e5a6b4d4SGreg Roach        return DB::table('user')
1440b5fd0a6SGreg Roach            ->join('user_setting', static function (JoinClause $join): void {
145e5a6b4d4SGreg Roach                $join
146e5a6b4d4SGreg Roach                    ->on('user_setting.user_id', '=', 'user.user_id')
147e5a6b4d4SGreg Roach                    ->where('user_setting.setting_name', '=', 'canadmin')
148e5a6b4d4SGreg Roach                    ->where('user_setting.setting_value', '=', '1');
149e5a6b4d4SGreg Roach            })
150e5a6b4d4SGreg Roach            ->where('user.user_id', '>', 0)
151e5a6b4d4SGreg Roach            ->orderBy('real_name')
152e5a6b4d4SGreg Roach            ->select(['user.*'])
153e5a6b4d4SGreg Roach            ->get()
154e5a6b4d4SGreg Roach            ->map(User::rowMapper());
155e5a6b4d4SGreg Roach    }
156e5a6b4d4SGreg Roach
157e5a6b4d4SGreg Roach    /**
158e5a6b4d4SGreg Roach     * Get a list of all managers.
159e5a6b4d4SGreg Roach     *
16054c7f8dfSGreg Roach     * @return Collection
161e5a6b4d4SGreg Roach     */
162e5a6b4d4SGreg Roach    public function managers(): Collection
163e5a6b4d4SGreg Roach    {
164e5a6b4d4SGreg Roach        return DB::table('user')
1650b5fd0a6SGreg Roach            ->join('user_gedcom_setting', static function (JoinClause $join): void {
166e5a6b4d4SGreg Roach                $join
167e5a6b4d4SGreg Roach                    ->on('user_gedcom_setting.user_id', '=', 'user.user_id')
168e5a6b4d4SGreg Roach                    ->where('user_gedcom_setting.setting_name', '=', 'canedit')
169e5a6b4d4SGreg Roach                    ->where('user_gedcom_setting.setting_value', '=', 'admin');
170e5a6b4d4SGreg Roach            })
171e5a6b4d4SGreg Roach            ->where('user.user_id', '>', 0)
172e5a6b4d4SGreg Roach            ->orderBy('real_name')
173e5a6b4d4SGreg Roach            ->select(['user.*'])
174e5a6b4d4SGreg Roach            ->get()
175e5a6b4d4SGreg Roach            ->map(User::rowMapper());
176e5a6b4d4SGreg Roach    }
177e5a6b4d4SGreg Roach
178e5a6b4d4SGreg Roach    /**
179e5a6b4d4SGreg Roach     * Get a list of all moderators.
180e5a6b4d4SGreg Roach     *
18154c7f8dfSGreg Roach     * @return Collection
182e5a6b4d4SGreg Roach     */
183e5a6b4d4SGreg Roach    public function moderators(): Collection
184e5a6b4d4SGreg Roach    {
185e5a6b4d4SGreg Roach        return DB::table('user')
1860b5fd0a6SGreg Roach            ->join('user_gedcom_setting', static function (JoinClause $join): void {
187e5a6b4d4SGreg Roach                $join
188e5a6b4d4SGreg Roach                    ->on('user_gedcom_setting.user_id', '=', 'user.user_id')
189e5a6b4d4SGreg Roach                    ->where('user_gedcom_setting.setting_name', '=', 'canedit')
190e5a6b4d4SGreg Roach                    ->where('user_gedcom_setting.setting_value', '=', 'accept');
191e5a6b4d4SGreg Roach            })
192e5a6b4d4SGreg Roach            ->where('user.user_id', '>', 0)
193e5a6b4d4SGreg Roach            ->orderBy('real_name')
194e5a6b4d4SGreg Roach            ->select(['user.*'])
195e5a6b4d4SGreg Roach            ->get()
196e5a6b4d4SGreg Roach            ->map(User::rowMapper());
197e5a6b4d4SGreg Roach    }
198e5a6b4d4SGreg Roach
199e5a6b4d4SGreg Roach    /**
200e5a6b4d4SGreg Roach     * Get a list of all verified users.
201e5a6b4d4SGreg Roach     *
20254c7f8dfSGreg Roach     * @return Collection
203e5a6b4d4SGreg Roach     */
204e5a6b4d4SGreg Roach    public function unapproved(): Collection
205e5a6b4d4SGreg Roach    {
206e5a6b4d4SGreg Roach        return DB::table('user')
2070b5fd0a6SGreg Roach            ->join('user_setting', static function (JoinClause $join): void {
208e5a6b4d4SGreg Roach                $join
209e5a6b4d4SGreg Roach                    ->on('user_setting.user_id', '=', 'user.user_id')
210e5a6b4d4SGreg Roach                    ->where('user_setting.setting_name', '=', 'verified_by_admin')
211e5a6b4d4SGreg Roach                    ->where('user_setting.setting_value', '=', '0');
212e5a6b4d4SGreg Roach            })
213e5a6b4d4SGreg Roach            ->where('user.user_id', '>', 0)
214e5a6b4d4SGreg Roach            ->orderBy('real_name')
215e5a6b4d4SGreg Roach            ->select(['user.*'])
216e5a6b4d4SGreg Roach            ->get()
217e5a6b4d4SGreg Roach            ->map(User::rowMapper());
218e5a6b4d4SGreg Roach    }
219e5a6b4d4SGreg Roach
220e5a6b4d4SGreg Roach    /**
221e5a6b4d4SGreg Roach     * Get a list of all verified users.
222e5a6b4d4SGreg Roach     *
22354c7f8dfSGreg Roach     * @return Collection
224e5a6b4d4SGreg Roach     */
225e5a6b4d4SGreg Roach    public function unverified(): Collection
226e5a6b4d4SGreg Roach    {
227e5a6b4d4SGreg Roach        return DB::table('user')
2280b5fd0a6SGreg Roach            ->join('user_setting', static function (JoinClause $join): void {
229e5a6b4d4SGreg Roach                $join
230e5a6b4d4SGreg Roach                    ->on('user_setting.user_id', '=', 'user.user_id')
231e5a6b4d4SGreg Roach                    ->where('user_setting.setting_name', '=', 'verified')
232e5a6b4d4SGreg Roach                    ->where('user_setting.setting_value', '=', '0');
233e5a6b4d4SGreg Roach            })
234e5a6b4d4SGreg Roach            ->where('user.user_id', '>', 0)
235e5a6b4d4SGreg Roach            ->orderBy('real_name')
236e5a6b4d4SGreg Roach            ->select(['user.*'])
237e5a6b4d4SGreg Roach            ->get()
238e5a6b4d4SGreg Roach            ->map(User::rowMapper());
239e5a6b4d4SGreg Roach    }
240e5a6b4d4SGreg Roach
241e5a6b4d4SGreg Roach    /**
242e5a6b4d4SGreg Roach     * Get a list of all users who are currently logged in.
243e5a6b4d4SGreg Roach     *
24454c7f8dfSGreg Roach     * @return Collection
245e5a6b4d4SGreg Roach     */
246e5a6b4d4SGreg Roach    public function allLoggedIn(): Collection
247e5a6b4d4SGreg Roach    {
248e5a6b4d4SGreg Roach        return DB::table('user')
249e5a6b4d4SGreg Roach            ->join('session', 'session.user_id', '=', 'user.user_id')
250e5a6b4d4SGreg Roach            ->where('user.user_id', '>', 0)
251e5a6b4d4SGreg Roach            ->orderBy('real_name')
252e5a6b4d4SGreg Roach            ->select(['user.*'])
253e5a6b4d4SGreg Roach            ->distinct()
254e5a6b4d4SGreg Roach            ->get()
255e5a6b4d4SGreg Roach            ->map(User::rowMapper());
256e5a6b4d4SGreg Roach    }
257e5a6b4d4SGreg Roach
258e5a6b4d4SGreg Roach    /**
259e5a6b4d4SGreg Roach     * Create a new user.
260e5a6b4d4SGreg Roach     * The calling code needs to check for duplicates identifiers before calling
261e5a6b4d4SGreg Roach     * this function.
262e5a6b4d4SGreg Roach     *
263e5a6b4d4SGreg Roach     * @param string $user_name
264e5a6b4d4SGreg Roach     * @param string $real_name
265e5a6b4d4SGreg Roach     * @param string $email
266e5a6b4d4SGreg Roach     * @param string $password
267e5a6b4d4SGreg Roach     *
268e5a6b4d4SGreg Roach     * @return User
269e5a6b4d4SGreg Roach     */
2706be338f5SGreg Roach    public function create(string $user_name, string $real_name, string $email, string $password): User
271e5a6b4d4SGreg Roach    {
272e5a6b4d4SGreg Roach        DB::table('user')->insert([
273e5a6b4d4SGreg Roach            'user_name' => $user_name,
274e5a6b4d4SGreg Roach            'real_name' => $real_name,
275e5a6b4d4SGreg Roach            'email'     => $email,
276e5a6b4d4SGreg Roach            'password'  => password_hash($password, PASSWORD_DEFAULT),
277e5a6b4d4SGreg Roach        ]);
278e5a6b4d4SGreg Roach
279e5a6b4d4SGreg Roach        $user_id = (int) DB::connection()->getPdo()->lastInsertId();
280e5a6b4d4SGreg Roach
281e5a6b4d4SGreg Roach        return new User($user_id, $user_name, $real_name, $email);
282e5a6b4d4SGreg Roach    }
283e5a6b4d4SGreg Roach
284e5a6b4d4SGreg Roach    /**
285e5a6b4d4SGreg Roach     * Delete a user
286e5a6b4d4SGreg Roach     *
287e5a6b4d4SGreg Roach     * @param User $user
288e5a6b4d4SGreg Roach     *
289e5a6b4d4SGreg Roach     * @return void
290e5a6b4d4SGreg Roach     */
291e364afe4SGreg Roach    public function delete(User $user): void
292e5a6b4d4SGreg Roach    {
293e5a6b4d4SGreg Roach        // Don't delete the logs, just set the user to null.
294e5a6b4d4SGreg Roach        DB::table('log')
295e5a6b4d4SGreg Roach            ->where('user_id', '=', $user->id())
296e5a6b4d4SGreg Roach            ->update(['user_id' => null]);
297e5a6b4d4SGreg Roach
298e5a6b4d4SGreg Roach        // Take over the user’s pending changes. (What else could we do with them?)
299e5a6b4d4SGreg Roach        DB::table('change')
300e5a6b4d4SGreg Roach            ->where('user_id', '=', $user->id())
301e5a6b4d4SGreg Roach            ->where('status', '=', 'rejected')
302e5a6b4d4SGreg Roach            ->delete();
303e5a6b4d4SGreg Roach
304e5a6b4d4SGreg Roach        DB::table('change')
305e5a6b4d4SGreg Roach            ->where('user_id', '=', $user->id())
306e5a6b4d4SGreg Roach            ->update(['user_id' => Auth::id()]);
307e5a6b4d4SGreg Roach
308e5a6b4d4SGreg Roach        // Delete settings and preferences
309e5a6b4d4SGreg Roach        DB::table('block_setting')
310e5a6b4d4SGreg Roach            ->join('block', 'block_setting.block_id', '=', 'block.block_id')
311e5a6b4d4SGreg Roach            ->where('user_id', '=', $user->id())
312e5a6b4d4SGreg Roach            ->delete();
313e5a6b4d4SGreg Roach
314e5a6b4d4SGreg Roach        DB::table('block')->where('user_id', '=', $user->id())->delete();
315e5a6b4d4SGreg Roach        DB::table('user_gedcom_setting')->where('user_id', '=', $user->id())->delete();
316e5a6b4d4SGreg Roach        DB::table('user_setting')->where('user_id', '=', $user->id())->delete();
317e5a6b4d4SGreg Roach        DB::table('message')->where('user_id', '=', $user->id())->delete();
318e5a6b4d4SGreg Roach        DB::table('user')->where('user_id', '=', $user->id())->delete();
319e5a6b4d4SGreg Roach    }
32086730b84SGreg Roach
32186730b84SGreg Roach    /**
3224db4b4a9SGreg Roach     * @param User $contact_user
32386730b84SGreg Roach     *
32486730b84SGreg Roach     * @return string
32586730b84SGreg Roach     */
326dcbe9044SGreg Roach    public function contactLink(User $contact_user): string
327dcbe9044SGreg Roach    {
328cab242e7SGreg Roach        $tree    = app(Tree::class);
329cab242e7SGreg Roach        $user    = app(UserInterface::class);
3306ccdf4f0SGreg Roach        $request = app(ServerRequestInterface::class);
33186730b84SGreg Roach
33286730b84SGreg Roach        if ($contact_user->getPreference('contactmethod') === 'mailto') {
33386730b84SGreg Roach            $url = 'mailto:' . $contact_user->email();
33486730b84SGreg Roach        } elseif ($user instanceof User) {
33586730b84SGreg Roach            // Logged-in users send direct messages
3365d284d5dSGreg Roach            $url = route('message', ['to' => $contact_user->userName()]);
33786730b84SGreg Roach        } else {
33886730b84SGreg Roach            // Visitors use the contact form.
33986730b84SGreg Roach            $url = route('contact', [
34086730b84SGreg Roach                'ged' => $tree ? $tree->name() : '',
34186730b84SGreg Roach                'to'  => $contact_user->userName(),
342*add3fa41SGreg Roach                'url' => $request->getAttribute('request_uri'),
34386730b84SGreg Roach            ]);
34486730b84SGreg Roach        }
34586730b84SGreg Roach
34686730b84SGreg Roach        return '<a href="' . e($url) . '" dir="auto">' . e($contact_user->realName()) . '</a>';
34786730b84SGreg Roach    }
348e5a6b4d4SGreg Roach}
349