From e596cb768a786f019d9799afb4539ccdffad95b0 Mon Sep 17 00:00:00 2001
From: "alextselegidis@gmail.com"
Date: Mon, 23 Sep 2013 15:42:36 +0000
Subject: [PATCH] * Completed login + logout operation. * Updated the way the
system stores passwords in db.
---
src/application/config/constants.php | 2 +
src/application/controllers/backend.php | 9 +-
src/application/controllers/backend_api.php | 27 ++++
src/application/controllers/user.php | 20 ++-
src/application/helpers/general_helper.php | 31 +++-
src/application/models/admins_model.php | 45 ++++++
src/application/models/providers_model.php | 30 ++++
src/application/models/secretaries_model.php | 29 ++++
src/application/models/user_model.php | 44 +++++
.../views/appointments/book_success.php | 2 +-
src/application/views/backend/header.php | 2 +-
src/application/views/backend/settings.php | 2 +-
src/application/views/user/login.php | 30 ++--
src/application/views/user/logout.php | 85 +++++++++-
src/assets/css/backend.css | 2 +-
src/assets/js/backend.js | 30 ----
src/assets/js/backend_services.js | 14 +-
src/assets/js/backend_settings.js | 5 +-
src/assets/js/backend_users.js | 151 +++++++++++++-----
src/assets/js/general_functions.js | 34 ++++
20 files changed, 478 insertions(+), 116 deletions(-)
diff --git a/src/application/config/constants.php b/src/application/config/constants.php
index 994944c4..deefe73e 100644
--- a/src/application/config/constants.php
+++ b/src/application/config/constants.php
@@ -70,5 +70,7 @@ define('PAGE_SERVICES', 'services');
define('PAGE_USERS', 'users');
define('PAGE_SYSTEM_SETTINGS', 'system_settings');
define('PAGE_USER_SETTINGS', 'user_settings');
+
+define('MIN_PASSWORD_LENGTH', 7);
/* End of file constants.php */
/* Location: ./application/config/constants.php */
\ No newline at end of file
diff --git a/src/application/controllers/backend.php b/src/application/controllers/backend.php
index e12587af..20a38410 100644
--- a/src/application/controllers/backend.php
+++ b/src/application/controllers/backend.php
@@ -143,17 +143,12 @@ class Backend extends CI_Controller {
$this->load->model('settings_model');
$this->load->model('user_model');
- $this->load->library('session');
-
- // @task Apply data for testing this page (this must be done during the login process).
- $this->session->set_userdata('user_id', 18);
- $this->session->set_userdata('user_slug', DB_SLUG_ADMIN);
-
+ $this->load->library('session');
$user_id = $this->session->userdata('user_id');
$view['base_url'] = $this->config->item('base_url');
$view['company_name'] = $this->settings_model->get_setting('company_name');
- $view['user_slug'] = $this->session->userdata('user_slug');
+ $view['role_slug'] = $this->session->userdata('role_slug');
$view['system_settings'] = $this->settings_model->get_settings();
$view['user_settings'] = $this->user_model->get_settings($user_id);
diff --git a/src/application/controllers/backend_api.php b/src/application/controllers/backend_api.php
index b864c18d..9c7a555f 100644
--- a/src/application/controllers/backend_api.php
+++ b/src/application/controllers/backend_api.php
@@ -703,6 +703,13 @@ class Backend_api extends CI_Controller {
try {
$this->load->model('providers_model');
$provider = json_decode($_POST['provider'], true);
+
+ if (!isset($provider['working_plan'])) {
+ $this->load->model('settings_model');
+ $provider['settings']['working_plan'] = $this->settings_model
+ ->get_setting('company_working_plan');
+ }
+
$this->providers_model->add($provider);
echo json_encode(AJAX_SUCCESS);
} catch(Exception $exc) {
@@ -822,6 +829,26 @@ class Backend_api extends CI_Controller {
));
}
}
+
+ /**
+ * [AJAX] This method checks whether the username already exists in the database.
+ *
+ * @param string $_POST['username'] Record's username to validate.
+ * @param bool $_POST['record_exists'] Whether the record already exists in database.
+ */
+ public function ajax_validate_username() {
+ try {
+ // We will use the function in the admins_model because it is sufficient for
+ // the rest user types for now (providers, secretaries).
+ $this->load->model('admins_model');
+ $is_valid = $this->admins_model->validate_username($_POST['username'], $_POST['record_exists']);
+ echo json_encode($is_valid);
+ } catch(Exception $exc) {
+ echo json_encode(array(
+ 'exceptions' => array(exceptionToJavaScript($exc))
+ ));
+ }
+ }
}
/* End of file backend_api.php */
diff --git a/src/application/controllers/user.php b/src/application/controllers/user.php
index c3bb6a05..4966930f 100644
--- a/src/application/controllers/user.php
+++ b/src/application/controllers/user.php
@@ -13,11 +13,24 @@ class User extends CI_Controller {
public function login() {
$view['base_url'] = $this->config->item('base_url');
$view['dest_url'] = $this->session->userdata('dest_url');
+
+ if (!$view['dest_url']) {
+ $view['dest_url'] = $view['base_url'] . 'backend';
+ }
+
$this->load->view('user/login', $view);
}
public function logout() {
+ $this->session->unset_userdata('user_id');
+ $this->session->unset_userdata('user_email');
+ $this->session->unset_userdata('role_slug');
+ $this->session->unset_userdata('username');
+ $this->session->unset_userdata('dest_url');
+ $view['base_url'] = $this->config->item('base_url');
+
+ $this->load->view('user/logout', $view);
}
public function forgot_password() {
@@ -37,17 +50,14 @@ class User extends CI_Controller {
throw new Exception('Invalid credentials given!');
}
- $this->load->helper('general');
$this->load->model('user_model');
-
- $hash_password = $this->hash_password($_POST['password']);
- $user_data = $this->user_model->check_login($_POST['username'], $hash_password);
+ $user_data = $this->user_model->check_login($_POST['username'], $_POST['password']);
if ($user_data) {
$this->session->set_userdata($user_data); // Save data on user's session.
echo json_encode(AJAX_SUCCESS);
} else {
- echo json_encode(AJAX_SUCCESS);
+ echo json_encode(AJAX_FAILURE);
}
} catch(Exception $exc) {
diff --git a/src/application/helpers/general_helper.php b/src/application/helpers/general_helper.php
index 8f31c5a0..871c0cf6 100644
--- a/src/application/helpers/general_helper.php
+++ b/src/application/helpers/general_helper.php
@@ -29,13 +29,38 @@ function date3339($timestamp=0) {
* Generate a hash of password string.
*
* For user security, all system passwords are stored in hash string into the database. Use
- * this method to produce the hash.
+ * this method to produce the hashed password.
*
+ * @param string $salt Salt value for current user. This value is stored on the database and
+ * is used when generating the password hash.
* @param string $password Given string password.
* @return string Returns the hash string of the given password.
*/
-function hash_password($password) {
- return md5($password); // @task include salt and hash more times.
+function hash_password($salt, $password) {
+ $salt = strtoupper($salt);
+ $password = strtoupper($password);
+ $half = (int)(strlen($salt) / 2);
+ $hash = hash('sha256', substr($salt, 0, $half ) . $password . substr($salt, $half));
+
+ for ($i = 0; $i < 100000; $i++) {
+ $hash = hash('sha256', $hash);
+ }
+
+ return $hash; // @task include salt and hash more times.
+}
+
+/**
+ * Generate a new password salt.
+ *
+ * This method will not check if the salt is unique in database. This must be done
+ * from the calling procedure.
+ *
+ * @return string Returns a salt string.
+ */
+function generate_salt() {
+ $max_length = 100;
+ $salt = hash('sha256', (uniqid(rand(), true)));
+ return substr($salt, 0, $max_length);
}
/* End of file general_helper.php */
diff --git a/src/application/models/admins_model.php b/src/application/models/admins_model.php
index 07f3f22c..38149563 100644
--- a/src/application/models/admins_model.php
+++ b/src/application/models/admins_model.php
@@ -85,6 +85,8 @@ class Admins_Model extends CI_Model {
* @throws Exception When the insert operation fails.
*/
public function insert($admin) {
+ $this->load->helper('general');
+
$admin['id_roles'] = $this->get_admin_role_id();
$settings = $admin['settings'];
unset($admin['settings']);
@@ -97,6 +99,8 @@ class Admins_Model extends CI_Model {
$admin['id'] = intval($this->db->insert_id());
$settings['id_users'] = $admin['id'];
+ $settings['salt'] = generate_salt();
+ $settings['password'] = hash_password($settings['salt'], $settings['password']);
// Insert admin settings.
if (!$this->db->insert('ea_user_settings', $settings)) {
@@ -117,10 +121,17 @@ class Admins_Model extends CI_Model {
* @throws Exception When the update operation fails.
*/
public function update($admin) {
+ $this->load->helper('general');
+
$settings = $admin['settings'];
unset($admin['settings']);
$settings['id_users'] = $admin['id'];
+ if (isset($settings['password'])) {
+ $salt = $this->db->get_where('ea_user_settings', array('id_users' => $admin['id']))->row()->salt;
+ $settings['password'] = hash_password($salt, $settings['password']);
+ }
+
$this->db->where('id', $admin['id']);
if (!$this->db->update('ea_users', $admin)) {
throw new Exception('Could not update admin record.');
@@ -193,6 +204,24 @@ class Admins_Model extends CI_Model {
throw new Exception('Invalid email address provided : ' . $admin['email']);
}
+ // Validate admin username
+ if (isset($admin['settings']['username'])) {
+ $num_rows = $this->db->get_where('ea_user_settings',
+ array('username' => $admin['settings']['username']))->num_rows();
+ if ($num_rows > 0) {
+ throw new Exception('Username already exists, please select another '
+ . 'and try again (username: ' . $admin['settings']['username'] . ')');
+ }
+ }
+
+ // Validate admin password
+ if (isset($admin['settings']['password'])) {
+ if (strlen($admin['settings']['password']) < MIN_PASSWORD_LENGTH) {
+ throw new Exception('The user password must be at least '
+ . MIN_PASSWORD_LENGTH . ' characters long.');
+ }
+ }
+
return TRUE;
} catch (Exception $exc) {
return FALSE;
@@ -328,6 +357,22 @@ class Admins_Model extends CI_Model {
public function get_admin_role_id() {
return intval($this->db->get_where('ea_roles', array('slug' => DB_SLUG_ADMIN))->row()->id);
}
+
+ /**
+ * Validate Records Username
+ *
+ * @param string $username The provider records username.
+ * @param bool $record_exists Whether the record exists or not.
+ * @return bool Returns the validation result.
+ */
+ public function validate_username($username, $record_exists) {
+ $num_rows = $this->db->get_where('ea_user_settings', array('username' => $username))->num_rows();
+ if ($num_rows == 0 && $record_exists == FALSE || $num_rows == 1 && $record_exists == TRUE) {
+ return true;
+ } else {
+ return false;
+ }
+ }
}
/* End of file admins_model.php */
diff --git a/src/application/models/providers_model.php b/src/application/models/providers_model.php
index 6ef9d0af..d84513a9 100644
--- a/src/application/models/providers_model.php
+++ b/src/application/models/providers_model.php
@@ -98,6 +98,8 @@ class Providers_Model extends CI_Model {
* @throws Exception When the insert operation fails.
*/
public function insert($provider) {
+ $this->load->helper('general');
+
// Get provider role id.
$provider['id_roles'] = $this->get_providers_role_id();
@@ -112,6 +114,9 @@ class Providers_Model extends CI_Model {
throw new Exception('Could not insert provider into the database');
}
+ $settings['salt'] = generate_salt();
+ $settings['password'] = hash_password($settings['salt'], $settings['password']);
+
$provider['id'] = $this->db->insert_id();
$this->save_settings($settings, $provider['id']);
$this->save_services($services, $provider['id']);
@@ -128,12 +133,19 @@ class Providers_Model extends CI_Model {
* @throws Exception When the update operation fails.
*/
public function update($provider) {
+ $this->load->helper('general');
+
// Store service and settings (must not be present on the $provider array).
$services = $provider['services'];
unset($provider['services']);
$settings = $provider['settings'];
unset($provider['settings']);
+ if (isset($settings['password'])) {
+ $salt = $this->db->get_where('ea_user_settings', array('id_users' => $provider['id']))->row()->salt;
+ $settings['password'] = hash_password($salt, $settings['password']);
+ }
+
// Update provider record.
$this->db->where('id', $provider['id']);
if (!$this->db->update('ea_users', $provider)) {
@@ -224,6 +236,24 @@ class Providers_Model extends CI_Model {
throw new Exception('Invalid provider settings given: ' . print_r($provider, TRUE));
}
+ // Validate admin username
+ if (isset($provider['settings']['username'])) {
+ $num_rows = $this->db->get_where('ea_user_settings',
+ array('username' => $provider['settings']['username']))->num_rows();
+ if ($num_rows > 0) {
+ throw new Exception('Username already exists, please select another '
+ . 'and try again (username: ' . $provider['settings']['username'] . ')');
+ }
+ }
+
+ // Validate admin password
+ if (isset($provider['settings']['password'])) {
+ if (strlen($provider['settings']['password']) < MIN_PASSWORD_LENGTH) {
+ throw new Exception('The user password must be at least '
+ . MIN_PASSWORD_LENGTH . ' characters long.');
+ }
+ }
+
return TRUE;
} catch (Exception $exc) {
return FALSE;
diff --git a/src/application/models/secretaries_model.php b/src/application/models/secretaries_model.php
index 492db372..97a7a808 100644
--- a/src/application/models/secretaries_model.php
+++ b/src/application/models/secretaries_model.php
@@ -86,6 +86,8 @@ class Secretaries_Model extends CI_Model {
* @throws Exception When the insert operation fails.
*/
public function insert($secretary) {
+ $this->load->helper('general');
+
$providers = $secretary['providers'];
unset($secretary['providers']);
$settings = $secretary['settings'];
@@ -98,6 +100,8 @@ class Secretaries_Model extends CI_Model {
}
$secretary['id'] = intval($this->db->insert_id());
+ $settings['salt'] = generate_salt();
+ $settings['password'] = hash_password($settings['salt'], $settings['password']);
$this->save_providers($providers, $secretary['id']);
$this->save_settings($settings, $secretary['id']);
@@ -113,11 +117,18 @@ class Secretaries_Model extends CI_Model {
* @throws Exception When the update operation fails.
*/
public function update($secretary) {
+ $this->load->helper('general');
+
$providers = $secretary['providers'];
unset($secretary['providers']);
$settings = $secretary['settings'];
unset($secretary['settings']);
+ if (isset($settings['password'])) {
+ $salt = $this->db->get_where('ea_user_settings', array('id_users' => $secretary['id']))->row()->salt;
+ $settings['password'] = hash_password($salt, $settings['password']);
+ }
+
$this->db->where('id', $secretary['id']);
if (!$this->db->update('ea_users', $secretary)){
throw new Exception('Could not update secretary record.');
@@ -193,6 +204,24 @@ class Secretaries_Model extends CI_Model {
throw new Exception('Invalid email address provided : ' . $secretary['email']);
}
+ // Validate admin username
+ if (isset($secretary['settings']['username'])) {
+ $num_rows = $this->db->get_where('ea_user_settings',
+ array('username' => $secretary['settings']['username']))->num_rows();
+ if ($num_rows > 0) {
+ throw new Exception('Username already exists, please select another '
+ . 'and try again (username: ' . $secretary['settings']['username'] . ')');
+ }
+ }
+
+ // Validate admin password
+ if (isset($secretary['settings']['password'])) {
+ if (strlen($secretary['settings']['password']) < MIN_PASSWORD_LENGTH) {
+ throw new Exception('The user password must be at least '
+ . MIN_PASSWORD_LENGTH . ' characters long.');
+ }
+ }
+
return TRUE;
} catch (Exception $exc) {
return FALSE;
diff --git a/src/application/models/user_model.php b/src/application/models/user_model.php
index 0fb003e8..53a2173e 100644
--- a/src/application/models/user_model.php
+++ b/src/application/models/user_model.php
@@ -35,6 +35,13 @@ class User_Model extends CI_Model {
$user_settings['id_users'] = $user['id'];
unset($user['settings']);
+ // Prepare user password (hash).
+ if (isset($user_settings['password'])) {
+ $this->load->helper('general');
+ $salt = $this->db->get_where('ea_user_settings', array('id_users' => $user['id']))->row()->salt;
+ $user_settings['password'] = hash_password($salt, $user_settings['password']);
+ }
+
if (!$this->db->update('ea_users', $user, array('id' => $user['id']))) {
return FALSE;
}
@@ -45,6 +52,43 @@ class User_Model extends CI_Model {
return TRUE;
}
+
+ /**
+ * Retrieve user's salt from database.
+ *
+ * @param string $username This will be used to find the user record.
+ * @return string Returns the salt db value.
+ */
+ public function get_salt($username) {
+ $user = $this->db->get_where('ea_user_settings', array('username' => $username))->row_array();
+ return ($user) ? $user['salt'] : '';
+ }
+
+ /**
+ * Performs the check of the given user credentials.
+ *
+ * @param string $username Given user's name.
+ * @param type $password Given user's password (not hashed yet).
+ * @return array|null Returns the session data of the logged in user or null on
+ * failure.
+ */
+ public function check_login($username, $password) {
+ $this->load->helper('general');
+ $salt = $this->user_model->get_salt($username);
+ $password = hash_password($salt, $password);
+
+ $user_data = $this->db
+ ->select('ea_users.id AS user_id, ea_users.email AS user_email, '
+ . 'ea_roles.slug AS role_slug, ea_user_settings.username')
+ ->from('ea_users')
+ ->join('ea_roles', 'ea_roles.id = ea_users.id_roles', 'innder')
+ ->join('ea_user_settings', 'ea_user_settings.id_users = ea_users.id')
+ ->where('ea_user_settings.username', $username)
+ ->where('ea_user_settings.password', $password)
+ ->get()->row_array();
+
+ return ($user_data) ? $user_data : NULL;
+ }
}
/* End of file user_model.php */
diff --git a/src/application/views/appointments/book_success.php b/src/application/views/appointments/book_success.php
index 5320ea81..3ce128bb 100644
--- a/src/application/views/appointments/book_success.php
+++ b/src/application/views/appointments/book_success.php
@@ -149,7 +149,7 @@
'Your appointment has successfully been added to ' +
'your Google Calendar account.
' +
'' +
- 'Click here to view your appoinmtent on Google ' +
+ 'Click here to view your appointment on Google ' +
'Calendar.' +
'' +
'
' +
diff --git a/src/application/views/backend/header.php b/src/application/views/backend/header.php
index 42324473..634f70bf 100644
--- a/src/application/views/backend/header.php
+++ b/src/application/views/backend/header.php
@@ -103,7 +103,7 @@
-
diff --git a/src/application/views/backend/settings.php b/src/application/views/backend/settings.php
index 7487582b..d0d50330 100644
--- a/src/application/views/backend/settings.php
+++ b/src/application/views/backend/settings.php
@@ -8,7 +8,7 @@
-
Login Required
-
Welcome! You will need to login in order to view this page.
+
Backend Section
+
Welcome! You will need to login in order to view backend pages.
-
diff --git a/src/application/views/user/logout.php b/src/application/views/user/logout.php
index b6eddc13..f6d8af5c 100644
--- a/src/application/views/user/logout.php
+++ b/src/application/views/user/logout.php
@@ -1,7 +1,78 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/assets/css/backend.css b/src/assets/css/backend.css
index d1a45a5d..aa1c5779 100644
--- a/src/assets/css/backend.css
+++ b/src/assets/css/backend.css
@@ -160,7 +160,7 @@ body .modal-header h3 {
}
#calendar .fc-header-title h2 {
- font-size: 22px;
+ font-size: 20px;
margin: 0px;
line-height: 32px;
}
diff --git a/src/assets/js/backend.js b/src/assets/js/backend.js
index 99b32ed7..561b26ab 100644
--- a/src/assets/js/backend.js
+++ b/src/assets/js/backend.js
@@ -25,10 +25,6 @@ var Backend = {
/**
* Backend Constants
*/
- EXCEPTIONS_TITLE: 'Unexpected Issues',
- EXCEPTIONS_MESSAGE: 'The operation could not complete due to unexpected issues. ',
- WARNINGS_TITLE: 'Unexpected Warnings',
- WARNINGS_MESSAGE: 'The operation completed but some warnings appeared. ',
DB_SLUG_ADMIN: 'admin',
DB_SLUG_PROVIDER: 'provider',
DB_SLUG_SECRETARY: 'secretary',
@@ -91,31 +87,5 @@ var Backend = {
$('#notification').html(notificationHtml);
$('#notification').show('blind');
- },
-
- /**
- * All backend js code has the same way of dislaying exceptions that are raised on the
- * server during an ajax call.
- *
- * @param {object} response Contains the server response. If exceptions or warnings are
- * found, user friendly messages are going to be displayed to the user.
- * @returns {bool} Returns whether the the ajax callback should continue the execution or
- * stop, due to critical server exceptions.
- */
- handleAjaxExceptions: function(response) {
- if (response.exceptions) {
- response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
- GeneralFunctions.displayMessageBox(Backend.EXCEPTIONS_TITLE, Backend.EXCEPTIONS_MESSAGE);
- $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
- return false;
- }
-
- if (response.warnings) {
- response.warnings = GeneralFunctions.parseExceptions(response.warnings);
- GeneralFunctions.displayMessageBox(Backend.WARNINGS_TITLE, Backend.WARNINGS_MESSAGE);
- $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings));
- }
-
- return true;
}
};
\ No newline at end of file
diff --git a/src/assets/js/backend_services.js b/src/assets/js/backend_services.js
index c7d52627..1c940324 100644
--- a/src/assets/js/backend_services.js
+++ b/src/assets/js/backend_services.js
@@ -300,7 +300,7 @@ var BackendServices = {
console.log('Update Available Categories Response:', response);
///////////////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
GlobalVariables.categories = response;
var $select = $('#service-category');
@@ -334,7 +334,7 @@ ServicesHelper.prototype.save = function(service) {
$.post(postUrl, postData, function(response) {
console.log('Save Service Response:', response);
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Service saved successfully!');
BackendServices.helper.resetForm();
@@ -356,7 +356,7 @@ ServicesHelper.prototype.delete = function(id) {
console.log('Delete service response:', response);
////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Service deleted successfully!');
@@ -439,7 +439,7 @@ ServicesHelper.prototype.filter = function(key) {
console.log('Filter services response:', response);
/////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendServices.helper.filterResults = response;
$('#services .filter-results').html('');
@@ -492,7 +492,7 @@ CategoriesHelper.prototype.filter = function(key) {
console.log('Filter Categories Response:', response);
///////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendServices.helper.filterResults = response;
$('#categories .filter-results').html('');
@@ -518,7 +518,7 @@ CategoriesHelper.prototype.save = function(category) {
console.log('Save Service Category Response:', response);
///////////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Service saved successfully!');
BackendServices.helper.resetForm();
@@ -541,7 +541,7 @@ CategoriesHelper.prototype.delete = function(id) {
console.log('Delete category response:', response);
////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Category deleted successfully!');
diff --git a/src/assets/js/backend_settings.js b/src/assets/js/backend_settings.js
index 130721f1..da0a670c 100644
--- a/src/assets/js/backend_settings.js
+++ b/src/assets/js/backend_settings.js
@@ -394,7 +394,7 @@ SystemSettings.prototype.save = function(settings) {
console.log('Save General Settings Response:', response);
///////////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Settings saved successfully!');
}, 'json');
@@ -520,7 +520,6 @@ UserSettings.prototype.get = function() {
'notes': $('#notes').val(),
'settings': {
'username': $('#username').val(),
- 'password': $('#password').val(),
'notifications': $('#user-notifications').hasClass('active')
}
};
@@ -555,7 +554,7 @@ UserSettings.prototype.save = function(settings) {
console.log('Save User Settings Response: ', response);
//////////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Settings saved successfully!');
}, 'json');
diff --git a/src/assets/js/backend_users.js b/src/assets/js/backend_users.js
index c29040aa..5d7782ad 100644
--- a/src/assets/js/backend_users.js
+++ b/src/assets/js/backend_users.js
@@ -2,9 +2,12 @@
* This namespace handles the js functionality of the users backend page. It uses three other
* classes (defined below) in order to handle the admin, provider and secretary record types.
*
- * @namespace BackendUsers.
+ * @namespace BackendUsers
*/
var BackendUsers = {
+ MIN_PASSWORD_LENGTH: 7,
+
+
/**
* Contains the current tab record methods for the page.
*
@@ -76,7 +79,7 @@ var BackendUsers = {
console.log('Get all db providers response:', response);
//////////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
GlobalVariables.providers = response;
@@ -95,6 +98,26 @@ var BackendUsers = {
$('.filter-key').val('');
});
+ $('#admin-username').focusout(function() {
+ // Validate username.
+ var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_validate_username';
+ var postData = {
+ 'username': $('#admin-username').val(),
+ 'record_exists': ($('#admin-id').val() != '') ? true : false
+ };
+ $.post(postUrl, postData, function(response) {
+ ///////////////////////////////////////////////////////
+ console.log('Validate Username Response:', response);
+ ///////////////////////////////////////////////////////
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
+ if (!response) {
+ $('#admin-username').css('border', '2px solid red');
+ $('#admins .form-message').text('Username already exists.');
+ $('#admins .form-message').show();
+ }
+ }, 'json');
+ });
+
/**
* Event: Filter Admins Button "Click"
*
@@ -113,8 +136,8 @@ var BackendUsers = {
* Display the selected admin data to the user.
*/
$(document).on('click', '.admin-row', function() {
- if ($('#admin .filter-admins').prop('disabled')) {
- $('#admin .filter-results').css('color', '#AAA');
+ if ($('#admins .filter-admins').prop('disabled')) {
+ $('#admins .filter-results').css('color', '#AAA');
return; // exit because we are currently on edit mode
}
@@ -243,8 +266,8 @@ var BackendUsers = {
* Display the selected provider data to the user.
*/
$(document).on('click', '.provider-row', function() {
- if ($('#provider .filter-providers').prop('disabled')) {
- $('#provider .filter-results').css('color', '#AAA');
+ if ($('#providers .filter-providers').prop('disabled')) {
+ $('#providers .filter-results').css('color', '#AAA');
return; // exit because we are currently on edit mode
}
@@ -383,8 +406,8 @@ var BackendUsers = {
* Display the selected secretary data to the user.
*/
$(document).on('click', '.secretary-row', function() {
- if ($('#secretary .filter-secretaries').prop('disabled')) {
- $('#secretary .filter-results').css('color', '#AAA');
+ if ($('#secretaries .filter-secretaries').prop('disabled')) {
+ $('#secretaries .filter-results').css('color', '#AAA');
return; // exit because we are currently on edit mode
}
@@ -522,9 +545,9 @@ var AdminsHelper = function() {
* then the update operation is going to be executed.
*/
AdminsHelper.prototype.save = function(admin) {
- //////////////////////////////////////////
+ ////////////////////////////////////////////
console.log('Admin data to save:', admin);
- //////////////////////////////////////////
+ ////////////////////////////////////////////
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_admin';
var postData = { 'admin': JSON.stringify(admin) };
@@ -533,7 +556,7 @@ AdminsHelper.prototype.save = function(admin) {
////////////////////////////////////////////////
console.log('Save Admin Response:', response);
////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Admin saved successfully!');
BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#admins .filter-key').val());
@@ -550,10 +573,10 @@ AdminsHelper.prototype.delete = function(id) {
var postData = { 'admin_id': id };
$.post(postUrl, postData, function(response) {
- ////////////////////////////////////////////////////
+ //////////////////////////////////////////////////
console.log('Delete admin response:', response);
- ////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ //////////////////////////////////////////////////
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Admin deleted successfully!');
BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#admins .filter-key').val());
@@ -589,6 +612,12 @@ AdminsHelper.prototype.validate = function(admin) {
throw 'Passwords mismatch!';
}
+ if ($('#admin-password').val().length < BackendUsers.MIN_PASSWORD_LENGTH) {
+ $('#admin-password, #admin-password-confirm').css('border', '2px solid red');
+ throw 'Password must be at least ' + BackendUsers.MIN_PASSWORD_LENGTH
+ + ' characters long.';
+ }
+
// Validate user email.
if (!GeneralFunctions.validateEmail($('#admin-email').val())) {
$('#admin-email').css('border', '2px solid red');
@@ -657,11 +686,11 @@ AdminsHelper.prototype.filter = function(key) {
var postData = { 'key': key };
$.post(postUrl, postData, function(response) {
- /////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////
console.log('Filter admins response:', response);
- /////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendUsers.helper.filterResults = response;
@@ -705,18 +734,18 @@ var ProvidersHelper = function() {
* then the update operation is going to be executed.
*/
ProvidersHelper.prototype.save = function(provider) {
- //////////////////////////////////////////
+ //////////////////////////////////////////////////
console.log('Provider data to save:', provider);
- //////////////////////////////////////////
+ //////////////////////////////////////////////////
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_provider';
var postData = { 'provider': JSON.stringify(provider) };
$.post(postUrl, postData, function(response) {
- ////////////////////////////////////////////////
+ ///////////////////////////////////////////////////
console.log('Save Provider Response:', response);
- ////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ ///////////////////////////////////////////////////
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Provider saved successfully!');
BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#providers .filter-key').val());
@@ -733,10 +762,10 @@ ProvidersHelper.prototype.delete = function(id) {
var postData = { 'provider_id': id };
$.post(postUrl, postData, function(response) {
- ////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////
console.log('Delete provider response:', response);
- ////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ /////////////////////////////////////////////////////
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Provider deleted successfully!');
BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#providers .filter-key').val());
@@ -772,12 +801,34 @@ ProvidersHelper.prototype.validate = function(provider) {
throw 'Passwords mismatch!';
}
+ if ($('#provider-password').val().length < BackendUsers.MIN_PASSWORD_LENGTH) {
+ $('#provider-password, #provider-password-confirm').css('border', '2px solid red');
+ throw 'Password must be at least ' + BackendUsers.MIN_PASSWORD_LENGTH
+ + ' characters long.';
+ }
+
// Validate user email.
if (!GeneralFunctions.validateEmail($('#provider-email').val())) {
$('#provider-email').css('border', '2px solid red');
throw 'Invalid email address!';
}
+ // Validate username.
+ var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_validate_username';
+ var postData = {
+ 'username': $('#provider-username').val(),
+ 'record_exists': ($('#provider-id').val() != '') ? true : false
+ };
+ $.post(postUrl, postData, function(response) {
+ ///////////////////////////////////////////////////////
+ console.log('Validate Username Response:', response);
+ ///////////////////////////////////////////////////////
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
+ if (!response) {
+ throw('Username already exists, please enter another one and try again.');
+ }
+ });
+
return true;
} catch(exc) {
$('#providers .form-message').text(exc);
@@ -851,11 +902,11 @@ ProvidersHelper.prototype.filter = function(key) {
var postData = { 'key': key };
$.post(postUrl, postData, function(response) {
- /////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////
console.log('Filter providers response:', response);
- /////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendUsers.helper.filterResults = response;
@@ -899,18 +950,18 @@ var SecretariesHelper = function() {
* then the update operation is going to be executed.
*/
SecretariesHelper.prototype.save = function(secretary) {
- //////////////////////////////////////////
+ ////////////////////////////////////////////////////
console.log('Secretary data to save:', secretary);
- //////////////////////////////////////////
+ ////////////////////////////////////////////////////
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_secretary';
var postData = { 'secretary': JSON.stringify(secretary) };
$.post(postUrl, postData, function(response) {
- ////////////////////////////////////////////////
+ ////////////////////////////////////////////////////
console.log('Save Secretary Response:', response);
- ////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ ////////////////////////////////////////////////////
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Secretary saved successfully!');
BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#secretaries .filter-key').val());
@@ -927,10 +978,10 @@ SecretariesHelper.prototype.delete = function(id) {
var postData = { 'secretary_id': id };
$.post(postUrl, postData, function(response) {
- ////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////
console.log('Delete secretary response:', response);
- ////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ //////////////////////////////////////////////////////
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Secretary deleted successfully!');
BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#secretaries .filter-key').val());
@@ -966,12 +1017,34 @@ SecretariesHelper.prototype.validate = function(secretary) {
throw 'Passwords mismatch!';
}
+ if ($('#secretary-password').val().length < BackendUsers.MIN_PASSWORD_LENGTH) {
+ $('#secretary-password, #secretary-password-confirm').css('border', '2px solid red');
+ throw 'Password must be at least ' + BackendUsers.MIN_PASSWORD_LENGTH
+ + ' characters long.';
+ }
+
// Validate user email.
if (!GeneralFunctions.validateEmail($('#secretary-email').val())) {
$('#secretary-email').css('border', '2px solid red');
throw 'Invalid email address!';
}
+ // Validate username.
+ var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_validate_username';
+ var postData = {
+ 'username': $('#secretary-username').val(),
+ 'record_exists': ($('#secretary-id').val() != '') ? true : false
+ };
+ $.post(postUrl, postData, function(response) {
+ ///////////////////////////////////////////////////////
+ console.log('Validate Username Response:', response);
+ ///////////////////////////////////////////////////////
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
+ if (!response) {
+ throw('Username already exists, please enter another one and try again.');
+ }
+ });
+
return true;
} catch(exc) {
$('#secretaries .form-message').text(exc);
@@ -1045,11 +1118,11 @@ SecretariesHelper.prototype.filter = function(key) {
var postData = { 'key': key };
$.post(postUrl, postData, function(response) {
- /////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////
console.log('Filter secretaries response:', response);
- /////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////
- if (!Backend.handleAjaxExceptions(response)) return;
+ if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendUsers.helper.filterResults = response;
diff --git a/src/assets/js/general_functions.js b/src/assets/js/general_functions.js
index ef5d6a41..14f91457 100644
--- a/src/assets/js/general_functions.js
+++ b/src/assets/js/general_functions.js
@@ -6,6 +6,14 @@
* @namespace GeneralFunctions
*/
var GeneralFunctions = {
+ /**
+ * General Functions Constants
+ */
+ EXCEPTIONS_TITLE: 'Unexpected Issues',
+ EXCEPTIONS_MESSAGE: 'The operation could not complete due to unexpected issues. ',
+ WARNINGS_TITLE: 'Unexpected Warnings',
+ WARNINGS_MESSAGE: 'The operation completed but some warnings appeared. ',
+
/**
* This functions displays a message box in
* the admin array. It is usefull when user
@@ -234,5 +242,31 @@ var GeneralFunctions = {
*/
ucaseFirstLetter: function(str){
return str.charAt(0).toUpperCase() + str.slice(1);
+ },
+
+ /**
+ * All backend js code has the same way of dislaying exceptions that are raised on the
+ * server during an ajax call.
+ *
+ * @param {object} response Contains the server response. If exceptions or warnings are
+ * found, user friendly messages are going to be displayed to the user.
+ * @returns {bool} Returns whether the the ajax callback should continue the execution or
+ * stop, due to critical server exceptions.
+ */
+ handleAjaxExceptions: function(response) {
+ if (response.exceptions) {
+ response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
+ GeneralFunctions.displayMessageBox(GeneralFunctions.EXCEPTIONS_TITLE, GeneralFunctions.EXCEPTIONS_MESSAGE);
+ $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
+ return false;
+ }
+
+ if (response.warnings) {
+ response.warnings = GeneralFunctions.parseExceptions(response.warnings);
+ GeneralFunctions.displayMessageBox(GeneralFunctions.WARNINGS_TITLE, GeneralFunctions.WARNINGS_MESSAGE);
+ $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings));
+ }
+
+ return true;
}
};
\ No newline at end of file