diff options
-rw-r--r-- | assets/css/app.css | 9 | ||||
-rw-r--r-- | controllers/user.php | 78 | ||||
-rw-r--r-- | core/helper.php | 7 | ||||
-rw-r--r-- | locales/fr_FR/translations.php | 3 | ||||
-rw-r--r-- | locales/pl_PL/translations.php | 3 | ||||
-rw-r--r-- | models/user.php | 158 | ||||
-rw-r--r-- | templates/project_new.php | 2 | ||||
-rw-r--r-- | templates/task_new.php | 2 | ||||
-rw-r--r-- | templates/user_edit.php | 3 | ||||
-rw-r--r-- | templates/user_new.php | 2 |
10 files changed, 231 insertions, 36 deletions
diff --git a/assets/css/app.css b/assets/css/app.css index a2a73be2..4935c296 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -156,9 +156,6 @@ textarea { font-size: 99%; } -select { -} - ::-webkit-input-placeholder { color: #bbb; padding-top: 2px; @@ -183,6 +180,12 @@ textarea.form-error { border: 2px solid #b94a48; } +.form-required { + color: red; + padding-left: 5px; + font-weight: bold; +} + .form-errors { color: #b94a48; list-style-type: none; diff --git a/controllers/user.php b/controllers/user.php index e5b2030b..bc5c48fe 100644 --- a/controllers/user.php +++ b/controllers/user.php @@ -4,9 +4,19 @@ namespace Controller; require_once __DIR__.'/base.php'; +/** + * User controller + * + * @package controller + * @author Frederic Guillot + */ class User extends Base { - // Display access forbidden page + /** + * Display access forbidden page + * + * @access public + */ public function forbidden() { $this->response->html($this->template->layout('user_forbidden', array( @@ -15,14 +25,22 @@ class User extends Base ))); } - // Logout and destroy session + /** + * Logout and destroy session + * + * @access public + */ public function logout() { $this->session->close(); $this->response->redirect('?controller=user&action=login'); } - // Display the form login + /** + * Display the form login + * + * @access public + */ public function login() { if (isset($_SESSION['user'])) $this->response->redirect('?controller=app'); @@ -35,7 +53,11 @@ class User extends Base ))); } - // Check credentials + /** + * Check credentials + * + * @access public + */ public function check() { $values = $this->request->getValues(); @@ -51,7 +73,11 @@ class User extends Base ))); } - // List all users + /** + * List all users + * + * @access public + */ public function index() { $users = $this->user->getAll(); @@ -67,7 +93,11 @@ class User extends Base ))); } - // Display a form to create a new user + /** + * Display a form to create a new user + * + * @access public + */ public function create() { $this->response->html($this->template->layout('user_new', array( @@ -79,7 +109,11 @@ class User extends Base ))); } - // Validate and save a new user + /** + * Validate and save a new user + * + * @access public + */ public function save() { $values = $this->request->getValues(); @@ -105,14 +139,18 @@ class User extends Base ))); } - // Display a form to edit a user + /** + * Display a form to edit a user + * + * @access public + */ public function edit() { $user = $this->user->getById($this->request->getIntegerParam('user_id')); if (! $user) $this->notfound(); - if (! $_SESSION['user']['is_admin'] && $_SESSION['user']['id'] != $user['id']) { + if ($this->acl->isRegularUser() && $this->acl->getUserId() != $user['id']) { $this->forbidden(); } @@ -127,17 +165,21 @@ class User extends Base ))); } - // Validate and update a user + /** + * Validate and update a user + * + * @access public + */ public function update() { $values = $this->request->getValues(); - if ($_SESSION['user']['is_admin'] == 1) { + if ($this->acl->isAdminUser()) { $values += array('is_admin' => 0); } else { - if ($_SESSION['user']['id'] != $values['id']) { + if ($this->acl->getUserId() != $values['id']) { $this->forbidden(); } @@ -168,7 +210,11 @@ class User extends Base ))); } - // Confirmation dialog before to remove a user + /** + * Confirmation dialog before to remove a user + * + * @access public + */ public function confirm() { $user = $this->user->getById($this->request->getIntegerParam('user_id')); @@ -182,7 +228,11 @@ class User extends Base ))); } - // Remove a user + /** + * Remove a user + * + * @access public + */ public function remove() { $user_id = $this->request->getIntegerParam('user_id'); diff --git a/core/helper.php b/core/helper.php index 0eeec4cd..da90bad6 100644 --- a/core/helper.php +++ b/core/helper.php @@ -18,6 +18,11 @@ function is_admin() return $_SESSION['user']['is_admin'] == 1; } +function get_username() +{ + return $_SESSION['user']['username']; +} + function markdown($text) { require_once __DIR__.'/../vendor/Michelf/MarkdownExtra.inc.php'; @@ -206,6 +211,7 @@ function form_textarea($name, $values = array(), array $errors = array(), array $html .= implode(' ', $attributes).'>'; $html .= isset($values->$name) ? escape($values->$name) : isset($values[$name]) ? $values[$name] : ''; $html .= '</textarea>'; + if (in_array('required', $attributes)) $html .= '<span class="form-required">*</span>'; $html .= error_list($errors, $name); return $html; @@ -217,6 +223,7 @@ function form_input($type, $name, $values = array(), array $errors = array(), ar $html = '<input type="'.$type.'" name="'.$name.'" id="form-'.$name.'" '.form_value($values, $name).' class="'.$class.'" '; $html .= implode(' ', $attributes).'/>'; + if (in_array('required', $attributes)) $html .= '<span class="form-required">*</span>'; $html .= error_list($errors, $name); return $html; diff --git a/locales/fr_FR/translations.php b/locales/fr_FR/translations.php index 9a73228b..362d29c2 100644 --- a/locales/fr_FR/translations.php +++ b/locales/fr_FR/translations.php @@ -264,4 +264,7 @@ return array( 'Do you really want to remove this comment?' => 'Voulez-vous vraiment supprimer ce commentaire ?', 'Only administrators or the creator of the comment can access to this page.' => 'Uniquement les administrateurs ou le créateur du commentaire peuvent accéder à cette page.', 'Details' => 'Détails', + 'Current password for the user "%s"' => 'Mot de passe actuel pour l\'utilisateur « %s »', + 'The current password is required' => 'Le mot de passe actuel est obligatoire', + 'Wrong password' => 'Mauvais mot de passe', ); diff --git a/locales/pl_PL/translations.php b/locales/pl_PL/translations.php index 27ffdef7..25c3e637 100644 --- a/locales/pl_PL/translations.php +++ b/locales/pl_PL/translations.php @@ -267,4 +267,7 @@ return array( // 'Do you really want to remove this comment?' => '', // 'Only administrators or the creator of the comment can access to this page.' => '', // 'Details' => '', + // 'Current password for the user "%s"' => '', + // 'The current password is required' => '', + // 'Wrong password' => '', ); diff --git a/models/user.php b/models/user.php index 21c65b59..496ae0da 100644 --- a/models/user.php +++ b/models/user.php @@ -7,20 +7,51 @@ require_once __DIR__.'/base.php'; use \SimpleValidator\Validator; use \SimpleValidator\Validators; +/** + * User model + * + * @package model + * @author Frederic Guillot + */ class User extends Base { + /** + * SQL table name + * + * @var string + */ const TABLE = 'users'; + /** + * Get a specific user by id + * + * @access public + * @param integer $user_id User id + * @return array + */ public function getById($user_id) { return $this->db->table(self::TABLE)->eq('id', $user_id)->findOne(); } + /** + * Get a specific user by the username + * + * @access public + * @param string $username Username + * @return array + */ public function getByUsername($username) { return $this->db->table(self::TABLE)->eq('username', $username)->findOne(); } + /** + * Get all users + * + * @access public + * @return array + */ public function getAll() { return $this->db @@ -30,11 +61,24 @@ class User extends Base ->findAll(); } + /** + * List all users (key-value pairs with id/username) + * + * @access public + * @return array + */ public function getList() { return $this->db->table(self::TABLE)->asc('username')->listing('id', 'username'); } + /** + * Add a new user in the database + * + * @access public + * @param array $values Form values + * @return boolean + */ public function create(array $values) { if (isset($values['confirmation'])) unset($values['confirmation']); @@ -43,6 +87,13 @@ class User extends Base return $this->db->table(self::TABLE)->save($values); } + /** + * Modify a new user + * + * @access public + * @param array $values Form values + * @return array + */ public function update(array $values) { if (! empty($values['password'])) { @@ -52,17 +103,25 @@ class User extends Base unset($values['password']); } - unset($values['confirmation']); + if (isset($values['confirmation'])) unset($values['confirmation']); + if (isset($values['current_password'])) unset($values['current_password']); - $this->db->table(self::TABLE)->eq('id', $values['id'])->save($values); + $result = $this->db->table(self::TABLE)->eq('id', $values['id'])->update($values); if ($_SESSION['user']['id'] == $values['id']) { $this->updateSession(); } - return true; + return $result; } + /** + * Remove a specific user + * + * @access public + * @param integer $user_id User id + * @return boolean + */ public function remove($user_id) { $this->db->startTransaction(); @@ -76,17 +135,32 @@ class User extends Base return true; } + /** + * Update user session information + * + * @access public + * @param array $user User data + */ public function updateSession(array $user = array()) { if (empty($user)) { $user = $this->getById($_SESSION['user']['id']); } - if (isset($user['password'])) unset($user['password']); + if (isset($user['password'])) { + unset($user['password']); + } $_SESSION['user'] = $user; } + /** + * Validate user creation + * + * @access public + * @param array $values Form values + * @return array $valid, $errors [0] = Success or not, [1] = List of errors + */ public function validateCreation(array $values) { $v = new Validator($values, array( @@ -108,23 +182,28 @@ class User extends Base ); } + /** + * Validate user modification + * + * @access public + * @param array $values Form values + * @return array $valid, $errors [0] = Success or not, [1] = List of errors + */ public function validateModification(array $values) { if (! empty($values['password'])) { - return $this->validateCreation($values); + return $this->validatePasswordModification($values); } - else { - $v = new Validator($values, array( - new Validators\Required('id', t('The user id is required')), - new Validators\Required('username', t('The username is required')), - new Validators\MaxLength('username', t('The maximum length is %d characters', 50), 50), - new Validators\AlphaNumeric('username', t('The username must be alphanumeric')), - new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), self::TABLE, 'id'), - new Validators\Integer('default_project_id', t('This value must be an integer')), - new Validators\Integer('is_admin', t('This value must be an integer')), - )); - } + $v = new Validator($values, array( + new Validators\Required('id', t('The user id is required')), + new Validators\Required('username', t('The username is required')), + new Validators\MaxLength('username', t('The maximum length is %d characters', 50), 50), + new Validators\AlphaNumeric('username', t('The username must be alphanumeric')), + new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), self::TABLE, 'id'), + new Validators\Integer('default_project_id', t('This value must be an integer')), + new Validators\Integer('is_admin', t('This value must be an integer')), + )); return array( $v->execute(), @@ -132,6 +211,53 @@ class User extends Base ); } + /** + * Validate password modification + * + * @access public + * @param array $values Form values + * @return array $valid, $errors [0] = Success or not, [1] = List of errors + */ + public function validatePasswordModification(array $values) + { + $v = new Validator($values, array( + new Validators\Required('id', t('The user id is required')), + new Validators\Required('username', t('The username is required')), + new Validators\MaxLength('username', t('The maximum length is %d characters', 50), 50), + new Validators\AlphaNumeric('username', t('The username must be alphanumeric')), + new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), self::TABLE, 'id'), + new Validators\Required('current_password', t('The current password is required')), + new Validators\Required('password', t('The password is required')), + new Validators\MinLength('password', t('The minimum length is %d characters', 6), 6), + new Validators\Required('confirmation', t('The confirmation is required')), + new Validators\Equals('password', 'confirmation', t('Passwords doesn\'t matches')), + new Validators\Integer('default_project_id', t('This value must be an integer')), + new Validators\Integer('is_admin', t('This value must be an integer')), + )); + + if ($v->execute()) { + + // Check password + $user = $this->getById($_SESSION['user']['id']); + + if ($user !== false && \password_verify($values['current_password'], $user['password'])) { + return array(true, array()); + } + else { + return array(false, array('current_password' => array(t('Wrong password')))); + } + } + + return array(false, $v->getErrors()); + } + + /** + * Validate user login + * + * @access public + * @param array $values Form values + * @return array $valid, $errors [0] = Success or not, [1] = List of errors + */ public function validateLogin(array $values) { $v = new Validator($values, array( diff --git a/templates/project_new.php b/templates/project_new.php index 5ce6f97d..2026d461 100644 --- a/templates/project_new.php +++ b/templates/project_new.php @@ -9,7 +9,7 @@ <form method="post" action="?controller=project&action=save" autocomplete="off"> <?= Helper\form_label(t('Name'), 'name') ?> - <?= Helper\form_text('name', $values, $errors, array('autofocus required')) ?> + <?= Helper\form_text('name', $values, $errors, array('autofocus', 'required')) ?> <div class="form-actions"> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> diff --git a/templates/task_new.php b/templates/task_new.php index 4280bf80..efb9cb62 100644 --- a/templates/task_new.php +++ b/templates/task_new.php @@ -6,7 +6,7 @@ <form method="post" action="?controller=task&action=save" autocomplete="off"> <?= Helper\form_label(t('Title'), 'title') ?> - <?= Helper\form_text('title', $values, $errors, array('autofocus required')) ?><br/> + <?= Helper\form_text('title', $values, $errors, array('autofocus', 'required')) ?><br/> <?= Helper\form_hidden('project_id', $values) ?> diff --git a/templates/user_edit.php b/templates/user_edit.php index c65f3381..0c82793d 100644 --- a/templates/user_edit.php +++ b/templates/user_edit.php @@ -13,6 +13,9 @@ <?= Helper\form_label(t('Username'), 'username') ?> <?= Helper\form_text('username', $values, $errors, array('required')) ?><br/> + <?= Helper\form_label(t('Current password for the user "%s"', Helper\get_username()), 'current_password') ?> + <?= Helper\form_password('current_password', $values, $errors) ?><br/> + <?= Helper\form_label(t('Password'), 'password') ?> <?= Helper\form_password('password', $values, $errors) ?><br/> diff --git a/templates/user_new.php b/templates/user_new.php index 0c753c2a..8b15525b 100644 --- a/templates/user_new.php +++ b/templates/user_new.php @@ -9,7 +9,7 @@ <form method="post" action="?controller=user&action=save" autocomplete="off"> <?= Helper\form_label(t('Username'), 'username') ?> - <?= Helper\form_text('username', $values, $errors, array('autofocus required')) ?><br/> + <?= Helper\form_text('username', $values, $errors, array('autofocus', 'required')) ?><br/> <?= Helper\form_label(t('Password'), 'password') ?> <?= Helper\form_password('password', $values, $errors, array('required')) ?><br/> |