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