* Added username validation (username must be unique for every record).

* Admins can manage the working plan of a single provider on the backend/users page.
* Before sending a new notification email the system checks whether the provider user has notifications enabled.
* Added salt field in the "ea_user_settings" table.
This commit is contained in:
alextselegidis@gmail.com 2013-09-24 13:09:04 +00:00
parent e596cb768a
commit 08a50c14be
11 changed files with 789 additions and 187 deletions

View file

@ -3,7 +3,7 @@
-- http://www.phpmyadmin.net
--
-- Φιλοξενητής: localhost
-- Χρόνος δημιουργίας: 13 Σεπ 2013 στις 16:10:44
-- Χρόνος δημιουργίας: 24 Σεπ 2013 στις 11:03:51
-- Έκδοση διακομιστή: 5.5.24-log
-- Έκδοση PHP: 5.4.3
@ -42,7 +42,7 @@ CREATE TABLE IF NOT EXISTS `ea_appointments` (
KEY `id_users_customer` (`id_users_customer`),
KEY `id_services` (`id_services`),
KEY `id_users_provider` (`id_users_provider`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=41 ;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=42 ;
--
-- Άδειασμα δεδομένων του πίνακα `ea_appointments`
@ -53,7 +53,8 @@ INSERT INTO `ea_appointments` (`id`, `book_datetime`, `start_datetime`, `end_dat
(37, '2013-09-13 13:47:54', '2013-09-14 11:30:00', '2013-09-14 13:30:00', 'Γυμναστήριο ', '3ace1513fdf92a4983b7ae719a8475b5', 1, 2, NULL, NULL, 'cqm0t14p50d0917ghkirtruuno'),
(38, '2013-09-13 13:47:54', '2013-09-14 15:00:00', '2013-09-14 18:00:00', 'Ε!Α ', '3ace1513fdf92a4983b7ae719a8475b5', 1, 2, NULL, NULL, 'vs0btdvi34t73rvkeubh77ln40'),
(39, '2013-09-13 15:39:44', '2013-09-13 17:00:00', '2013-09-13 17:20:00', 'This is a test appt.', '6fd60f567310511d8f2fb4ff4c787d5e', 0, 2, 22, 3, NULL),
(40, '2013-09-13 15:50:14', '2013-09-14 10:00:00', '2013-09-14 11:00:00', 'heart decease', '39b81301e5bb1a82f77bd23d07ec63ce', 0, 4, 23, 2, NULL);
(40, '2013-09-13 15:50:14', '2013-09-14 10:00:00', '2013-09-14 11:00:00', 'heart decease', '39b81301e5bb1a82f77bd23d07ec63ce', 0, 4, 23, 2, NULL),
(41, '2013-09-23 17:04:53', '2013-09-24 09:45:00', '2013-09-24 10:15:00', '', '4c782e7af14a98e03657cc64c9a4fe61', 0, 25, 26, 4, NULL);
-- --------------------------------------------------------
@ -66,11 +67,12 @@ CREATE TABLE IF NOT EXISTS `ea_roles` (
`name` varchar(256) DEFAULT NULL,
`slug` varchar(256) DEFAULT NULL,
`is_admin` tinyint(4) DEFAULT NULL COMMENT '0',
`services` int(4) DEFAULT NULL COMMENT '0',
`providers` int(4) DEFAULT NULL COMMENT '0',
`customers` int(4) DEFAULT NULL COMMENT '0',
`notifications` int(4) DEFAULT NULL COMMENT '0',
`appointments` int(4) DEFAULT NULL COMMENT '0',
`customers` int(4) DEFAULT NULL COMMENT '0',
`services` int(4) DEFAULT NULL COMMENT '0',
`users` int(4) DEFAULT NULL COMMENT '0',
`system_settings` int(4) DEFAULT NULL COMMENT '0',
`user_settings` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
@ -78,11 +80,11 @@ CREATE TABLE IF NOT EXISTS `ea_roles` (
-- Άδειασμα δεδομένων του πίνακα `ea_roles`
--
INSERT INTO `ea_roles` (`id`, `name`, `slug`, `is_admin`, `services`, `providers`, `customers`, `notifications`, `appointments`) VALUES
(1, 'Administrator', 'admin', 1, 15, 15, 15, 15, 15),
(2, 'Provider', 'provider', 0, 0, 0, 15, 0, 15),
(3, 'Customer', 'customer', 0, 0, 0, 0, 0, 0),
(4, 'Secretary', 'secretary', 0, 0, 0, 15, 15, 15);
INSERT INTO `ea_roles` (`id`, `name`, `slug`, `is_admin`, `appointments`, `customers`, `services`, `users`, `system_settings`, `user_settings`) VALUES
(1, 'Administrator', 'admin', 1, 15, 15, 15, 15, 15, NULL),
(2, 'Provider', 'provider', 0, 15, 15, 0, 0, 0, NULL),
(3, 'Customer', 'customer', 0, 0, 0, 0, 0, 0, NULL),
(4, 'Secretary', 'secretary', 0, 15, 15, 0, 0, 15, NULL);
-- --------------------------------------------------------
@ -155,7 +157,8 @@ INSERT INTO `ea_services_providers` (`id_users`, `id_services`) VALUES
(4, 2),
(2, 3),
(3, 3),
(2, 4);
(2, 4),
(25, 4);
-- --------------------------------------------------------
@ -190,18 +193,19 @@ CREATE TABLE IF NOT EXISTS `ea_settings` (
`name` varchar(512) DEFAULT NULL,
`value` longtext,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=16 ;
--
-- Άδειασμα δεδομένων του πίνακα `ea_settings`
--
INSERT INTO `ea_settings` (`id`, `name`, `value`) VALUES
(1, 'company_name', 'Easy!Appointments & Co'),
(1, 'company_name', 'Easy!Appointmnets & Co'),
(2, 'company_working_plan', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}'),
(3, 'company_email', 'info@alextselegidis.com'),
(8, 'company_link', 'http://easyappointments.org'),
(9, 'book_advance_timeout', '30');
(9, 'book_advance_timeout', '30'),
(15, NULL, NULL);
-- --------------------------------------------------------
@ -224,7 +228,7 @@ CREATE TABLE IF NOT EXISTS `ea_users` (
`id_roles` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `id_roles` (`id_roles`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=24 ;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=27 ;
--
-- Άδειασμα δεδομένων του πίνακα `ea_users`
@ -234,11 +238,14 @@ INSERT INTO `ea_users` (`id`, `first_name`, `last_name`, `email`, `mobile_number
(2, 'Ned', 'Janger', 'alextselegidis@gmail.com', '659875666', '785448465', 'Kloesel', 'Berlin', '', '23980', '', 2),
(3, 'Urlich', 'Setzel', 'u.setzel@piorin.com', '23908252398', '20923798723', 'Groundliche Str. 23', 'Munich', 'Bayern', '86895', '', 2),
(4, 'Brandon', 'Clod', 'b.clod@besters.org', '239072439', '858754487', 'Wellin Str 8', 'Plymouth', '', '20940', '', 2),
(18, 'Tod', 'Cliffer', 'info@alextselegidis.com', '987568857', '875986878', 'Yourd Str 98', 'Blackpool', '', '09234', '', 1),
(18, 'Tod', 'Cliffer', 'info@alextselegidis.com', '987568857', '875986878', 'Yourd Str 98', 'Blackpool', 'MyState', '85874', 'This is a test admin record used for testing the project. All the data are not real.', 1),
(20, 'Sonia', 'Sterling', 's.sterling@reo.com', '584256658', '4265462587', '', '', '', '', '', 4),
(21, 'Alex', 'Tselegidis', 'info@alextselegidis.com', NULL, '98765465712', '', '', NULL, '', '', 3),
(22, 'John', 'Doe', 'john.doe@oizent.com', NULL, '8757595445', 'Orizend 51', 'London', NULL, '56648', 'Test customer record.', 3),
(23, 'James', 'Goern', 'james.goern@softiner.com', NULL, '98654869544', 'Ureklin 09', 'New York', NULL, '56987', NULL, 3);
(23, 'James', 'Goern', 'james.goern@softiner.com', NULL, '98654869544', 'Ureklin 09', 'New York', NULL, '56987', NULL, 3),
(24, 'test', 'test', 'test@test.com', '233252325', '234523342', 'test', 'test', '', '', '', 1),
(25, 'Jason', 'Brandon', 'j.brandon@solyell.uk', '7899875789', '7854789897', 'Hilton Str. 52', 'Michigan', '', '87786', 'This is a test provider. All data are fictional.', 2),
(26, 'John', 'Doe', 'j.doe@doens.com', NULL, '897987657', '', '', NULL, '', NULL, 3);
-- --------------------------------------------------------
@ -250,8 +257,9 @@ CREATE TABLE IF NOT EXISTS `ea_user_settings` (
`id_users` bigint(20) unsigned NOT NULL,
`username` varchar(256) DEFAULT NULL,
`password` varchar(512) DEFAULT NULL,
`salt` varchar(512) DEFAULT NULL,
`working_plan` text,
`notifications` text,
`notifications` tinyint(4) DEFAULT '0',
`google_sync` tinyint(4) DEFAULT '0',
`google_token` text,
`sync_past_days` int(11) DEFAULT '5',
@ -263,12 +271,14 @@ CREATE TABLE IF NOT EXISTS `ea_user_settings` (
-- Άδειασμα δεδομένων του πίνακα `ea_user_settings`
--
INSERT INTO `ea_user_settings` (`id_users`, `username`, `password`, `working_plan`, `notifications`, `google_sync`, `google_token`, `sync_past_days`, `sync_future_days`) VALUES
(2, 'ned.janger', 'test', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', '1', 0, NULL, 5, 5),
(3, 'u.setzel', 'test', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', '1', 0, NULL, 5, 5),
(4, 'b.clod', 'test', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', '0', 0, NULL, 5, 5),
(18, 't.cliffer', 'test', NULL, '0', 0, NULL, 5, 5),
(20, 's.sterling', 'test', NULL, '0', 0, NULL, 5, 5);
INSERT INTO `ea_user_settings` (`id_users`, `username`, `password`, `salt`, `working_plan`, `notifications`, `google_sync`, `google_token`, `sync_past_days`, `sync_future_days`) VALUES
(2, 'ned.janger', '6ad76c5daab92f2aaf9f9d725cb72bc2774fdb4ac2172828a8f1c6aa69e9b0d1', 'edd27f8204a0cc47c60a3cd031fe03211be2561c76b334678e0f982ef582bf6e', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', 1, 0, NULL, 5, 5),
(3, 'u.setzel', 'f00e1e6f3780859b40645be7ff8e91878ea2679eb62fbc45a8bff1243338b741', '7f8231dd21df341c651522e4091637e6a93d160decb6a7a99bd08a5dc5d947c8', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', 1, 0, NULL, 5, 5),
(4, 'b.clod', '811acf5c450e0eb2866a17cdc3701a0b1fddb98ea2065e91259e8e6ce9b678b6', 'edd27f8204a0cc47c60a3cd031fe03211be2561c76b334678e0f982ef582bf6e', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', 0, 0, NULL, 5, 5),
(18, 'admin', '9e81360f0a631fe7e49e9d051b05c581a0f17575ca043a340be4441e166de821', 'd6ac3bfb4e6d9f82ec54e606852a9afbe8697696cddd28f30423eddf98762f41', NULL, 0, 0, NULL, 5, 5),
(20, 's.sterling', '8746aff0a416b63e71046d6a6adc6e2fd9de4a1cf4de0281e5b5f60ba8ae4451', 'edd27f8204a0cc47c60a3cd031fe03211be2561c76b334678e0f982ef582bf6e', NULL, 0, 0, NULL, 5, 5),
(24, 'test', 'd1dce587f7eefdb93adceb4e8903d72036bf97d37482b9c7b1d5f08353d061f3', 'd6ac3bfb4e6d9f82ec54e606852a9afbe8697696cddd28f30423eddf98762f41', NULL, 0, 0, NULL, 5, 5),
(25, 'j.brandon', 'dc93d098ccbcaa871e4adcc2dd770d71f6fca7a24dbd635e00006b5075dc2db1', '7f8231dd21df341c651522e4091637e6a93d160decb6a7a99bd08a5dc5d947c8', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', 1, 0, NULL, 5, 5);
--
-- Περιορισμοί για άχρηστους πίνακες

View file

@ -138,6 +138,9 @@ class Appointments extends CI_Controller {
try {
$this->load->library('Notifications');
$send_provider = $this->providers_model
->get_setting('notifications', $provider['id']);
if (!$post_data['manage_mode']) {
$customer_title = 'Your appointment has been successfully booked!';
$customer_message = 'Thank you for arranging an appointment with us. '
@ -167,9 +170,11 @@ class Appointments extends CI_Controller {
$service, $customer,$company_settings, $customer_title,
$customer_message, $customer_link, $customer['email']);
if ($send_provider == TRUE) {
$this->notifications->send_appointment_details($appointment, $provider,
$service, $customer, $company_settings, $provider_title,
$provider_message, $provider_link, $provider['email']);
}
} catch(Exception $exc) {
$view['exceptions'][] = $exc;
}
@ -254,9 +259,16 @@ class Appointments extends CI_Controller {
// :: SEND NOTIFICATION EMAILS TO CUSTOMER AND PROVIDER
try {
$this->load->library('Notifications');
$send_provider = $this->providers_model
->get_setting('notifications', $provider['id']);
if ($send_provider == TRUE) {
$this->notifications->send_delete_appointment($appointment, $provider,
$service, $customer, $company_settings, $provider['email'],
$_POST['cancel_reason']);
}
$this->notifications->send_delete_appointment($appointment, $provider,
$service, $customer, $company_settings, $customer['email'],
$_POST['cancel_reason']);
@ -268,6 +280,8 @@ class Appointments extends CI_Controller {
$exceptions[] = $exc;
}
$view = array();
if (isset($exceptions)) {
$view['exceptions'] = $exceptions;
}

View file

@ -122,6 +122,7 @@ class Backend extends CI_Controller {
$view['providers'] = $this->providers_model->get_batch();
$view['secretaries'] = $this->secretaries_model->get_batch();
$view['services'] = $this->services_model->get_batch();
$view['working_plan'] = $this->settings_model->get_setting('company_working_plan');
$this->load->view('backend/header', $view);
$this->load->view('backend/users', $view);

View file

@ -142,6 +142,9 @@ class Backend_api extends CI_Controller {
try {
$this->load->library('Notifications');
$send_provider = $this->providers_model
->get_setting('notifications', $provider['id']);
if (!$manage_mode) {
$customer_title = 'Your appointment has been successfully booked!';
$customer_message = 'Thank you for arranging an appointment with us. '
@ -171,9 +174,11 @@ class Backend_api extends CI_Controller {
$service, $customer, $company_settings, $customer_title,
$customer_message, $customer_link, $customer['email']);
if ($send_provider == TRUE) {
$this->notifications->send_appointment_details($appointment, $provider,
$service, $customer, $company_settings, $provider_title,
$provider_message, $provider_link, $provider['email']);
}
} catch(Exception $exc) {
$warnings[] = exceptionToJavaScript($exc);
@ -250,9 +255,16 @@ class Backend_api extends CI_Controller {
// :: SEND NOTIFICATION EMAILS TO PROVIDER AND CUSTOMER
try {
$this->load->library('Notifications');
$send_provider = $this->providers_model
->get_setting('notifications', $provider['id']);
if ($send_provider == TRUE) {
$this->notifications->send_delete_appointment($appointment, $provider,
$service, $customer, $company_settings, $provider['email'],
$_POST['delete_reason']);
}
$this->notifications->send_delete_appointment($appointment, $provider,
$service, $customer, $company_settings, $customer['email'],
$_POST['delete_reason']);
@ -704,7 +716,7 @@ class Backend_api extends CI_Controller {
$this->load->model('providers_model');
$provider = json_decode($_POST['provider'], true);
if (!isset($provider['working_plan'])) {
if (!isset($provider['settings']['working_plan'])) {
$this->load->model('settings_model');
$provider['settings']['working_plan'] = $this->settings_model
->get_setting('company_working_plan');

View file

@ -37,8 +37,6 @@ function date3339($timestamp=0) {
* @return string Returns the hash string of the given password.
*/
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));

View file

@ -204,16 +204,6 @@ 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) {
@ -367,10 +357,10 @@ class Admins_Model extends CI_Model {
*/
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;
if (($num_rows == 0 && $record_exists == FALSE) || ($num_rows == 1 && $record_exists == TRUE)) {
return TRUE;
} else {
return false;
return FALSE;
}
}
}

View file

@ -236,16 +236,6 @@ 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) {

View file

@ -60,6 +60,13 @@
<input type="text" id="company-link" data-field="company_link">
<span class="help-block">Company link should point to the official website of
the company (optional).</span>
<br><br>
<a href="<?php echo $this->config->base_url(); ?>" class="btn btn-primary btn-large">
<i class="icon-calendar icon-white"></i>
Visit Book Appointment Page
</a>
</fieldset>
</form>
</div>
@ -230,7 +237,7 @@
<input type="text" id="zip-code" class="span9" />
<label for="notes">Notes</label>
<textarea id="notes" class="span9"></textarea>
<textarea id="notes" class="span9" rows="3"></textarea>
</fieldset>
<fieldset class="span5">

View file

@ -1,5 +1,9 @@
<script type="text/javascript"
src="<?php echo $base_url; ?>assets/js/backend_users.js"></script>
<script type="text/javascript"
src="<?php echo $base_url; ?>assets/js/libs/jquery/jquery-ui-timepicker-addon.js"></script>
<script type="text/javascript"
src="<?php echo $base_url; ?>assets/js/libs/jquery/jquery.jeditable.min.js"></script>
<script type="text/javascript">
var GlobalVariables = {
@ -7,7 +11,8 @@
'admins': <?php echo json_encode($admins); ?>,
'providers': <?php echo json_encode($providers); ?>,
'secretaries': <?php echo json_encode($secretaries); ?>,
'services': <?php echo json_encode($services); ?>
'services': <?php echo json_encode($services); ?>,
'workingPlan': $.parseJSON(<?php echo json_encode($working_plan); ?>)
};
$(document).ready(function() {
@ -63,7 +68,7 @@
<div class="form-message alert" style="display:none;"></div>
<input type="hidden" id="admin-id" />
<input type="hidden" id="admin-id" class="record-id" />
<div class="row-fluid">
<div class="admin-details span6">
@ -95,17 +100,17 @@
<input type="text" id="admin-zip-code" class="span11" />
<label for="admin-notes">Notes</label>
<textarea id="admin-notes" class="span11"></textarea>
<textarea id="admin-notes" class="span11" rows="3"></textarea>
</div>
<div class="admin-settings span6">
<label for="admin-username">Username *</label>
<input type="text" id="admin-username" class="span7 required" />
<input type="text" id="admin-username" class="span9 required" />
<label for="admin-password">Password *</label>
<input type="password" id="admin-password" class="span7 required"/>
<input type="password" id="admin-password" class="span9 required"/>
<label for="admin-password-confirm">Retype Password *</label>
<input type="password" id="admin-password-confirm" class="span7 required" />
<input type="password" id="admin-password-confirm" class="span9 required" />
<br>
@ -130,7 +135,7 @@
</div>
<div class="details span7">
<div class="btn-toolbar">
<div class="btn-toolbar span5">
<div class="add-edit-delete-group btn-group">
<button id="add-provider" class="btn">
<i class="icon-plus"></i>
@ -153,11 +158,17 @@
</div>
</div>
<h2>Details</h2>
<div class="switch-view pull-right">
<div class="display-details current">Details</div>
<div class="display-working-plan">Working Plan</div>
</div>
<div class="form-message alert" style="display:none;"></div>
<input type="hidden" id="provider-id" />
<div class="details-view">
<h2>Details</h2>
<input type="hidden" id="provider-id" class="record-id" />
<div class="row-fluid">
<div class="provider-details span6">
@ -189,17 +200,17 @@
<input type="text" id="provider-zip-code" class="span11" />
<label for="provider-notes">Notes</label>
<textarea id="provider-notes" class="span11"></textarea>
<textarea id="provider-notes" class="span11" rows="3"></textarea>
</div>
<div class="provider-settings span6">
<label for="provider-username">Username *</label>
<input type="text" id="provider-username" class="span7 required" />
<input type="text" id="provider-username" class="span9 required" />
<label for="provider-password">Password *</label>
<input type="password" id="provider-password" class="span7 required"/>
<input type="password" id="provider-password" class="span9 required"/>
<label for="provider-password-confirm">Retype Password *</label>
<input type="password" id="provider-password-confirm" class="span7 required" />
<input type="password" id="provider-password-confirm" class="span9 required" />
<br>
@ -215,6 +226,88 @@
</div>
</div>
</div>
<div class="working-plan-view" style="display: none;">
<h2>Working Plan</h2>
<table class="working-plan table table-striped">
<thead>
<tr>
<th>Day</th>
<th>Start</th>
<th>End</th>
</tr>
</thead>
<tbody>
<tr>
<td><label class="checkbox"><input type="checkbox" id="monday" />Monday</label></td>
<td><input type="text" id="monday-start" class="work-start" /></td>
<td><input type="text" id="monday-end" class="work-end" /></td>
</tr>
<tr>
<td><label class="checkbox"><input type="checkbox" id="tuesday" />Tuesday</label></td>
<td><input type="text" id="tuesday-start" class="work-start" /></td>
<td><input type="text" id="tuesday-end" class="work-end" /></td>
</tr>
<tr>
<td><label class="checkbox"><input type="checkbox" id="wednesday" />Wednesday</label></td>
<td><input type="text" id="wednesday-start" class="work-start" /></td>
<td><input type="text" id="wednesday-end" class="work-end" /></td>
</tr>
<tr>
<td><label class="checkbox"><input type="checkbox" id="thursday" />Thursday</label></td>
<td><input type="text" id="thursday-start" class="work-start" /></td>
<td><input type="text" id="thursday-end" class="work-end" /></td>
</tr>
<tr>
<td><label class="checkbox"><input type="checkbox" id="friday" />Friday</label></td>
<td><input type="text" id="friday-start" class="work-start" /></td>
<td><input type="text" id="friday-end" class="work-end" /></td>
</tr>
<tr>
<td><label class="checkbox"><input type="checkbox" id="saturday" />Saturday</label></td>
<td><input type="text" id="saturday-start" class="work-start" /></td>
<td><input type="text" id="saturday-end" class="work-end" /></td>
</tr>
<tr>
<td><label class="checkbox"><input type="checkbox" id="sunday" />Sunday</label></td>
<td><input type="text" id="sunday-start" class="work-start" /></td>
<td><input type="text" id="sunday-end" class="work-end" /></td>
</tr>
</tbody>
</table>
<br>
<h2>Breaks</h2>
<span class="help-block">
Add the working breaks during each day. These breaks will be applied for
all new providers.
</span>
<div>
<button type="button" class="add-break btn btn-primary">
<i class="icon-white icon-plus"></i>
Add Break
</button>
</div>
<br>
<table id="breaks" class="table table-striped">
<thead>
<tr>
<th>Day</th>
<th>Start</th>
<th>End</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
<?php // Secretaries Tab ?>
@ -256,7 +349,7 @@
<div class="form-message alert" style="display:none;"></div>
<input type="hidden" id="secretary-id" />
<input type="hidden" id="secretary-id" class="record-id" />
<div class="row-fluid">
<div class="secretary-details span6">
@ -288,17 +381,17 @@
<input type="text" id="secretary-zip-code" class="span11" />
<label for="secretary-notes">Notes</label>
<textarea id="secretary-notes" class="span11"></textarea>
<textarea id="secretary-notes" class="span11" rows="3"></textarea>
</div>
<div class="secretary-settings span6">
<label for="secretary-username">Username *</label>
<input type="text" id="secretary-username" class="span7 required" />
<input type="text" id="secretary-username" class="span9 required" />
<label for="secretary-password">Password *</label>
<input type="password" id="secretary-password" class="span7 required"/>
<input type="password" id="secretary-password" class="span9 required"/>
<label for="secretary-password-confirm">Retype Password *</label>
<input type="password" id="secretary-password-confirm" class="span7 required" />
<input type="password" id="secretary-password-confirm" class="span9 required" />
<br>

View file

@ -184,6 +184,7 @@ body .modal-header h3 {
#calendar table thead .fc-first th {
vertical-align: middle;
padding: 2px 0;
color: #555;
}
#manage-appointment {
@ -369,6 +370,48 @@ body .modal-header h3 {
padding: 7px;
}
#users-page #providers .switch-view {
overflow: auto;
margin-bottom: 5px;
}
#users-page #providers .switch-view div {
display: inline-block;
padding: 10px 15px;
border-radius: 4px;
color: #333;
float: left;
margin-right: 5px;
cursor: pointer;
}
#users-page #providers .switch-view div:hover:not(.current) {
background: #F5F5F5;
}
#users-page #providers .switch-view .current {
color: #FFF;
background: #95E4A8;
}
#users-page #providers .details-view,
#users-page #providers .working-plan-view {
clear: both;
}
#users-page .btn-toolbar {
margin-top: 0;
margin-bottom: 15px;
}
#users-page #providers .form-message {
clear: both;
}
#users-page #providers #breaks .btn {
margin-right: 5px;
padding: 4px 7px;
}
/* BACKEND SETTINGS PAGE
-------------------------------------------------------------------- */

View file

@ -7,6 +7,21 @@
var BackendUsers = {
MIN_PASSWORD_LENGTH: 7,
/**
* This flag is used when trying to cancel row editing. It is
* true only whenever the user presses the cancel button.
*
* @type {bool}
*/
enableCancel: false,
/**
* This flag determines whether the jeditables are allowed to submit. It is
* true only whenever the user presses the save button.
*
* @type {bool}
*/
enableSubmit: false,
/**
* Contains the current tab record methods for the page.
@ -98,26 +113,45 @@ var BackendUsers = {
$('.filter-key').val('');
});
$('#admin-username').focusout(function() {
// Validate username.
/**
* Event: Admin, Provider, Secretary Username "Focusout"
*
* When the user leaves the username input field we will need to check if the username
* is not taken by another record in the system. Usernames must be unique.
*/
$('#admin-username, #provider-username, #secretary-username').focusout(function() {
var $input = $(this);
if ($input.prop('readonly') == true || $input.val() == '') {
return;
}
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_validate_username';
var postData = {
'username': $('#admin-username').val(),
'record_exists': ($('#admin-id').val() != '') ? true : false
'username': $input.val(),
'record_exists': ($input.parents().eq(2).find('.record-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();
if (response == false) {
$input.css('border', '2px solid red');
$input.parents().eq(3).find('.form-message').text('Username already exists.');
$input.parents().eq(3).find('.form-message').show();
} else {
$input.css('border', '');
if ($input.parents().eq(3).find('.form-message').text() == 'Username already exists.') {
$input.parents().eq(3).find('.form-message').hide();
}
}
}, 'json');
});
// -----------------------------------------------------------------
/**
* Event: Filter Admins Button "Click"
*
@ -244,6 +278,19 @@ var BackendUsers = {
*/
$('#cancel-admin').click(function() {
BackendUsers.helper.resetForm();
var admin = { 'id': $('#admins .selected-row').attr('data-id') };
$.each(BackendUsers.helper.filterResults, function(index, item) {
if (item.id === admin.id) {
admin = item;
return;
}
});
BackendUsers.helper.display(admin);
$('#edit-admin, #delete-admin').prop('disabled', false);
});
// ------------------------------------------------------------------------
@ -297,6 +344,186 @@ var BackendUsers = {
$('#provider-password, #provider-password-confirm').addClass('required');
$('#provider-notifications').prop('disabled', false);
$('#provider-services input[type="checkbox"]').prop('disabled', false);
$('#providers .add-break').prop('disabled', false);
$('.edit-break, .delete-break').prop('disabled', false);
$('#providers input[type="checkbox"]').prop('disabled', false);
// Apply default working plan
$.each(GlobalVariables.workingPlan, function(index, workingDay) {
if (workingDay != null) {
$('#' + index).prop('checked', true);
$('#' + index + '-start').val(workingDay.start);
$('#' + index + '-end').val(workingDay.end);
// Add the day's breaks on the breaks table.
$.each(workingDay.breaks, function(i, brk) {
var tr =
'<tr>' +
'<td class="break-day editable">' + GeneralFunctions.ucaseFirstLetter(index) + '</td>' +
'<td class="break-start editable">' + brk.start + '</td>' +
'<td class="break-end editable">' + brk.end + '</td>' +
'<td>' +
'<button type="button" class="btn edit-break" title="Edit Break">' +
'<i class="icon-pencil"></i>' +
'</button>' +
'<button type="button" class="btn delete-break" title="Delete Break">' +
'<i class="icon-remove"></i>' +
'</button>' +
'<button type="button" class="btn save-break hidden" title="Save Break">' +
'<i class="icon-ok"></i>' +
'</button>' +
'<button type="button" class="btn cancel-break hidden" title="Cancel Break">' +
'<i class="icon-ban-circle"></i>' +
'</button>' +
'</td>' +
'</tr>';
$('#breaks').append(tr);
});
} else {
$('#' + index).prop('checked', false);
$('#' + index + '-start').prop('disabled', true);
$('#' + index + '-end').prop('disabled', true);
}
});
// Make break cells editable.
BackendUsers.editableBreakDay($('#breaks .break-day'));
BackendUsers.editableBreakTime($('#breaks').find('.break-start, .break-end'));
// Set timepickers where needed.
$('.working-plan input').timepicker({
'timeFormat': 'HH:mm',
'onSelect': function(datetime, inst) {
// Start time must be earlier than end time.
var start = Date.parse($(this).parent().parent().find('.work-start').val());
var end = Date.parse($(this).parent().parent().find('.work-end').val());
if (start > end) {
$(this).parent().parent().find('.work-end').val(start.addHours(1).toString('HH:mm'));
}
}
});
});
/**
* Event: Day Checkbox "Click"
*
* Enable or disable the time selection for each day.
*/
$('.working-plan input[type="checkbox"]').click(function() {
var id = $(this).attr('id');
if ($(this).prop('checked') == true) {
$('#' + id + '-start').prop('disabled', false).val('09:00');
$('#' + id + '-end').prop('disabled', false).val('18:00');
} else {
$('#' + id + '-start').prop('disabled', true).val('');
$('#' + id + '-end').prop('disabled', true).val('');
}
});
/**
* Event: Add Break Button "Click"
*
* A new row is added on the table and the user can enter the new break
* data. After that he can either press the save or cancel button.
*/
$('.add-break').click(function() {
var tr =
'<tr>' +
'<td class="break-day editable">Monday</td>' +
'<td class="break-start editable">09:00</td>' +
'<td class="break-end editable">10:00</td>' +
'<td>' +
'<button type="button" class="btn edit-break" title="Edit Break">' +
'<i class="icon-pencil"></i>' +
'</button>' +
'<button type="button" class="btn delete-break" title="Delete Break">' +
'<i class="icon-remove"></i>' +
'</button>' +
'<button type="button" class="btn save-break hidden" title="Save Break">' +
'<i class="icon-ok"></i>' +
'</button>' +
'<button type="button" class="btn cancel-break hidden" title="Cancel Break">' +
'<i class="icon-ban-circle"></i>' +
'</button>' +
'</td>' +
'</tr>';
$('#breaks').prepend(tr);
// Bind editable and event handlers.
tr = $('#breaks tr').get()[1];
BackendUsers.editableBreakDay($(tr).find('.break-day'));
BackendUsers.editableBreakTime($(tr).find('.break-start, .break-end'));
$(tr).find('.edit-break').trigger('click');
});
/**
* Event: Edit Break Button "Click"
*
* Enables the row editing for the "Breaks" table rows.
*/
$(document).on('click', '.edit-break', function() {
// Reset previous editable tds
var $previousEdt = $(this).closest('table').find('.editable').get();
$.each($previousEdt, function(index, edt) {
edt.reset();
});
// Make all cells in current row editable.
$(this).parent().parent().children().trigger('edit');
$(this).parent().parent().find('.break-start input, .break-end input').timepicker();
$(this).parent().parent().find('.break-day select').focus();
// Show save - cancel buttons.
$(this).closest('table').find('.edit-break, .delete-break').addClass('hidden');
$(this).parent().find('.save-break, .cancel-break').removeClass('hidden');
});
/**
* Event: Delete Break Button "Click"
*
* Removes the current line from the "Breaks" table.
*/
$(document).on('click', '.delete-break', function() {
$(this).parent().parent().remove();
});
/**
* Event: Cancel Break Button "Click"
*
* Bring the "#breaks" table back to its initial state.
*/
$(document).on('click', '.cancel-break', function() {
BackendUsers.enableCancel = true;
$(this).parent().parent().find('.cancel-editable').trigger('click');
BackendUsers.enableCancel = false;
$(this).closest('table').find('.edit-break, .delete-break').removeClass('hidden');
$(this).parent().find('.save-break, .cancel-break').addClass('hidden');
});
/**
* Event: Save Break Button "Click"
*
* Save the editable values and restore the table to its initial state.
*/
$(document).on('click', '.save-break', function() {
// Break's start time must always be prior to break's end.
var start = Date.parse($(this).parent().parent().find('.break-start input').val());
var end = Date.parse($(this).parent().parent().find('.break-end input').val());
if (start > end) {
$(this).parent().parent().find('.break-end input').val(start.addHours(1).toString('HH:mm'));
}
BackendUsers.enableSubmit = true;
$(this).parent().parent().find('.editable .submit-editable').trigger('click');
BackendUsers.enableSubmit = false;
$(this).closest('table').find('.edit-break, .delete-break').removeClass('hidden');
$(this).parent().find('.save-break, .cancel-break').addClass('hidden');
});
/**
@ -311,6 +538,10 @@ var BackendUsers = {
$('#provider-password, #provider-password-confirm').removeClass('required');
$('#provider-notifications').prop('disabled', false);
$('#provider-services input[type="checkbox"]').prop('disabled', false);
$('#providers .add-break').prop('disabled', false);
$('.edit-break, .delete-break').prop('disabled', false);
$('#providers input[type="checkbox"]').prop('disabled', false);
});
/**
@ -350,6 +581,7 @@ var BackendUsers = {
'notes': $('#provider-notes').val(),
'settings': {
'username': $('#provider-username').val(),
'working_plan': BackendUsers.helper.getWorkingPlan(),
'notifications': $('#provider-notifications').hasClass('active')
}
};
@ -384,6 +616,42 @@ var BackendUsers = {
*/
$('#cancel-provider').click(function() {
BackendUsers.helper.resetForm();
var provider = { 'id': $('#providers .selected-row').attr('data-id') };
$.each(BackendUsers.helper.filterResults, function(index, item) {
if (item.id === provider.id) {
provider = item;
return;
}
});
BackendUsers.helper.display(provider);
$('#edit-provider, #delete-provider').prop('disabled', false);
});
/**
* Event: Display Provider Details "Click"
*/
$('#providers .display-details').click(function() {
$('#providers .switch-view .current').removeClass('current');
$(this).addClass('current');
$('.working-plan-view').hide('fade', function() {
$('.details-view').show('fade');
});
});
/**
* Event: Display Provider Working Plan "Click"
*/
$('#providers .display-working-plan').click(function() {
$('#providers .switch-view .current').removeClass('current');
$(this).addClass('current');
$('.details-view').hide('fade', function() {
$('.working-plan-view').show('fade');
});
});
// ------------------------------------------------------------------------
@ -525,7 +793,57 @@ var BackendUsers = {
$('#cancel-secretary').click(function() {
BackendUsers.helper.resetForm();
});
},
/**
* Initialize the editable functionality to the break day table cells.
*
* @param {object} $selector The cells to be initialized.
*/
editableBreakDay: function($selector) {
$selector.editable(function(value, settings) {
return value;
}, {
'type': 'select',
'data': '{ "Monday": "Monday", "Tuesday": "Tuesday", "Wednesday": "Wednesday", '
+ '"Thursday": "Thursday", "Friday": "Friday", "Saturday": "Saturday", '
+ '"Sunday": "Sunday", "selected": "Monday"}',
'event': 'edit',
'height': '30px',
'submit': '<button type="button" class="hidden submit-editable">Submit</button>',
'cancel': '<button type="button" class="hidden cancel-editable">Cancel</button>',
'onblur': 'ignore',
'onreset': function(settings, td) {
if (!BackendUsers.enableCancel) return false; // disable ESC button
},
'onsubmit': function(settings, td) {
if (!BackendUsers.enableSubmit) return false; // disable Enter button
}
});
},
/**
* Initialize the editable functionality to the break time table cells.
*
* @param {object} $selector The cells to be initialized.
*/
editableBreakTime: function($selector) {
$selector.editable(function(value, settings) {
// Do not return the value because the user needs to press the "Save" button.
return value;
}, {
'event': 'edit',
'height': '25px',
'submit': '<button type="button" class="hidden submit-editable">Submit</button>',
'cancel': '<button type="button" class="hidden cancel-editable">Cancel</button>',
'onblur': 'ignore',
'onreset': function(settings, td) {
if (!BackendUsers.enableCancel) return false; // disable ESC button
},
'onsubmit': function(settings, td) {
if (!BackendUsers.enableSubmit) return false; // disable Enter button
}
});
}
};
@ -558,8 +876,11 @@ AdminsHelper.prototype.save = function(admin) {
////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Admin saved successfully!');
BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#admins .filter-key').val());
BackendUsers.helper.resetForm(true);
// When adding a new record the "admin.id" will be undefined. In this situation
// no record will be selected because we do not yet know the id of the new record,
// but no error will occur either.
BackendUsers.helper.filter($('#admins .filter-key').val(), admin.id);
}, 'json');
};
@ -612,7 +933,8 @@ AdminsHelper.prototype.validate = function(admin) {
throw 'Passwords mismatch!';
}
if ($('#admin-password').val().length < BackendUsers.MIN_PASSWORD_LENGTH) {
if ($('#admin-password').val().length < BackendUsers.MIN_PASSWORD_LENGTH
&& $('#admin-password').val() != '') {
$('#admin-password, #admin-password-confirm').css('border', '2px solid red');
throw 'Password must be at least ' + BackendUsers.MIN_PASSWORD_LENGTH
+ ' characters long.';
@ -634,20 +956,28 @@ AdminsHelper.prototype.validate = function(admin) {
/**
* Resets the admin tab form back to its initial state.
*
* @param {bool} keepRecordData (OPTIONAL = false) If false then the current record data
* will remain on the form.
*/
AdminsHelper.prototype.resetForm = function() {
$('#admins .details').find('input, textarea').val('');
AdminsHelper.prototype.resetForm = function(keepRecordData) {
if (keepRecordData == undefined) keepRecordData = false;
$('#admins .add-edit-delete-group').show();
$('#admins .save-cancel-group').hide();
$('#edit-admin, #delete-admin').prop('disabled', true);
$('#admins .details').find('input, textarea').prop('readonly', true);
$('.filter-admins').prop('disabled', false);
$('#admins .filter-results').css('color', '');
$('#admins .form-message').hide();
$('#admin-notifications').removeClass('active');
$('#admin-notifications').prop('disabled', true);
$('#admins .required').css('border', '');
$('#admin-password, #admin-password-confirm').css('border', '');
if (!keepRecordData) {
$('#admins .details').find('input, textarea').val('');
$('#admin-notifications').removeClass('active');
$('#edit-admin, #delete-admin').prop('disabled', true);
}
};
/**
@ -681,7 +1011,7 @@ AdminsHelper.prototype.display = function(admin) {
*
* @param {string} key This is used to filter the admin records of the database.
*/
AdminsHelper.prototype.filter = function(key) {
AdminsHelper.prototype.filter = function(key, selectRecordId) {
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_admins';
var postData = { 'key': key };
@ -699,6 +1029,15 @@ AdminsHelper.prototype.filter = function(key) {
var html = AdminsHelper.prototype.getFilterHtml(admin);
$('#admins .filter-results').append(html);
});
if (selectRecordId != undefined) {
$('.admin-row').each(function() {
if ($(this).attr('data-id') == selectRecordId) {
$(this).addClass('selected-row');
return false;
}
});
}
}, 'json');
};
@ -747,8 +1086,10 @@ ProvidersHelper.prototype.save = function(provider) {
///////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Provider saved successfully!');
BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#providers .filter-key').val());
BackendUsers.helper.resetForm(true);
// If "id" is not defined then no record will be selected (applies when adding
// a new provider record).
BackendUsers.helper.filter($('#providers .filter-key').val(), provider.id);
}, 'json');
};
@ -801,7 +1142,8 @@ ProvidersHelper.prototype.validate = function(provider) {
throw 'Passwords mismatch!';
}
if ($('#provider-password').val().length < BackendUsers.MIN_PASSWORD_LENGTH) {
if ($('#provider-password').val().length < BackendUsers.MIN_PASSWORD_LENGTH
&& $('#provider-password').val() != '') {
$('#provider-password, #provider-password-confirm').css('border', '2px solid red');
throw 'Password must be at least ' + BackendUsers.MIN_PASSWORD_LENGTH
+ ' characters long.';
@ -813,22 +1155,6 @@ ProvidersHelper.prototype.validate = function(provider) {
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);
@ -839,22 +1165,36 @@ ProvidersHelper.prototype.validate = function(provider) {
/**
* Resets the admin tab form back to its initial state.
*
* @param {bool} keepRecordData (OPTIONAL = false) If true then the current record data will
* remain on the form.
*/
ProvidersHelper.prototype.resetForm = function() {
$('#providers .details').find('input, textarea').val('');
ProvidersHelper.prototype.resetForm = function(keepRecordData) {
if (keepRecordData == undefined) keepRecordData = false;
$('#providers .add-edit-delete-group').show();
$('#providers .save-cancel-group').hide();
$('#edit-provider, #delete-provider').prop('disabled', true);
$('#providers .details').find('input, textarea').prop('readonly', true);
$('.filter-providers').prop('disabled', false);
$('#providers .filter-results').css('color', '');
$('#providers .form-message').hide();
$('#provider-notifications').removeClass('active');
$('#provider-notifications').prop('disabled', true);
$('#provider-services input[type="checkbox"]').prop('checked', false);
$('#provider-services input[type="checkbox"]').prop('disabled', true);
$('#providers .required').css('border', '');
$('#provider-password, #provider-password-confirm').css('border', '');
$('#providers .add-break').prop('disabled', true);
$('#providers input[type="checkbox"]').prop('disabled', true);
$('#providers .working-plan input[type="text"]').timepicker('destroy');
$('#breaks').find('.edit-break, .delete-break').prop('disabled', true);
if (!keepRecordData) {
$('#edit-provider, #delete-provider').prop('disabled', true);
$('#providers .details').find('input, textarea').val('');
$('#providers input[type="checkbox"]').prop('checked', false);
$('#provider-services input[type="checkbox"]').prop('checked', false);
$('#providers #breaks tbody').empty();
}
};
/**
@ -890,14 +1230,76 @@ ProvidersHelper.prototype.display = function(provider) {
}
});
});
// Display working plan
$('#providers #breaks tbody').empty();
var workingPlan = $.parseJSON(provider.settings.working_plan);
$.each(workingPlan, function(index, workingDay) {
if (workingDay != null) {
$('#' + index).prop('checked', true);
$('#' + index + '-start').val(workingDay.start);
$('#' + index + '-end').val(workingDay.end);
// Add the day's breaks on the breaks table.
$.each(workingDay.breaks, function(i, brk) {
var tr =
'<tr>' +
'<td class="break-day editable">' + GeneralFunctions.ucaseFirstLetter(index) + '</td>' +
'<td class="break-start editable">' + brk.start + '</td>' +
'<td class="break-end editable">' + brk.end + '</td>' +
'<td>' +
'<button type="button" class="btn edit-break" title="Edit Break">' +
'<i class="icon-pencil"></i>' +
'</button>' +
'<button type="button" class="btn delete-break" title="Delete Break">' +
'<i class="icon-remove"></i>' +
'</button>' +
'<button type="button" class="btn save-break hidden" title="Save Break">' +
'<i class="icon-ok"></i>' +
'</button>' +
'<button type="button" class="btn cancel-break hidden" title="Cancel Break">' +
'<i class="icon-ban-circle"></i>' +
'</button>' +
'</td>' +
'</tr>';
$('#breaks').append(tr);
});
} else {
$('#' + index).prop('checked', false);
$('#' + index + '-start').prop('disabled', true);
$('#' + index + '-end').prop('disabled', true);
}
});
$('.edit-break, .delete-break').prop('disabled', true);
// Make break cells editable.
BackendUsers.editableBreakDay($('#breaks .break-day'));
BackendUsers.editableBreakTime($('#breaks').find('.break-start, .break-end'));
// Set timepickers where needed.
$('.working-plan input').timepicker({
'timeFormat': 'HH:mm',
'onSelect': function(datetime, inst) {
// Start time must be earlier than end time.
var start = Date.parse($(this).parent().parent().find('.work-start').val());
var end = Date.parse($(this).parent().parent().find('.work-end').val());
if (start > end) {
$(this).parent().parent().find('.work-end').val(start.addHours(1).toString('HH:mm'));
}
}
});
};
/**
* Filters provider records depending a string key.
*
* @param {string} key This is used to filter the provider records of the database.
* @param {numeric} selectRecordId (OPTIONAL) If set, when the function is complete
* a result row can be set as selected.
*/
ProvidersHelper.prototype.filter = function(key) {
ProvidersHelper.prototype.filter = function(key, selectRecordId) {
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_providers';
var postData = { 'key': key };
@ -915,6 +1317,15 @@ ProvidersHelper.prototype.filter = function(key) {
var html = ProvidersHelper.prototype.getFilterHtml(provider);
$('#providers .filter-results').append(html);
});
if (selectRecordId != undefined) {
$('.provider-row').each(function() {
if ($(this).attr('data-id') == selectRecordId) {
$(this).addClass('selected-row');
return false;
}
});
}
}, 'json');
};
@ -934,6 +1345,43 @@ ProvidersHelper.prototype.getFilterHtml = function(provider) {
return html;
};
/**
* Get the current working plan.
*
* @return {string} Returns the working plan (already stringified).
*/
ProvidersHelper.prototype.getWorkingPlan = function() {
var workingPlan = {};
$('.working-plan input[type="checkbox"').each(function() {
var id = $(this).attr('id');
if ($(this).prop('checked') == true) {
workingPlan[id] = {}
workingPlan[id].start = $('#' + id + '-start').val();
workingPlan[id].end = $('#' + id + '-end').val();
workingPlan[id].breaks = [];
$('#breaks tr').each(function(index, tr) {
var day = $(tr).find('.break-day').text().toLowerCase();
if (day == id) {
var start = $(tr).find('.break-start').text();
var end = $(tr).find('.break-end').text();
workingPlan[id].breaks.push({
'start': start,
'end': end
});
}
});
} else {
workingPlan[id] = null;
}
});
return JSON.stringify(workingPlan);
};
/**
* This class contains the methods that will be used by the "Secretaries" tab of the page.
*
@ -1017,7 +1465,8 @@ SecretariesHelper.prototype.validate = function(secretary) {
throw 'Passwords mismatch!';
}
if ($('#secretary-password').val().length < BackendUsers.MIN_PASSWORD_LENGTH) {
if ($('#secretary-password').val().length < BackendUsers.MIN_PASSWORD_LENGTH
&& $('#secretary-password').val() != '') {
$('#secretary-password, #secretary-password-confirm').css('border', '2px solid red');
throw 'Password must be at least ' + BackendUsers.MIN_PASSWORD_LENGTH
+ ' characters long.';
@ -1029,22 +1478,6 @@ SecretariesHelper.prototype.validate = function(secretary) {
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);
@ -1112,8 +1545,10 @@ SecretariesHelper.prototype.display = function(secretary) {
* Filters secretary records depending a string key.
*
* @param {string} key This is used to filter the secretary records of the database.
* @param {numeric} selectRecordId (OPTIONAL) If provided then the given id will be
* selected in the filter results (only selected, not displayed).
*/
SecretariesHelper.prototype.filter = function(key) {
SecretariesHelper.prototype.filter = function(key, selectRecordId) {
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_secretaries';
var postData = { 'key': key };
@ -1131,6 +1566,15 @@ SecretariesHelper.prototype.filter = function(key) {
var html = SecretariesHelper.prototype.getFilterHtml(secretary);
$('#secretaries .filter-results').append(html);
});
if (selectRecordId != undefined) {
$('.secretary-row').each(function() {
if ($(this).attr('data-id') == selectRecordId) {
$(this).addClass('selected-row');
return false;
}
});
}
}, 'json');
};