* Completed login + logout operation.

* Updated the way the system stores passwords in db.
This commit is contained in:
alextselegidis@gmail.com 2013-09-23 15:42:36 +00:00
parent fcc142a11b
commit e596cb768a
20 changed files with 478 additions and 116 deletions

View file

@ -70,5 +70,7 @@ define('PAGE_SERVICES', 'services');
define('PAGE_USERS', 'users'); define('PAGE_USERS', 'users');
define('PAGE_SYSTEM_SETTINGS', 'system_settings'); define('PAGE_SYSTEM_SETTINGS', 'system_settings');
define('PAGE_USER_SETTINGS', 'user_settings'); define('PAGE_USER_SETTINGS', 'user_settings');
define('MIN_PASSWORD_LENGTH', 7);
/* End of file constants.php */ /* End of file constants.php */
/* Location: ./application/config/constants.php */ /* Location: ./application/config/constants.php */

View file

@ -144,16 +144,11 @@ class Backend extends CI_Controller {
$this->load->model('user_model'); $this->load->model('user_model');
$this->load->library('session'); $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);
$user_id = $this->session->userdata('user_id'); $user_id = $this->session->userdata('user_id');
$view['base_url'] = $this->config->item('base_url'); $view['base_url'] = $this->config->item('base_url');
$view['company_name'] = $this->settings_model->get_setting('company_name'); $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['system_settings'] = $this->settings_model->get_settings();
$view['user_settings'] = $this->user_model->get_settings($user_id); $view['user_settings'] = $this->user_model->get_settings($user_id);

View file

@ -703,6 +703,13 @@ class Backend_api extends CI_Controller {
try { try {
$this->load->model('providers_model'); $this->load->model('providers_model');
$provider = json_decode($_POST['provider'], true); $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); $this->providers_model->add($provider);
echo json_encode(AJAX_SUCCESS); echo json_encode(AJAX_SUCCESS);
} catch(Exception $exc) { } 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 */ /* End of file backend_api.php */

View file

@ -13,11 +13,24 @@ class User extends CI_Controller {
public function login() { public function login() {
$view['base_url'] = $this->config->item('base_url'); $view['base_url'] = $this->config->item('base_url');
$view['dest_url'] = $this->session->userdata('dest_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); $this->load->view('user/login', $view);
} }
public function logout() { 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() { public function forgot_password() {
@ -37,17 +50,14 @@ class User extends CI_Controller {
throw new Exception('Invalid credentials given!'); throw new Exception('Invalid credentials given!');
} }
$this->load->helper('general');
$this->load->model('user_model'); $this->load->model('user_model');
$user_data = $this->user_model->check_login($_POST['username'], $_POST['password']);
$hash_password = $this->hash_password($_POST['password']);
$user_data = $this->user_model->check_login($_POST['username'], $hash_password);
if ($user_data) { if ($user_data) {
$this->session->set_userdata($user_data); // Save data on user's session. $this->session->set_userdata($user_data); // Save data on user's session.
echo json_encode(AJAX_SUCCESS); echo json_encode(AJAX_SUCCESS);
} else { } else {
echo json_encode(AJAX_SUCCESS); echo json_encode(AJAX_FAILURE);
} }
} catch(Exception $exc) { } catch(Exception $exc) {

View file

@ -29,13 +29,38 @@ function date3339($timestamp=0) {
* Generate a hash of password string. * Generate a hash of password string.
* *
* For user security, all system passwords are stored in hash string into the database. Use * 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. * @param string $password Given string password.
* @return string Returns the hash string of the given password. * @return string Returns the hash string of the given password.
*/ */
function hash_password($password) { function hash_password($salt, $password) {
return md5($password); // @task include salt and hash more times. $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 */ /* End of file general_helper.php */

View file

@ -85,6 +85,8 @@ class Admins_Model extends CI_Model {
* @throws Exception When the insert operation fails. * @throws Exception When the insert operation fails.
*/ */
public function insert($admin) { public function insert($admin) {
$this->load->helper('general');
$admin['id_roles'] = $this->get_admin_role_id(); $admin['id_roles'] = $this->get_admin_role_id();
$settings = $admin['settings']; $settings = $admin['settings'];
unset($admin['settings']); unset($admin['settings']);
@ -97,6 +99,8 @@ class Admins_Model extends CI_Model {
$admin['id'] = intval($this->db->insert_id()); $admin['id'] = intval($this->db->insert_id());
$settings['id_users'] = $admin['id']; $settings['id_users'] = $admin['id'];
$settings['salt'] = generate_salt();
$settings['password'] = hash_password($settings['salt'], $settings['password']);
// Insert admin settings. // Insert admin settings.
if (!$this->db->insert('ea_user_settings', $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. * @throws Exception When the update operation fails.
*/ */
public function update($admin) { public function update($admin) {
$this->load->helper('general');
$settings = $admin['settings']; $settings = $admin['settings'];
unset($admin['settings']); unset($admin['settings']);
$settings['id_users'] = $admin['id']; $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']); $this->db->where('id', $admin['id']);
if (!$this->db->update('ea_users', $admin)) { if (!$this->db->update('ea_users', $admin)) {
throw new Exception('Could not update admin record.'); 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']); 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; return TRUE;
} catch (Exception $exc) { } catch (Exception $exc) {
return FALSE; return FALSE;
@ -328,6 +357,22 @@ class Admins_Model extends CI_Model {
public function get_admin_role_id() { public function get_admin_role_id() {
return intval($this->db->get_where('ea_roles', array('slug' => DB_SLUG_ADMIN))->row()->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 */ /* End of file admins_model.php */

View file

@ -98,6 +98,8 @@ class Providers_Model extends CI_Model {
* @throws Exception When the insert operation fails. * @throws Exception When the insert operation fails.
*/ */
public function insert($provider) { public function insert($provider) {
$this->load->helper('general');
// Get provider role id. // Get provider role id.
$provider['id_roles'] = $this->get_providers_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'); 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(); $provider['id'] = $this->db->insert_id();
$this->save_settings($settings, $provider['id']); $this->save_settings($settings, $provider['id']);
$this->save_services($services, $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. * @throws Exception When the update operation fails.
*/ */
public function update($provider) { public function update($provider) {
$this->load->helper('general');
// Store service and settings (must not be present on the $provider array). // Store service and settings (must not be present on the $provider array).
$services = $provider['services']; $services = $provider['services'];
unset($provider['services']); unset($provider['services']);
$settings = $provider['settings']; $settings = $provider['settings'];
unset($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. // Update provider record.
$this->db->where('id', $provider['id']); $this->db->where('id', $provider['id']);
if (!$this->db->update('ea_users', $provider)) { 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)); 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; return TRUE;
} catch (Exception $exc) { } catch (Exception $exc) {
return FALSE; return FALSE;

View file

@ -86,6 +86,8 @@ class Secretaries_Model extends CI_Model {
* @throws Exception When the insert operation fails. * @throws Exception When the insert operation fails.
*/ */
public function insert($secretary) { public function insert($secretary) {
$this->load->helper('general');
$providers = $secretary['providers']; $providers = $secretary['providers'];
unset($secretary['providers']); unset($secretary['providers']);
$settings = $secretary['settings']; $settings = $secretary['settings'];
@ -98,6 +100,8 @@ class Secretaries_Model extends CI_Model {
} }
$secretary['id'] = intval($this->db->insert_id()); $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_providers($providers, $secretary['id']);
$this->save_settings($settings, $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. * @throws Exception When the update operation fails.
*/ */
public function update($secretary) { public function update($secretary) {
$this->load->helper('general');
$providers = $secretary['providers']; $providers = $secretary['providers'];
unset($secretary['providers']); unset($secretary['providers']);
$settings = $secretary['settings']; $settings = $secretary['settings'];
unset($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']); $this->db->where('id', $secretary['id']);
if (!$this->db->update('ea_users', $secretary)){ if (!$this->db->update('ea_users', $secretary)){
throw new Exception('Could not update secretary record.'); 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']); 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; return TRUE;
} catch (Exception $exc) { } catch (Exception $exc) {
return FALSE; return FALSE;

View file

@ -35,6 +35,13 @@ class User_Model extends CI_Model {
$user_settings['id_users'] = $user['id']; $user_settings['id_users'] = $user['id'];
unset($user['settings']); 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']))) { if (!$this->db->update('ea_users', $user, array('id' => $user['id']))) {
return FALSE; return FALSE;
} }
@ -45,6 +52,43 @@ class User_Model extends CI_Model {
return TRUE; 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 */ /* End of file user_model.php */

View file

@ -149,7 +149,7 @@
'Your appointment has successfully been added to ' + 'Your appointment has successfully been added to ' +
'your Google Calendar account. <br>' + 'your Google Calendar account. <br>' +
'<a href="' + response.htmlLink + '">' + '<a href="' + response.htmlLink + '">' +
'Click here to view your appoinmtent on Google ' + 'Click here to view your appointment on Google ' +
'Calendar.' + 'Calendar.' +
'</a>' + '</a>' +
'</p>' + '</p>' +

View file

@ -103,7 +103,7 @@
<?php // LOGOUT MENU ITEM <?php // LOGOUT MENU ITEM
// ------------------------------------------------------ ?> // ------------------------------------------------------ ?>
<a href="<?php echo $base_url; ?>backend/logout" class="menu-item"> <a href="<?php echo $base_url; ?>user/logout" class="menu-item">
Logout Logout
</a> </a>

View file

@ -8,7 +8,7 @@
<script type="text/javascript"> <script type="text/javascript">
var GlobalVariables = { var GlobalVariables = {
'baseUrl': <?php echo '"' . $base_url . '"'; ?>, 'baseUrl': <?php echo '"' . $base_url . '"'; ?>,
'userSlug': <?php echo '"' . $user_slug . '"'; ?>, 'userSlug': <?php echo '"' . $role_slug . '"'; ?>,
'settings': { 'settings': {
'system': <?php echo json_encode($system_settings); ?>, 'system': <?php echo json_encode($system_settings); ?>,
'user': <?php echo json_encode($user_settings); ?> 'user': <?php echo json_encode($user_settings); ?>

View file

@ -60,11 +60,13 @@
} }
</style> </style>
<script> <script type="text/javascript">
$(document).ready(function() { $(document).ready(function() {
var GlobalVariables = { var GlobalVariables = {
'baseUrl': <?php echo '"' . $base_url . '"'; ?>, 'baseUrl': <?php echo '"' . $base_url . '"'; ?>,
'destUrl': <?php echo '"' . $dest_url . '"'; ?> 'destUrl': <?php echo '"' . $dest_url . '"'; ?>,
'AJAX_SUCCESS': 'SUCCESS',
'AJAX_FAILURE': 'FAILURE'
}; };
/** /**
@ -73,37 +75,43 @@
* Make an ajax call to the server and check whether the user's credentials are right. * Make an ajax call to the server and check whether the user's credentials are right.
* If yes then redirect him to his desired page, otherwise display a message. * If yes then redirect him to his desired page, otherwise display a message.
*/ */
$('#login').click(function() { $('#login-form').submit(function() {
var postUrl = GlobalVariables.baseUrl . 'user/ajax_check_login'; event.preventDefault();
var postUrl = GlobalVariables.baseUrl + 'user/ajax_check_login';
var postData = { var postData = {
'username': $('#username').val(), 'username': $('#username').val(),
'password': $('#password').val() 'password': $('#password').val()
}; };
$('.alert').addClass('hidden');
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
////////////////////////////////////////////////// //////////////////////////////////////////////////
console.log('Check Login Response: ', response); console.log('Check Login Response: ', response);
////////////////////////////////////////////////// //////////////////////////////////////////////////
if (response == true) { if (!GeneralFunctions.handleAjaxExceptions(response)) return;
location(GlobalVariables.destUrl);
if (response == GlobalVariables.AJAX_SUCCESS) {
window.location.href = GlobalVariables.destUrl;
} else { } else {
$('.alert').text('Login failed, please enter the correct credentials ' $('.alert').text('Login failed, please enter the correct credentials '
+ 'and try again.'); + 'and try again.');
$('.alert').removeClass('hidden'); $('.alert').removeClass('hidden');
} }
}); }, 'json');
}); });
}); });
</script> </script>
</head> </head>
<body> <body>
<div id="login-frame" class="frame-container"> <div id="login-frame" class="frame-container">
<h2>Login Required</h2> <h2>Backend Section</h2>
<p>Welcome! You will need to login in order to view this page.</p> <p>Welcome! You will need to login in order to view backend pages.</p>
<hr> <hr>
<div class="alert hidden"></div> <div class="alert hidden"></div>
<form> <form id="login-form">
<label for="username">Username</label> <label for="username">Username</label>
<input type="text" id="username" placeholder="Enter your username here ..." /> <input type="text" id="username" placeholder="Enter your username here ..." />
@ -112,7 +120,7 @@
<br><br> <br><br>
<button type="button" id="login" class="btn btn-primary btn-large">Login</button> <button type="submit" id="login" class="btn btn-primary btn-large">Login</button>
<a href="<?php echo $base_url; ?>user/forgot_password" class="forgot-password">Forgot Your Password?</a> <a href="<?php echo $base_url; ?>user/forgot_password" class="forgot-password">Forgot Your Password?</a>
</form> </form>

View file

@ -1,7 +1,78 @@
<?php <!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
/* <?php // INCLUDE JS FILES ?>
* To change this template, choose Tools | Templates <script
* and open the template in the editor. type="text/javascript"
*/ src="<?php echo $this->config->base_url(); ?>assets/js/libs/jquery/jquery.min.js"></script>
?> <script
type="text/javascript"
src="<?php echo $this->config->base_url(); ?>assets/js/libs/bootstrap/bootstrap.min.js"></script>
<?php // INCLUDE CSS FILES ?>
<link
rel="stylesheet"
type="text/css"
href="<?php echo $this->config->base_url(); ?>assets/css/libs/bootstrap/bootstrap.css">
<link
rel="stylesheet"
type="text/css"
href="<?php echo $this->config->base_url(); ?>assets/css/libs/bootstrap/bootstrap-responsive.css">
<?php // SET FAVICON FOR PAGE ?>
<link
rel="icon"
type="image/x-icon"
href="<?php echo $this->config->base_url(); ?>assets/images/favicon.ico">
<style>
body {
background-color: #CAEDF3;
}
#logout-frame {
width: 630px;
margin: 150px auto 0 auto;
background: #FFF;
border: 1px solid #DDDADA;
padding: 70px;
}
#login-icon {
float: right;
margin-top: 17px;
}
label {
font-weight: bold;
}
.btn {
margin-right: 10px;
}
</style>
</head>
<body>
<div id="logout-frame" class="frame-container">
<h3>Logout</h3>
<p>
You have been successfully logged out! Click on one of the following buttons to
navigate to a different page.
</p>
<br>
<a href="<?php echo $this->config->base_url(); ?>" class="btn btn-primary btn-large">
<i class="icon-calendar icon-white"></i>
Book Appointment
</a>
<a href="<?php echo $this->config->base_url(); ?>backend" class="btn btn-danger btn-large">
<i class="icon-wrench icon-white"></i>
Backend Section
</a>
</div>
</body>
</html>

View file

@ -160,7 +160,7 @@ body .modal-header h3 {
} }
#calendar .fc-header-title h2 { #calendar .fc-header-title h2 {
font-size: 22px; font-size: 20px;
margin: 0px; margin: 0px;
line-height: 32px; line-height: 32px;
} }

View file

@ -25,10 +25,6 @@ var Backend = {
/** /**
* Backend Constants * 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_ADMIN: 'admin',
DB_SLUG_PROVIDER: 'provider', DB_SLUG_PROVIDER: 'provider',
DB_SLUG_SECRETARY: 'secretary', DB_SLUG_SECRETARY: 'secretary',
@ -91,31 +87,5 @@ var Backend = {
$('#notification').html(notificationHtml); $('#notification').html(notificationHtml);
$('#notification').show('blind'); $('#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;
} }
}; };

View file

@ -300,7 +300,7 @@ var BackendServices = {
console.log('Update Available Categories Response:', response); console.log('Update Available Categories Response:', response);
/////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
GlobalVariables.categories = response; GlobalVariables.categories = response;
var $select = $('#service-category'); var $select = $('#service-category');
@ -334,7 +334,7 @@ ServicesHelper.prototype.save = function(service) {
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
console.log('Save Service Response:', response); console.log('Save Service Response:', response);
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Service saved successfully!'); Backend.displayNotification('Service saved successfully!');
BackendServices.helper.resetForm(); BackendServices.helper.resetForm();
@ -356,7 +356,7 @@ ServicesHelper.prototype.delete = function(id) {
console.log('Delete service response:', response); console.log('Delete service response:', response);
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Service deleted successfully!'); Backend.displayNotification('Service deleted successfully!');
@ -439,7 +439,7 @@ ServicesHelper.prototype.filter = function(key) {
console.log('Filter services response:', response); console.log('Filter services response:', response);
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendServices.helper.filterResults = response; BackendServices.helper.filterResults = response;
$('#services .filter-results').html(''); $('#services .filter-results').html('');
@ -492,7 +492,7 @@ CategoriesHelper.prototype.filter = function(key) {
console.log('Filter Categories Response:', response); console.log('Filter Categories Response:', response);
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendServices.helper.filterResults = response; BackendServices.helper.filterResults = response;
$('#categories .filter-results').html(''); $('#categories .filter-results').html('');
@ -518,7 +518,7 @@ CategoriesHelper.prototype.save = function(category) {
console.log('Save Service Category Response:', response); console.log('Save Service Category Response:', response);
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Service saved successfully!'); Backend.displayNotification('Service saved successfully!');
BackendServices.helper.resetForm(); BackendServices.helper.resetForm();
@ -541,7 +541,7 @@ CategoriesHelper.prototype.delete = function(id) {
console.log('Delete category response:', response); console.log('Delete category response:', response);
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Category deleted successfully!'); Backend.displayNotification('Category deleted successfully!');

View file

@ -394,7 +394,7 @@ SystemSettings.prototype.save = function(settings) {
console.log('Save General Settings Response:', response); console.log('Save General Settings Response:', response);
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Settings saved successfully!'); Backend.displayNotification('Settings saved successfully!');
}, 'json'); }, 'json');
@ -520,7 +520,6 @@ UserSettings.prototype.get = function() {
'notes': $('#notes').val(), 'notes': $('#notes').val(),
'settings': { 'settings': {
'username': $('#username').val(), 'username': $('#username').val(),
'password': $('#password').val(),
'notifications': $('#user-notifications').hasClass('active') 'notifications': $('#user-notifications').hasClass('active')
} }
}; };
@ -555,7 +554,7 @@ UserSettings.prototype.save = function(settings) {
console.log('Save User Settings Response: ', response); console.log('Save User Settings Response: ', response);
////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Settings saved successfully!'); Backend.displayNotification('Settings saved successfully!');
}, 'json'); }, 'json');

View file

@ -2,9 +2,12 @@
* This namespace handles the js functionality of the users backend page. It uses three other * 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. * classes (defined below) in order to handle the admin, provider and secretary record types.
* *
* @namespace BackendUsers. * @namespace BackendUsers
*/ */
var BackendUsers = { var BackendUsers = {
MIN_PASSWORD_LENGTH: 7,
/** /**
* Contains the current tab record methods for the page. * Contains the current tab record methods for the page.
* *
@ -76,7 +79,7 @@ var BackendUsers = {
console.log('Get all db providers response:', response); console.log('Get all db providers response:', response);
////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
GlobalVariables.providers = response; GlobalVariables.providers = response;
@ -95,6 +98,26 @@ var BackendUsers = {
$('.filter-key').val(''); $('.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" * Event: Filter Admins Button "Click"
* *
@ -113,8 +136,8 @@ var BackendUsers = {
* Display the selected admin data to the user. * Display the selected admin data to the user.
*/ */
$(document).on('click', '.admin-row', function() { $(document).on('click', '.admin-row', function() {
if ($('#admin .filter-admins').prop('disabled')) { if ($('#admins .filter-admins').prop('disabled')) {
$('#admin .filter-results').css('color', '#AAA'); $('#admins .filter-results').css('color', '#AAA');
return; // exit because we are currently on edit mode return; // exit because we are currently on edit mode
} }
@ -243,8 +266,8 @@ var BackendUsers = {
* Display the selected provider data to the user. * Display the selected provider data to the user.
*/ */
$(document).on('click', '.provider-row', function() { $(document).on('click', '.provider-row', function() {
if ($('#provider .filter-providers').prop('disabled')) { if ($('#providers .filter-providers').prop('disabled')) {
$('#provider .filter-results').css('color', '#AAA'); $('#providers .filter-results').css('color', '#AAA');
return; // exit because we are currently on edit mode return; // exit because we are currently on edit mode
} }
@ -383,8 +406,8 @@ var BackendUsers = {
* Display the selected secretary data to the user. * Display the selected secretary data to the user.
*/ */
$(document).on('click', '.secretary-row', function() { $(document).on('click', '.secretary-row', function() {
if ($('#secretary .filter-secretaries').prop('disabled')) { if ($('#secretaries .filter-secretaries').prop('disabled')) {
$('#secretary .filter-results').css('color', '#AAA'); $('#secretaries .filter-results').css('color', '#AAA');
return; // exit because we are currently on edit mode 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. * then the update operation is going to be executed.
*/ */
AdminsHelper.prototype.save = function(admin) { AdminsHelper.prototype.save = function(admin) {
////////////////////////////////////////// ////////////////////////////////////////////
console.log('Admin data to save:', admin); console.log('Admin data to save:', admin);
////////////////////////////////////////// ////////////////////////////////////////////
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_admin'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_admin';
var postData = { 'admin': JSON.stringify(admin) }; var postData = { 'admin': JSON.stringify(admin) };
@ -533,7 +556,7 @@ AdminsHelper.prototype.save = function(admin) {
//////////////////////////////////////////////// ////////////////////////////////////////////////
console.log('Save Admin Response:', response); console.log('Save Admin Response:', response);
//////////////////////////////////////////////// ////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Admin saved successfully!'); Backend.displayNotification('Admin saved successfully!');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#admins .filter-key').val()); BackendUsers.helper.filter($('#admins .filter-key').val());
@ -550,10 +573,10 @@ AdminsHelper.prototype.delete = function(id) {
var postData = { 'admin_id': id }; var postData = { 'admin_id': id };
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
//////////////////////////////////////////////////// //////////////////////////////////////////////////
console.log('Delete admin response:', response); console.log('Delete admin response:', response);
//////////////////////////////////////////////////// //////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Admin deleted successfully!'); Backend.displayNotification('Admin deleted successfully!');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#admins .filter-key').val()); BackendUsers.helper.filter($('#admins .filter-key').val());
@ -589,6 +612,12 @@ AdminsHelper.prototype.validate = function(admin) {
throw 'Passwords mismatch!'; 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. // Validate user email.
if (!GeneralFunctions.validateEmail($('#admin-email').val())) { if (!GeneralFunctions.validateEmail($('#admin-email').val())) {
$('#admin-email').css('border', '2px solid red'); $('#admin-email').css('border', '2px solid red');
@ -657,11 +686,11 @@ AdminsHelper.prototype.filter = function(key) {
var postData = { 'key': key }; var postData = { 'key': key };
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////// ///////////////////////////////////////////////////
console.log('Filter admins response:', response); console.log('Filter admins response:', response);
///////////////////////////////////////////////////// ///////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendUsers.helper.filterResults = response; BackendUsers.helper.filterResults = response;
@ -705,18 +734,18 @@ var ProvidersHelper = function() {
* then the update operation is going to be executed. * then the update operation is going to be executed.
*/ */
ProvidersHelper.prototype.save = function(provider) { ProvidersHelper.prototype.save = function(provider) {
////////////////////////////////////////// //////////////////////////////////////////////////
console.log('Provider data to save:', provider); console.log('Provider data to save:', provider);
////////////////////////////////////////// //////////////////////////////////////////////////
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_provider'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_provider';
var postData = { 'provider': JSON.stringify(provider) }; var postData = { 'provider': JSON.stringify(provider) };
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
//////////////////////////////////////////////// ///////////////////////////////////////////////////
console.log('Save Provider Response:', response); console.log('Save Provider Response:', response);
//////////////////////////////////////////////// ///////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Provider saved successfully!'); Backend.displayNotification('Provider saved successfully!');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#providers .filter-key').val()); BackendUsers.helper.filter($('#providers .filter-key').val());
@ -733,10 +762,10 @@ ProvidersHelper.prototype.delete = function(id) {
var postData = { 'provider_id': id }; var postData = { 'provider_id': id };
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
//////////////////////////////////////////////////// /////////////////////////////////////////////////////
console.log('Delete provider response:', response); console.log('Delete provider response:', response);
//////////////////////////////////////////////////// /////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Provider deleted successfully!'); Backend.displayNotification('Provider deleted successfully!');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#providers .filter-key').val()); BackendUsers.helper.filter($('#providers .filter-key').val());
@ -772,12 +801,34 @@ ProvidersHelper.prototype.validate = function(provider) {
throw 'Passwords mismatch!'; 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. // Validate user email.
if (!GeneralFunctions.validateEmail($('#provider-email').val())) { if (!GeneralFunctions.validateEmail($('#provider-email').val())) {
$('#provider-email').css('border', '2px solid red'); $('#provider-email').css('border', '2px solid red');
throw 'Invalid email address!'; 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; return true;
} catch(exc) { } catch(exc) {
$('#providers .form-message').text(exc); $('#providers .form-message').text(exc);
@ -851,11 +902,11 @@ ProvidersHelper.prototype.filter = function(key) {
var postData = { 'key': key }; var postData = { 'key': key };
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////// //////////////////////////////////////////////////////
console.log('Filter providers response:', response); console.log('Filter providers response:', response);
///////////////////////////////////////////////////// //////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendUsers.helper.filterResults = response; BackendUsers.helper.filterResults = response;
@ -899,18 +950,18 @@ var SecretariesHelper = function() {
* then the update operation is going to be executed. * then the update operation is going to be executed.
*/ */
SecretariesHelper.prototype.save = function(secretary) { SecretariesHelper.prototype.save = function(secretary) {
////////////////////////////////////////// ////////////////////////////////////////////////////
console.log('Secretary data to save:', secretary); console.log('Secretary data to save:', secretary);
////////////////////////////////////////// ////////////////////////////////////////////////////
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_secretary'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_secretary';
var postData = { 'secretary': JSON.stringify(secretary) }; var postData = { 'secretary': JSON.stringify(secretary) };
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
//////////////////////////////////////////////// ////////////////////////////////////////////////////
console.log('Save Secretary Response:', response); console.log('Save Secretary Response:', response);
//////////////////////////////////////////////// ////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Secretary saved successfully!'); Backend.displayNotification('Secretary saved successfully!');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#secretaries .filter-key').val()); BackendUsers.helper.filter($('#secretaries .filter-key').val());
@ -927,10 +978,10 @@ SecretariesHelper.prototype.delete = function(id) {
var postData = { 'secretary_id': id }; var postData = { 'secretary_id': id };
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
//////////////////////////////////////////////////// //////////////////////////////////////////////////////
console.log('Delete secretary response:', response); console.log('Delete secretary response:', response);
//////////////////////////////////////////////////// //////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Secretary deleted successfully!'); Backend.displayNotification('Secretary deleted successfully!');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#secretaries .filter-key').val()); BackendUsers.helper.filter($('#secretaries .filter-key').val());
@ -966,12 +1017,34 @@ SecretariesHelper.prototype.validate = function(secretary) {
throw 'Passwords mismatch!'; 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. // Validate user email.
if (!GeneralFunctions.validateEmail($('#secretary-email').val())) { if (!GeneralFunctions.validateEmail($('#secretary-email').val())) {
$('#secretary-email').css('border', '2px solid red'); $('#secretary-email').css('border', '2px solid red');
throw 'Invalid email address!'; 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; return true;
} catch(exc) { } catch(exc) {
$('#secretaries .form-message').text(exc); $('#secretaries .form-message').text(exc);
@ -1045,11 +1118,11 @@ SecretariesHelper.prototype.filter = function(key) {
var postData = { 'key': key }; var postData = { 'key': key };
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////// ////////////////////////////////////////////////////////
console.log('Filter secretaries response:', response); console.log('Filter secretaries response:', response);
///////////////////////////////////////////////////// ////////////////////////////////////////////////////////
if (!Backend.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendUsers.helper.filterResults = response; BackendUsers.helper.filterResults = response;

View file

@ -6,6 +6,14 @@
* @namespace GeneralFunctions * @namespace GeneralFunctions
*/ */
var 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 * This functions displays a message box in
* the admin array. It is usefull when user * the admin array. It is usefull when user
@ -234,5 +242,31 @@ var GeneralFunctions = {
*/ */
ucaseFirstLetter: function(str){ ucaseFirstLetter: function(str){
return str.charAt(0).toUpperCase() + str.slice(1); 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;
} }
}; };