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