xref: /webtrees/app/Services/UserService.php (revision fed75bda96a7f38fcb7b42be805b37e091612146)
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     */
94    public function findByIndividual(Individual $individual): Collection
95    {
96        return DB::table('user')
97            ->join('user_gedcom_setting', 'user_gedcom_setting.user_id', '=', 'user.user_id')
98            ->where('gedcom_id', '=', $individual->tree()->id())
99            ->where('setting_value', '=', $individual->xref())
100            ->where('setting_name', '=', 'gedcomid')
101            ->select(['user.*'])
102            ->get()
103            ->map(User::rowMapper());
104    }
105
106    /**
107     * Find the user with a specified user_name.
108     *
109     * @param string $user_name
110     *
111     * @return User|null
112     */
113    public function findByUserName($user_name): ?User
114    {
115        return DB::table('user')
116            ->where('user_name', '=', $user_name)
117            ->get()
118            ->map(User::rowMapper())
119            ->first();
120    }
121
122    /**
123     * Get a list of all users.
124     *
125     * @return Collection
126     */
127    public function all(): Collection
128    {
129        return DB::table('user')
130            ->where('user_id', '>', 0)
131            ->orderBy('real_name')
132            ->get()
133            ->map(User::rowMapper());
134    }
135
136    /**
137     * Get a list of all administrators.
138     *
139     * @return Collection
140     */
141    public function administrators(): Collection
142    {
143        return DB::table('user')
144            ->join('user_setting', static function (JoinClause $join): void {
145                $join
146                    ->on('user_setting.user_id', '=', 'user.user_id')
147                    ->where('user_setting.setting_name', '=', 'canadmin')
148                    ->where('user_setting.setting_value', '=', '1');
149            })
150            ->where('user.user_id', '>', 0)
151            ->orderBy('real_name')
152            ->select(['user.*'])
153            ->get()
154            ->map(User::rowMapper());
155    }
156
157    /**
158     * Get a list of all managers.
159     *
160     * @return Collection
161     */
162    public function managers(): Collection
163    {
164        return DB::table('user')
165            ->join('user_gedcom_setting', static function (JoinClause $join): void {
166                $join
167                    ->on('user_gedcom_setting.user_id', '=', 'user.user_id')
168                    ->where('user_gedcom_setting.setting_name', '=', 'canedit')
169                    ->where('user_gedcom_setting.setting_value', '=', 'admin');
170            })
171            ->where('user.user_id', '>', 0)
172            ->orderBy('real_name')
173            ->select(['user.*'])
174            ->get()
175            ->map(User::rowMapper());
176    }
177
178    /**
179     * Get a list of all moderators.
180     *
181     * @return Collection
182     */
183    public function moderators(): Collection
184    {
185        return DB::table('user')
186            ->join('user_gedcom_setting', static function (JoinClause $join): void {
187                $join
188                    ->on('user_gedcom_setting.user_id', '=', 'user.user_id')
189                    ->where('user_gedcom_setting.setting_name', '=', 'canedit')
190                    ->where('user_gedcom_setting.setting_value', '=', 'accept');
191            })
192            ->where('user.user_id', '>', 0)
193            ->orderBy('real_name')
194            ->select(['user.*'])
195            ->get()
196            ->map(User::rowMapper());
197    }
198
199    /**
200     * Get a list of all verified users.
201     *
202     * @return Collection
203     */
204    public function unapproved(): Collection
205    {
206        return DB::table('user')
207            ->join('user_setting', static function (JoinClause $join): void {
208                $join
209                    ->on('user_setting.user_id', '=', 'user.user_id')
210                    ->where('user_setting.setting_name', '=', 'verified_by_admin')
211                    ->where('user_setting.setting_value', '=', '0');
212            })
213            ->where('user.user_id', '>', 0)
214            ->orderBy('real_name')
215            ->select(['user.*'])
216            ->get()
217            ->map(User::rowMapper());
218    }
219
220    /**
221     * Get a list of all verified users.
222     *
223     * @return Collection
224     */
225    public function unverified(): Collection
226    {
227        return DB::table('user')
228            ->join('user_setting', static function (JoinClause $join): void {
229                $join
230                    ->on('user_setting.user_id', '=', 'user.user_id')
231                    ->where('user_setting.setting_name', '=', 'verified')
232                    ->where('user_setting.setting_value', '=', '0');
233            })
234            ->where('user.user_id', '>', 0)
235            ->orderBy('real_name')
236            ->select(['user.*'])
237            ->get()
238            ->map(User::rowMapper());
239    }
240
241    /**
242     * Get a list of all users who are currently logged in.
243     *
244     * @return Collection
245     */
246    public function allLoggedIn(): Collection
247    {
248        return DB::table('user')
249            ->join('session', 'session.user_id', '=', 'user.user_id')
250            ->where('user.user_id', '>', 0)
251            ->orderBy('real_name')
252            ->select(['user.*'])
253            ->distinct()
254            ->get()
255            ->map(User::rowMapper());
256    }
257
258    /**
259     * Create a new user.
260     * The calling code needs to check for duplicates identifiers before calling
261     * this function.
262     *
263     * @param string $user_name
264     * @param string $real_name
265     * @param string $email
266     * @param string $password
267     *
268     * @return User
269     */
270    public function create(string $user_name, string $real_name, string $email, string $password): User
271    {
272        DB::table('user')->insert([
273            'user_name' => $user_name,
274            'real_name' => $real_name,
275            'email'     => $email,
276            'password'  => password_hash($password, PASSWORD_DEFAULT),
277        ]);
278
279        $user_id = (int) DB::connection()->getPdo()->lastInsertId();
280
281        return new User($user_id, $user_name, $real_name, $email);
282    }
283
284    /**
285     * Delete a user
286     *
287     * @param User $user
288     *
289     * @return void
290     */
291    public function delete(User $user): void
292    {
293        // Don't delete the logs, just set the user to null.
294        DB::table('log')
295            ->where('user_id', '=', $user->id())
296            ->update(['user_id' => null]);
297
298        // Take over the user’s pending changes. (What else could we do with them?)
299        DB::table('change')
300            ->where('user_id', '=', $user->id())
301            ->where('status', '=', 'rejected')
302            ->delete();
303
304        DB::table('change')
305            ->where('user_id', '=', $user->id())
306            ->update(['user_id' => Auth::id()]);
307
308        // Delete settings and preferences
309        DB::table('block_setting')
310            ->join('block', 'block_setting.block_id', '=', 'block.block_id')
311            ->where('user_id', '=', $user->id())
312            ->delete();
313
314        DB::table('block')->where('user_id', '=', $user->id())->delete();
315        DB::table('user_gedcom_setting')->where('user_id', '=', $user->id())->delete();
316        DB::table('user_setting')->where('user_id', '=', $user->id())->delete();
317        DB::table('message')->where('user_id', '=', $user->id())->delete();
318        DB::table('user')->where('user_id', '=', $user->id())->delete();
319    }
320
321    /**
322     * @param User $contact_user
323     *
324     * @return string
325     */
326    public function contactLink(User $contact_user): string
327    {
328        $tree    = app(Tree::class);
329        $user    = app(UserInterface::class);
330        $request = app(ServerRequestInterface::class);
331
332        if ($contact_user->getPreference('contactmethod') === 'mailto') {
333            $url = 'mailto:' . $contact_user->email();
334        } elseif ($user instanceof User) {
335            // Logged-in users send direct messages
336            $url = route('message', ['to' => $contact_user->userName()]);
337        } else {
338            // Visitors use the contact form.
339            $url = route('contact', [
340                'ged' => $tree ? $tree->name() : '',
341                'to'  => $contact_user->userName(),
342                'url' => $request->getAttribute('request_uri'),
343            ]);
344        }
345
346        return '<a href="' . e($url) . '" dir="auto">' . e($contact_user->realName()) . '</a>';
347    }
348}
349