1a25f0a04SGreg Roach<?php 23976b470SGreg Roach 3a25f0a04SGreg Roach/** 4a25f0a04SGreg Roach * webtrees: online genealogy 589f7189bSGreg Roach * Copyright (C) 2021 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 1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 16a25f0a04SGreg Roach */ 17fcfa147eSGreg Roach 18c04dd3c1SGreg Roachdeclare(strict_types=1); 19c04dd3c1SGreg Roach 2076692c8bSGreg Roachnamespace Fisharebest\Webtrees; 21a25f0a04SGreg Roach 228b67c11aSGreg Roachuse Closure; 23e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface; 2401461f86SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 2560bc3e3fSGreg Roach 26*b55cbc6bSGreg Roachuse function is_string; 27*b55cbc6bSGreg Roach 28a25f0a04SGreg Roach/** 2976692c8bSGreg Roach * Provide an interface to the wt_user table. 30a25f0a04SGreg Roach */ 31e5a6b4d4SGreg Roachclass User implements UserInterface 32c1010edaSGreg Roach{ 33ee76412bSGreg Roach private int $user_id; 34a25f0a04SGreg Roach 35ee76412bSGreg Roach private string $user_name; 36a25f0a04SGreg Roach 37ee76412bSGreg Roach private string $real_name; 38a25f0a04SGreg Roach 39ee76412bSGreg Roach private string $email; 40a25f0a04SGreg Roach 4145f11dc7SGreg Roach /** @var array<string,string> */ 42ee76412bSGreg Roach private array $preferences; 43a25f0a04SGreg Roach 44a25f0a04SGreg Roach /** 45e5a6b4d4SGreg Roach * User constructor. 46f7fb7d41SGreg Roach * 478b67c11aSGreg Roach * @param int $user_id 488b67c11aSGreg Roach * @param string $user_name 498b67c11aSGreg Roach * @param string $real_name 508b67c11aSGreg Roach * @param string $email 51f7fb7d41SGreg Roach */ 52e5a6b4d4SGreg Roach public function __construct(int $user_id, string $user_name, string $real_name, string $email) 53c1010edaSGreg Roach { 548b67c11aSGreg Roach $this->user_id = $user_id; 558b67c11aSGreg Roach $this->user_name = $user_name; 568b67c11aSGreg Roach $this->real_name = $real_name; 578b67c11aSGreg Roach $this->email = $email; 58ee76412bSGreg Roach 59ee76412bSGreg Roach $this->preferences = DB::table('user_setting') 60ee76412bSGreg Roach ->where('user_id', '=', $this->user_id) 61ee76412bSGreg Roach ->pluck('setting_value', 'setting_name') 62ee76412bSGreg Roach ->all(); 638b67c11aSGreg Roach } 648b67c11aSGreg Roach 658b67c11aSGreg Roach /** 66e5a6b4d4SGreg Roach * The user‘s internal identifier. 67a25f0a04SGreg Roach * 68c04dd3c1SGreg Roach * @return int 69a25f0a04SGreg Roach */ 70895230eeSGreg Roach public function id(): int 71c1010edaSGreg Roach { 72a25f0a04SGreg Roach return $this->user_id; 73a25f0a04SGreg Roach } 74a25f0a04SGreg Roach 75a25f0a04SGreg Roach /** 76e5a6b4d4SGreg Roach * The users email address. 77a25f0a04SGreg Roach * 78a25f0a04SGreg Roach * @return string 79a25f0a04SGreg Roach */ 80e5a6b4d4SGreg Roach public function email(): string 81c1010edaSGreg Roach { 82a25f0a04SGreg Roach return $this->email; 83a25f0a04SGreg Roach } 84a25f0a04SGreg Roach 85a25f0a04SGreg Roach /** 86a25f0a04SGreg Roach * Set the email address of this user. 87a25f0a04SGreg Roach * 88a25f0a04SGreg Roach * @param string $email 89a25f0a04SGreg Roach * 90a25f0a04SGreg Roach * @return User 91a25f0a04SGreg Roach */ 9224f2a3afSGreg Roach public function setEmail(string $email): User 93c1010edaSGreg Roach { 94a25f0a04SGreg Roach if ($this->email !== $email) { 95a25f0a04SGreg Roach $this->email = $email; 9601461f86SGreg Roach 9701461f86SGreg Roach DB::table('user') 9801461f86SGreg Roach ->where('user_id', '=', $this->user_id) 9901461f86SGreg Roach ->update([ 10001461f86SGreg Roach 'email' => $email, 101c1010edaSGreg Roach ]); 102a25f0a04SGreg Roach } 103a25f0a04SGreg Roach 104a25f0a04SGreg Roach return $this; 105a25f0a04SGreg Roach } 106a25f0a04SGreg Roach 107a25f0a04SGreg Roach /** 108e5a6b4d4SGreg Roach * The user‘s real name. 109a25f0a04SGreg Roach * 110e5a6b4d4SGreg Roach * @return string 111e5a6b4d4SGreg Roach */ 112e5a6b4d4SGreg Roach public function realName(): string 113e5a6b4d4SGreg Roach { 114e5a6b4d4SGreg Roach return $this->real_name; 115e5a6b4d4SGreg Roach } 116e5a6b4d4SGreg Roach 117e5a6b4d4SGreg Roach /** 118e5a6b4d4SGreg Roach * Set the real name of this user. 119e5a6b4d4SGreg Roach * 120e5a6b4d4SGreg Roach * @param string $real_name 121a25f0a04SGreg Roach * 122a25f0a04SGreg Roach * @return User 123a25f0a04SGreg Roach */ 12424f2a3afSGreg Roach public function setRealName(string $real_name): User 125c1010edaSGreg Roach { 126e5a6b4d4SGreg Roach if ($this->real_name !== $real_name) { 127e5a6b4d4SGreg Roach $this->real_name = $real_name; 128e5a6b4d4SGreg Roach 12901461f86SGreg Roach DB::table('user') 13001461f86SGreg Roach ->where('user_id', '=', $this->user_id) 13101461f86SGreg Roach ->update([ 132e5a6b4d4SGreg Roach 'real_name' => $real_name, 133015c99a2SGreg Roach ]); 134e5a6b4d4SGreg Roach } 135e5a6b4d4SGreg Roach 136e5a6b4d4SGreg Roach return $this; 137e5a6b4d4SGreg Roach } 138e5a6b4d4SGreg Roach 139e5a6b4d4SGreg Roach /** 140e5a6b4d4SGreg Roach * The user‘s login name. 141e5a6b4d4SGreg Roach * 142e5a6b4d4SGreg Roach * @return string 143e5a6b4d4SGreg Roach */ 144e5a6b4d4SGreg Roach public function userName(): string 145e5a6b4d4SGreg Roach { 146e5a6b4d4SGreg Roach return $this->user_name; 147e5a6b4d4SGreg Roach } 148e5a6b4d4SGreg Roach 149e5a6b4d4SGreg Roach /** 150e5a6b4d4SGreg Roach * Set the login name for this user. 151e5a6b4d4SGreg Roach * 152e5a6b4d4SGreg Roach * @param string $user_name 153e5a6b4d4SGreg Roach * 154e5a6b4d4SGreg Roach * @return $this 155e5a6b4d4SGreg Roach */ 15624f2a3afSGreg Roach public function setUserName(string $user_name): self 157e5a6b4d4SGreg Roach { 158e5a6b4d4SGreg Roach if ($this->user_name !== $user_name) { 159e5a6b4d4SGreg Roach $this->user_name = $user_name; 160e5a6b4d4SGreg Roach 161e5a6b4d4SGreg Roach DB::table('user') 162e5a6b4d4SGreg Roach ->where('user_id', '=', $this->user_id) 163e5a6b4d4SGreg Roach ->update([ 164e5a6b4d4SGreg Roach 'user_name' => $user_name, 165e5a6b4d4SGreg Roach ]); 166e5a6b4d4SGreg Roach } 167a25f0a04SGreg Roach 168a25f0a04SGreg Roach return $this; 169a25f0a04SGreg Roach } 170a25f0a04SGreg Roach 171a25f0a04SGreg Roach /** 172a25f0a04SGreg Roach * Fetch a user option/setting from the wt_user_setting table. 173ee76412bSGreg Roach * Since we'll fetch several settings for each user, and since there aren't 174a25f0a04SGreg Roach * that many of them, fetch them all in one database query 175a25f0a04SGreg Roach * 176a25f0a04SGreg Roach * @param string $setting_name 17715d603e7SGreg Roach * @param string $default 178a25f0a04SGreg Roach * 17915d603e7SGreg Roach * @return string 180a25f0a04SGreg Roach */ 181e5a6b4d4SGreg Roach public function getPreference(string $setting_name, string $default = ''): string 182c1010edaSGreg Roach { 183ee76412bSGreg Roach return $this->preferences[$setting_name] ?? $default; 184a25f0a04SGreg Roach } 185a25f0a04SGreg Roach 186a25f0a04SGreg Roach /** 187a25f0a04SGreg Roach * Update a setting for the user. 188a25f0a04SGreg Roach * 189a25f0a04SGreg Roach * @param string $setting_name 190a25f0a04SGreg Roach * @param string $setting_value 191a25f0a04SGreg Roach * 1927c4add84SGreg Roach * @return void 193a25f0a04SGreg Roach */ 1947c4add84SGreg Roach public function setPreference(string $setting_name, string $setting_value): void 195c1010edaSGreg Roach { 196ee76412bSGreg Roach if ($this->getPreference($setting_name) !== $setting_value) { 19701461f86SGreg Roach DB::table('user_setting')->updateOrInsert([ 19801461f86SGreg Roach 'user_id' => $this->user_id, 19901461f86SGreg Roach 'setting_name' => $setting_name, 20001461f86SGreg Roach ], [ 20101461f86SGreg Roach 'setting_value' => $setting_value, 202c1010edaSGreg Roach ]); 20315d603e7SGreg Roach 204a25f0a04SGreg Roach $this->preferences[$setting_name] = $setting_value; 205a25f0a04SGreg Roach } 206a25f0a04SGreg Roach } 207e5a6b4d4SGreg Roach 208e5a6b4d4SGreg Roach /** 209e5a6b4d4SGreg Roach * Set the password of this user. 210e5a6b4d4SGreg Roach * 211e5a6b4d4SGreg Roach * @param string $password 212e5a6b4d4SGreg Roach * 213e5a6b4d4SGreg Roach * @return User 214e5a6b4d4SGreg Roach */ 215e5a6b4d4SGreg Roach public function setPassword(string $password): User 216e5a6b4d4SGreg Roach { 217e5a6b4d4SGreg Roach DB::table('user') 218e5a6b4d4SGreg Roach ->where('user_id', '=', $this->user_id) 219e5a6b4d4SGreg Roach ->update([ 220e5a6b4d4SGreg Roach 'password' => password_hash($password, PASSWORD_DEFAULT), 221e5a6b4d4SGreg Roach ]); 222e5a6b4d4SGreg Roach 223e5a6b4d4SGreg Roach return $this; 224e5a6b4d4SGreg Roach } 225e5a6b4d4SGreg Roach 226e5a6b4d4SGreg Roach 227e5a6b4d4SGreg Roach /** 228e5a6b4d4SGreg Roach * Validate a supplied password 229e5a6b4d4SGreg Roach * 230e5a6b4d4SGreg Roach * @param string $password 231e5a6b4d4SGreg Roach * 232e5a6b4d4SGreg Roach * @return bool 233e5a6b4d4SGreg Roach */ 234e5a6b4d4SGreg Roach public function checkPassword(string $password): bool 235e5a6b4d4SGreg Roach { 236e5a6b4d4SGreg Roach $password_hash = DB::table('user') 2373e1b7b6eSGreg Roach ->where('user_id', '=', $this->id()) 238e5a6b4d4SGreg Roach ->value('password'); 239e5a6b4d4SGreg Roach 240*b55cbc6bSGreg Roach if (is_string($password_hash) && password_verify($password, $password_hash)) { 241e5a6b4d4SGreg Roach if (password_needs_rehash($password_hash, PASSWORD_DEFAULT)) { 242e5a6b4d4SGreg Roach $this->setPassword($password); 243e5a6b4d4SGreg Roach } 244e5a6b4d4SGreg Roach 245e5a6b4d4SGreg Roach return true; 246e5a6b4d4SGreg Roach } 247e5a6b4d4SGreg Roach 248e5a6b4d4SGreg Roach return false; 249e5a6b4d4SGreg Roach } 2503e1b7b6eSGreg Roach 2513e1b7b6eSGreg Roach /** 2523e1b7b6eSGreg Roach * A closure which will create an object from a database row. 2533e1b7b6eSGreg Roach * 2543e1b7b6eSGreg Roach * @return Closure 2553e1b7b6eSGreg Roach */ 2563e1b7b6eSGreg Roach public static function rowMapper(): Closure 2573e1b7b6eSGreg Roach { 258f70bcff5SGreg Roach return static function (object $row): User { 2591e752ebbSGreg Roach return new self((int) $row->user_id, $row->user_name, $row->real_name, $row->email); 2603e1b7b6eSGreg Roach }; 2613e1b7b6eSGreg Roach } 262a25f0a04SGreg Roach} 263