From 13530f595c6a57d01bd20b7e0d9e9011b6126bbd Mon Sep 17 00:00:00 2001 From: Eike Foken Date: Wed, 10 Aug 2011 19:24:25 +0200 Subject: [PATCH 1/7] PHP5! And fix PHPDoc in Messages library --- application/libraries/Messages.php | 59 +++++++++++++++++++----------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/application/libraries/Messages.php b/application/libraries/Messages.php index 1b8d1c8..46f26bf 100644 --- a/application/libraries/Messages.php +++ b/application/libraries/Messages.php @@ -8,18 +8,22 @@ * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * - * @author Vijay Mahrra & Sheikh Ahmed - * @url http://www.designbyfail.com/ + * @author Vijay Mahrra & Sheikh Ahmed + * @author Eike Foken + * @link http://www.designbyfail.com/ * @version 1.0 */ +class Messages { -class Messages -{ var $_ci; var $_types = array('success', 'error', 'notice'); - function Messages($params = array()) - { + /** + * Constructor. + * + * @param array $params + */ + public function __construct($params = array()) { $this->_ci =& get_instance(); $this->_ci->load->library('session'); // check if theres already messages, if not, initialise the messages array in the session @@ -29,9 +33,10 @@ class Messages } } - // clear all messages - function clear() - { + /** + * Clears all messages + */ + public function clear() { $messages = array(); foreach ($this->_types as $type) { $messages[$type] = array(); @@ -39,9 +44,10 @@ class Messages $this->_ci->session->set_userdata('messages', $messages); } - // add a message, default type is message - function add($message, $type = 'message') - { + /** + * Adds a message (default type is 'notice'). + */ + public function add($message, $type = 'notice') { $messages = $this->_ci->session->userdata('messages'); // handle PEAR errors gracefully if (is_a($message, 'PEAR_Error')) { @@ -49,7 +55,7 @@ class Messages $type = 'error'; } else if (!in_array($type, $this->_types)) { // set the type to message if the user specified a type that's unknown - $type = 'message'; + $type = 'notice'; } // don't repeat messages! if (!in_array($message, $messages[$type]) && is_string($message)) { @@ -58,9 +64,13 @@ class Messages $messages = $this->_ci->session->set_userdata('messages', $messages); } - // return messages of given type or all types, return false if none - function sum($type = null) - { + /** + * Returns messages of given type or all types, return false if none. + * + * @param string $type + * @return boolean|integer + */ + public function sum($type = null) { $messages = $this->_ci->session->userdata('messages'); if (!empty($type)) { $i = count($messages[$type]); @@ -70,12 +80,16 @@ class Messages foreach ($this->_types as $type) { $i += count($messages[$type]); } - return $i; + return $i > 0 ? $i : false; } - // return messages of given type or all types, return false if none, clearing stack - function get($type = null) - { + /** + * Returns messages of given type or all types, return false if none, clearing stack. + * + * @param string $type + * @return mixed + */ + public function get($type = null) { $messages = $this->_ci->session->userdata('messages'); if (!empty($type)) { if (count($messages[$type]) == 0) { @@ -100,4 +114,7 @@ class Messages $this->clear(); return $return; } -} \ No newline at end of file +} + +/* End of file Messages.php */ +/* Location: ./application/libraries/Messages.php */ From 5140deaca85974bc3ccc24ca48ba84ba65ffc97f Mon Sep 17 00:00:00 2001 From: Eike Foken Date: Wed, 10 Aug 2011 19:25:20 +0200 Subject: [PATCH 2/7] Overwrite default error delimiters for form validation --- application/libraries/MY_Form_validation.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/application/libraries/MY_Form_validation.php b/application/libraries/MY_Form_validation.php index 6ada3b0..6840882 100644 --- a/application/libraries/MY_Form_validation.php +++ b/application/libraries/MY_Form_validation.php @@ -12,6 +12,9 @@ class MY_Form_validation extends CI_Form_validation { */ public function __construct() { parent::__construct(); + + // overwrite default error delimiters + $this->set_error_delimiters('

', '

'); } /** From 24fbe455a1622c4dcc042b12f23ea4da77271c47 Mon Sep 17 00:00:00 2001 From: Eike Foken Date: Wed, 10 Aug 2011 19:26:44 +0200 Subject: [PATCH 3/7] Handle ajax requests correctly --- application/hooks/global.php | 12 +-- application/libraries/MY_Session.php | 129 ++++++++++++++------------- 2 files changed, 75 insertions(+), 66 deletions(-) diff --git a/application/hooks/global.php b/application/hooks/global.php index 23c53b1..a67e033 100644 --- a/application/hooks/global.php +++ b/application/hooks/global.php @@ -2,17 +2,17 @@ /* * Copyright (c) 2011 Karsten Heiken - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is + * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -33,9 +33,9 @@ function check_login() { // whitelisted (publicly available) controllers $public_controllers = array('auth'); - + $CI = & get_instance(); - if (!$CI->access->loggedIn() && !in_array($CI->router->class, $public_controllers)) { + if (!$CI->input->is_ajax_request() && !$CI->access->loggedIn() && !in_array($CI->router->class, $public_controllers)) { redirect('auth/login'); } } \ No newline at end of file diff --git a/application/libraries/MY_Session.php b/application/libraries/MY_Session.php index e7e1e80..9beff5c 100644 --- a/application/libraries/MY_Session.php +++ b/application/libraries/MY_Session.php @@ -7,83 +7,92 @@ */ class MY_Session extends CI_Session { - /** - * Calls the parent constructor. - */ - public function __construct() { - parent::__construct(); - } + /** + * Calls the parent constructor. + */ + public function __construct() { + parent::__construct(); + } - /** - * Generates a random and unique session ID. - * - * @return string - */ - private function generateHash() { - return sha1(uniqid(microtime() . $this->CI->input->ip_address(), true)); - } + /** + * Generates a random and unique session ID. + * + * @return string + */ + private function generateHash() { + return sha1(uniqid(microtime() . $this->CI->input->ip_address(), true)); + } - /** - * Creates a new session. - */ - public function sess_create() { - $this->userdata = array( + /** + * Creates a new session. + * + * @see CI_Session::sess_create() + */ + public function sess_create() { + $this->userdata = array( 'session_id' => $this->generateHash(), 'ip_address' => $this->CI->input->ip_address(), 'user_agent' => substr($this->CI->input->user_agent(), 0, 50), 'last_activity' => $this->now - ); + ); - // save data to the DB if needed - if ($this->sess_use_database === true) { - $this->CI->db->insert($this->sess_table_name, $this->userdata); - } + // save data to the DB if needed + if ($this->sess_use_database === true) { + $this->CI->db->insert($this->sess_table_name, $this->userdata); + } - // write the cookie - $this->_set_cookie(); - } + // write the cookie + $this->_set_cookie(); + } - /** - * Updates an existing session. - */ - public function sess_update() { - // skip the session update in case of an ajax call - if ($this->CI->input->is_ajax_request()) { - return; - } + /** + * Updates an existing session. + * + * @see CI_Session::sess_update() + */ + public function sess_update() { + // we only update the session every five minutes by default + if ($this->userdata['last_activity'] + $this->sess_time_to_update >= $this->now) { + return; + } - // we only update the session every five minutes by default - if ($this->userdata['last_activity'] + $this->sess_time_to_update >= $this->now) { - return; - } + $oldSessionID = $this->userdata['session_id']; + $newSessionID = $this->generateHash(); - $oldSessionID = $this->userdata['session_id']; - $newSessionID = $this->generateHash(); + $this->userdata['session_id'] = $newSessionID; + $this->userdata['last_activity'] = $this->now; - $this->userdata['session_id'] = $newSessionID; - $this->userdata['last_activity'] = $this->now; + $cookieData = null; - $cookieData = null; + // update the DB if needed + if ($this->sess_use_database === true) { + // set cookie explicitly to only have our session data + $cookieData = array(); + foreach (array('session_id', 'user_id', 'ip_address', 'user_agent', 'last_activity') as $val) { + $cookieData[$val] = $this->userdata[$val]; + } - // update the DB if needed - if ($this->sess_use_database === true) { - // set cookie explicitly to only have our session data - $cookieData = array(); - foreach (array('session_id', 'user_id', 'ip_address', 'user_agent', 'last_activity') as $val) { - $cookieData[$val] = $this->userdata[$val]; - } + $this->CI->db->update($this->sess_table_name, array('last_activity' => $this->now, 'user_id' => $this->userdata['user_id'], 'session_id' => $newSessionID), array('session_id' => $oldSessionID)); - $this->CI->db->update($this->sess_table_name, array('last_activity' => $this->now, 'user_id' => $this->userdata['user_id'], 'session_id' => $newSessionID), array('session_id' => $oldSessionID)); + // update users table if user is logged in + if (array_key_exists('user_id', $this->userdata) && $this->userdata['user_id'] > 0) { + $this->CI->db->update('users', array('last_activity' => $this->now), array('id' => $this->userdata['user_id'])); + } + } - // update users table if user is logged in - if (array_key_exists('user_id', $this->userdata) && $this->userdata['user_id'] > 0) { - $this->CI->db->update('users', array('last_activity' => $this->now), array('id' => $this->userdata['user_id'])); - } - } + // write the cookie + $this->_set_cookie($cookieData); + } - // write the cookie - $this->_set_cookie($cookieData); - } + /** + * Destroys an existing session. + * + * @see CI_Session::sess_destroy() + */ + public function sess_destroy() { + parent::sess_destroy(); + $this->userdata = array(); + } } /* End of file MY_Session.php */ From b66d65cc5b71c88a15abf9b7d1ea07d2d7323f4b Mon Sep 17 00:00:00 2001 From: Eike Foken Date: Wed, 10 Aug 2011 19:42:17 +0200 Subject: [PATCH 4/7] A lot of fixes in the user model --- application/libraries/Access.php | 2 +- application/models/user.php | 49 ++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/application/libraries/Access.php b/application/libraries/Access.php index dba18fd..fb70b8a 100644 --- a/application/libraries/Access.php +++ b/application/libraries/Access.php @@ -238,7 +238,7 @@ class Access { * @return object */ public function getCurrentUser() { - return $this->ci->user->getUserByID($this->ci->session->userdata('user_id'))->row_array(); + return $this->ci->user->getUserByID($this->ci->session->userdata('user_id')); } /** diff --git a/application/models/user.php b/application/models/user.php index e7f5e30..28fea9b 100644 --- a/application/models/user.php +++ b/application/models/user.php @@ -82,7 +82,7 @@ class User extends CI_Model { * @return string */ private function salt() { - return substr(md5(uniqid(rand(), true)), 0, $this->saltLength); + return substr(sha1(uniqid(rand(), true)), 0, $this->saltLength); } /** @@ -211,32 +211,37 @@ class User extends CI_Model { } /** - * register + * Registers a new user. * + * @param string $username + * @param string $password + * @param string $email + * @param array $additionalData + * @param string $groupName * @return boolean */ - public function register($username, $password, $email, $additionalData = false, $groupName = false) { + public function register($username, $password, $email, $additionalData = array(), $groupName = '') { if ($this->checkUsername($username)) { $this->access->setError('account_creation_duplicate_username'); return false; } + print_r($additionalData); // if a groupID was passed, use it - if (isset($additional_data['group_id'])) { - $groupID = $additional_data['group_id']; - unset($additional_data['group_id']); + if (isset($additionalData['group_id'])) { + $groupID = $additionalData['group_id']; + unset($additionalData['group_id']); } else { // otherwise get default groupID - $groupName = !$groupName ? 'users' : $groupName; + $groupName = ($groupName == '') ? 'users' : $groupName; $groupID = $this->db->select('id')->where('name', $groupName)->get('groups')->row()->id; } - // IP Address - $ipAddress = $this->input->ip_address(); $salt = $this->storeSalt ? $this->salt() : false; $password = $this->hashPassword($password, $salt); - // Users table. + // users table $data = array( + 'id' => random_hash(16), 'username' => $username, 'password' => $password, 'email' => $email, @@ -247,11 +252,11 @@ class User extends CI_Model { if ($this->storeSalt) { $data['salt'] = $salt; } + print_r($data); - $this->db->insert('users', $data); - $id = $this->db->insert_id(); + $this->db->insert('users', array_merge($data, $additionalData)); - return $this->db->affected_rows() > 0 ? $id : false; + return $this->db->affected_rows() > 0 ? $data['id'] : false; } /** @@ -340,9 +345,9 @@ class User extends CI_Model { } /** - * getUserByID + * Gets a user by ID. * - * @return object + * @return array */ public function getUserByID($id = false) { // if no ID was passed use the current users ID @@ -353,7 +358,7 @@ class User extends CI_Model { $this->db->where('users.id', $id); $this->db->limit(1); - return $this->get(); + return $this->get()->row_array(); } /** @@ -411,11 +416,11 @@ class User extends CI_Model { * @return boolean */ public function update($id, $data) { - $user = $this->getUserByID($id)->row(); + $user = $this->getUserByID($id); $this->db->trans_begin(); - if (array_key_exists('username', $data) && $this->checkUsername($data['username']) && $user->username !== $data['username']) { + if (array_key_exists('username', $data) && $this->checkUsername($data['username']) && $user['username'] !== $data['username']) { $this->db->trans_rollback(); $this->access->setError('account_creation_duplicate_username'); return false; @@ -423,7 +428,7 @@ class User extends CI_Model { if (array_key_exists('username', $data) || array_key_exists('password', $data) || array_key_exists('email', $data)) { if (array_key_exists('password', $data)) { - $data['password'] = $this->hashPassword($data['password'], $user->salt); + $data['password'] = $this->hashPassword($data['password'], $user['salt']); } $this->db->update('users', $data, array('id' => $id)); @@ -518,16 +523,16 @@ class User extends CI_Model { return false; } - $user = $this->getUserByID($id)->row(); + $user = $this->getUserByID($id); - $salt = sha1($user->password); + $salt = sha1($user['password']); $this->db->update('users', array('remember_code' => $salt), array('id' => $id)); if ($this->db->affected_rows() > -1) { set_cookie(array( 'name' => 'username', - 'value' => $user->username, + 'value' => $user['username'], 'expire' => $this->config->item('user_expire', 'auth'), )); set_cookie(array( From 2c10799aa361aa1cb0589d15526ec0f3b64ead45 Mon Sep 17 00:00:00 2001 From: Eike Foken Date: Wed, 10 Aug 2011 20:19:13 +0200 Subject: [PATCH 5/7] Fix style for form errors and global messages --- assets/css/form.css | 4 ++-- assets/css/style.css | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/assets/css/form.css b/assets/css/form.css index 44716d4..83aab14 100644 --- a/assets/css/form.css +++ b/assets/css/form.css @@ -55,11 +55,11 @@ input.medium { width: 45%;} input.long { width:70%;} input.max { width: 95%;} -.success { +p.success { color: #008000; } -.error, .req { +p.error, p.req { color: #d8122d; font-weight: normal; } \ No newline at end of file diff --git a/assets/css/style.css b/assets/css/style.css index a453038..99d1102 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -21,7 +21,7 @@ p { margin: 0px 0px 20px 0px; line-height: 18px;} ul { margin: 5px 0px 15px 0px; padding: 0px;} li { margin-left: 20px;} -.notice { +div.notice { margin: 0 0 15px; padding: 0 10px; background: #fffbcc; @@ -30,7 +30,7 @@ li { margin-left: 20px;} color: #222; } -.success { +div.success { margin: 0 0 15px; padding: 0 10px; background: #d1ecb8; @@ -39,7 +39,7 @@ li { margin-left: 20px;} color: #222; } -.error { +div.error { margin: 0 0 15px; padding: 0 10px; background: #ffebe8; From c4dfe084b6be517cb95565972184c339ea9bfeb7 Mon Sep 17 00:00:00 2001 From: Eike Foken Date: Wed, 10 Aug 2011 20:19:44 +0200 Subject: [PATCH 6/7] Add english language for form validation --- .../language/english/form_validation_lang.php | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/application/language/english/form_validation_lang.php b/application/language/english/form_validation_lang.php index ca9df3a..c57ded2 100644 --- a/application/language/english/form_validation_lang.php +++ b/application/language/english/form_validation_lang.php @@ -1,6 +1,28 @@ Date: Wed, 10 Aug 2011 20:21:02 +0200 Subject: [PATCH 7/7] Continue implementing user management --- application/controllers/users.php | 134 ++++++++++++++++++++ application/language/english/users_lang.php | 10 ++ application/models/user.php | 3 +- application/views/admin/users/create.php | 28 +++- application/views/admin/users/edit.php | 67 ++++++++++ 5 files changed, 234 insertions(+), 8 deletions(-) create mode 100644 application/views/admin/users/edit.php diff --git a/application/controllers/users.php b/application/controllers/users.php index a2eae6b..e5acb80 100644 --- a/application/controllers/users.php +++ b/application/controllers/users.php @@ -13,6 +13,7 @@ class Users extends MY_Controller { */ public function __construct() { parent::__construct(); + $this->load->library('form_validation'); $this->load->model('user'); } @@ -28,6 +29,139 @@ class Users extends MY_Controller { * Allows admins to create a new user. */ public function create() { + $config = array( + array( + 'field' => 'username', + 'label' => 'lang:field_username', + 'rules' => 'trim|required|min_length[4]|max_length[20]|unique[users.username]', + ), + array( + 'field' => 'password', + 'label' => 'lang:field_password', + 'rules' => 'required|min_length[6]|matches[password_confirm]', + ), + array( + 'field' => 'password_confirm', + 'label' => 'lang:field_password_confirm', + ), + array( + 'field' => 'firstname', + 'label' => 'lang:field_firstname', + 'rules' => 'trim|required|max_length[50]', + ), + array( + 'field' => 'lastname', + 'label' => 'lang:field_lastname', + 'rules' => 'trim|required|max_length[50]', + ), + array( + 'field' => 'email', + 'label' => 'lang:field_email', + 'rules' => 'trim|required|valid_email', + ), + array( + 'field' => 'institution', + 'label' => 'lang:field_institution', + 'rules' => 'trim|max_length[100]', + ), + array( + 'field' => 'phone', + 'label' => 'lang:field_phone', + 'rules' => 'trim|regex_match[/^\+\d{2,4}\w\d{2,4}\w\d{3,10}+$/i]', + ) + ); + $this->form_validation->set_rules($config); + + if ($this->form_validation->run() === true) { + $username = $this->input->post('username'); + + $data = array( + 'firstname' => $this->input->post('firstname'), + 'lastname' => $this->input->post('lastname'), + 'institution' => $this->input->post('institution'), + 'phone' => $this->input->post('phone') + ); + + if ($this->user->register($username, $this->input->post('password'), $this->input->post('email'), $data)) { + $this->messages->add("The user '" . $username . "' was created", 'success'); + redirect('users', 201); + } + } + $this->load->view('admin/users/create'); } + + /** + * Allows admins to edit the specified user. + * + * @param integer $id + */ + public function edit($id = '') { + $user = $this->user->getUserByID($id); + + if (!isset($user) || !is_array($user)){ + show_404(); + } + + $config = array( + array( + 'field' => 'firstname', + 'label' => 'lang:field_firstname', + 'rules' => 'trim|required|max_length[50]', + ), + array( + 'field' => 'lastname', + 'label' => 'lang:field_lastname', + 'rules' => 'trim|required|max_length[50]', + ), + array( + 'field' => 'email', + 'label' => 'lang:field_email', + 'rules' => 'trim|required|valid_email', + ), + array( + 'field' => 'institution', + 'label' => 'lang:field_institution', + 'rules' => 'trim|max_length[100]', + ), + array( + 'field' => 'phone', + 'label' => 'lang:field_phone', + //'rules' => 'trim|regex_match[/^\+\d{2,4}\w\d{2,4}\w\d{3,10}+$/i]', + ) + ); + $this->form_validation->set_rules($config); + + if ($this->form_validation->run() === true) { + $data = array( + 'email' => $this->input->post('email'), + 'firstname' => $this->input->post('firstname'), + 'lastname' => $this->input->post('lastname'), + 'institution' => $this->input->post('institution'), + 'phone' => $this->input->post('phone') + ); + + if ($this->user->update($user['id'], $data)) { + $this->messages->add("The user '" . $user['username'] . "' was updated", 'success'); + redirect('users', 200); + } + } + + $this->load->view('admin/users/edit', array('user' => $user)); + } + + /** + * Allows admins to delete the specified user. + * + * @param integer $id + */ + public function delete($id = '') { + if (!is_array($this->user->getUserByID())) { + show_404(); + } + + $this->user->delete($id); + $this->messages->add('The selected user was deleted', 'success'); + redirect('users', 200); + } } \ No newline at end of file diff --git a/application/language/english/users_lang.php b/application/language/english/users_lang.php index d9ee277..829211e 100644 --- a/application/language/english/users_lang.php +++ b/application/language/english/users_lang.php @@ -10,6 +10,16 @@ $lang['user_create'] = "Create new user"; $lang['user_delete'] = "Delete"; $lang['create_user'] = "Create a new user"; +$lang['edit_user'] = "Edit user"; + +$lang['field_username'] = "Username"; +$lang['field_password'] = "Password"; +$lang['field_password_confirm'] = "Confirm password"; +$lang['field_firstname'] = "First name"; +$lang['field_lastname'] = "Last name"; +$lang['field_email'] = "Email address"; +$lang['field_institution'] = "Institution"; +$lang['field_phone'] = "Phone number"; /* End of file users_lang.php */ /* Location: ./application/language/english/users_lang.php */ diff --git a/application/models/user.php b/application/models/user.php index 28fea9b..adc5024 100644 --- a/application/models/user.php +++ b/application/models/user.php @@ -350,9 +350,8 @@ class User extends CI_Model { * @return array */ public function getUserByID($id = false) { - // if no ID was passed use the current users ID if (empty($id)) { - $id = $this->session->userdata('user_id'); + return false; } $this->db->where('users.id', $id); diff --git a/application/views/admin/users/create.php b/application/views/admin/users/create.php index aa7810a..72fabd5 100644 --- a/application/views/admin/users/create.php +++ b/application/views/admin/users/create.php @@ -11,35 +11,43 @@

Required information

  • - +
    +
  • - + +
    + + +
    +
  • +
  • +
  • - +
  • - +
  • - +
    @@ -49,12 +57,20 @@

    Optional information

    • - +
    • +
    • + +
      + + +
      + +
    • diff --git a/application/views/admin/users/edit.php b/application/views/admin/users/edit.php new file mode 100644 index 0000000..73664d9 --- /dev/null +++ b/application/views/admin/users/edit.php @@ -0,0 +1,67 @@ +load->view('header');?> + +
      + +
      +

      ''

      +
      + +
      +
      +

      Required information

      +
        +
      • + +
        + + +
        +
      • +
      • + +
        + + +
        +
      • +
      • + +
        + + +
        +
      • +
      +

      Optional information

      +
        +
      • + +
        + + +
        +
      • +
      • + +
        + + +
        + +
      • +
      • + +
        + + +
        +
      • +
      +

      + Speichern +

      +
      +
      +
      + +load->view('footer');?> \ No newline at end of file