1a25f0a04SGreg Roach<?php 2*3976b470SGreg Roach 3a25f0a04SGreg Roach/** 4a25f0a04SGreg Roach * webtrees: online genealogy 58fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team 6a25f0a04SGreg Roach * This program is free software: you can redistribute it and/or modify 7a25f0a04SGreg Roach * it under the terms of the GNU General Public License as published by 8a25f0a04SGreg Roach * the Free Software Foundation, either version 3 of the License, or 9a25f0a04SGreg Roach * (at your option) any later version. 10a25f0a04SGreg Roach * This program is distributed in the hope that it will be useful, 11a25f0a04SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 12a25f0a04SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13a25f0a04SGreg Roach * GNU General Public License for more details. 14a25f0a04SGreg Roach * You should have received a copy of the GNU General Public License 15a25f0a04SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 16a25f0a04SGreg Roach */ 17c04dd3c1SGreg Roachdeclare(strict_types=1); 18c04dd3c1SGreg Roach 1976692c8bSGreg Roachnamespace Fisharebest\Webtrees; 20a25f0a04SGreg Roach 218b67c11aSGreg Roachuse Closure; 22e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface; 2301461f86SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 242b7831a1SGreg Roachuse Illuminate\Support\Collection; 25b0b72ea4SGreg Roachuse stdClass; 2660bc3e3fSGreg Roach 27a25f0a04SGreg Roach/** 2876692c8bSGreg Roach * Provide an interface to the wt_user table. 29a25f0a04SGreg Roach */ 30e5a6b4d4SGreg Roachclass User implements UserInterface 31c1010edaSGreg Roach{ 32c04dd3c1SGreg Roach /** @var int The primary key of this user. */ 33a25f0a04SGreg Roach private $user_id; 34a25f0a04SGreg Roach 35a25f0a04SGreg Roach /** @var string The login name of this user. */ 36a25f0a04SGreg Roach private $user_name; 37a25f0a04SGreg Roach 38a25f0a04SGreg Roach /** @var string The real (display) name of this user. */ 39a25f0a04SGreg Roach private $real_name; 40a25f0a04SGreg Roach 41a25f0a04SGreg Roach /** @var string The email address of this user. */ 42a25f0a04SGreg Roach private $email; 43a25f0a04SGreg Roach 4415d603e7SGreg Roach /** @var string[] Cached copy of the wt_user_setting table. */ 4515d603e7SGreg Roach private $preferences = []; 46a25f0a04SGreg Roach 47a25f0a04SGreg Roach /** 48e5a6b4d4SGreg Roach * User constructor. 49f7fb7d41SGreg Roach * 508b67c11aSGreg Roach * @param int $user_id 518b67c11aSGreg Roach * @param string $user_name 528b67c11aSGreg Roach * @param string $real_name 538b67c11aSGreg Roach * @param string $email 54f7fb7d41SGreg Roach */ 55e5a6b4d4SGreg Roach public function __construct(int $user_id, string $user_name, string $real_name, string $email) 56c1010edaSGreg Roach { 578b67c11aSGreg Roach $this->user_id = $user_id; 588b67c11aSGreg Roach $this->user_name = $user_name; 598b67c11aSGreg Roach $this->real_name = $real_name; 608b67c11aSGreg Roach $this->email = $email; 618b67c11aSGreg Roach } 628b67c11aSGreg Roach 638b67c11aSGreg Roach /** 64e5a6b4d4SGreg Roach * The user‘s internal identifier. 65a25f0a04SGreg Roach * 66c04dd3c1SGreg Roach * @return int 67a25f0a04SGreg Roach */ 68895230eeSGreg Roach public function id(): int 69c1010edaSGreg Roach { 70a25f0a04SGreg Roach return $this->user_id; 71a25f0a04SGreg Roach } 72a25f0a04SGreg Roach 73a25f0a04SGreg Roach /** 74e5a6b4d4SGreg Roach * The users email address. 75a25f0a04SGreg Roach * 76a25f0a04SGreg Roach * @return string 77a25f0a04SGreg Roach */ 78e5a6b4d4SGreg Roach public function email(): string 79c1010edaSGreg Roach { 80a25f0a04SGreg Roach return $this->email; 81a25f0a04SGreg Roach } 82a25f0a04SGreg Roach 83a25f0a04SGreg Roach /** 84a25f0a04SGreg Roach * Set the email address of this user. 85a25f0a04SGreg Roach * 86a25f0a04SGreg Roach * @param string $email 87a25f0a04SGreg Roach * 88a25f0a04SGreg Roach * @return User 89a25f0a04SGreg Roach */ 908f53f488SRico Sonntag public function setEmail($email): User 91c1010edaSGreg Roach { 92a25f0a04SGreg Roach if ($this->email !== $email) { 93a25f0a04SGreg Roach $this->email = $email; 9401461f86SGreg Roach 9501461f86SGreg Roach DB::table('user') 9601461f86SGreg Roach ->where('user_id', '=', $this->user_id) 9701461f86SGreg Roach ->update([ 9801461f86SGreg Roach 'email' => $email, 99c1010edaSGreg Roach ]); 100a25f0a04SGreg Roach } 101a25f0a04SGreg Roach 102a25f0a04SGreg Roach return $this; 103a25f0a04SGreg Roach } 104a25f0a04SGreg Roach 105a25f0a04SGreg Roach /** 106e5a6b4d4SGreg Roach * The user‘s real name. 107a25f0a04SGreg Roach * 108e5a6b4d4SGreg Roach * @return string 109e5a6b4d4SGreg Roach */ 110e5a6b4d4SGreg Roach public function realName(): string 111e5a6b4d4SGreg Roach { 112e5a6b4d4SGreg Roach return $this->real_name; 113e5a6b4d4SGreg Roach } 114e5a6b4d4SGreg Roach 115e5a6b4d4SGreg Roach /** 116e5a6b4d4SGreg Roach * Set the real name of this user. 117e5a6b4d4SGreg Roach * 118e5a6b4d4SGreg Roach * @param string $real_name 119a25f0a04SGreg Roach * 120a25f0a04SGreg Roach * @return User 121a25f0a04SGreg Roach */ 122e5a6b4d4SGreg Roach public function setRealName($real_name): User 123c1010edaSGreg Roach { 124e5a6b4d4SGreg Roach if ($this->real_name !== $real_name) { 125e5a6b4d4SGreg Roach $this->real_name = $real_name; 126e5a6b4d4SGreg Roach 12701461f86SGreg Roach DB::table('user') 12801461f86SGreg Roach ->where('user_id', '=', $this->user_id) 12901461f86SGreg Roach ->update([ 130e5a6b4d4SGreg Roach 'real_name' => $real_name, 131015c99a2SGreg Roach ]); 132e5a6b4d4SGreg Roach } 133e5a6b4d4SGreg Roach 134e5a6b4d4SGreg Roach return $this; 135e5a6b4d4SGreg Roach } 136e5a6b4d4SGreg Roach 137e5a6b4d4SGreg Roach /** 138e5a6b4d4SGreg Roach * The user‘s login name. 139e5a6b4d4SGreg Roach * 140e5a6b4d4SGreg Roach * @return string 141e5a6b4d4SGreg Roach */ 142e5a6b4d4SGreg Roach public function userName(): string 143e5a6b4d4SGreg Roach { 144e5a6b4d4SGreg Roach return $this->user_name; 145e5a6b4d4SGreg Roach } 146e5a6b4d4SGreg Roach 147e5a6b4d4SGreg Roach /** 148e5a6b4d4SGreg Roach * Set the login name for this user. 149e5a6b4d4SGreg Roach * 150e5a6b4d4SGreg Roach * @param string $user_name 151e5a6b4d4SGreg Roach * 152e5a6b4d4SGreg Roach * @return $this 153e5a6b4d4SGreg Roach */ 154e5a6b4d4SGreg Roach public function setUserName($user_name): self 155e5a6b4d4SGreg Roach { 156e5a6b4d4SGreg Roach if ($this->user_name !== $user_name) { 157e5a6b4d4SGreg Roach $this->user_name = $user_name; 158e5a6b4d4SGreg Roach 159e5a6b4d4SGreg Roach DB::table('user') 160e5a6b4d4SGreg Roach ->where('user_id', '=', $this->user_id) 161e5a6b4d4SGreg Roach ->update([ 162e5a6b4d4SGreg Roach 'user_name' => $user_name, 163e5a6b4d4SGreg Roach ]); 164e5a6b4d4SGreg Roach } 165a25f0a04SGreg Roach 166a25f0a04SGreg Roach return $this; 167a25f0a04SGreg Roach } 168a25f0a04SGreg Roach 169a25f0a04SGreg Roach /** 170a25f0a04SGreg Roach * Fetch a user option/setting from the wt_user_setting table. 171a25f0a04SGreg Roach * Since we'll fetch several settings for each user, and since there aren’t 172a25f0a04SGreg Roach * that many of them, fetch them all in one database query 173a25f0a04SGreg Roach * 174a25f0a04SGreg Roach * @param string $setting_name 17515d603e7SGreg Roach * @param string $default 176a25f0a04SGreg Roach * 17715d603e7SGreg Roach * @return string 178a25f0a04SGreg Roach */ 179e5a6b4d4SGreg Roach public function getPreference(string $setting_name, string $default = ''): string 180c1010edaSGreg Roach { 1812b7831a1SGreg Roach $preferences = app('cache.array')->rememberForever('user_setting' . $this->user_id, function (): Collection { 18283c7613eSGreg Roach if ($this->user_id) { 18383c7613eSGreg Roach return DB::table('user_setting') 18401461f86SGreg Roach ->where('user_id', '=', $this->user_id) 1852b7831a1SGreg Roach ->pluck('setting_value', 'setting_name'); 186a25f0a04SGreg Roach } 187e364afe4SGreg Roach 188e364afe4SGreg Roach return new Collection(); 18983c7613eSGreg Roach }); 190a25f0a04SGreg Roach 1912b7831a1SGreg Roach return $preferences->get($setting_name) ?? $default; 192a25f0a04SGreg Roach } 193a25f0a04SGreg Roach 194a25f0a04SGreg Roach /** 195a25f0a04SGreg Roach * Update a setting for the user. 196a25f0a04SGreg Roach * 197a25f0a04SGreg Roach * @param string $setting_name 198a25f0a04SGreg Roach * @param string $setting_value 199a25f0a04SGreg Roach * 200e5a6b4d4SGreg Roach * @return UserInterface 201a25f0a04SGreg Roach */ 202e5a6b4d4SGreg Roach public function setPreference(string $setting_name, string $setting_value): UserInterface 203c1010edaSGreg Roach { 204c04dd3c1SGreg Roach if ($this->user_id !== 0 && $this->getPreference($setting_name) !== $setting_value) { 20501461f86SGreg Roach DB::table('user_setting')->updateOrInsert([ 20601461f86SGreg Roach 'user_id' => $this->user_id, 20701461f86SGreg Roach 'setting_name' => $setting_name, 20801461f86SGreg Roach ], [ 20901461f86SGreg Roach 'setting_value' => $setting_value, 210c1010edaSGreg Roach ]); 21115d603e7SGreg Roach 212a25f0a04SGreg Roach $this->preferences[$setting_name] = $setting_value; 213a25f0a04SGreg Roach } 214a25f0a04SGreg Roach 215611d1316SGreg Roach app('cache.array')->forget('user_setting' . $this->user_id); 216611d1316SGreg Roach 217a25f0a04SGreg Roach return $this; 218a25f0a04SGreg Roach } 219e5a6b4d4SGreg Roach 220e5a6b4d4SGreg Roach /** 221e5a6b4d4SGreg Roach * Set the password of this user. 222e5a6b4d4SGreg Roach * 223e5a6b4d4SGreg Roach * @param string $password 224e5a6b4d4SGreg Roach * 225e5a6b4d4SGreg Roach * @return User 226e5a6b4d4SGreg Roach */ 227e5a6b4d4SGreg Roach public function setPassword(string $password): User 228e5a6b4d4SGreg Roach { 229e5a6b4d4SGreg Roach DB::table('user') 230e5a6b4d4SGreg Roach ->where('user_id', '=', $this->user_id) 231e5a6b4d4SGreg Roach ->update([ 232e5a6b4d4SGreg Roach 'password' => password_hash($password, PASSWORD_DEFAULT), 233e5a6b4d4SGreg Roach ]); 234e5a6b4d4SGreg Roach 235e5a6b4d4SGreg Roach return $this; 236e5a6b4d4SGreg Roach } 237e5a6b4d4SGreg Roach 238e5a6b4d4SGreg Roach 239e5a6b4d4SGreg Roach /** 240e5a6b4d4SGreg Roach * Validate a supplied password 241e5a6b4d4SGreg Roach * 242e5a6b4d4SGreg Roach * @param string $password 243e5a6b4d4SGreg Roach * 244e5a6b4d4SGreg Roach * @return bool 245e5a6b4d4SGreg Roach */ 246e5a6b4d4SGreg Roach public function checkPassword(string $password): bool 247e5a6b4d4SGreg Roach { 248e5a6b4d4SGreg Roach $password_hash = DB::table('user') 2493e1b7b6eSGreg Roach ->where('user_id', '=', $this->id()) 250e5a6b4d4SGreg Roach ->value('password'); 251e5a6b4d4SGreg Roach 252e5a6b4d4SGreg Roach if ($password_hash !== null && password_verify($password, $password_hash)) { 253e5a6b4d4SGreg Roach if (password_needs_rehash($password_hash, PASSWORD_DEFAULT)) { 254e5a6b4d4SGreg Roach $this->setPassword($password); 255e5a6b4d4SGreg Roach } 256e5a6b4d4SGreg Roach 257e5a6b4d4SGreg Roach return true; 258e5a6b4d4SGreg Roach } 259e5a6b4d4SGreg Roach 260e5a6b4d4SGreg Roach return false; 261e5a6b4d4SGreg Roach } 2623e1b7b6eSGreg Roach 2633e1b7b6eSGreg Roach /** 2643e1b7b6eSGreg Roach * A closure which will create an object from a database row. 2653e1b7b6eSGreg Roach * 2663e1b7b6eSGreg Roach * @return Closure 2673e1b7b6eSGreg Roach */ 2683e1b7b6eSGreg Roach public static function rowMapper(): Closure 2693e1b7b6eSGreg Roach { 2706c2179e2SGreg Roach return static function (stdClass $row): User { 2713e1b7b6eSGreg Roach return new static((int) $row->user_id, $row->user_name, $row->real_name, $row->email); 2723e1b7b6eSGreg Roach }; 2733e1b7b6eSGreg Roach } 274a25f0a04SGreg Roach} 275