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