18add1155SRico Sonntag<?php 23976b470SGreg Roach 38add1155SRico Sonntag/** 48add1155SRico Sonntag * webtrees: online genealogy 5*5bfc6897SGreg Roach * Copyright (C) 2022 webtrees development team 68add1155SRico Sonntag * This program is free software: you can redistribute it and/or modify 78add1155SRico Sonntag * it under the terms of the GNU General Public License as published by 88add1155SRico Sonntag * the Free Software Foundation, either version 3 of the License, or 98add1155SRico Sonntag * (at your option) any later version. 108add1155SRico Sonntag * This program is distributed in the hope that it will be useful, 118add1155SRico Sonntag * but WITHOUT ANY WARRANTY; without even the implied warranty of 128add1155SRico Sonntag * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 138add1155SRico Sonntag * GNU General Public License for more details. 148add1155SRico Sonntag * You should have received a copy of the GNU General Public License 1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 168add1155SRico Sonntag */ 17fcfa147eSGreg Roach 188add1155SRico Sonntagdeclare(strict_types=1); 198add1155SRico Sonntag 208add1155SRico Sonntagnamespace Fisharebest\Webtrees\Statistics\Repository; 218add1155SRico Sonntag 228add1155SRico Sonntaguse Fisharebest\Webtrees\Auth; 23e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface; 246b9cb339SGreg Roachuse Fisharebest\Webtrees\Registry; 25e381f98dSGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\MessagePage; 268add1155SRico Sonntaguse Fisharebest\Webtrees\I18N; 27c0112ce8SGreg Roachuse Fisharebest\Webtrees\Individual; 28e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Services\UserService; 298add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Repository\Interfaces\UserRepositoryInterface; 308add1155SRico Sonntaguse Fisharebest\Webtrees\Tree; 318add1155SRico Sonntag 3271378461SGreg Roachuse function count; 334c78e066SGreg Roachuse function e; 344c78e066SGreg Roachuse function route; 354c78e066SGreg Roachuse function view; 3671378461SGreg Roach 378add1155SRico Sonntag/** 388add1155SRico Sonntag * A repository providing methods for user related statistics. 398add1155SRico Sonntag */ 408add1155SRico Sonntagclass UserRepository implements UserRepositoryInterface 418add1155SRico Sonntag{ 424c78e066SGreg Roach private Tree $tree; 434c78e066SGreg Roach 444c78e066SGreg Roach private UserService $user_service; 458add1155SRico Sonntag 468add1155SRico Sonntag /** 478add1155SRico Sonntag * @param Tree $tree 48e5a6b4d4SGreg Roach * @param UserService $user_service 498add1155SRico Sonntag */ 50e5a6b4d4SGreg Roach public function __construct(Tree $tree, UserService $user_service) 518add1155SRico Sonntag { 528add1155SRico Sonntag $this->tree = $tree; 53e5a6b4d4SGreg Roach $this->user_service = $user_service; 548add1155SRico Sonntag } 558add1155SRico Sonntag 568add1155SRico Sonntag /** 578add1155SRico Sonntag * Who is currently logged in? 588add1155SRico Sonntag * 59c0112ce8SGreg Roach * @param string $type "list" or "nolist" 608add1155SRico Sonntag * 618add1155SRico Sonntag * @return string 628add1155SRico Sonntag */ 63f78da678SGreg Roach private function usersLoggedInQuery(string $type): string 648add1155SRico Sonntag { 658add1155SRico Sonntag $content = ''; 66c0112ce8SGreg Roach $anonymous = 0; 67c0112ce8SGreg Roach $logged_in = []; 688add1155SRico Sonntag 69e5a6b4d4SGreg Roach foreach ($this->user_service->allLoggedIn() as $user) { 701fe542e9SGreg Roach if (Auth::isAdmin() || $user->getPreference(UserInterface::PREF_IS_VISIBLE_ONLINE) === '1') { 71c0112ce8SGreg Roach $logged_in[] = $user; 728add1155SRico Sonntag } else { 73c0112ce8SGreg Roach $anonymous++; 748add1155SRico Sonntag } 758add1155SRico Sonntag } 768add1155SRico Sonntag 776ccdf4f0SGreg Roach $count_logged_in = count($logged_in); 78c0112ce8SGreg Roach 79c0112ce8SGreg Roach if ($count_logged_in === 0 && $anonymous === 0) { 80c0112ce8SGreg Roach $content .= I18N::translate('No signed-in and no anonymous users'); 818add1155SRico Sonntag } 828add1155SRico Sonntag 83c0112ce8SGreg Roach if ($anonymous > 0) { 84c0112ce8SGreg Roach $content .= '<b>' . I18N::plural('%s anonymous signed-in user', '%s anonymous signed-in users', $anonymous, I18N::number($anonymous)) . '</b>'; 858add1155SRico Sonntag } 868add1155SRico Sonntag 87c0112ce8SGreg Roach if ($count_logged_in > 0) { 88c0112ce8SGreg Roach if ($anonymous) { 898add1155SRico Sonntag if ($type === 'list') { 908add1155SRico Sonntag $content .= '<br><br>'; 918add1155SRico Sonntag } else { 928add1155SRico Sonntag $content .= ' ' . I18N::translate('and') . ' '; 938add1155SRico Sonntag } 948add1155SRico Sonntag } 95c0112ce8SGreg Roach $content .= '<b>' . I18N::plural('%s signed-in user', '%s signed-in users', $count_logged_in, I18N::number($count_logged_in)) . '</b>'; 968add1155SRico Sonntag if ($type === 'list') { 978add1155SRico Sonntag $content .= '<ul>'; 988add1155SRico Sonntag } else { 998add1155SRico Sonntag $content .= ': '; 1008add1155SRico Sonntag } 1018add1155SRico Sonntag } 1028add1155SRico Sonntag 1038add1155SRico Sonntag if (Auth::check()) { 104c0112ce8SGreg Roach foreach ($logged_in as $user) { 1058add1155SRico Sonntag if ($type === 'list') { 106c0112ce8SGreg Roach $content .= '<li>'; 1078add1155SRico Sonntag } 1088add1155SRico Sonntag 1091fe542e9SGreg Roach $individual = Registry::individualFactory()->make($this->tree->getUserPreference($user, UserInterface::PREF_TREE_ACCOUNT_XREF), $this->tree); 110c0112ce8SGreg Roach 111c0112ce8SGreg Roach if ($individual instanceof Individual && $individual->canShow()) { 112c0112ce8SGreg Roach $content .= '<a href="' . e($individual->url()) . '">' . e($user->realName()) . '</a>'; 113c0112ce8SGreg Roach } else { 114c0112ce8SGreg Roach $content .= e($user->realName()); 115c0112ce8SGreg Roach } 116c0112ce8SGreg Roach 117c0112ce8SGreg Roach $content .= ' - ' . e($user->userName()); 118c0112ce8SGreg Roach 1191fe542e9SGreg Roach if ($user->getPreference(UserInterface::PREF_CONTACT_METHOD) !== 'none' && Auth::id() !== $user->id()) { 120e381f98dSGreg Roach $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>'; 1218add1155SRico Sonntag } 1228add1155SRico Sonntag 1238add1155SRico Sonntag if ($type === 'list') { 1248add1155SRico Sonntag $content .= '</li>'; 1258add1155SRico Sonntag } 1268add1155SRico Sonntag } 1278add1155SRico Sonntag } 1288add1155SRico Sonntag 1298add1155SRico Sonntag if ($type === 'list') { 1308add1155SRico Sonntag $content .= '</ul>'; 1318add1155SRico Sonntag } 1328add1155SRico Sonntag 1338add1155SRico Sonntag return $content; 1348add1155SRico Sonntag } 1358add1155SRico Sonntag 1368add1155SRico Sonntag /** 1370dcd9387SGreg Roach * @return string 1388add1155SRico Sonntag */ 1398add1155SRico Sonntag public function usersLoggedIn(): string 1408add1155SRico Sonntag { 141c0112ce8SGreg Roach return $this->usersLoggedInQuery('nolist'); 1428add1155SRico Sonntag } 1438add1155SRico Sonntag 1448add1155SRico Sonntag /** 1450dcd9387SGreg Roach * @return string 1468add1155SRico Sonntag */ 1478add1155SRico Sonntag public function usersLoggedInList(): string 1488add1155SRico Sonntag { 1498add1155SRico Sonntag return $this->usersLoggedInQuery('list'); 1508add1155SRico Sonntag } 1518add1155SRico Sonntag 1528add1155SRico Sonntag /** 1538add1155SRico Sonntag * Returns true if the given user is visible to others. 1548add1155SRico Sonntag * 155e5a6b4d4SGreg Roach * @param UserInterface $user 1568add1155SRico Sonntag * 1578add1155SRico Sonntag * @return bool 1588add1155SRico Sonntag */ 159e5a6b4d4SGreg Roach private function isUserVisible(UserInterface $user): bool 1608add1155SRico Sonntag { 1611fe542e9SGreg Roach return Auth::isAdmin() || $user->getPreference(UserInterface::PREF_IS_VISIBLE_ONLINE) === '1'; 1628add1155SRico Sonntag } 1638add1155SRico Sonntag 1648add1155SRico Sonntag /** 1650dcd9387SGreg Roach * @return int 1668add1155SRico Sonntag */ 1678add1155SRico Sonntag public function usersLoggedInTotal(): int 1688add1155SRico Sonntag { 1696ccdf4f0SGreg Roach return count($this->user_service->allLoggedIn()); 1708add1155SRico Sonntag } 1718add1155SRico Sonntag 1728add1155SRico Sonntag /** 1730dcd9387SGreg Roach * @return int 1748add1155SRico Sonntag */ 1758add1155SRico Sonntag public function usersLoggedInTotalAnon(): int 1768add1155SRico Sonntag { 1778add1155SRico Sonntag $anonymous = 0; 1788add1155SRico Sonntag 179e5a6b4d4SGreg Roach foreach ($this->user_service->allLoggedIn() as $user) { 1808add1155SRico Sonntag if (!$this->isUserVisible($user)) { 1818add1155SRico Sonntag ++$anonymous; 1828add1155SRico Sonntag } 1838add1155SRico Sonntag } 1848add1155SRico Sonntag 1858add1155SRico Sonntag return $anonymous; 1868add1155SRico Sonntag } 1878add1155SRico Sonntag 1888add1155SRico Sonntag /** 1890dcd9387SGreg Roach * @return int 1908add1155SRico Sonntag */ 1918add1155SRico Sonntag public function usersLoggedInTotalVisible(): int 1928add1155SRico Sonntag { 1938add1155SRico Sonntag $visible = 0; 1948add1155SRico Sonntag 195e5a6b4d4SGreg Roach foreach ($this->user_service->allLoggedIn() as $user) { 1968add1155SRico Sonntag if ($this->isUserVisible($user)) { 1978add1155SRico Sonntag ++$visible; 1988add1155SRico Sonntag } 1998add1155SRico Sonntag } 2008add1155SRico Sonntag 2018add1155SRico Sonntag return $visible; 2028add1155SRico Sonntag } 2038add1155SRico Sonntag 2048add1155SRico Sonntag /** 2050dcd9387SGreg Roach * @return string 2068add1155SRico Sonntag */ 2078add1155SRico Sonntag public function userId(): string 2088add1155SRico Sonntag { 2098add1155SRico Sonntag return (string) Auth::id(); 2108add1155SRico Sonntag } 2118add1155SRico Sonntag 2128add1155SRico Sonntag /** 2130dcd9387SGreg Roach * @param string $visitor_text 2140dcd9387SGreg Roach * 2150dcd9387SGreg Roach * @return string 2168add1155SRico Sonntag */ 2178add1155SRico Sonntag public function userName(string $visitor_text = ''): string 2188add1155SRico Sonntag { 2198add1155SRico Sonntag if (Auth::check()) { 220e5a6b4d4SGreg Roach return e(Auth::user()->userName()); 2218add1155SRico Sonntag } 2228add1155SRico Sonntag 2238add1155SRico Sonntag // if #username:visitor# was specified, then "visitor" will be returned when the user is not logged in 2248add1155SRico Sonntag return e($visitor_text); 2258add1155SRico Sonntag } 2268add1155SRico Sonntag 2278add1155SRico Sonntag /** 2280dcd9387SGreg Roach * @return string 2298add1155SRico Sonntag */ 2308add1155SRico Sonntag public function userFullName(): string 2318add1155SRico Sonntag { 232315eb316SGreg Roach return Auth::check() ? '<bdi>' . e(Auth::user()->realName()) . '</bdi>' : ''; 2338add1155SRico Sonntag } 2348add1155SRico Sonntag 2358add1155SRico Sonntag /** 2368add1155SRico Sonntag * Returns the user count. 2378add1155SRico Sonntag * 2388add1155SRico Sonntag * @return int 2398add1155SRico Sonntag */ 2408add1155SRico Sonntag private function getUserCount(): int 2418add1155SRico Sonntag { 2426ccdf4f0SGreg Roach return count($this->user_service->all()); 2438add1155SRico Sonntag } 2448add1155SRico Sonntag 2458add1155SRico Sonntag /** 2468add1155SRico Sonntag * Returns the administrator count. 2478add1155SRico Sonntag * 2488add1155SRico Sonntag * @return int 2498add1155SRico Sonntag */ 2508add1155SRico Sonntag private function getAdminCount(): int 2518add1155SRico Sonntag { 2526ccdf4f0SGreg Roach return count($this->user_service->administrators()); 2538add1155SRico Sonntag } 2548add1155SRico Sonntag 2558add1155SRico Sonntag /** 2560dcd9387SGreg Roach * @return string 2578add1155SRico Sonntag */ 2588add1155SRico Sonntag public function totalUsers(): string 2598add1155SRico Sonntag { 2608add1155SRico Sonntag return I18N::number($this->getUserCount()); 2618add1155SRico Sonntag } 2628add1155SRico Sonntag 2638add1155SRico Sonntag /** 2640dcd9387SGreg Roach * @return string 2658add1155SRico Sonntag */ 2668add1155SRico Sonntag public function totalAdmins(): string 2678add1155SRico Sonntag { 2688add1155SRico Sonntag return I18N::number($this->getAdminCount()); 2698add1155SRico Sonntag } 2708add1155SRico Sonntag 2718add1155SRico Sonntag /** 2720dcd9387SGreg Roach * @return string 2738add1155SRico Sonntag */ 2748add1155SRico Sonntag public function totalNonAdmins(): string 2758add1155SRico Sonntag { 2768add1155SRico Sonntag return I18N::number($this->getUserCount() - $this->getAdminCount()); 2778add1155SRico Sonntag } 2788add1155SRico Sonntag} 279