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\Http\RequestHandlers; 21 22use Fisharebest\Webtrees\Carbon; 23use Fisharebest\Webtrees\Contracts\UserInterface; 24use Fisharebest\Webtrees\I18N; 25use Fisharebest\Webtrees\Module\ModuleLanguageInterface; 26use Fisharebest\Webtrees\Services\DatatablesService; 27use Fisharebest\Webtrees\Services\ModuleService; 28use Fisharebest\Webtrees\Services\UserService; 29use Illuminate\Database\Capsule\Manager as DB; 30use Illuminate\Database\Query\JoinClause; 31use Psr\Http\Message\ResponseInterface; 32use Psr\Http\Message\ServerRequestInterface; 33use Psr\Http\Server\RequestHandlerInterface; 34use stdClass; 35 36use function e; 37 38/** 39 * List of users. 40 */ 41class UserListData implements RequestHandlerInterface 42{ 43 /** @var DatatablesService */ 44 private $datatables_service; 45 46 /** @var ModuleService */ 47 private $module_service; 48 49 /** @var UserService */ 50 private $user_service; 51 52 /** 53 * UserListData constructor. 54 * 55 * @param DatatablesService $datatables_service 56 * @param ModuleService $module_service 57 * @param UserService $user_service 58 */ 59 public function __construct( 60 DatatablesService $datatables_service, 61 ModuleService $module_service, 62 UserService $user_service 63 ) { 64 $this->datatables_service = $datatables_service; 65 $this->module_service = $module_service; 66 $this->user_service = $user_service; 67 } 68 69 /** 70 * @param ServerRequestInterface $request 71 * 72 * @return ResponseInterface 73 */ 74 public function handle(ServerRequestInterface $request): ResponseInterface 75 { 76 $user = $request->getAttribute('user'); 77 78 $languages = $this->module_service->findByInterface(ModuleLanguageInterface::class, true) 79 ->mapWithKeys(static function (ModuleLanguageInterface $module): array { 80 $locale = $module->locale(); 81 82 return [$locale->languageTag() => $locale->endonym()]; 83 }); 84 85 $query = DB::table('user') 86 ->leftJoin('user_setting AS us1', static function (JoinClause $join): void { 87 $join 88 ->on('us1.user_id', '=', 'user.user_id') 89 ->where('us1.setting_name', '=', 'language'); 90 }) 91 ->leftJoin('user_setting AS us2', static function (JoinClause $join): void { 92 $join 93 ->on('us2.user_id', '=', 'user.user_id') 94 ->where('us2.setting_name', '=', UserInterface::PREF_TIMESTAMP_REGISTERED); 95 }) 96 ->leftJoin('user_setting AS us3', static function (JoinClause $join): void { 97 $join 98 ->on('us3.user_id', '=', 'user.user_id') 99 ->where('us3.setting_name', '=', UserInterface::PREF_TIMESTAMP_ACTIVE); 100 }) 101 ->leftJoin('user_setting AS us4', static function (JoinClause $join): void { 102 $join 103 ->on('us4.user_id', '=', 'user.user_id') 104 ->where('us4.setting_name', '=', UserInterface::PREF_IS_EMAIL_VERIFIED); 105 }) 106 ->leftJoin('user_setting AS us5', static function (JoinClause $join): void { 107 $join 108 ->on('us5.user_id', '=', 'user.user_id') 109 ->where('us5.setting_name', '=', UserInterface::PREF_IS_ACCOUNT_APPROVED); 110 }) 111 ->where('user.user_id', '>', '0') 112 ->select([ 113 'user.user_id AS edit_menu', // Hidden column 114 'user.user_id', 115 'user_name', 116 'real_name', 117 'email', 118 'us1.setting_value AS language', 119 'us2.setting_value AS registered_at_sort', // Hidden column 120 'us2.setting_value AS registered_at', 121 'us3.setting_value AS active_at_sort', // Hidden column 122 'us3.setting_value AS active_at', 123 'us4.setting_value AS verified', 124 'us5.setting_value AS verified_by_admin', 125 ]); 126 127 $search_columns = ['user_name', 'real_name', 'email']; 128 $sort_columns = []; 129 130 $callback = function (stdClass $row) use ($languages, $user): array { 131 $row_user = $this->user_service->find((int) $row->user_id); 132 $datum = [ 133 view('admin/users-table-options', ['row' => $row, 'self' => $user, 'user' => $row_user]), 134 $row->user_id, 135 '<span dir="auto">' . e($row->user_name) . '</span>', 136 '<span dir="auto">' . e($row->real_name) . '</span>', 137 '<a href="mailto:' . e($row->email) . '">' . e($row->email) . '</a>', 138 $languages->get($row->language, $row->language), 139 $row->registered_at, 140 $row->registered_at ? view('components/datetime-diff', ['timestamp' => Carbon::createFromTimestamp((int) $row->registered_at)]) : '', 141 $row->active_at, 142 $row->active_at ? view('components/datetime-diff', ['timestamp' => Carbon::createFromTimestamp((int) $row->active_at)]) : I18N::translate('Never'), 143 $row->verified ? I18N::translate('yes') : I18N::translate('no'), 144 $row->verified_by_admin ? I18N::translate('yes') : I18N::translate('no'), 145 ]; 146 147 // Highlight old registrations. 148 if (!$datum[10] && date('U') - $datum[6] > 604800) { 149 $datum[7] = '<span class="text-danger">' . $datum[7] . '</span>'; 150 } 151 152 return $datum; 153 }; 154 155 return $this->datatables_service->handleQuery($request, $query, $search_columns, $sort_columns, $callback); 156 } 157} 158