1a25f0a04SGreg Roach<?php 2a25f0a04SGreg Roach/** 3a25f0a04SGreg Roach * webtrees: online genealogy 48fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team 5a25f0a04SGreg Roach * This program is free software: you can redistribute it and/or modify 6a25f0a04SGreg Roach * it under the terms of the GNU General Public License as published by 7a25f0a04SGreg Roach * the Free Software Foundation, either version 3 of the License, or 8a25f0a04SGreg Roach * (at your option) any later version. 9a25f0a04SGreg Roach * This program is distributed in the hope that it will be useful, 10a25f0a04SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 11a25f0a04SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12a25f0a04SGreg Roach * GNU General Public License for more details. 13a25f0a04SGreg Roach * You should have received a copy of the GNU General Public License 14a25f0a04SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 15a25f0a04SGreg Roach */ 16c04dd3c1SGreg Roachdeclare(strict_types=1); 17c04dd3c1SGreg Roach 1876692c8bSGreg Roachnamespace Fisharebest\Webtrees; 19a25f0a04SGreg Roach 208b67c11aSGreg Roachuse Closure; 21*e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface; 2201461f86SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 23b0b72ea4SGreg Roachuse stdClass; 2460bc3e3fSGreg Roach 25a25f0a04SGreg Roach/** 2676692c8bSGreg Roach * Provide an interface to the wt_user table. 27a25f0a04SGreg Roach */ 28*e5a6b4d4SGreg Roachclass User implements UserInterface 29c1010edaSGreg Roach{ 30c04dd3c1SGreg Roach /** @var int The primary key of this user. */ 31a25f0a04SGreg Roach private $user_id; 32a25f0a04SGreg Roach 33a25f0a04SGreg Roach /** @var string The login name of this user. */ 34a25f0a04SGreg Roach private $user_name; 35a25f0a04SGreg Roach 36a25f0a04SGreg Roach /** @var string The real (display) name of this user. */ 37a25f0a04SGreg Roach private $real_name; 38a25f0a04SGreg Roach 39a25f0a04SGreg Roach /** @var string The email address of this user. */ 40a25f0a04SGreg Roach private $email; 41a25f0a04SGreg Roach 4215d603e7SGreg Roach /** @var string[] Cached copy of the wt_user_setting table. */ 4315d603e7SGreg Roach private $preferences = []; 44a25f0a04SGreg Roach 45a25f0a04SGreg Roach /** 46*e5a6b4d4SGreg Roach * User constructor. 47f7fb7d41SGreg Roach * 488b67c11aSGreg Roach * @param int $user_id 498b67c11aSGreg Roach * @param string $user_name 508b67c11aSGreg Roach * @param string $real_name 518b67c11aSGreg Roach * @param string $email 52f7fb7d41SGreg Roach */ 53*e5a6b4d4SGreg Roach public function __construct(int $user_id, string $user_name, string $real_name, string $email) 54c1010edaSGreg Roach { 558b67c11aSGreg Roach $this->user_id = $user_id; 568b67c11aSGreg Roach $this->user_name = $user_name; 578b67c11aSGreg Roach $this->real_name = $real_name; 588b67c11aSGreg Roach $this->email = $email; 598b67c11aSGreg Roach } 608b67c11aSGreg Roach 618b67c11aSGreg Roach /** 62*e5a6b4d4SGreg Roach * The user‘s internal identifier. 63a25f0a04SGreg Roach * 64c04dd3c1SGreg Roach * @return int 65a25f0a04SGreg Roach */ 66895230eeSGreg Roach public function id(): int 67c1010edaSGreg Roach { 68a25f0a04SGreg Roach return $this->user_id; 69a25f0a04SGreg Roach } 70a25f0a04SGreg Roach 71a25f0a04SGreg Roach /** 72*e5a6b4d4SGreg Roach * The users email address. 73a25f0a04SGreg Roach * 74a25f0a04SGreg Roach * @return string 75a25f0a04SGreg Roach */ 76*e5a6b4d4SGreg Roach public function email(): string 77c1010edaSGreg Roach { 78a25f0a04SGreg Roach return $this->email; 79a25f0a04SGreg Roach } 80a25f0a04SGreg Roach 81a25f0a04SGreg Roach /** 82a25f0a04SGreg Roach * Set the email address of this user. 83a25f0a04SGreg Roach * 84a25f0a04SGreg Roach * @param string $email 85a25f0a04SGreg Roach * 86a25f0a04SGreg Roach * @return User 87a25f0a04SGreg Roach */ 888f53f488SRico Sonntag public function setEmail($email): User 89c1010edaSGreg Roach { 90a25f0a04SGreg Roach if ($this->email !== $email) { 91a25f0a04SGreg Roach $this->email = $email; 9201461f86SGreg Roach 9301461f86SGreg Roach DB::table('user') 9401461f86SGreg Roach ->where('user_id', '=', $this->user_id) 9501461f86SGreg Roach ->update([ 9601461f86SGreg Roach 'email' => $email, 97c1010edaSGreg Roach ]); 98a25f0a04SGreg Roach } 99a25f0a04SGreg Roach 100a25f0a04SGreg Roach return $this; 101a25f0a04SGreg Roach } 102a25f0a04SGreg Roach 103a25f0a04SGreg Roach /** 104*e5a6b4d4SGreg Roach * The user‘s real name. 105a25f0a04SGreg Roach * 106*e5a6b4d4SGreg Roach * @return string 107*e5a6b4d4SGreg Roach */ 108*e5a6b4d4SGreg Roach public function realName(): string 109*e5a6b4d4SGreg Roach { 110*e5a6b4d4SGreg Roach return $this->real_name; 111*e5a6b4d4SGreg Roach } 112*e5a6b4d4SGreg Roach 113*e5a6b4d4SGreg Roach /** 114*e5a6b4d4SGreg Roach * Set the real name of this user. 115*e5a6b4d4SGreg Roach * 116*e5a6b4d4SGreg Roach * @param string $real_name 117a25f0a04SGreg Roach * 118a25f0a04SGreg Roach * @return User 119a25f0a04SGreg Roach */ 120*e5a6b4d4SGreg Roach public function setRealName($real_name): User 121c1010edaSGreg Roach { 122*e5a6b4d4SGreg Roach if ($this->real_name !== $real_name) { 123*e5a6b4d4SGreg Roach $this->real_name = $real_name; 124*e5a6b4d4SGreg Roach 12501461f86SGreg Roach DB::table('user') 12601461f86SGreg Roach ->where('user_id', '=', $this->user_id) 12701461f86SGreg Roach ->update([ 128*e5a6b4d4SGreg Roach 'real_name' => $real_name, 129015c99a2SGreg Roach ]); 130*e5a6b4d4SGreg Roach } 131*e5a6b4d4SGreg Roach 132*e5a6b4d4SGreg Roach return $this; 133*e5a6b4d4SGreg Roach } 134*e5a6b4d4SGreg Roach 135*e5a6b4d4SGreg Roach /** 136*e5a6b4d4SGreg Roach * The user‘s login name. 137*e5a6b4d4SGreg Roach * 138*e5a6b4d4SGreg Roach * @return string 139*e5a6b4d4SGreg Roach */ 140*e5a6b4d4SGreg Roach public function userName(): string 141*e5a6b4d4SGreg Roach { 142*e5a6b4d4SGreg Roach return $this->user_name; 143*e5a6b4d4SGreg Roach } 144*e5a6b4d4SGreg Roach 145*e5a6b4d4SGreg Roach /** 146*e5a6b4d4SGreg Roach * Set the login name for this user. 147*e5a6b4d4SGreg Roach * 148*e5a6b4d4SGreg Roach * @param string $user_name 149*e5a6b4d4SGreg Roach * 150*e5a6b4d4SGreg Roach * @return $this 151*e5a6b4d4SGreg Roach */ 152*e5a6b4d4SGreg Roach public function setUserName($user_name): self 153*e5a6b4d4SGreg Roach { 154*e5a6b4d4SGreg Roach if ($this->user_name !== $user_name) { 155*e5a6b4d4SGreg Roach $this->user_name = $user_name; 156*e5a6b4d4SGreg Roach 157*e5a6b4d4SGreg Roach DB::table('user') 158*e5a6b4d4SGreg Roach ->where('user_id', '=', $this->user_id) 159*e5a6b4d4SGreg Roach ->update([ 160*e5a6b4d4SGreg Roach 'user_name' => $user_name, 161*e5a6b4d4SGreg Roach ]); 162*e5a6b4d4SGreg Roach } 163a25f0a04SGreg Roach 164a25f0a04SGreg Roach return $this; 165a25f0a04SGreg Roach } 166a25f0a04SGreg Roach 167a25f0a04SGreg Roach /** 168a25f0a04SGreg Roach * Fetch a user option/setting from the wt_user_setting table. 169a25f0a04SGreg Roach * Since we'll fetch several settings for each user, and since there aren’t 170a25f0a04SGreg Roach * that many of them, fetch them all in one database query 171a25f0a04SGreg Roach * 172a25f0a04SGreg Roach * @param string $setting_name 17315d603e7SGreg Roach * @param string $default 174a25f0a04SGreg Roach * 17515d603e7SGreg Roach * @return string 176a25f0a04SGreg Roach */ 177*e5a6b4d4SGreg Roach public function getPreference(string $setting_name, string $default = ''): string 178c1010edaSGreg Roach { 17983c7613eSGreg Roach $preferences = app('cache.array')->rememberForever('user_setting' . $this->user_id, function () { 18083c7613eSGreg Roach if ($this->user_id) { 18183c7613eSGreg Roach return DB::table('user_setting') 18201461f86SGreg Roach ->where('user_id', '=', $this->user_id) 18301461f86SGreg Roach ->pluck('setting_value', 'setting_name') 18401461f86SGreg Roach ->all(); 18583c7613eSGreg Roach } else { 18683c7613eSGreg Roach return []; 187a25f0a04SGreg Roach } 18883c7613eSGreg Roach }); 189a25f0a04SGreg Roach 19083c7613eSGreg Roach return $preferences[$setting_name] ?? $default; 191a25f0a04SGreg Roach } 192a25f0a04SGreg Roach 193a25f0a04SGreg Roach /** 194a25f0a04SGreg Roach * Update a setting for the user. 195a25f0a04SGreg Roach * 196a25f0a04SGreg Roach * @param string $setting_name 197a25f0a04SGreg Roach * @param string $setting_value 198a25f0a04SGreg Roach * 199*e5a6b4d4SGreg Roach * @return UserInterface 200a25f0a04SGreg Roach */ 201*e5a6b4d4SGreg Roach public function setPreference(string $setting_name, string $setting_value): UserInterface 202c1010edaSGreg Roach { 203c04dd3c1SGreg Roach if ($this->user_id !== 0 && $this->getPreference($setting_name) !== $setting_value) { 20401461f86SGreg Roach DB::table('user_setting')->updateOrInsert([ 20501461f86SGreg Roach 'user_id' => $this->user_id, 20601461f86SGreg Roach 'setting_name' => $setting_name, 20701461f86SGreg Roach ], [ 20801461f86SGreg Roach 'setting_value' => $setting_value, 209c1010edaSGreg Roach ]); 21015d603e7SGreg Roach 211a25f0a04SGreg Roach $this->preferences[$setting_name] = $setting_value; 212a25f0a04SGreg Roach } 213a25f0a04SGreg Roach 214611d1316SGreg Roach app('cache.array')->forget('user_setting' . $this->user_id); 215611d1316SGreg Roach 216a25f0a04SGreg Roach return $this; 217a25f0a04SGreg Roach } 218*e5a6b4d4SGreg Roach 219*e5a6b4d4SGreg Roach /** 220*e5a6b4d4SGreg Roach * Set the password of this user. 221*e5a6b4d4SGreg Roach * 222*e5a6b4d4SGreg Roach * @param string $password 223*e5a6b4d4SGreg Roach * 224*e5a6b4d4SGreg Roach * @return User 225*e5a6b4d4SGreg Roach */ 226*e5a6b4d4SGreg Roach public function setPassword(string $password): User 227*e5a6b4d4SGreg Roach { 228*e5a6b4d4SGreg Roach DB::table('user') 229*e5a6b4d4SGreg Roach ->where('user_id', '=', $this->user_id) 230*e5a6b4d4SGreg Roach ->update([ 231*e5a6b4d4SGreg Roach 'password' => password_hash($password, PASSWORD_DEFAULT), 232*e5a6b4d4SGreg Roach ]); 233*e5a6b4d4SGreg Roach 234*e5a6b4d4SGreg Roach return $this; 235*e5a6b4d4SGreg Roach } 236*e5a6b4d4SGreg Roach 237*e5a6b4d4SGreg Roach /** 238*e5a6b4d4SGreg Roach * A closure which will create an object from a database row. 239*e5a6b4d4SGreg Roach * 240*e5a6b4d4SGreg Roach * @return Closure 241*e5a6b4d4SGreg Roach */ 242*e5a6b4d4SGreg Roach public static function rowMapper(): Closure 243*e5a6b4d4SGreg Roach { 244*e5a6b4d4SGreg Roach return function (stdClass $row): User { 245*e5a6b4d4SGreg Roach return new static((int) $row->user_id, $row->user_name, $row->real_name, $row->email); 246*e5a6b4d4SGreg Roach }; 247*e5a6b4d4SGreg Roach } 248*e5a6b4d4SGreg Roach 249*e5a6b4d4SGreg Roach /** 250*e5a6b4d4SGreg Roach * Validate a supplied password 251*e5a6b4d4SGreg Roach * 252*e5a6b4d4SGreg Roach * @param string $password 253*e5a6b4d4SGreg Roach * 254*e5a6b4d4SGreg Roach * @return bool 255*e5a6b4d4SGreg Roach */ 256*e5a6b4d4SGreg Roach public function checkPassword(string $password): bool 257*e5a6b4d4SGreg Roach { 258*e5a6b4d4SGreg Roach $password_hash = DB::table('user') 259*e5a6b4d4SGreg Roach ->where('user_id', '=', $this->user_id) 260*e5a6b4d4SGreg Roach ->value('password'); 261*e5a6b4d4SGreg Roach 262*e5a6b4d4SGreg Roach if ($password_hash !== null && password_verify($password, $password_hash)) { 263*e5a6b4d4SGreg Roach if (password_needs_rehash($password_hash, PASSWORD_DEFAULT)) { 264*e5a6b4d4SGreg Roach $this->setPassword($password); 265*e5a6b4d4SGreg Roach } 266*e5a6b4d4SGreg Roach 267*e5a6b4d4SGreg Roach return true; 268*e5a6b4d4SGreg Roach } 269*e5a6b4d4SGreg Roach 270*e5a6b4d4SGreg Roach return false; 271*e5a6b4d4SGreg Roach } 272a25f0a04SGreg Roach} 273