xref: /webtrees/app/Statistics/Repository/UserRepository.php (revision 4c78e066e3ba48f4c71bb900fac88b9e85e97474)
1<?php
2
3/**
4 * webtrees: online genealogy
5 * Copyright (C) 2021 webtrees development team
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18declare(strict_types=1);
19
20namespace Fisharebest\Webtrees\Statistics\Repository;
21
22use Fisharebest\Webtrees\Auth;
23use Fisharebest\Webtrees\Contracts\UserInterface;
24use Fisharebest\Webtrees\Registry;
25use Fisharebest\Webtrees\Http\RequestHandlers\MessagePage;
26use Fisharebest\Webtrees\I18N;
27use Fisharebest\Webtrees\Individual;
28use Fisharebest\Webtrees\Services\UserService;
29use Fisharebest\Webtrees\Statistics\Repository\Interfaces\UserRepositoryInterface;
30use Fisharebest\Webtrees\Tree;
31
32use function count;
33use function e;
34use function route;
35use function view;
36
37/**
38 * A repository providing methods for user related statistics.
39 */
40class UserRepository implements UserRepositoryInterface
41{
42    private Tree $tree;
43
44    private UserService $user_service;
45
46    /**
47     * @param Tree        $tree
48     * @param UserService $user_service
49     */
50    public function __construct(Tree $tree, UserService $user_service)
51    {
52        $this->tree         = $tree;
53        $this->user_service = $user_service;
54    }
55
56    /**
57     * Who is currently logged in?
58     *
59     * @param string $type "list" or "nolist"
60     *
61     * @return string
62     */
63    private function usersLoggedInQuery(string $type = 'nolist'): string
64    {
65        $content   = '';
66        $anonymous = 0;
67        $logged_in = [];
68
69        foreach ($this->user_service->allLoggedIn() as $user) {
70            if (Auth::isAdmin() || $user->getPreference(UserInterface::PREF_IS_VISIBLE_ONLINE) === '1') {
71                $logged_in[] = $user;
72            } else {
73                $anonymous++;
74            }
75        }
76
77        $count_logged_in = count($logged_in);
78
79        if ($count_logged_in === 0 && $anonymous === 0) {
80            $content .= I18N::translate('No signed-in and no anonymous users');
81        }
82
83        if ($anonymous > 0) {
84            $content .= '<b>' . I18N::plural('%s anonymous signed-in user', '%s anonymous signed-in users', $anonymous, I18N::number($anonymous)) . '</b>';
85        }
86
87        if ($count_logged_in > 0) {
88            if ($anonymous) {
89                if ($type === 'list') {
90                    $content .= '<br><br>';
91                } else {
92                    $content .= ' ' . I18N::translate('and') . ' ';
93                }
94            }
95            $content .= '<b>' . I18N::plural('%s signed-in user', '%s signed-in users', $count_logged_in, I18N::number($count_logged_in)) . '</b>';
96            if ($type === 'list') {
97                $content .= '<ul>';
98            } else {
99                $content .= ': ';
100            }
101        }
102
103        if (Auth::check()) {
104            foreach ($logged_in as $user) {
105                if ($type === 'list') {
106                    $content .= '<li>';
107                }
108
109                $individual = Registry::individualFactory()->make($this->tree->getUserPreference($user, UserInterface::PREF_TREE_ACCOUNT_XREF), $this->tree);
110
111                if ($individual instanceof Individual && $individual->canShow()) {
112                    $content .= '<a href="' . e($individual->url()) . '">' . e($user->realName()) . '</a>';
113                } else {
114                    $content .= e($user->realName());
115                }
116
117                $content .= ' - ' . e($user->userName());
118
119                if ($user->getPreference(UserInterface::PREF_CONTACT_METHOD) !== 'none' && Auth::id() !== $user->id()) {
120                    $content .= '<a href="' . e(route(MessagePage::class, ['to' => $user->userName(), 'tree' => $this->tree->name()])) . '" class="btn btn-link" title="' . I18N::translate('Send a message') . '">' . view('icons/email') . '</a>';
121                }
122
123                if ($type === 'list') {
124                    $content .= '</li>';
125                }
126            }
127        }
128
129        if ($type === 'list') {
130            $content .= '</ul>';
131        }
132
133        return $content;
134    }
135
136    /**
137     * @return string
138     */
139    public function usersLoggedIn(): string
140    {
141        return $this->usersLoggedInQuery('nolist');
142    }
143
144    /**
145     * @return string
146     */
147    public function usersLoggedInList(): string
148    {
149        return $this->usersLoggedInQuery('list');
150    }
151
152    /**
153     * Returns true if the given user is visible to others.
154     *
155     * @param UserInterface $user
156     *
157     * @return bool
158     */
159    private function isUserVisible(UserInterface $user): bool
160    {
161        return Auth::isAdmin() || $user->getPreference(UserInterface::PREF_IS_VISIBLE_ONLINE) === '1';
162    }
163
164    /**
165     * @return int
166     */
167    public function usersLoggedInTotal(): int
168    {
169        return count($this->user_service->allLoggedIn());
170    }
171
172    /**
173     * @return int
174     */
175    public function usersLoggedInTotalAnon(): int
176    {
177        $anonymous = 0;
178
179        foreach ($this->user_service->allLoggedIn() as $user) {
180            if (!$this->isUserVisible($user)) {
181                ++$anonymous;
182            }
183        }
184
185        return $anonymous;
186    }
187
188    /**
189     * @return int
190     */
191    public function usersLoggedInTotalVisible(): int
192    {
193        $visible = 0;
194
195        foreach ($this->user_service->allLoggedIn() as $user) {
196            if ($this->isUserVisible($user)) {
197                ++$visible;
198            }
199        }
200
201        return $visible;
202    }
203
204    /**
205     * @return string
206     */
207    public function userId(): string
208    {
209        return (string) Auth::id();
210    }
211
212    /**
213     * @param string $visitor_text
214     *
215     * @return string
216     */
217    public function userName(string $visitor_text = ''): string
218    {
219        if (Auth::check()) {
220            return e(Auth::user()->userName());
221        }
222
223        // if #username:visitor# was specified, then "visitor" will be returned when the user is not logged in
224        return e($visitor_text);
225    }
226
227    /**
228     * @return string
229     */
230    public function userFullName(): string
231    {
232        return Auth::check() ? '<bdi>' . e(Auth::user()->realName()) . '</bdi>' : '';
233    }
234
235    /**
236     * Returns the user count.
237     *
238     * @return int
239     */
240    private function getUserCount(): int
241    {
242        return count($this->user_service->all());
243    }
244
245    /**
246     * Returns the administrator count.
247     *
248     * @return int
249     */
250    private function getAdminCount(): int
251    {
252        return count($this->user_service->administrators());
253    }
254
255    /**
256     * @return string
257     */
258    public function totalUsers(): string
259    {
260        return I18N::number($this->getUserCount());
261    }
262
263    /**
264     * @return string
265     */
266    public function totalAdmins(): string
267    {
268        return I18N::number($this->getAdminCount());
269    }
270
271    /**
272     * @return string
273     */
274    public function totalNonAdmins(): string
275    {
276        return I18N::number($this->getUserCount() - $this->getAdminCount());
277    }
278}
279