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