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