* @copyright 2014 Heinrich-Heine-Universität Düsseldorf * @license http://www.gnu.org/licenses/gpl.html * @link https://bitbucket.org/coderkun/the-legend-of-z */ namespace hhu\z\models; /** * Model of the UsersAgent to list users and get their data. * * @author Oliver Hanraths */ class UsersModel extends \hhu\z\Model { /** * Construct a new UsersModel. */ public function __construct() { parent::__construct(); } /** * Get count of registered users. * * @return int Count of users */ public function getUsersCount() { $data = $this->db->query( 'SELECT count(DISTINCT id) AS c '. 'FROM users ' ); if(!empty($data)) { return $data[0]['c']; } return 0; } /** * Get registered users. * * @throws ParamsNotValidException * @param string $sort Field to sort by * @param int $limit Limit amount of Characters (optional) * @param int $offset Offset (optional) * @return array Users */ public function getUsers($sort, $limit=null, $offset=0) { switch($sort) { case 'username': case 'created': $orders = array( 'username' => 'ASC', 'created' => 'DESC' ); return $this->db->query( sprintf( 'SELECT id, created, username, url, surname, prename, email, mailing '. 'FROM users '. 'ORDER BY %s %s '. (!empty($limit) ? sprintf('LIMIT %d, %d', $offset, $limit) : null), $sort, $orders[$sort] ) ); break; case 'role': return $this->db->query( 'SELECT DISTINCT users.id, users.created, users.username, users.url, users.surname, users.prename, users.email, users.mailing '. 'FROM users '. 'LEFT JOIN users_userroles ON users_userroles.user_id = users.id '. 'LEFT JOIN userroles ON userroles.id = users_userroles.user_id '. 'ORDER BY userroles.id IS NULL, userroles.id ASC '. (!empty($limit) ? sprintf('LIMIT %d, %d', $offset, $limit) : null) ); break; default: throw new \nre\exceptions\ParamsNotValidException($sort); break; } } /** * Get users with the given user role. * * @param string $userrole User role * @return array List of users */ public function getUsersWithRole($userrole) { return $this->db->query( 'SELECT users.id, users.created, users.username, users.url, users.surname, users.prename, users.email, users.mailing'. 'FROM users '. 'LEFT JOIN users_userroles ON users_userroles.user_id = users.id '. 'LEFT JOIN userroles ON userroles.id = users_userroles.userrole_id '. 'WHERE userroles.name = ? '. 'ORDER BY username ASC', 's', $userrole ); } /** * Get a user and its data by its ID. * * @throws IdNotFoundException * @param int $userId ID of an user * @return array Userdata */ public function getUserById($userId) { // Get user $user = $this->db->query( 'SELECT id, created, username, url, surname, prename, email, mailing '. 'FROM users '. 'WHERE id = ?', 'i', $userId ); if(empty($user)) { throw new \nre\exceptions\IdNotFoundException($userId); } return $user[0]; } /** * Get a user and its data by its URL-username. * * @throws IdNotFoundException * @param string $userUrl URL-Username of an user * @return array Userdata */ public function getUserByUrl($userUrl) { // Get user $user = $this->db->query( 'SELECT id, created, username, url, surname, prename, email, mailing '. 'FROM users '. 'WHERE url = ?', 's', $userUrl ); if(empty($user)) { throw new \nre\exceptions\IdNotFoundException($userUrl); } return $user[0]; } /** * Log a user in if its credentials are valid. * * @throws DatamodelException * @param string $username The name of the user to log in * @param string $password Plaintext password of the user to log in */ public function login($username, $password) { $data = $this->db->query('SELECT id, password FROM users WHERE username = ?', 's', $username); if(!empty($data)) { $data = $data[0]; if($this->verify($password, $data['password'])) { return $data['id']; } } return null; } /** * Check if an username already exists. * * @param string $username Username to check * @param int $userId Do not check this ID (for editing) * @return boolean Whether username exists or not */ public function usernameExists($username, $userId=null) { $data = $this->db->query( 'SELECT id '. 'FROM users '. 'WHERE username = ? OR url = ?', 'ss', $username, \nre\core\Linker::createLinkParam($username) ); return (!empty($data) && (is_null($userId) || $userId != $data[0]['id'])); } /** * Check if an e‑mail address already exists. * * @param string $email E‑mail address to check * @param int $userId Do not check this ID (for editing) * @return boolean Whether e‑mail address exists or not */ public function emailExists($email, $userId=null) { $data = $this->db->query( 'SELECT id '. 'FROM users '. 'WHERE email = ?', 's', $email ); return (!empty($data) && (is_null($userId) || $userId != $data[0]['id'])); } /** * Create a new user. * * @param string $username Username of the user to create * @param string $email E‑Mail-Address of the user to create * @param string $password Password of the user to create * @return int ID of the newly created user */ public function createUser($username, $prename, $surname, $email, $password) { $userId = null; $this->db->setAutocommit(false); try { // Create user $this->db->query( 'INSERT INTO users '. '(username, url, surname, prename, email, password) '. 'VALUES '. '(?, ?, ?, ?, ?, ?)', 'ssssss', $username, \nre\core\Linker::createLinkParam($username), $surname, $prename, $email, $this->hash($password) ); $userId = $this->db->getInsertId(); // Add role “user” $this->db->query( 'INSERT INTO users_userroles '. '(user_id, userrole_id) '. 'SELECT ?, userroles.id '. 'FROM userroles '. 'WHERE userroles.name = ?', 'is', $userId, 'user' ); } catch(Exception $e) { $this->db->rollback(); $this->db->setAutocommit(true); throw $e; } $this->db->setAutocommit(true); return $userId; } /** * Edit a user. * * @throws DatamodelException * @param int $userId ID of the user to delete * @param string $username New name of user * @param string $email Changed e‑mail-address of user * @param string $password Changed plaintext password of user */ public function editUser($userId, $username, $prename, $surname, $email, $password, $mailing) { $this->db->setAutocommit(false); try { // Update user data $this->db->query( 'UPDATE users '. 'SET username = ?, url = ?, prename = ?, surname = ?, email = ?, mailing = ? '. 'WHERE id = ?', 'sssssii', $username, \nre\core\Linker::createLinkParam($username), $prename, $surname, $email, $mailing, $userId ); // Set new password if(!empty($password)) { $this->db->query( 'UPDATE users '. 'SET password = ? '. 'WHERE id = ?', 'si', $this->hash($password), $userId ); } } catch(Exception $e) { $this->db->rollback(); $this->db->setAutocommit(true); throw $e; } $this->db->setAutocommit(true); } /** * Delete a user. * * @param int $userId ID of the user to delete */ public function deleteUser($userId) { $this->db->query('DELETE FROM users WHERE id = ?', 'i', $userId); } /** * Hash a password. * * @param string $password Plaintext password * @return string Hashed password */ public function hash($password) { if(!function_exists('password_hash')) { \hhu\z\lib\Password::load(); } return password_hash($password, PASSWORD_DEFAULT); } /** * Verify a password. * * @param string $password Plaintext password to verify * @param string $hash Hashed password to match with * @return boolean Verified */ private function verify($password, $hash) { if(!function_exists('password_verify')) { \hhu\z\lib\Password::load(); } return password_verify($password, $hash); } } ?>