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