diff --git a/application/config/autoload.php b/application/config/autoload.php index 00dbce27..1d600e7d 100644 --- a/application/config/autoload.php +++ b/application/config/autoload.php @@ -81,7 +81,7 @@ $autoload['helper'] = ['custom_exceptions', 'url', 'file', 'language', 'asset', | */ -$autoload['config'] = []; +$autoload['config'] = ['google', 'email']; /* diff --git a/application/config/config.php b/application/config/config.php index 1b8369de..a1f46617 100644 --- a/application/config/config.php +++ b/application/config/config.php @@ -10,7 +10,7 @@ */ $config['version'] = '1.4.0'; // This must be changed manually. $config['release_label'] = 'Dev'; // Leave empty for no title or add Alpha, Beta etc ... -$config['google_sync_feature'] = Config::GOOGLE_SYNC_FEATURE; +$config['debug'] = Config::DEBUG_MODE; /* |-------------------------------------------------------------------------- diff --git a/application/config/google.php b/application/config/google.php new file mode 100644 index 00000000..2e1c4955 --- /dev/null +++ b/application/config/google.php @@ -0,0 +1,17 @@ +load->library('session'); $this->load->helper('installation'); - - // Set user's selected language. - if ($this->session->userdata('language')) - { - $this->config->set_item('language', $this->session->userdata('language')); - $this->lang->load('translations', $this->session->userdata('language')); - } - else - { - $this->lang->load('translations', $this->config->item('language')); // default - } - - // Common helpers $this->load->helper('google_analytics'); - } - - /** - * Default callback method of the application. - * - * This method creates the appointment book wizard. If an appointment hash - * is provided then it means that the customer followed the appointment - * manage link that was send with the book success email. - * - * @param string $appointment_hash DB appointment hash of an existing record (default ''). - */ - public function index($appointment_hash = '') - { - if ( ! is_ea_installed()) - { - redirect('installation/index'); - return; - } - $this->load->model('appointments_model'); $this->load->model('providers_model'); $this->load->model('services_model'); @@ -70,8 +61,37 @@ class Appointments extends CI_Controller { $this->load->model('settings_model'); $this->load->model('timezones_model'); + if ($this->session->userdata('language')) + { + // Set the user's selected language. + $this->config->set_item('language', $this->session->userdata('language')); + $this->lang->load('translations', $this->session->userdata('language')); + } + else + { + // Set the default language. + $this->lang->load('translations', $this->config->item('language')); + } + } + + /** + * Default callback method of the application. + * + * This method creates the appointment book wizard. If an appointment hash is provided then it means that the + * customer followed the appointment manage link that was send with the book success email. + * + * @param string $appointment_hash The appointment hash identifier. + */ + public function index($appointment_hash = '') + { try { + if ( ! is_ea_installed()) + { + redirect('installation/index'); + return; + } + $available_services = $this->services_model->get_available_services(); $available_providers = $this->providers_model->get_available_providers(); $company_name = $this->settings_model->get_setting('company_name'); @@ -101,8 +121,8 @@ class Appointments extends CI_Controller { $available_providers[$index] = $stripped_data; } - // If an appointment hash is provided then it means that the customer - // is trying to edit a registered appointment record. + // If an appointment hash is provided then it means that the customer is trying to edit a registered + // appointment record. if ($appointment_hash !== '') { // Load the appointments data and enable the manage mode of the page. @@ -110,16 +130,17 @@ class Appointments extends CI_Controller { $results = $this->appointments_model->get_batch(['hash' => $appointment_hash]); - if (count($results) === 0) + if (empty($results)) { - // The requested appointment doesn't exist in the database. Display - // a message to the customer. - $view = [ - 'message_title' => $this->lang->line('appointment_not_found'), - 'message_text' => $this->lang->line('appointment_does_not_exist_in_db'), + // The requested appointment doesn't exist in the database. Display a message to the customer. + $variables = [ + 'message_title' => lang('appointment_not_found'), + 'message_text' => lang('appointment_does_not_exist_in_db'), 'message_icon' => base_url('assets/img/error.png') ]; - $this->load->view('appointments/message', $view); + + $this->load->view('appointments/message', $variables); + return; } @@ -127,16 +148,16 @@ class Appointments extends CI_Controller { $provider = $this->providers_model->get_row($appointment['id_users_provider']); $customer = $this->customers_model->get_row($appointment['id_users_customer']); - $customer_token = md5(uniqid(mt_rand(), true)); + $customer_token = md5(uniqid(mt_rand(), TRUE)); $this->load->driver('cache', ['adapter' => 'file']); - - $this->cache->save('customer-token-' . $customer_token, $customer['id'], 600); // save for 10 minutes + // Save the token for 10 minutes. + $this->cache->save('customer-token-' . $customer_token, $customer['id'], 600); } else { - // The customer is going to book a new appointment so there is no - // need for the manage functionality to be initialized. + // The customer is going to book a new appointment so there is no need for the manage functionality to + // be initialized. $manage_mode = FALSE; $customer_token = FALSE; $appointment = []; @@ -145,7 +166,7 @@ class Appointments extends CI_Controller { } // Load the book appointment view. - $view = [ + $variables = [ 'available_services' => $available_services, 'available_providers' => $available_providers, 'company_name' => $company_name, @@ -168,12 +189,12 @@ class Appointments extends CI_Controller { 'display_any_provider' => $display_any_provider, ]; } - catch (Exception $exc) + catch (Exception $exception) { - $view['exceptions'][] = $exc; + $variables['exceptions'][] = $exception; } - $this->load->view('appointments/book', $view); + $this->load->view('appointments/book', $variables); } /** @@ -181,33 +202,28 @@ class Appointments extends CI_Controller { * * This method removes an appointment from the company's schedule. In order for the appointment to be deleted, the * hash string must be provided. The customer can only cancel the appointment if the edit time period is not over - * yet. Provide the $_POST['cancel_reason'] parameter to describe the cancellation reason. + * yet. * - * @param string $appointment_hash This is used to distinguish the appointment record. + * @param string $appointment_hash This appointment hash identifier. */ public function cancel($appointment_hash) { try { - $this->load->model('appointments_model'); - $this->load->model('providers_model'); - $this->load->model('customers_model'); - $this->load->model('services_model'); - $this->load->model('settings_model'); - // Check whether the appointment hash exists in the database. - $records = $this->appointments_model->get_batch(['hash' => $appointment_hash]); - if (count($records) == 0) + $appointments = $this->appointments_model->get_batch(['hash' => $appointment_hash]); + + if (empty($appointments)) { throw new Exception('No record matches the provided hash.'); } - $appointment = $records[0]; + $appointment = $appointments[0]; $provider = $this->providers_model->get_row($appointment['id_users_provider']); $customer = $this->customers_model->get_row($appointment['id_users_customer']); $service = $this->services_model->get_row($appointment['id_services']); - $company_settings = [ + $settings = [ 'company_name' => $this->settings_model->get_setting('company_name'), 'company_email' => $this->settings_model->get_setting('company_email'), 'company_link' => $this->settings_model->get_setting('company_link'), @@ -215,21 +231,22 @@ class Appointments extends CI_Controller { 'time_format' => $this->settings_model->get_setting('time_format') ]; - // :: DELETE APPOINTMENT RECORD FROM THE DATABASE. + // Remove the appointment record from the data. if ( ! $this->appointments_model->delete($appointment['id'])) { throw new Exception('Appointment could not be deleted from the database.'); } - // :: SYNC APPOINTMENT REMOVAL WITH GOOGLE CALENDAR + // Remove the appointment from Google Calendar if needed. if ($appointment['id_google_calendar'] != NULL) { try { - $google_sync = filter_var($this->providers_model - ->get_setting('google_sync', $appointment['id_users_provider']), FILTER_VALIDATE_BOOLEAN); + $google_sync = filter_var( + $this->providers_model->get_setting('google_sync', $appointment['id_users_provider']), + FILTER_VALIDATE_BOOLEAN); - if ($google_sync == TRUE) + if ($google_sync === TRUE) { $google_token = json_decode($this->providers_model ->get_setting('google_token', $provider['id'])); @@ -238,53 +255,54 @@ class Appointments extends CI_Controller { $this->google_sync->delete_appointment($provider, $appointment['id_google_calendar']); } } - catch (Exception $exc) + catch (Exception $exception) { - $exceptions[] = $exc; + $exceptions[] = $exception; } } - // :: SEND NOTIFICATION EMAILS TO CUSTOMER AND PROVIDER + // Send email notification to customer and provider. try { - $this->config->load('email'); - $email = new \EA\Engine\Notifications\Email($this, $this->config->config); + $email = new EmailClient($this, $this->config->config); $send_provider = filter_var($this->providers_model - ->get_setting('notifications', $provider['id']), FILTER_VALIDATE_BOOLEAN); + ->get_setting('notifications', $provider['id']), + FILTER_VALIDATE_BOOLEAN); if ($send_provider === TRUE) { $email->sendDeleteAppointment($appointment, $provider, - $service, $customer, $company_settings, new Email($provider['email']), + $service, $customer, $settings, new Email($provider['email']), new Text($this->input->post('cancel_reason'))); } - $send_customer = filter_var($this->settings_model->get_setting('customer_notifications'), + $send_customer = filter_var( + $this->settings_model->get_setting('customer_notifications'), FILTER_VALIDATE_BOOLEAN); if ($send_customer === TRUE) { $email->sendDeleteAppointment($appointment, $provider, - $service, $customer, $company_settings, new Email($customer['email']), + $service, $customer, $settings, new Email($customer['email']), new Text($this->input->post('cancel_reason'))); } } - catch (Exception $exc) + catch (Exception $exception) { - $exceptions[] = $exc; + $exceptions[] = $exception; } } - catch (Exception $exc) + catch (Exception $exception) { // Display the error message to the customer. - $exceptions[] = $exc; + $exceptions[] = $exception; } $view = [ - 'message_title' => $this->lang->line('appointment_cancelled_title'), - 'message_text' => $this->lang->line('appointment_cancelled'), + 'message_title' => lang('appointment_cancelled_title'), + 'message_text' => lang('appointment_cancelled'), 'message_icon' => base_url('assets/img/success.png') ]; @@ -299,21 +317,21 @@ class Appointments extends CI_Controller { /** * GET an specific appointment book and redirect to the success screen. * - * @param int $appointment_id Contains the ID of the appointment to retrieve. + * @param string $appointment_hash The appointment hash identifier. + * + * @throws Exception */ - public function book_success($appointment_id) + public function book_success($appointment_hash) { - // If the appointment id doesn't exist or zero redirect to index. - if ( ! $appointment_id) + $appointments = $this->appointments_model->get_batch(['hash' => $appointment_hash]); + + if (empty($appointments)) { - redirect('appointments'); + redirect('appointments'); // The appointment does not exist. + return; } - $this->load->model('appointments_model'); - $this->load->model('providers_model'); - $this->load->model('services_model'); - $this->load->model('settings_model'); - //retrieve the data needed in the view - $appointment = $this->appointments_model->get_row($appointment_id); + + $appointment = $appointments[0]; unset($appointment['notes']); $provider = $this->providers_model->get_row($appointment['id_users_provider']); @@ -322,22 +340,22 @@ class Appointments extends CI_Controller { $service = $this->services_model->get_row($appointment['id_services']); $company_name = $this->settings_model->get_setting('company_name'); - //get the exceptions + + // Get any pending exceptions. $exceptions = $this->session->flashdata('book_success'); - unset($provider['settings']); - - // :: LOAD THE BOOK SUCCESS VIEW $view = [ 'appointment_data' => $appointment, 'provider_data' => $provider, 'service_data' => $service, 'company_name' => $company_name, ]; + if ($exceptions) { $view['exceptions'] = $exceptions; } + $this->load->view('appointments/book_success', $view); } @@ -347,81 +365,69 @@ class Appointments extends CI_Controller { * This method answers to an AJAX request. It calculates the available hours for the given service, provider and * date. * - * Required POST parameters: - * - * - int $_POST['service_id'] Selected service record ID. - * - int|string $_POST['provider_id'] Selected provider record id, can also be 'any-provider'. - * - string $_POST['selected_date'] Selected date for availabilities. - * - int $_POST['service_duration'] Selected service duration in minutes. - * - string $_POST['manage_mode'] Contains either 'true' or 'false' and determines the if current user - * is managing an already booked appointment or not. - * * Outputs a JSON string with the availabilities. - * - * @deprecated Since v1.3.0, this method will be replaced with a future release. */ public function ajax_get_available_hours() { - $this->load->model('providers_model'); - $this->load->model('appointments_model'); - $this->load->model('settings_model'); - $this->load->model('services_model'); - try { + $provider_id = $this->input->post('provider_id'); + $service_id = $this->input->post('service_id'); + $selected_date = $this->input->post('selected_date'); + // Do not continue if there was no provider selected (more likely there is no provider in the system). - if (empty($this->input->post('provider_id'))) + if (empty($provider_id)) { $this->output ->set_content_type('application/json') ->set_output(json_encode([])); + return; } - // If manage mode is TRUE then the following we should not consider the selected - // appointment when calculating the available time periods of the provider. - $exclude_appointments = ($this->input->post('manage_mode') === 'true') - ? [$this->input->post('appointment_id')] - : []; + // If manage mode is TRUE then the following we should not consider the selected appointment when + // calculating the available time periods of the provider. + $exclude_appointments = []; - // If the user has selected the "any-provider" option then we will need to search - // for an available provider that will provide the requested service. - if ($this->input->post('provider_id') === ANY_PROVIDER) + if ($this->input->post('manage_mode') === 'true') { - $_POST['provider_id'] = $this->_search_any_provider($this->input->post('service_id'), - $this->input->post('selected_date')); - if ($this->input->post('provider_id') === NULL) + $exclude_appointments[] = $this->input->post('appointment_id'); + } + + // If the user has selected the "any-provider" option then we will need to search for an available provider + // that will provide the requested service. + if ($provider_id === ANY_PROVIDER) + { + $provider_id = $this->search_any_provider($service_id, $selected_date); + + if ($provider_id === NULL) { $this->output ->set_content_type('application/json') ->set_output(json_encode([])); + return; } } - $service = $this->services_model->get_row($this->input->post('service_id')); - $provider = $this->providers_model->get_row($_POST['provider_id']); + $service = $this->services_model->get_row($service_id); + $provider = $this->providers_model->get_row($provider_id); - $empty_periods = $this->_get_provider_available_time_periods($this->input->post('provider_id'), - $this->input->post('service_id'), - $this->input->post('selected_date'), $exclude_appointments); + $empty_periods = $this->get_provider_available_time_periods($provider_id, + $selected_date, $exclude_appointments); - $available_hours = $this->_calculate_available_hours($empty_periods, $this->input->post('selected_date'), - $this->input->post('service_duration'), - filter_var($this->input->post('manage_mode'), FILTER_VALIDATE_BOOLEAN), - $service['availabilities_type']); + $available_hours = $this->calculate_available_hours($empty_periods, $selected_date, + $service['duration'], $service['availabilities_type']); if ($service['attendants_number'] > 1) { - $available_hours = $this->_get_multiple_attendants_hours($this->input->post('selected_date'), $service, + $available_hours = $this->get_multiple_attendants_hours($selected_date, $service, $provider); } - // If the selected date is today, remove past hours. It is important include the timeout before - // booking that is set in the back-office the system. Normally we might want the customer to book - // an appointment that is at least half or one hour from now. The setting is stored in minutes. - $selected_date = $this->input->post('selected_date'); - + // If the selected date is today, remove past hours. It is important include the timeout before booking + // that is set in the back-office the system. Normally we might want the customer to book an appointment + // that is at least half or one hour from now. The setting is stored in minutes. $provider_timezone = new DateTimeZone($provider['timezone']); $book_advance_timeout = $this->settings_model->get_setting('book_advance_timeout'); @@ -442,361 +448,73 @@ class Appointments extends CI_Controller { sort($available_hours, SORT_STRING); $available_hours = array_values($available_hours); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($available_hours)); + $response = $available_hours; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'exceptions' => [exceptionToJavaScript($exc)] - ])); - } - } + $this->output->set_status_header(500); - /** - * [AJAX] Register the appointment to the database. - * - * Outputs a JSON string with the appointment ID. - */ - public function ajax_register_appointment() - { - try - { - $post_data = $this->input->post('post_data'); // alias - $post_data['manage_mode'] = filter_var($post_data['manage_mode'], FILTER_VALIDATE_BOOLEAN); - - $this->load->model('appointments_model'); - $this->load->model('providers_model'); - $this->load->model('services_model'); - $this->load->model('customers_model'); - $this->load->model('settings_model'); - - // Validate the CAPTCHA string. - if ($this->settings_model->get_setting('require_captcha') === '1' - && $this->session->userdata('captcha_phrase') !== $this->input->post('captcha')) - { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'captcha_verification' => FALSE - ])); - return; - } - - // Check appointment availability. - if ( ! $this->_check_datetime_availability()) - { - throw new Exception($this->lang->line('requested_hour_is_unavailable')); - } - - $appointment = $_POST['post_data']['appointment']; - $customer = $_POST['post_data']['customer']; - - if ($this->customers_model->exists($customer)) - { - $customer['id'] = $this->customers_model->find_record_id($customer); - } - - $provider = $this->providers_model->get_row($appointment['id_users_provider']); - $service = $this->services_model->get_row($appointment['id_services']); - - if (empty($appointment['location']) && !empty($service['location'])) { - $appointment['location'] = $service['location']; - } - - $customer_id = $this->customers_model->add($customer); - $appointment['id_users_customer'] = $customer_id; - $appointment['is_unavailable'] = (int)$appointment['is_unavailable']; // needs to be type casted - $appointment['id'] = $this->appointments_model->add($appointment); - $appointment['hash'] = $this->appointments_model->get_value('hash', $appointment['id']); - - $company_settings = [ - 'company_name' => $this->settings_model->get_setting('company_name'), - 'company_link' => $this->settings_model->get_setting('company_link'), - 'company_email' => $this->settings_model->get_setting('company_email'), - 'date_format' => $this->settings_model->get_setting('date_format'), - 'time_format' => $this->settings_model->get_setting('time_format') + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] ]; - - // :: SYNCHRONIZE APPOINTMENT WITH PROVIDER'S GOOGLE CALENDAR - // The provider must have previously granted access to his google calendar account - // in order to sync the appointment. - try - { - $google_sync = filter_var($this->providers_model->get_setting('google_sync', - $appointment['id_users_provider']), FILTER_VALIDATE_BOOLEAN); - - if ($google_sync == TRUE) - { - $google_token = json_decode($this->providers_model - ->get_setting('google_token', $appointment['id_users_provider'])); - - $this->load->library('google_sync'); - $this->google_sync->refresh_token($google_token->refresh_token); - - if ($post_data['manage_mode'] === FALSE) - { - // Add appointment to Google Calendar. - $google_event = $this->google_sync->add_appointment($appointment, $provider, - $service, $customer, $company_settings); - $appointment['id_google_calendar'] = $google_event->id; - $this->appointments_model->add($appointment); - } - else - { - // Update appointment to Google Calendar. - $appointment['id_google_calendar'] = $this->appointments_model - ->get_value('id_google_calendar', $appointment['id']); - - $this->google_sync->update_appointment($appointment, $provider, - $service, $customer, $company_settings); - } - } - } - catch (Exception $exc) - { - log_message('error', $exc->getMessage()); - log_message('error', $exc->getTraceAsString()); - } - - // :: SEND NOTIFICATION EMAILS TO BOTH CUSTOMER AND PROVIDER - try - { - $this->config->load('email'); - $email = new \EA\Engine\Notifications\Email($this, $this->config->config); - - if ($post_data['manage_mode'] == FALSE) - { - $customer_title = new Text($this->lang->line('appointment_booked')); - $customer_message = new Text($this->lang->line('thank_you_for_appointment')); - $provider_title = new Text($this->lang->line('appointment_added_to_your_plan')); - $provider_message = new Text($this->lang->line('appointment_link_description')); - - } - else - { - $customer_title = new Text($this->lang->line('appointment_changes_saved')); - $customer_message = new Text(''); - $provider_title = new Text($this->lang->line('appointment_details_changed')); - $provider_message = new Text(''); - } - - $customer_link = new Url(site_url('appointments/index/' . $appointment['hash'])); - $provider_link = new Url(site_url('backend/index/' . $appointment['hash'])); - - $send_customer = filter_var($this->settings_model->get_setting('customer_notifications'), - FILTER_VALIDATE_BOOLEAN); - - $this->load->library('ics_file'); - $ics_stream = $this->ics_file->get_stream($appointment, $service, $provider, $customer); - - if ($send_customer === TRUE) - { - $email->sendAppointmentDetails($appointment, $provider, - $service, $customer, $company_settings, $customer_title, - $customer_message, $customer_link, new Email($customer['email']), new Text($ics_stream)); - } - - $send_provider = filter_var($this->providers_model->get_setting('notifications', $provider['id']), - FILTER_VALIDATE_BOOLEAN); - - if ($send_provider === TRUE) - { - $email->sendAppointmentDetails($appointment, $provider, - $service, $customer, $company_settings, $provider_title, - $provider_message, $provider_link, new Email($provider['email']), new Text($ics_stream)); - } - } - catch (Exception $exc) - { - log_message('error', $exc->getMessage()); - log_message('error', $exc->getTraceAsString()); - } - - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'appointment_id' => $appointment['id'] - ])); - } - catch (Exception $exc) - { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'exceptions' => [exceptionToJavaScript($exc)] - ])); } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Get Unavailable Dates + * Search for any provider that can handle the requested service. * - * Get an array with the available dates of a specific provider, service and month of the year. Provide the - * "provider_id", "service_id" and "selected_date" as GET parameters to the request. The "selected_date" parameter - * must have the Y-m-d format. + * This method will return the database ID of the provider with the most available periods. * - * Outputs a JSON string with the unavailable dates. that are unavailable. + * @param int $service_id The requested service ID. + * @param string $selected_date The date to be searched. * - * @deprecated Since v1.3.0, this method will be replaced with a future release. + * @return int Returns the ID of the provider that can provide the service at the selected date. + * + * @throws Exception */ - public function ajax_get_unavailable_dates() + protected function search_any_provider($service_id, $selected_date) { - try + $available_providers = $this->providers_model->get_available_providers(); + + $service = $this->services_model->get_row($service_id); + + $provider_id = NULL; + + $max_hours_count = 0; + + foreach ($available_providers as $provider) { - $provider_id = $this->input->get('provider_id'); - $service_id = $this->input->get('service_id'); - $selected_date_string = $this->input->get('selected_date'); - $selected_date = new DateTime($selected_date_string); - $number_of_days_in_month = (int)$selected_date->format('t'); - $unavailable_dates = []; - $manage_mode = filter_var($this->input->get('manage_mode'), FILTER_VALIDATE_BOOLEAN); - - $exclude_appointments = ($_REQUEST['manage_mode'] === 'true') - ? [$_REQUEST['appointment_id']] - : []; - - $provider_list = ($provider_id === ANY_PROVIDER) ? $this->_search_providers_by_service($service_id) : [$provider_id] ; - - $this->load->model('providers_model'); - - // Get the service record. - $this->load->model('services_model'); - $service = $this->services_model->get_row($service_id); - - for ($i = 1; $i <= $number_of_days_in_month; $i++) + foreach ($provider['services'] as $provider_service_id) { - $current_date = new DateTime($selected_date->format('Y-m') . '-' . $i); - - if ($current_date < new DateTime(date('Y-m-d 00:00:00'))) + if ($provider_service_id == $service_id) { - // Past dates become immediately unavailable. - $unavailable_dates[] = $current_date->format('Y-m-d'); - continue; - } + // Check if the provider is available for the requested date. + $empty_periods = $this->get_provider_available_time_periods($provider['id'], $selected_date); - // Finding at least one slot of availablity - foreach ($provider_list as $curr_provider_id) - { - // Get the provider record. - $curr_provider = $this->providers_model->get_row($curr_provider_id); - - $empty_periods = $this->_get_provider_available_time_periods($curr_provider_id, - $service_id, - $current_date->format('Y-m-d'), $exclude_appointments); - - $available_hours = $this->_calculate_available_hours($empty_periods, $current_date->format('Y-m-d'), - $service['duration'], $manage_mode, $service['availabilities_type']); - if (! empty($available_hours)) break; + $available_hours = $this->calculate_available_hours($empty_periods, $selected_date, + $service['duration'], $service['availabilities_type']); if ($service['attendants_number'] > 1) { - $available_hours = $this->_get_multiple_attendants_hours($current_date->format('Y-m-d'), $service, - $curr_provider); - if (! empty($available_hours)) break; + $available_hours = $this->get_multiple_attendants_hours($selected_date, $service, + $provider); + } + + if (count($available_hours) > $max_hours_count) + { + $provider_id = $provider['id']; + $max_hours_count = count($available_hours); } } - - // No availability amongst all the provider - if (empty($available_hours)) - { - $unavailable_dates[] = $current_date->format('Y-m-d'); - } - } - - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($unavailable_dates)); - } - catch (Exception $exc) - { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'exceptions' => [exceptionToJavaScript($exc)] - ])); - } - } - - /** - * Check whether the provider is still available in the selected appointment date. - * - * It might be times where two or more customers select the same appointment date and time. This shouldn't be - * allowed to happen, so one of the two customers will eventually get the preferred date and the other one will have - * to choose for another date. Use this method just before the customer confirms the appointment details. If the - * selected date was taken in the mean time, the customer must be prompted to select another time for his - * appointment. - * - * @return bool Returns whether the selected datetime is still available. - */ - protected function _check_datetime_availability() - { - $this->load->model('services_model'); - $this->load->model('appointments_model'); - - $appointment = $_POST['post_data']['appointment']; - - $service_duration = $this->services_model->get_value('duration', $appointment['id_services']); - - $exclude_appointments = (isset($appointment['id'])) ? [$appointment['id']] : []; - - $attendants_number = $this->services_model->get_value('attendants_number', $appointment['id_services']); - - if ($attendants_number > 1) - { - // Exclude all the appointments that will are currently registered. - $exclude = $this->appointments_model->get_batch([ - 'id_services' => $appointment['id_services'], - 'start_datetime' => $appointment['start_datetime'] - ]); - - if ( ! empty($exclude) && count($exclude) < $attendants_number) - { - foreach ($exclude as $entry) - { - $exclude_appointments[] = $entry['id']; - } } } - if ($appointment['id_users_provider'] === ANY_PROVIDER) - { - $appointment['id_users_provider'] = $this->_search_any_provider($appointment['id_services'], - date('Y-m-d', strtotime($appointment['start_datetime']))); - $_POST['post_data']['appointment']['id_users_provider'] = $appointment['id_users_provider']; - return TRUE; // The selected provider is always available. - } - - $available_periods = $this->_get_provider_available_time_periods( - $appointment['id_users_provider'], $appointment['id_services'], - date('Y-m-d', strtotime($appointment['start_datetime'])), - $exclude_appointments); - - $is_still_available = FALSE; - - foreach ($available_periods as $period) - { - $appt_start = new DateTime($appointment['start_datetime']); - $appt_start = $appt_start->format('H:i'); - - $appt_end = new DateTime($appointment['start_datetime']); - $appt_end->add(new DateInterval('PT' . $service_duration . 'M')); - $appt_end = $appt_end->format('H:i'); - - $period_start = date('H:i', strtotime($period['start'])); - $period_end = date('H:i', strtotime($period['end'])); - - if ($period_start <= $appt_start && $period_end >= $appt_end) - { - $is_still_available = TRUE; - break; - } - } - - return $is_still_available; + return $provider_id; } /** @@ -807,23 +525,20 @@ class Appointments extends CI_Controller { * values that have the start and the end time of an available time period. * * @param int $provider_id Provider record ID. - * @param int $service_id Service record ID. * @param string $selected_date Date to be checked (MySQL formatted string). * @param array $excluded_appointment_ids Array containing the IDs of the appointments that will not be taken into * consideration when the available time periods are calculated. * * @return array Returns an array with the available time periods of the provider. + * + * @throws Exception */ - protected function _get_provider_available_time_periods( + protected function get_provider_available_time_periods( $provider_id, - $service_id, $selected_date, $excluded_appointment_ids = [] - ) { - $this->load->model('appointments_model'); - $this->load->model('providers_model'); - $this->load->model('services_model'); - + ) + { // Get the service, provider's working plan and provider appointments. $working_plan = json_decode($this->providers_model->get_setting('working_plan', $provider_id), TRUE); @@ -852,13 +567,14 @@ class Appointments extends CI_Controller { $selected_date_working_plan = $working_plan[strtolower(date('l', strtotime($selected_date)))]; // Search if the $selected_date is an extra date added outside the normal working plan - if ($selected_date_working_plan == null) { - if (isset($extra_working_plan[strtolower(date('Y-m-d', strtotime($selected_date)))])){ + if ($selected_date_working_plan == NULL) + { + if (isset($extra_working_plan[strtolower(date('Y-m-d', strtotime($selected_date)))])) + { $selected_date_working_plan = $extra_working_plan[strtolower(date('Y-m-d', strtotime($selected_date)))]; } } - $periods = []; if (isset($selected_date_working_plan['breaks'])) @@ -940,7 +656,8 @@ class Appointments extends CI_Controller { $appointment_start = new DateTime($provider_appointment['start_datetime']); $appointment_end = new DateTime($provider_appointment['end_datetime']); - if ($appointment_start >= $appointment_end) { + if ($appointment_start >= $appointment_end) + { continue; } @@ -950,6 +667,7 @@ class Appointments extends CI_Controller { if ($appointment_start <= $period_start && $appointment_end <= $period_end && $appointment_end <= $period_start) { // The appointment does not belong in this time period, so we will not change anything. + continue; } else { @@ -994,6 +712,7 @@ class Appointments extends CI_Controller { if ($appointment_start >= $period_start && $appointment_end >= $period_end && $appointment_start >= $period_end) { // The appointment does not belong in the period so do not change anything. + continue; } else { @@ -1013,86 +732,6 @@ class Appointments extends CI_Controller { return array_values($periods); } - /** - * Search for any provider that can handle the requested service. - * - * This method will return the database ID of the provider with the most available periods. - * - * @param int $service_id The requested service ID. - * @param string $selected_date The date to be searched. - * - * @return int Returns the ID of the provider that can provide the service at the selected date. - */ - protected function _search_any_provider($service_id, $selected_date) - { - $this->load->model('providers_model'); - $this->load->model('services_model'); - $available_providers = $this->providers_model->get_available_providers(); - $service = $this->services_model->get_row($service_id); - $provider_id = NULL; - $max_hours_count = 0; - - foreach ($available_providers as $provider) - { - foreach ($provider['services'] as $provider_service_id) - { - if ($provider_service_id == $service_id) - { - // Check if the provider is available for the requested date. - $empty_periods = $this->_get_provider_available_time_periods($provider['id'], $service_id, - $selected_date); - - $available_hours = $this->_calculate_available_hours($empty_periods, $selected_date, - $service['duration'], FALSE, $service['availabilities_type']); - - if ($service['attendants_number'] > 1) - { - $available_hours = $this->_get_multiple_attendants_hours($selected_date, $service, - $provider); - } - - if (count($available_hours) > $max_hours_count) - { - $provider_id = $provider['id']; - $max_hours_count = count($available_hours); - } - } - } - } - - return $provider_id; - } - - /** - * Search for any provider that can handle the requested service. - * - * This method will return the database ID of the providers affected to the requested service. - * - * @param numeric $service_id The requested service ID. - * - * @return array Returns the ID of the provider that can provide the requested service. - */ - protected function _search_providers_by_service($service_id) - { - $this->load->model('providers_model'); - $available_providers = $this->providers_model->get_available_providers(); - $provider_list = array(); - - foreach ($available_providers as $provider) - { - foreach ($provider['services'] as $provider_service_id) - { - if ($provider_service_id === $service_id) - { - // Check if the provider is affected to the selected service. - $provider_list[] = $provider['id']; - } - } - } - - return $provider_list; - } - /** * Calculate the available appointment hours. * @@ -1100,24 +739,22 @@ class Appointments extends CI_Controller { * are broken down to 15 min and if the service fit in each quarter then a new * available hour is added to the "$available_hours" array. * - * @param array $empty_periods Contains the empty periods as generated by the "_get_provider_available_time_periods" + * @param array $empty_periods Contains the empty periods as generated by the "get_provider_available_time_periods" * method. * @param string $selected_date The selected date to be search (format ) * @param int $service_duration The service duration is required for the hour calculation. - * @param bool $manage_mode (optional) Whether we are currently on manage mode (editing an existing appointment). * @param string $availabilities_type Optional ('flexible'), the service availabilities type. * * @return array Returns an array with the available hours for the appointment. + * @throws Exception */ - protected function _calculate_available_hours( + protected function calculate_available_hours( array $empty_periods, $selected_date, $service_duration, - $manage_mode = FALSE, $availabilities_type = 'flexible' - ) { - $this->load->model('settings_model'); - + ) + { $available_hours = []; foreach ($empty_periods as $period) @@ -1150,17 +787,15 @@ class Appointments extends CI_Controller { * @param array $provider Selected provider data. * * @return array Returns the available hours array. + * @throws Exception */ - protected function _get_multiple_attendants_hours( + protected function get_multiple_attendants_hours( $selected_date, $service, $provider - ) { - $this->load->model('appointments_model'); - $this->load->model('services_model'); - $this->load->model('providers_model'); - - $unavailabilities = $this->appointments_model->get_batch([ + ) + { + $unavailability_events = $this->appointments_model->get_batch([ 'is_unavailable' => TRUE, 'DATE(start_datetime)' => $selected_date, 'id_users_provider' => $provider['id'] @@ -1178,7 +813,7 @@ class Appointments extends CI_Controller { ]; $periods = $this->remove_breaks($selected_date, $periods, $working_hours['breaks']); - $periods = $this->remove_unavailabilities($periods, $unavailabilities); + $periods = $this->remove_unavailability_events($periods, $unavailability_events); $hours = []; @@ -1219,6 +854,7 @@ class Appointments extends CI_Controller { * @param array $breaks Breaks array for the current date. * * @return array Returns the available time periods without the breaks. + * @throws Exception */ public function remove_breaks($selected_date, $periods, $breaks) { @@ -1275,19 +911,21 @@ class Appointments extends CI_Controller { } /** - * Remove the unavailabilities from the available time periods of the selected date. + * Remove the unavailability entries from the available time periods of the selected date. * * @param array $periods Available time periods. - * @param array $unavailabilities Unavailabilities of the current date. + * @param array $unavailability_events Unavailability events of the current date. * - * @return array Returns the available time periods without the unavailabilities. + * @return array Returns the available time periods without the unavailability events. + * + * @throws Exception */ - public function remove_unavailabilities($periods, $unavailabilities) + public function remove_unavailability_events($periods, $unavailability_events) { - foreach ($unavailabilities as $unavailability) + foreach ($unavailability_events as $unavailability_event) { - $unavailability_start = new DateTime($unavailability['start_datetime']); - $unavailability_end = new DateTime($unavailability['end_datetime']); + $unavailability_start = new DateTime($unavailability_event['start_datetime']); + $unavailability_end = new DateTime($unavailability_event['end_datetime']); foreach ($periods as &$period) { @@ -1321,7 +959,7 @@ class Appointments extends CI_Controller { if ($unavailability_start <= $period_start && $unavailability_end >= $period_end) { - // Unavaibility contains period + // Unavailability contains period $period['start'] = $unavailability_end; continue; } @@ -1330,4 +968,409 @@ class Appointments extends CI_Controller { return $periods; } + + /** + * [AJAX] Register the appointment to the database. + * + * Outputs a JSON string with the appointment ID. + */ + public function ajax_register_appointment() + { + try + { + $this->load->model('appointments_model'); + $this->load->model('providers_model'); + $this->load->model('services_model'); + $this->load->model('customers_model'); + $this->load->model('settings_model'); + + $post_data = $this->input->post('post_data'); + $captcha = $this->input->post('captcha'); + $manage_mode = filter_var($post_data['manage_mode'], FILTER_VALIDATE_BOOLEAN); + $appointment = $post_data['appointment']; + $customer = $post_data['customer']; + + $provider = $this->providers_model->get_row($appointment['id_users_provider']); + $service = $this->services_model->get_row($appointment['id_services']); + + $require_captcha = $this->settings_model->get_setting('require_captcha'); + $captcha_phrase = $this->session->userdata('captcha_phrase'); + + // Validate the CAPTCHA string. + if ($require_captcha === '1' && $captcha_phrase !== $captcha) + { + $this->output + ->set_content_type('application/json') + ->set_output(json_encode([ + 'captcha_verification' => FALSE + ])); + + return; + } + + // Check appointment availability before registering it to the database. + if ( ! $this->check_datetime_availability()) + { + throw new Exception(lang('requested_hour_is_unavailable')); + } + + if ($this->customers_model->exists($customer)) + { + $customer['id'] = $this->customers_model->find_record_id($customer); + } + + if (empty($appointment['location']) && ! empty($service['location'])) + { + $appointment['location'] = $service['location']; + } + + $customer_id = $this->customers_model->add($customer); + + $appointment['id_users_customer'] = $customer_id; + $appointment['is_unavailable'] = (int)$appointment['is_unavailable']; // needs to be type casted + $appointment['id'] = $this->appointments_model->add($appointment); + $appointment['hash'] = $this->appointments_model->get_value('hash', $appointment['id']); + + $settings = [ + 'company_name' => $this->settings_model->get_setting('company_name'), + 'company_link' => $this->settings_model->get_setting('company_link'), + 'company_email' => $this->settings_model->get_setting('company_email'), + 'date_format' => $this->settings_model->get_setting('date_format'), + 'time_format' => $this->settings_model->get_setting('time_format') + ]; + + // Synchronize the appointment with the provider's Google Calendar. + try + { + $google_sync = filter_var( + $this->providers_model->get_setting('google_sync', $appointment['id_users_provider']), + FILTER_VALIDATE_BOOLEAN); + + if ($google_sync === TRUE) + { + $google_token = json_decode( + $this->providers_model->get_setting('google_token', $appointment['id_users_provider'])); + + $this->load->library('google_sync'); + + $this->google_sync->refresh_token($google_token->refresh_token); + + if ($manage_mode === FALSE) + { + // Add appointment to Google Calendar. + $google_event = $this->google_sync->add_appointment($appointment, $provider, + $service, $customer, $settings); + $appointment['id_google_calendar'] = $google_event->id; + $this->appointments_model->add($appointment); + } + else + { + // Update appointment to Google Calendar. + $appointment['id_google_calendar'] = $this->appointments_model + ->get_value('id_google_calendar', $appointment['id']); + + $this->google_sync->update_appointment($appointment, $provider, + $service, $customer, $settings); + } + } + } + catch (Exception $exception) + { + log_message('error', $exception->getMessage()); + log_message('error', $exception->getTraceAsString()); + } + + // Send email notifications to customer and provider. + try + { + $this->config->load('email'); + + $email = new EmailClient($this, $this->config->config); + + if ($manage_mode === FALSE) + { + $customer_title = new Text(lang('appointment_booked')); + $customer_message = new Text(lang('thank_you_for_appointment')); + $provider_title = new Text(lang('appointment_added_to_your_plan')); + $provider_message = new Text(lang('appointment_link_description')); + + } + else + { + $customer_title = new Text(lang('appointment_changes_saved')); + $customer_message = new Text(''); + $provider_title = new Text(lang('appointment_details_changed')); + $provider_message = new Text(''); + } + + $customer_link = new Url(site_url('appointments/index/' . $appointment['hash'])); + $provider_link = new Url(site_url('backend/index/' . $appointment['hash'])); + + $send_customer = filter_var( + $this->settings_model->get_setting('customer_notifications'), + FILTER_VALIDATE_BOOLEAN); + + $this->load->library('ics_file'); + + $ics_stream = $this->ics_file->get_stream($appointment, $service, $provider, $customer); + + if ($send_customer === TRUE) + { + $email->sendAppointmentDetails($appointment, $provider, + $service, $customer, $settings, $customer_title, + $customer_message, $customer_link, new Email($customer['email']), new Text($ics_stream)); + } + + $send_provider = filter_var( + $this->providers_model->get_setting('notifications', $provider['id']), + FILTER_VALIDATE_BOOLEAN); + + if ($send_provider === TRUE) + { + $email->sendAppointmentDetails($appointment, $provider, + $service, $customer, $settings, $provider_title, + $provider_message, $provider_link, new Email($provider['email']), new Text($ics_stream)); + } + } + catch (Exception $exception) + { + log_message('error', $exception->getMessage()); + log_message('error', $exception->getTraceAsString()); + } + + $response = [ + 'appointment_id' => $appointment['id'], + 'appointment_hash' => $appointment['hash'] + ]; + } + catch (Exception $exception) + { + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; + } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); + } + + /** + * Check whether the provider is still available in the selected appointment date. + * + * It might be times where two or more customers select the same appointment date and time. This shouldn't be + * allowed to happen, so one of the two customers will eventually get the preferred date and the other one will have + * to choose for another date. Use this method just before the customer confirms the appointment details. If the + * selected date was taken in the mean time, the customer must be prompted to select another time for his + * appointment. + * + * @return int Returns the ID of the provider that is available for the appointment. + * + * @throws Exception + */ + protected function check_datetime_availability() + { + $this->load->model('services_model'); + $this->load->model('appointments_model'); + + $post_data = $this->input->post('post_data'); + + $appointment = $post_data['appointment']; + + $service_duration = $this->services_model->get_value('duration', $appointment['id_services']); + + $exclude_appointments = []; + + if (isset($appointment['id'])) + { + $exclude_appointments[] = $appointment['id']; + } + + $attendants_number = $this->services_model->get_value('attendants_number', $appointment['id_services']); + + if ($attendants_number > 1) + { + // Exclude all the appointments that are currently registered. + $existing_appointments = $this->appointments_model->get_batch([ + 'id_services' => $appointment['id_services'], + 'start_datetime' => $appointment['start_datetime'] + ]); + + if ( ! empty($existing_appointments) && count($existing_appointments) < $attendants_number) + { + foreach ($existing_appointments as $existing_appointment) + { + $exclude_appointments[] = $existing_appointment['id']; + } + } + } + + if ($appointment['id_users_provider'] === ANY_PROVIDER) + { + $appointment['id_users_provider'] = $this->search_any_provider($appointment['id_services'], + date('Y-m-d', strtotime($appointment['start_datetime']))); + + return $appointment['id_users_provider']; + } + + $available_periods = $this->get_provider_available_time_periods( + $appointment['id_users_provider'], + date('Y-m-d', strtotime($appointment['start_datetime'])), + $exclude_appointments); + + $is_still_available = FALSE; + + foreach ($available_periods as $period) + { + $appt_start = new DateTime($appointment['start_datetime']); + $appt_start = $appt_start->format('H:i'); + + $appt_end = new DateTime($appointment['start_datetime']); + $appt_end->add(new DateInterval('PT' . $service_duration . 'M')); + $appt_end = $appt_end->format('H:i'); + + $period_start = date('H:i', strtotime($period['start'])); + $period_end = date('H:i', strtotime($period['end'])); + + if ($period_start <= $appt_start && $period_end >= $appt_end) + { + $is_still_available = TRUE; + break; + } + } + + return $is_still_available ? $appointment['id_users_provider'] : NULL; + } + + /** + * [AJAX] Get Unavailable Dates + * + * Get an array with the available dates of a specific provider, service and month of the year. Provide the + * "provider_id", "service_id" and "selected_date" as GET parameters to the request. The "selected_date" parameter + * must have the Y-m-d format. + * + * Outputs a JSON string with the unavailable dates. that are unavailable. + */ + public function ajax_get_unavailable_dates() + { + try + { + $this->load->model('providers_model'); + $this->load->model('services_model'); + + $provider_id = $this->input->get('provider_id'); + $service_id = $this->input->get('service_id'); + $appointment_id = $this->input->get_post('appointment_id'); + $manage_mode = $this->input->get_post('manage_mode'); + $selected_date_string = $this->input->get('selected_date'); + $selected_date = new DateTime($selected_date_string); + $number_of_days_in_month = (int)$selected_date->format('t'); + $unavailable_dates = []; + + $exclude_appointments = []; + + if ($manage_mode === 'true') + { + $exclude_appointments[] = $appointment_id; + } + + $provider_list = $provider_id === ANY_PROVIDER + ? $this->search_providers_by_service($service_id) + : [$provider_id]; + + // Get the service record. + $service = $this->services_model->get_row($service_id); + + for ($i = 1; $i <= $number_of_days_in_month; $i++) + { + $current_date = new DateTime($selected_date->format('Y-m') . '-' . $i); + + if ($current_date < new DateTime(date('Y-m-d 00:00:00'))) + { + // Past dates become immediately unavailable. + $unavailable_dates[] = $current_date->format('Y-m-d'); + continue; + } + + // Finding at least one slot of availability. + foreach ($provider_list as $current_provider_id) + { + // Get the provider record. + $curr_provider = $this->providers_model->get_row($current_provider_id); + + $empty_periods = $this->get_provider_available_time_periods($current_provider_id, + $current_date->format('Y-m-d'), $exclude_appointments); + + $available_hours = $this->calculate_available_hours($empty_periods, $current_date->format('Y-m-d'), + $service['duration'], $service['availabilities_type']); + + if ( ! empty($available_hours)) + { + break; + } + + if ($service['attendants_number'] > 1) + { + $available_hours = $this->get_multiple_attendants_hours($current_date->format('Y-m-d'), $service, + $curr_provider); + if ( ! empty($available_hours)) break; + } + } + + // No availability amongst all the provider. + if (empty($available_hours)) + { + $unavailable_dates[] = $current_date->format('Y-m-d'); + } + } + + $response = $unavailable_dates; + } + catch (Exception $exception) + { + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; + } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); + } + + /** + * Search for any provider that can handle the requested service. + * + * This method will return the database ID of the providers affected to the requested service. + * + * @param int $service_id The requested service ID. + * + * @return array Returns the ID of the provider that can provide the requested service. + */ + protected function search_providers_by_service($service_id) + { + $this->load->model('providers_model'); + $available_providers = $this->providers_model->get_available_providers(); + $provider_list = []; + + foreach ($available_providers as $provider) + { + foreach ($provider['services'] as $provider_service_id) + { + if ($provider_service_id === $service_id) + { + // Check if the provider is affected to the selected service. + $provider_list[] = $provider['id']; + } + } + } + + return $provider_list; + } } diff --git a/application/controllers/Backend.php b/application/controllers/Backend.php index ae9e705f..839c03ad 100755 --- a/application/controllers/Backend.php +++ b/application/controllers/Backend.php @@ -1,4 +1,4 @@ -load->library('session'); - // Set user's selected language. if ($this->session->userdata('language')) { + // Set user's selected language. $this->config->set_item('language', $this->session->userdata('language')); $this->lang->load('translations', $this->session->userdata('language')); } else { - $this->lang->load('translations', $this->config->item('language')); // default + // Set the default language. + $this->lang->load('translations', $this->config->item('language')); } } @@ -45,12 +68,14 @@ class Backend extends CI_Controller { * menus at the top of the page. * * @param string $appointment_hash Appointment edit dialog will appear when the page loads (default ''). + * + * @throws Exception */ public function index($appointment_hash = '') { $this->session->set_userdata('dest_url', site_url('backend')); - if ( ! $this->_has_privileges(PRIV_APPOINTMENTS)) + if ( ! $this->has_privileges(PRIV_APPOINTMENTS)) { return; } @@ -76,7 +101,7 @@ class Backend extends CI_Controller { $view['available_providers'] = $this->providers_model->get_available_providers(); $view['available_services'] = $this->services_model->get_available_services(); $view['customers'] = $this->customers_model->get_batch(); - $user = $this->user_model->get_settings($this->session->userdata('user_id')); + $user = $this->user_model->get_user($this->session->userdata('user_id')); $view['calendar_view'] = $user['settings']['calendar_view']; $view['timezones'] = $this->timezones_model->to_array(); $this->set_user_data($view); @@ -109,6 +134,72 @@ class Backend extends CI_Controller { $this->load->view('backend/footer', $view); } + /** + * Check whether current user is logged in and has the required privileges to view a page. + * + * The backend page requires different privileges from the users to display pages. Not all pages are available to + * all users. For example secretaries should not be able to edit the system users. + * + * @param string $page This argument must match the roles field names of each section (eg "appointments", "users" + * ...). + * @param bool $redirect If the user has not the required privileges (either not logged in or insufficient role + * privileges) then the user will be redirected to another page. Set this argument to FALSE when using ajax (default + * true). + * + * @return bool Returns whether the user has the required privileges to view the page or not. If the user is not + * logged in then he will be prompted to log in. If he hasn't the required privileges then an info message will be + * displayed. + */ + protected function has_privileges($page, $redirect = TRUE) + { + // Check if user is logged in. + $user_id = $this->session->userdata('user_id'); + + if ($user_id == FALSE) + { + // User not logged in, display the login view. + if ($redirect) + { + header('Location: ' . site_url('user/login')); + } + return FALSE; + } + + // Check if the user has the required privileges for viewing the selected page. + $role_slug = $this->session->userdata('role_slug'); + + $role_privileges = $this->db->get_where('ea_roles', ['slug' => $role_slug])->row_array(); + + if ($role_privileges[$page] < PRIV_VIEW) + { + // User does not have the permission to view the page. + if ($redirect) + { + header('Location: ' . site_url('user/no_privileges')); + } + return FALSE; + } + + return TRUE; + } + + /** + * Set the user data in order to be available at the view and js code. + * + * @param array $view Contains the view data. + */ + protected function set_user_data(&$view) + { + $this->load->model('roles_model'); + + // Get privileges + $view['user_id'] = $this->session->userdata('user_id'); + $view['user_email'] = $this->session->userdata('user_email'); + $view['timezone'] = $this->session->userdata('timezone'); + $view['role_slug'] = $this->session->userdata('role_slug'); + $view['privileges'] = $this->roles_model->get_privileges($this->session->userdata('role_slug')); + } + /** * Display the backend customers page. * @@ -118,7 +209,7 @@ class Backend extends CI_Controller { { $this->session->set_userdata('dest_url', site_url('backend/customers')); - if ( ! $this->_has_privileges(PRIV_CUSTOMERS)) + if ( ! $this->has_privileges(PRIV_CUSTOMERS)) { return; } @@ -173,7 +264,7 @@ class Backend extends CI_Controller { { $this->session->set_userdata('dest_url', site_url('backend/services')); - if ( ! $this->_has_privileges(PRIV_SERVICES)) + if ( ! $this->has_privileges(PRIV_SERVICES)) { return; } @@ -211,7 +302,7 @@ class Backend extends CI_Controller { { $this->session->set_userdata('dest_url', site_url('backend/users')); - if ( ! $this->_has_privileges(PRIV_USERS)) + if ( ! $this->has_privileges(PRIV_USERS)) { return; } @@ -255,8 +346,8 @@ class Backend extends CI_Controller { public function settings() { $this->session->set_userdata('dest_url', site_url('backend/settings')); - if ( ! $this->_has_privileges(PRIV_SYSTEM_SETTINGS, FALSE) - && ! $this->_has_privileges(PRIV_USER_SETTINGS)) + if ( ! $this->has_privileges(PRIV_SYSTEM_SETTINGS, FALSE) + && ! $this->has_privileges(PRIV_USER_SETTINGS)) { return; } @@ -277,7 +368,7 @@ class Backend extends CI_Controller { $view['time_format'] = $this->settings_model->get_setting('time_format'); $view['role_slug'] = $this->session->userdata('role_slug'); $view['system_settings'] = $this->settings_model->get_settings(); - $view['user_settings'] = $this->user_model->get_settings($user_id); + $view['user_settings'] = $this->user_model->get_user($user_id); $view['timezones'] = $this->timezones_model->to_array(); $this->set_user_data($view); @@ -286,52 +377,6 @@ class Backend extends CI_Controller { $this->load->view('backend/footer', $view); } - /** - * Check whether current user is logged in and has the required privileges to view a page. - * - * The backend page requires different privileges from the users to display pages. Not all pages are available to - * all users. For example secretaries should not be able to edit the system users. - * - * @see Constant definition in application/config/constants.php. - * - * @param string $page This argument must match the roles field names of each section (eg "appointments", "users" - * ...). - * @param bool $redirect If the user has not the required privileges (either not logged in or insufficient role - * privileges) then the user will be redirected to another page. Set this argument to FALSE when using ajax (default - * true). - * - * @return bool Returns whether the user has the required privileges to view the page or not. If the user is not - * logged in then he will be prompted to log in. If he hasn't the required privileges then an info message will be - * displayed. - */ - protected function _has_privileges($page, $redirect = TRUE) - { - // Check if user is logged in. - $user_id = $this->session->userdata('user_id'); - if ($user_id == FALSE) - { // User not logged in, display the login view. - if ($redirect) - { - header('Location: ' . site_url('user/login')); - } - return FALSE; - } - - // Check if the user has the required privileges for viewing the selected page. - $role_slug = $this->session->userdata('role_slug'); - $role_priv = $this->db->get_where('ea_roles', ['slug' => $role_slug])->row_array(); - if ($role_priv[$page] < PRIV_VIEW) - { // User does not have the permission to view the page. - if ($redirect) - { - header('Location: ' . site_url('user/no_privileges')); - } - return FALSE; - } - - return TRUE; - } - /** * This method will update the installation to the latest available version in the server. * @@ -345,7 +390,7 @@ class Backend extends CI_Controller { { try { - if ( ! $this->_has_privileges(PRIV_SYSTEM_SETTINGS, TRUE)) + if ( ! $this->has_privileges(PRIV_SYSTEM_SETTINGS, TRUE)) { throw new Exception('You do not have the required privileges for this task!'); } @@ -359,28 +404,11 @@ class Backend extends CI_Controller { $view = ['success' => TRUE]; } - catch (Exception $exc) + catch (Exception $exception) { - $view = ['success' => FALSE, 'exception' => $exc->getMessage()]; + $view = ['success' => FALSE, 'exception' => $exception->getMessage()]; } $this->load->view('general/update', $view); } - - /** - * Set the user data in order to be available at the view and js code. - * - * @param array $view Contains the view data. - */ - protected function set_user_data(&$view) - { - $this->load->model('roles_model'); - - // Get privileges - $view['user_id'] = $this->session->userdata('user_id'); - $view['user_email'] = $this->session->userdata('user_email'); - $view['timezone'] = $this->session->userdata('timezone'); - $view['role_slug'] = $this->session->userdata('role_slug'); - $view['privileges'] = $this->roles_model->get_privileges($this->session->userdata('role_slug')); - } } diff --git a/application/controllers/Backend_api.php b/application/controllers/Backend_api.php index 0aede844..0345c6ac 100755 --- a/application/controllers/Backend_api.php +++ b/application/controllers/Backend_api.php @@ -1,4 +1,4 @@ -security->csrf_show_error(); - } - $this->load->library('session'); $this->load->model('roles_model'); @@ -146,26 +163,26 @@ class Backend_api extends CI_Controller { $this->output->set_output(json_encode($response)); } - catch (Exception $exc) + catch (Exception $exception) { - $this->output->set_output(json_encode([ - 'exceptions' => [exceptionToJavaScript($exc)] - ])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Get the registered appointments for the given date period and record. + * Get the registered appointments for the given date period and record. * * This method returns the database appointments and unavailable periods for the * user selected date period and record type (provider or service). - * - * Required POST Parameters: - * - * - int $_POST['record_id'] Selected record id. - * - string $_POST['filter_type'] Could be either FILTER_TYPE_PROVIDER or FILTER_TYPE_SERVICE. - * - string $_POST['start_date'] The user selected start date. - * - string $_POST['end_date'] The user selected end date. */ public function ajax_get_calendar_appointments() { @@ -199,9 +216,9 @@ class Backend_api extends CI_Controller { } // Get appointments - $record_id = $this->db->escape($_POST['record_id']); - $start_date = $this->db->escape($_POST['start_date']); - $end_date = $this->db->escape(date('Y-m-d', strtotime($_POST['end_date'] . ' +1 day'))); + $record_id = $this->db->escape($this->input->post('record_id')); + $start_date = $this->db->escape($this->input->post('start_date')); + $end_date = $this->db->escape(date('Y-m-d', strtotime($this->input->post('end_date') . ' +1 day'))); $where_clause = $where_id . ' = ' . $record_id . ' AND ((start_datetime > ' . $start_date . ' AND start_datetime < ' . $end_date . ') @@ -236,21 +253,23 @@ class Backend_api extends CI_Controller { ->set_content_type('application/json') ->set_output(json_encode($response)); } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Save appointment changes that are made from the backend calendar page. - * - * Required POST Parameters: - * - * - array $_POST['appointment_data'] (OPTIONAL) Array with the appointment data. - * - array $_POST['customer_data'] (OPTIONAL) Array with the customer data. + * Save appointment changes that are made from the backend calendar page. */ public function ajax_save_appointment() { @@ -263,15 +282,15 @@ class Backend_api extends CI_Controller { $this->load->model('settings_model'); $this->load->model('timezones_model'); - // :: SAVE CUSTOMER CHANGES TO DATABASE + // Save customer changes to the database. if ($this->input->post('customer_data')) { $customer = json_decode($this->input->post('customer_data'), TRUE); - $REQUIRED_PRIV = ( ! isset($customer['id'])) + $required_privilegesileges = ( ! isset($customer['id'])) ? $this->privileges[PRIV_CUSTOMERS]['add'] : $this->privileges[PRIV_CUSTOMERS]['edit']; - if ($REQUIRED_PRIV == FALSE) + if ($required_privilegesileges == FALSE) { throw new Exception('You do not have the required privileges for this task.'); } @@ -279,15 +298,15 @@ class Backend_api extends CI_Controller { $customer['id'] = $this->customers_model->add($customer); } - // :: SAVE APPOINTMENT CHANGES TO DATABASE + // Save appointment changes to the database. if ($this->input->post('appointment_data')) { $appointment = json_decode($this->input->post('appointment_data'), TRUE); - $REQUIRED_PRIV = ( ! isset($appointment['id'])) + $required_privilegesileges = ( ! isset($appointment['id'])) ? $this->privileges[PRIV_APPOINTMENTS]['add'] : $this->privileges[PRIV_APPOINTMENTS]['edit']; - if ($REQUIRED_PRIV == FALSE) + if ($required_privilegesileges == FALSE) { throw new Exception('You do not have the required privileges for this task.'); } @@ -326,7 +345,7 @@ class Backend_api extends CI_Controller { 'time_format' => $this->settings_model->get_setting('time_format') ]; - // :: SYNC APPOINTMENT CHANGES WITH GOOGLE CALENDAR + // Sync appointment changes with Google Calendar. try { $google_sync = $this->providers_model->get_setting('google_sync', @@ -354,32 +373,35 @@ class Backend_api extends CI_Controller { } } } - catch (Exception $exc) + catch (Exception $exception) { - $warnings[] = exceptionToJavaScript($exc); + $warnings[] = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } - // :: SEND EMAIL NOTIFICATIONS TO PROVIDER AND CUSTOMER + // Send email notifications to provider and customer. try { $this->config->load('email'); - $email = new \EA\Engine\Notifications\Email($this, $this->config->config); + $email = new EmailClient($this, $this->config->config); $send_provider = $this->providers_model ->get_setting('notifications', $provider['id']); if ( ! $manage_mode) { - $customer_title = new Text($this->lang->line('appointment_booked')); - $customer_message = new Text($this->lang->line('thank_you_for_appointment')); - $provider_title = new Text($this->lang->line('appointment_added_to_your_plan')); - $provider_message = new Text($this->lang->line('appointment_link_description')); + $customer_title = new Text(lang('appointment_booked')); + $customer_message = new Text(lang('thank_you_for_appointment')); + $provider_title = new Text(lang('appointment_added_to_your_plan')); + $provider_message = new Text(lang('appointment_link_description')); } else { - $customer_title = new Text($this->lang->line('appointment_details_changed')); + $customer_title = new Text(lang('appointment_details_changed')); $customer_message = new Text(''); - $provider_title = new Text($this->lang->line('appointment_changes_saved')); + $provider_title = new Text(lang('appointment_changes_saved')); $provider_message = new Text(''); } @@ -406,42 +428,44 @@ class Backend_api extends CI_Controller { } } - catch (Exception $exc) + catch (Exception $exception) { - $warnings[] = exceptionToJavaScript($exc); + $warnings[] = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } - if ( ! isset($warnings)) + if (empty($warnings)) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_SUCCESS)); + $response = AJAX_SUCCESS; } else { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['warnings' => $warnings])); + $response = ['warnings' => $warnings]; } } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Delete appointment from the database. + * Delete appointment from the database. * * This method deletes an existing appointment from the database. Once this action is finished it cannot be undone. * Notification emails are send to both provider and customer and the delete action is executed to the Google * Calendar account of the provider, if the "google_sync" setting is enabled. - * - * Required POST Parameters: - * - * - int $_POST['appointment_id'] The appointment id to be deleted. */ public function ajax_delete_appointment() { @@ -457,7 +481,7 @@ class Backend_api extends CI_Controller { throw new Exception('No appointment id provided.'); } - // :: STORE APPOINTMENT DATA FOR LATER USE IN THIS METHOD + // Store appointment data for later use in this method. $this->load->model('appointments_model'); $this->load->model('providers_model'); $this->load->model('customers_model'); @@ -477,10 +501,10 @@ class Backend_api extends CI_Controller { 'time_format' => $this->settings_model->get_setting('time_format') ]; - // :: DELETE APPOINTMENT RECORD FROM DATABASE + // Delete appointment record from the database. $this->appointments_model->delete($this->input->post('appointment_id')); - // :: SYNC DELETE WITH GOOGLE CALENDAR + // Sync removal with Google Calendar. if ($appointment['id_google_calendar'] != NULL) { try @@ -496,17 +520,21 @@ class Backend_api extends CI_Controller { $this->google_sync->delete_appointment($provider, $appointment['id_google_calendar']); } } - catch (Exception $exc) + catch (Exception $exception) { - $warnings[] = exceptionToJavaScript($exc); + $warnings[] = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } } - // :: SEND NOTIFICATION EMAILS TO PROVIDER AND CUSTOMER + // Send notification emails to provider and customer. try { $this->config->load('email'); - $email = new \EA\Engine\Notifications\Email($this, $this->config->config); + + $email = new EmailClient($this, $this->config->config); $send_provider = $this->providers_model ->get_setting('notifications', $provider['id']); @@ -527,42 +555,43 @@ class Backend_api extends CI_Controller { new Text($this->input->post('delete_reason'))); } } - catch (Exception $exc) + catch (Exception $exception) { - $warnings[] = exceptionToJavaScript($exc); + $warnings[] = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } - // :: SEND RESPONSE TO CLIENT BROWSER - if ( ! isset($warnings)) + if (empty($warnings)) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_SUCCESS)); + $response = AJAX_SUCCESS; } else { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['warnings' => $warnings])); + $response = ['warnings' => $warnings]; } } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Disable a providers sync setting. + * Disable a providers sync setting. * * This method deletes the "google_sync" and "google_token" settings from the database. After that the provider's * appointments will be no longer synced with google calendar. - * - * Required POST Parameters: - * - * - string $_POST['provider_id'] The selected provider record id. */ public function ajax_disable_provider_sync() { @@ -585,24 +614,25 @@ class Backend_api extends CI_Controller { $this->providers_model->set_setting('google_token', NULL, $this->input->post('provider_id')); $this->appointments_model->clear_google_sync_ids($this->input->post('provider_id')); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_SUCCESS)); + $response = AJAX_SUCCESS; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Filter the customer records with the given key string. - * - * Required POST Parameters: - * - * - string $_POST['key'] The filter key string. + * Filter the customer records with the given key string. * * Outputs the search results. */ @@ -658,24 +688,25 @@ class Backend_api extends CI_Controller { $customer['appointments'] = $appointments; } - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($customers)); + $response = $customers; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Insert of update unavailable time period to database. - * - * Required POST Parameters: - * - * - array $_POST['unavailable'] JSON encoded array that contains the unavailable period data. + * Insert of update unavailable time period to database. */ public function ajax_save_unavailable() { @@ -684,10 +715,10 @@ class Backend_api extends CI_Controller { // Check privileges $unavailable = json_decode($this->input->post('unavailable'), TRUE); - $REQUIRED_PRIV = ( ! isset($unavailable['id'])) + $required_privileges = ( ! isset($unavailable['id'])) ? $this->privileges[PRIV_APPOINTMENTS]['add'] : $this->privileges[PRIV_APPOINTMENTS]['edit']; - if ($REQUIRED_PRIV == FALSE) + if ($required_privileges == FALSE) { throw new Exception('You do not have the required privileges for this task.'); } @@ -723,13 +754,13 @@ class Backend_api extends CI_Controller { } else { - $google_event = $this->google_sync->update_unavailable($provider, $unavailable); + $this->google_sync->update_unavailable($provider, $unavailable); } } } - catch (Exception $exc) + catch (Exception $exception) { - $warnings[] = $exc; + $warnings[] = $exception; } if (isset($warnings)) @@ -746,20 +777,23 @@ class Backend_api extends CI_Controller { } } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Delete an unavailable time period from database. - * - * Required POST Parameters: - * - * - int $_POST['unavailable_id'] Record id to be deleted. + * Delete an unavailable time period from database. */ public function ajax_delete_unavailable() { @@ -791,39 +825,37 @@ class Backend_api extends CI_Controller { $this->google_sync->delete_unavailable($provider, $unavailable['id_google_calendar']); } } - catch (Exception $exc) + catch (Exception $exception) { - $warnings[] = $exc; + $warnings[] = $exception; } - if (isset($warnings)) + if (empty($warnings)) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['warnings' => $warnings])); + $response = AJAX_SUCCESS; } else { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_SUCCESS)); + $response = ['warnings' => $warnings]; } - } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Insert of update extra working plan time period to database. - * - * Required POST Parameters: - * - * - array $_POST['extra_period'] JSON encoded array that contains the unavailable period data. + * Insert of update extra working plan time period to database. */ public function ajax_save_extra_period() { @@ -832,10 +864,10 @@ class Backend_api extends CI_Controller { // Check privileges $extra_period = json_decode($this->input->post('extra_period'), TRUE); - $REQUIRED_PRIV = ( ! isset($extra_period['id'])) + $required_privileges = ( ! isset($extra_period['id'])) ? $this->privileges[PRIV_APPOINTMENTS]['add'] : $this->privileges[PRIV_APPOINTMENTS]['edit']; - if ($REQUIRED_PRIV == FALSE) + if ($required_privileges == FALSE) { throw new Exception('You do not have the required privileges for this task.'); } @@ -844,34 +876,32 @@ class Backend_api extends CI_Controller { $success = $this->providers_model->set_extra_working_day($extra_period, $extra_period['id_users_provider']); - if ( ! $success) + if ($success) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['warnings' => 'Error on saving extra period.'])); + $response = AJAX_SUCCESS; } else { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_SUCCESS)); + $response = ['warnings' => 'Error on saving extra period.']; } } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Delete an extra working plan time period to database. - * - * Required POST Parameters: - * - * - String $_POST['extra_period'] Date to be deleted. - * - int $_POST['provider_id'] Record id to be deleted. + * Delete an extra working plan time period to database. */ public function ajax_delete_extra_period() { @@ -891,34 +921,32 @@ class Backend_api extends CI_Controller { // Delete unavailable $success = $this->providers_model->delete_extra_working_day($extra_period, $provider_id); - if ( ! $success) + if ($success) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['warnings' => 'Error on deleting extra working day'])); + $response = AJAX_SUCCESS; } else { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_SUCCESS)); + $response = ['warnings' => 'Error on deleting extra period.']; } + } + catch (Exception $exception) + { + $this->output->set_status_header(500); - } // - catch (Exception $exc) // - { // - $this->output // - ->set_content_type('application/json') // - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); // - }// - } // + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; + } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); + } /** - * [AJAX] Save (insert or update) a customer record. - * - * Require POST Parameters: - * - * - array $_POST['customer'] JSON encoded array that contains the customer's data. + * Save (insert or update) a customer record. */ public function ajax_save_customer() { @@ -927,36 +955,38 @@ class Backend_api extends CI_Controller { $this->load->model('customers_model'); $customer = json_decode($this->input->post('customer'), TRUE); - $REQUIRED_PRIV = ( ! isset($customer['id'])) + $required_privilegesileges = ( ! isset($customer['id'])) ? $this->privileges[PRIV_CUSTOMERS]['add'] : $this->privileges[PRIV_CUSTOMERS]['edit']; - if ($REQUIRED_PRIV == FALSE) + if ($required_privilegesileges == FALSE) { throw new Exception('You do not have the required privileges for this task.'); } $customer_id = $this->customers_model->add($customer); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'status' => AJAX_SUCCESS, - 'id' => $customer_id - ])); + + $response = [ + 'status' => AJAX_SUCCESS, + 'id' => $customer_id + ]; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Delete customer from database. - * - * Required POST Parameters: - * - * - int $_POST['customer_id'] Customer record id to be deleted. + * Delete customer from database. */ public function ajax_delete_customer() { @@ -968,25 +998,28 @@ class Backend_api extends CI_Controller { } $this->load->model('customers_model'); + $this->customers_model->delete($this->input->post('customer_id')); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_SUCCESS)); + + $response = AJAX_SUCCESS; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Save (insert or update) service record. - * - * Required POST Parameters: - * - * - array $_POST['service'] Contains the service data (json encoded). + * Save (insert or update) service record. */ public function ajax_save_service() { @@ -995,36 +1028,37 @@ class Backend_api extends CI_Controller { $this->load->model('services_model'); $service = json_decode($this->input->post('service'), TRUE); - $REQUIRED_PRIV = ( ! isset($service['id'])) + $required_privilegesileges = ( ! isset($service['id'])) ? $this->privileges[PRIV_SERVICES]['add'] : $this->privileges[PRIV_SERVICES]['edit']; - if ($REQUIRED_PRIV == FALSE) + if ($required_privilegesileges == FALSE) { throw new Exception('You do not have the required privileges for this task.'); } $service_id = $this->services_model->add($service); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'status' => AJAX_SUCCESS, - 'id' => $service_id - ])); + $response = [ + 'status' => AJAX_SUCCESS, + 'id' => $service_id + ]; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Delete service record from database. - * - * Required POST Parameters: - * - * - int $_POST['service_id'] Record id to be deleted. + * Delete service record from database. */ public function ajax_delete_service() { @@ -1036,28 +1070,28 @@ class Backend_api extends CI_Controller { } $this->load->model('services_model'); + $result = $this->services_model->delete($this->input->post('service_id')); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($result ? AJAX_SUCCESS : AJAX_FAILURE)); + $response = $result ? AJAX_SUCCESS : AJAX_FAILURE; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Filter service records by given key string. - * - * Required POST Parameters: - * - * - string $_POST['key'] Key string used to filter the records. - * - * Outputs a JSON encoded array back to client. + * Filter service records by given key string. */ public function ajax_filter_services() { @@ -1069,31 +1103,33 @@ class Backend_api extends CI_Controller { } $this->load->model('services_model'); + $key = $this->db->escape_str($this->input->post('key')); + $where = '(name LIKE "%' . $key . '%" OR duration LIKE "%' . $key . '%" OR ' . 'price LIKE "%' . $key . '%" OR currency LIKE "%' . $key . '%" OR ' . 'description LIKE "%' . $key . '%")'; - $services = $this->services_model->get_batch($where); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($services)); + + $response = $this->services_model->get_batch($where); } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Save (insert or update) category record. - * - * Required POST Parameters: - * - * - array $_POST['category'] Json encoded array with the category data. If an ID value is provided then the - * category is going to be updated instead of inserted. + * Save (insert or update) category record. */ public function ajax_save_service_category() { @@ -1102,35 +1138,38 @@ class Backend_api extends CI_Controller { $this->load->model('services_model'); $category = json_decode($this->input->post('category'), TRUE); - $REQUIRED_PRIV = ( ! isset($category['id'])) + $required_privilegesileges = ( ! isset($category['id'])) ? $this->privileges[PRIV_SERVICES]['add'] : $this->privileges[PRIV_SERVICES]['edit']; - if ($REQUIRED_PRIV == FALSE) + if ($required_privilegesileges == FALSE) { throw new Exception('You do not have the required privileges for this task.'); } $category_id = $this->services_model->add_category($category); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'status' => AJAX_SUCCESS, - 'id' => $category_id - ])); + $response = [ + 'status' => AJAX_SUCCESS, + 'id' => $category_id + ]; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Delete category record from database. - * - * - int $_POST['category_id'] Record id to be deleted. + * Delete category record from database. */ public function ajax_delete_service_category() { @@ -1142,28 +1181,28 @@ class Backend_api extends CI_Controller { } $this->load->model('services_model'); + $result = $this->services_model->delete_category($this->input->post('category_id')); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($result ? AJAX_SUCCESS : AJAX_FAILURE)); + $response = $result ? AJAX_SUCCESS : AJAX_FAILURE; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Filter services categories with key string. - * - * Required POST Parameters: - * - * - string $_POST['key'] The key string used to filter the records. - * - * Outputs a JSON encoded array back to client with the category records. + * Filter services categories with key string. */ public function ajax_filter_service_categories() { @@ -1175,29 +1214,30 @@ class Backend_api extends CI_Controller { } $this->load->model('services_model'); + $key = $this->db->escape_str($this->input->post('key')); + $where = '(name LIKE "%' . $key . '%" OR description LIKE "%' . $key . '%")'; - $categories = $this->services_model->get_all_categories($where); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($categories)); + + $response = $this->services_model->get_all_categories($where); } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Filter admin records with string key. - * - * Required POST Parameters: - * - * - string $_POST['key'] The key string used to filter the records. - * - * Outputs a JSON encoded array back to client with the admin records. + * Filter admin records with string key. */ public function ajax_filter_admins() { @@ -1209,35 +1249,35 @@ class Backend_api extends CI_Controller { } $this->load->model('admins_model'); + $key = $this->db->escape_str($this->input->post('key')); + $where = '(first_name LIKE "%' . $key . '%" OR last_name LIKE "%' . $key . '%" ' . 'OR email LIKE "%' . $key . '%" OR mobile_number LIKE "%' . $key . '%" ' . 'OR phone_number LIKE "%' . $key . '%" OR address LIKE "%' . $key . '%" ' . 'OR city LIKE "%' . $key . '%" OR state LIKE "%' . $key . '%" ' . 'OR zip_code LIKE "%' . $key . '%" OR notes LIKE "%' . $key . '%")'; - $admins = $this->admins_model->get_batch($where); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($admins)); + + $response = $this->admins_model->get_batch($where); } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Save (insert or update) admin record into database. - * - * Required POST Parameters: - * - * - array $_POST['admin'] A json encoded array that contains the admin data. If an 'id' - * value is provided then the record is going to be updated. - * - * Outputs an array with the operation status and the record id that was saved into the database. + * Save (insert or update) admin record into database. */ public function ajax_save_admin() { @@ -1246,10 +1286,10 @@ class Backend_api extends CI_Controller { $this->load->model('admins_model'); $admin = json_decode($this->input->post('admin'), TRUE); - $REQUIRED_PRIV = ( ! isset($admin['id'])) + $required_privileges = ( ! isset($admin['id'])) ? $this->privileges[PRIV_USERS]['add'] : $this->privileges[PRIV_USERS]['edit']; - if ($REQUIRED_PRIV == FALSE) + if ($required_privileges == FALSE) { throw new Exception('You do not have the required privileges for this task.'); } @@ -1260,27 +1300,24 @@ class Backend_api extends CI_Controller { 'status' => AJAX_SUCCESS, 'id' => $admin_id ]; - - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($response)); } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Delete an admin record from the database. - * - * Required POST Parameters: - * - * - int $_POST['admin_id'] The id of the record to be deleted. - * - * Outputs the operation result constant (AJAX_SUCCESS or AJAX_FAILURE). + * Delete an admin record from the database. */ public function ajax_delete_admin() { @@ -1292,27 +1329,28 @@ class Backend_api extends CI_Controller { } $this->load->model('admins_model'); + $result = $this->admins_model->delete($this->input->post('admin_id')); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($result ? AJAX_SUCCESS : AJAX_FAILURE)); + + $response = $result ? AJAX_SUCCESS : AJAX_FAILURE; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Filter provider records with string key. - * - * Required POST Parameters: - * - * - string $_POST['key'] The key string used to filter the records. - * - * Outputs a JSON encoded array back to client with the provider records. + * Filter provider records with string key. */ public function ajax_filter_providers() { @@ -1324,35 +1362,35 @@ class Backend_api extends CI_Controller { } $this->load->model('providers_model'); + $key = $this->db->escape_str($this->input->post('key')); + $where = '(first_name LIKE "%' . $key . '%" OR last_name LIKE "%' . $key . '%" ' . 'OR email LIKE "%' . $key . '%" OR mobile_number LIKE "%' . $key . '%" ' . 'OR phone_number LIKE "%' . $key . '%" OR address LIKE "%' . $key . '%" ' . 'OR city LIKE "%' . $key . '%" OR state LIKE "%' . $key . '%" ' . 'OR zip_code LIKE "%' . $key . '%" OR notes LIKE "%' . $key . '%")'; - $providers = $this->providers_model->get_batch($where); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($providers)); + + $response = $this->providers_model->get_batch($where); } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Save (insert or update) a provider record into database. - * - * Required POST Parameters: - * - * - array $_POST['provider'] A json encoded array that contains the provider data. If an 'id' - * value is provided then the record is going to be updated. - * - * Outputs the success constant 'AJAX_SUCCESS' so javascript knows that everything completed successfully. + * Save (insert or update) a provider record into database. */ public function ajax_save_provider() { @@ -1361,10 +1399,10 @@ class Backend_api extends CI_Controller { $this->load->model('providers_model'); $provider = json_decode($this->input->post('provider'), TRUE); - $REQUIRED_PRIV = ( ! isset($provider['id'])) + $required_privileges = ( ! isset($provider['id'])) ? $this->privileges[PRIV_USERS]['add'] : $this->privileges[PRIV_USERS]['edit']; - if ($REQUIRED_PRIV == FALSE) + if ($required_privileges == FALSE) { throw new Exception('You do not have the required privileges for this task.'); } @@ -1378,30 +1416,28 @@ class Backend_api extends CI_Controller { $provider_id = $this->providers_model->add($provider); - - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'status' => AJAX_SUCCESS, - 'id' => $provider_id - ])); + $response = [ + 'status' => AJAX_SUCCESS, + 'id' => $provider_id + ]; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Delete a provider record from the database. - * - * Required POST Parameters: - * - * - int $_POST['provider_id'] The id of the record to be deleted. - * - * Outputs the operation result constant (AJAX_SUCCESS or AJAX_FAILURE). + * Delete a provider record from the database. */ public function ajax_delete_provider() { @@ -1413,27 +1449,28 @@ class Backend_api extends CI_Controller { } $this->load->model('providers_model'); + $result = $this->providers_model->delete($this->input->post('provider_id')); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($result ? AJAX_SUCCESS : AJAX_FAILURE)); + + $response =$result ? AJAX_SUCCESS : AJAX_FAILURE; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Filter secretary records with string key. - * - * Required POST Parameters: - * - * - string $_POST['key'] The key string used to filter the records. - * - * Outputs a JSON encoded array back to client with the secretary records. + * Filter secretary records with string key. */ public function ajax_filter_secretaries() { @@ -1445,35 +1482,35 @@ class Backend_api extends CI_Controller { } $this->load->model('secretaries_model'); + $key = $this->db->escape_str($this->input->post('key')); + $where = '(first_name LIKE "%' . $key . '%" OR last_name LIKE "%' . $key . '%" ' . 'OR email LIKE "%' . $key . '%" OR mobile_number LIKE "%' . $key . '%" ' . 'OR phone_number LIKE "%' . $key . '%" OR address LIKE "%' . $key . '%" ' . 'OR city LIKE "%' . $key . '%" OR state LIKE "%' . $key . '%" ' . 'OR zip_code LIKE "%' . $key . '%" OR notes LIKE "%' . $key . '%")'; - $secretaries = $this->secretaries_model->get_batch($where); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($secretaries)); + + $response = $this->secretaries_model->get_batch($where); } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Save (insert or update) a secretary record into database. - * - * Required POST Parameters: - * - * - array $_POST['secretary'] A json encoded array that contains the secretary data. - * If an 'id' value is provided then the record is going to be updated. - * - * Outputs the success constant 'AJAX_SUCCESS' so JavaScript knows that everything completed successfully. + * Save (insert or update) a secretary record into database. */ public function ajax_save_secretary() { @@ -1482,39 +1519,38 @@ class Backend_api extends CI_Controller { $this->load->model('secretaries_model'); $secretary = json_decode($this->input->post('secretary'), TRUE); - $REQUIRED_PRIV = ( ! isset($secretary['id'])) + $required_privileges = ( ! isset($secretary['id'])) ? $this->privileges[PRIV_USERS]['add'] : $this->privileges[PRIV_USERS]['edit']; - if ($REQUIRED_PRIV == FALSE) + if ($required_privileges == FALSE) { throw new Exception('You do not have the required privileges for this task.'); } $secretary_id = $this->secretaries_model->add($secretary); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'status' => AJAX_SUCCESS, - 'id' => $secretary_id - ])); + $response =[ + 'status' => AJAX_SUCCESS, + 'id' => $secretary_id + ]; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Delete a secretary record from the database. - * - * Required POST Parameters: - * - * - int $_POST['secretary_id'] The id of the record to be deleted. - * - * Outputs the operation result constant (AJAX_SUCCESS or AJAX_FAILURE). + * Delete a secretary record from the database. */ public function ajax_delete_secretary() { @@ -1526,30 +1562,28 @@ class Backend_api extends CI_Controller { } $this->load->model('secretaries_model'); + $result = $this->secretaries_model->delete($this->input->post('secretary_id')); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($result ? AJAX_SUCCESS : AJAX_FAILURE)); + $response =$result ? AJAX_SUCCESS : AJAX_FAILURE; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Save a setting or multiple settings in the database. - * - * This method is used to store settings in the database. It can be either system or user settings, one or many. - * Use the $_POST variables accordingly. - * - * Required POST Parameters: - * - * - array $_POST['settings'] Contains an array with settings. - * - bool $_POST['type'] Determines the settings type, can be either SETTINGS_SYSTEM or SETTINGS_USER. + * Save a setting or multiple settings in the database. */ public function ajax_save_settings() { @@ -1561,8 +1595,11 @@ class Backend_api extends CI_Controller { { throw new Exception('You do not have the required privileges for this task.'); } + $this->load->model('settings_model'); + $settings = json_decode($this->input->post('settings'), TRUE); + $this->settings_model->save_settings($settings); } else @@ -1573,60 +1610,66 @@ class Backend_api extends CI_Controller { { throw new Exception('You do not have the required privileges for this task.'); } + $this->load->model('user_model'); - $this->user_model->save_settings(json_decode($this->input->post('settings'), TRUE)); + + $this->user_model->save_user(json_decode($this->input->post('settings'), TRUE)); } } - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_SUCCESS)); + $response = AJAX_SUCCESS; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] This method checks whether the username already exists in the database. - * - * Required POST Parameters: - * - * - string $_POST['username'] Record's username to validate. - * - bool $_POST['record_exists'] Whether the record already exists in database. + * This method checks whether the username already exists in the database. */ public function ajax_validate_username() { try { - // We will only use the function in the admins_model because it is sufficient - // for the rest user types for now (providers, secretaries). + // We will only 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($this->input->post('username'), $this->input->post('user_id')); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($is_valid)); + + $response = $is_valid; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** - * [AJAX] Change system language for current user. + * Change system language for current user. * * The language setting is stored in session data and retrieved every time the user visits any of the system pages. - * - * Required POST Parameters: - * - * - string $_POST['language'] Selected language name. */ public function ajax_change_language() { @@ -1634,6 +1677,7 @@ class Backend_api extends CI_Controller { { // Check if language exists in the available languages. $found = FALSE; + foreach ($this->config->item('available_languages') as $lang) { if ($lang == $this->input->post('language')) @@ -1651,17 +1695,21 @@ class Backend_api extends CI_Controller { $this->session->set_userdata('language', $this->input->post('language')); $this->config->set_item('language', $this->input->post('language')); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_SUCCESS)); - + $response = AJAX_SUCCESS; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** @@ -1669,10 +1717,6 @@ class Backend_api extends CI_Controller { * * The user will need to select a specific calendar from this list to sync his appointments with. Google access must * be already granted for the specific provider. - * - * Required POST Parameters: - * - * - string $_POST['provider_id'] Provider record id. */ public function ajax_get_google_calendars() { @@ -1688,40 +1732,41 @@ class Backend_api extends CI_Controller { // Check if selected provider has sync enabled. $google_sync = $this->providers_model->get_setting('google_sync', $this->input->post('provider_id')); + if ($google_sync) { $google_token = json_decode($this->providers_model->get_setting('google_token', $this->input->post('provider_id'))); $this->google_sync->refresh_token($google_token->refresh_token); + $calendars = $this->google_sync->get_google_calendars(); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($calendars)); + + $response = $calendars; } else { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_FAILURE)); + $response =AJAX_FAILURE; } } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** * Select a specific google calendar for a provider. * * All the appointments will be synced with this particular calendar. - * - * Required POST Parameters: - * - * - int $_POST['provider_id'] Provider record id. - * - string $_POST['calendar_id'] Google calendar's id. */ public function ajax_select_google_calendar() { @@ -1734,19 +1779,25 @@ class Backend_api extends CI_Controller { } $this->load->model('providers_model'); + $result = $this->providers_model->set_setting('google_calendar', $this->input->post('calendar_id'), $this->input->post('provider_id')); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($result ? AJAX_SUCCESS : AJAX_FAILURE)); + $response = $result ? AJAX_SUCCESS : AJAX_FAILURE; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** @@ -1772,14 +1823,20 @@ class Backend_api extends CI_Controller { $this->providers_model->set_setting('working_plan', $working_plan, $provider['id']); } - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_SUCCESS)); - } catch (Exception $exc) - { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $response =AJAX_SUCCESS; } + catch (Exception $exception) + { + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; + } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } } diff --git a/application/controllers/Captcha.php b/application/controllers/Captcha.php index 8c4d5db8..634f6d95 100644 --- a/application/controllers/Captcha.php +++ b/application/controllers/Captcha.php @@ -1,4 +1,4 @@ -input->post('consent'); - $this->load->model('consents_model'); + $consent = $this->input->post('consent'); + $consent['ip'] = $this->input->ip_address(); $consent['id'] = $this->consents_model->add($consent); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'success' => TRUE, - 'id' => $consent['id'] - ])); + $response = [ + 'success' => TRUE, + 'id' => $consent['id'] + ]; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'exceptions' => [exceptionToJavaScript($exc)] - ])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } } diff --git a/application/controllers/Errors.php b/application/controllers/Errors.php index d0f4d583..a831a993 100644 --- a/application/controllers/Errors.php +++ b/application/controllers/Errors.php @@ -1,4 +1,4 @@ -load->library('session'); - // Set user's selected language. if ($this->session->userdata('language')) { + // Set user's selected language. $this->config->set_item('language', $this->session->userdata('language')); $this->lang->load('translations', $this->session->userdata('language')); } else { - $this->lang->load('translations', $this->config->item('language')); // default + // Set the default language. + $this->lang->load('translations', $this->config->item('language')); } } @@ -43,7 +66,7 @@ class Errors extends CI_Controller { */ public function index() { - $this->e404(); + $this->error404(); } /** @@ -53,7 +76,9 @@ class Errors extends CI_Controller { { $this->load->helper('google_analytics'); $this->load->model('settings_model'); + $view['company_name'] = $this->settings_model->get_setting('company_name'); + $this->load->view('general/error404', $view); } } diff --git a/application/controllers/Google.php b/application/controllers/Google.php index df19e76a..7f589f40 100644 --- a/application/controllers/Google.php +++ b/application/controllers/Google.php @@ -1,4 +1,4 @@ -session->set_userdata('oauth_provider_id', $provider_id); // Redirect browser to google user content page. - $this->load->library('Google_sync'); + $this->load->library('google_sync'); header('Location: ' . $this->google_sync->get_auth_url()); } @@ -55,7 +77,7 @@ class Google extends CI_Controller { * * IMPORTANT: Because it is necessary to authorize the application using the web server flow (see official * documentation of OAuth), every Easy!Appointments installation should use its own calendar api key. So in every - * api console account, the "http://path-to-e!a/google/oauth_callback" should be included in an allowed redirect URL. + * api console account, the "http://path-to-Easy!Appointments/google/oauth_callback" should be included in an allowed redirect URL. */ public function oauth_callback() { @@ -65,12 +87,14 @@ class Google extends CI_Controller { $token = $this->google_sync->authenticate($this->input->get('code')); // Store the token into the database for future reference. - if (isset($_SESSION['oauth_provider_id'])) + $oauth_provider_id = $this->session->userdata('oauth_provider_id'); + + if ($oauth_provider_id) { $this->load->model('providers_model'); - $this->providers_model->set_setting('google_sync', TRUE, $_SESSION['oauth_provider_id']); - $this->providers_model->set_setting('google_token', $token, $_SESSION['oauth_provider_id']); - $this->providers_model->set_setting('google_calendar', 'primary', $_SESSION['oauth_provider_id']); + $this->providers_model->set_setting('google_sync', TRUE, $oauth_provider_id); + $this->providers_model->set_setting('google_token', $token, $oauth_provider_id); + $this->providers_model->set_setting('google_calendar', 'primary', $oauth_provider_id); } else { @@ -149,7 +173,7 @@ class Google extends CI_Controller { 'company_email' => $this->settings_model->get_setting('company_email') ]; - $provider_timezone = new \DateTimeZone($provider['timezone']); + $provider_timezone = new DateTimeZone($provider['timezone']); // Sync each appointment with Google Calendar by following the project's sync protocol (see documentation). foreach ($appointments as $appointment) @@ -165,13 +189,13 @@ class Google extends CI_Controller { $customer = NULL; } - // If current appointment not synced yet, add to gcal. + // If current appointment not synced yet, add to Google Calendar. if ($appointment['id_google_calendar'] == NULL) { $google_event = $this->google_sync->add_appointment($appointment, $provider, $service, $customer, $company_settings); $appointment['id_google_calendar'] = $google_event->id; - $this->appointments_model->add($appointment); // Save gcal id + $this->appointments_model->add($appointment); // Save the Google Calendar ID. } else { @@ -185,13 +209,14 @@ class Google extends CI_Controller { throw new Exception('Event is cancelled, remove the record from Easy!Appointments.'); } - // If gcal event is different from e!a appointment then update e!a record. + // If Google Calendar event is different from Easy!Appointments appointment then update + // Easy!Appointments record. $is_different = FALSE; $appt_start = strtotime($appointment['start_datetime']); $appt_end = strtotime($appointment['end_datetime']); - $event_start = new \DateTime($google_event->getStart()->getDateTime()); + $event_start = new DateTime($google_event->getStart()->getDateTime()); $event_start->setTimezone($provider_timezone); - $event_end = new \DateTime($google_event->getEnd()->getDateTime()); + $event_end = new DateTime($google_event->getEnd()->getDateTime()); $event_end->setTimezone($provider_timezone); @@ -210,49 +235,52 @@ class Google extends CI_Controller { } } - catch (Exception $exc) + catch (Exception $exception) { - // Appointment not found on gcal, delete from e!a. + // Appointment not found on Google Calendar, delete from Easy!Appoinmtents. $this->appointments_model->delete($appointment['id']); $appointment['id_google_calendar'] = NULL; } } } - // :: ADD GCAL EVENTS THAT ARE NOT PRESENT ON E!A + // Add Google Calendar events that do not exist in Easy!Appointments. $google_calendar = $provider['settings']['google_calendar']; - $events = $this->google_sync->get_sync_events($google_calendar, $start, $end); + $google_events = $this->google_sync->get_sync_events($google_calendar, $start, $end); - foreach ($events->getItems() as $event) + foreach ($google_events->getItems() as $google_event) { - if ($event->getStatus() === 'cancelled') { + if ($google_event->getStatus() === 'cancelled') + { continue; } - if ($event->getStart() === null || $event->getEnd() === null) { + if ($google_event->getStart() === NULL || $google_event->getEnd() === NULL) + { continue; } - $results = $this->appointments_model->get_batch(['id_google_calendar' => $event->getId()]); + $results = $this->appointments_model->get_batch(['id_google_calendar' => $google_event->getId()]); - if (!empty($results)) { + if ( ! empty($results)) + { continue; } - $event_start = new \DateTime($event->getStart()->getDateTime()); + $event_start = new DateTime($google_event->getStart()->getDateTime()); $event_start->setTimezone($provider_timezone); - $event_end = new \DateTime($event->getEnd()->getDateTime()); + $event_end = new DateTime($google_event->getEnd()->getDateTime()); $event_end->setTimezone($provider_timezone); - // Record doesn't exist in E!A, so add the event now. + // Record doesn't exist in the Easy!Appointments, so add the event now. $appointment = [ 'start_datetime' => $event_start->format('Y-m-d H:i:s'), 'end_datetime' => $event_end->format('Y-m-d H:i:s'), 'is_unavailable' => TRUE, - 'location' => $event->getLocation(), - 'notes' => $event->getSummary() . ' ' . $event->getDescription(), + 'location' => $google_event->getLocation(), + 'notes' => $google_event->getSummary() . ' ' . $google_event->getDescription(), 'id_users_provider' => $provider_id, - 'id_google_calendar' => $event->getId(), + 'id_google_calendar' => $google_event->getId(), 'id_users_customer' => NULL, 'id_services' => NULL, ]; @@ -260,15 +288,20 @@ class Google extends CI_Controller { $this->appointments_model->add($appointment); } - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_SUCCESS)); + $response = AJAX_SUCCESS; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } } diff --git a/application/controllers/Installation.php b/application/controllers/Installation.php index 20ec62e1..b6f79c69 100644 --- a/application/controllers/Installation.php +++ b/application/controllers/Installation.php @@ -1,4 +1,4 @@ -load->helper('installation'); $this->load->library('session'); - // Set user's selected language. if ($this->session->userdata('language')) { + // Set user's selected language. $this->config->set_item('language', $this->session->userdata('language')); $this->lang->load('translations', $this->session->userdata('language')); } else { - $this->lang->load('translations', $this->config->item('language')); // default + // Set the default language. + $this->lang->load('translations', $this->config->item('language')); } } @@ -58,11 +82,6 @@ class Installation extends CI_Controller { /** * [AJAX] Installs Easy!Appointments on the server. - * - * Required POST Parameters - * - * - array $_POST['admin'] Contains the initial admin user data. The App needs at least one admin user to work. - * - array $_POST['company'] Contains the basic company data. */ public function ajax_install() { @@ -73,7 +92,17 @@ class Installation extends CI_Controller { return; } - // Create E!A database structure. + $this->load->model('admins_model'); + $this->load->model('settings_model'); + $this->load->model('services_model'); + $this->load->model('providers_model'); + $this->load->library('session'); + + $admin = $this->input->post('admin'); + $company = $this->input->post('company'); + + + // Create the Easy!Appointments database structure. $file_contents = file_get_contents(__DIR__ . '/../../assets/sql/structure.sql'); $sql_queries = explode(';', $file_contents); array_pop($sql_queries); @@ -82,7 +111,7 @@ class Installation extends CI_Controller { $this->db->query($query); } - // Insert default E!A entries into the database. + // Insert default Easy!Appointments entries into the database. $file_contents = file_get_contents(__DIR__ . '/../../assets/sql/data.sql'); $sql_queries = explode(';', $file_contents); array_pop($sql_queries); @@ -92,47 +121,43 @@ class Installation extends CI_Controller { } // Insert admin - $this->load->model('admins_model'); - $admin = $this->input->post('admin'); $admin['settings']['username'] = $admin['username']; $admin['settings']['password'] = $admin['password']; $admin['settings']['calendar_view'] = CALENDAR_VIEW_DEFAULT; unset($admin['username'], $admin['password']); $admin['id'] = $this->admins_model->add($admin); - $this->load->library('session'); $this->session->set_userdata('user_id', $admin['id']); $this->session->set_userdata('user_email', $admin['email']); $this->session->set_userdata('role_slug', DB_SLUG_ADMIN); $this->session->set_userdata('username', $admin['settings']['username']); // Save company settings - $this->load->model('settings_model'); - $company = $this->input->post('company'); $this->settings_model->set_setting('company_name', $company['company_name']); $this->settings_model->set_setting('company_email', $company['company_email']); $this->settings_model->set_setting('company_link', $company['company_link']); // Create sample records. - $this->load->model('services_model'); - $this->load->model('providers_model'); - $sample_service = get_sample_service(); $sample_service['id'] = $this->services_model->add($sample_service); $sample_provider = get_sample_provider(); $sample_provider['services'][] = $sample_service['id']; $this->providers_model->add($sample_provider); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_SUCCESS)); - + $response = AJAX_SUCCESS; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } } diff --git a/application/controllers/Privacy.php b/application/controllers/Privacy.php index 7a30b5d8..8d54b72d 100644 --- a/application/controllers/Privacy.php +++ b/application/controllers/Privacy.php @@ -1,4 +1,4 @@ -load->model('customers_model'); $this->customers_model->delete($customer_id); - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'success' => TRUE - ])); + $response = [ + 'success' => TRUE + ]; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode([ - 'exceptions' => [exceptionToJavaScript($exc)] - ])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } } diff --git a/application/controllers/User.php b/application/controllers/User.php index b56c151b..e2d07c88 100644 --- a/application/controllers/User.php +++ b/application/controllers/User.php @@ -1,4 +1,4 @@ -load->library('session'); - // Set user's selected language. if ($this->session->userdata('language')) { + // Set user's selected language. $this->config->set_item('language', $this->session->userdata('language')); $this->lang->load('translations', $this->session->userdata('language')); } else { + // Set the default language. $this->lang->load('translations', $this->config->item('language')); // default } } @@ -52,6 +77,8 @@ class User extends CI_Controller { /** * Display the login page. + * + * @throws Exception */ public function login() { @@ -66,6 +93,7 @@ class User extends CI_Controller { } $view['company_name'] = $this->settings_model->get_setting('company_name'); + $this->load->view('user/login', $view); } @@ -89,6 +117,7 @@ class User extends CI_Controller { /** * Display the "forgot password" page. + * @throws Exception */ public function forgot_password() { @@ -100,6 +129,7 @@ class User extends CI_Controller { /** * Display the "not authorized" page. + * @throws Exception */ public function no_privileges() { @@ -128,29 +158,33 @@ class User extends CI_Controller { } $this->load->model('user_model'); + $user_data = $this->user_model->check_login($this->input->post('username'), $this->input->post('password')); if ($user_data) { $this->session->set_userdata($user_data); // Save data on user's session. - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_SUCCESS)); + + $response = AJAX_SUCCESS; } else { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(AJAX_FAILURE)); + $response = AJAX_FAILURE; } - } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } /** @@ -175,13 +209,17 @@ class User extends CI_Controller { $this->load->model('user_model'); $this->load->model('settings_model'); - $new_password = $this->user_model->regenerate_password($this->input->post('username'), - $this->input->post('email')); + $new_password = $this->user_model->regenerate_password( + $this->input->post('username'), + $this->input->post('email') + ); if ($new_password != FALSE) { $this->config->load('email'); - $email = new \EA\Engine\Notifications\Email($this, $this->config->config); + + $email = new EmailClient($this, $this->config->config); + $company_settings = [ 'company_name' => $this->settings_model->get_setting('company_name'), 'company_link' => $this->settings_model->get_setting('company_link'), @@ -192,15 +230,20 @@ class User extends CI_Controller { $company_settings); } - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($new_password != FALSE ? AJAX_SUCCESS : AJAX_FAILURE)); + $response = $new_password != FALSE ? AJAX_SUCCESS : AJAX_FAILURE; } - catch (Exception $exc) + catch (Exception $exception) { - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(['exceptions' => [exceptionToJavaScript($exc)]])); + $this->output->set_status_header(500); + + $response = [ + 'message' => $exception->getMessage(), + 'trace' => config('debug') ? $exception->getTrace() : [] + ]; } + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode($response)); } } diff --git a/application/controllers/api/v1/API_V1_Controller.php b/application/controllers/api/v1/API_V1_Controller.php index c92a47ea..103c0f81 100644 --- a/application/controllers/api/v1/API_V1_Controller.php +++ b/application/controllers/api/v1/API_V1_Controller.php @@ -1,4 +1,4 @@ -settings_model->get_setting('api_token'); - $authorization = new \EA\Engine\Api\V1\Authorization($this); + $authorization = new Authorization($this); if ( ! empty($api_token) && $api_token === $this->_getBearerToken()) { @@ -59,7 +60,8 @@ class API_V1_Controller extends CI_Controller { $username = new NonEmptyText($_SERVER['PHP_AUTH_USER']); $password = new NonEmptyText($_SERVER['PHP_AUTH_PW']); $authorization->basic($username, $password); - } catch (\Exception $exception) + } + catch (Exception $exception) { exit($this->_handleException($exception)); } @@ -96,13 +98,15 @@ class API_V1_Controller extends CI_Controller { if (isset($_SERVER['Authorization'])) { $headers = trim($_SERVER['Authorization']); - } else + } + else { if (isset($_SERVER['HTTP_AUTHORIZATION'])) { //Nginx or fast CGI $headers = trim($_SERVER['HTTP_AUTHORIZATION']); - } elseif (function_exists('apache_request_headers')) + } + elseif (function_exists('apache_request_headers')) { $requestHeaders = apache_request_headers(); // Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization) @@ -132,9 +136,9 @@ class API_V1_Controller extends CI_Controller { * * Call this method from catch blocks of child controller callbacks. * - * @param \Exception $exception Thrown exception to be outputted. + * @param Exception $exception Thrown exception to be outputted. */ - protected function _handleException(\Exception $exception) + protected function _handleException(Exception $exception) { $error = [ 'code' => $exception->getCode() ?: 500, diff --git a/application/controllers/api/v1/Admins.php b/application/controllers/api/v1/Admins.php index 90dc8c18..d33985b9 100644 --- a/application/controllers/api/v1/Admins.php +++ b/application/controllers/api/v1/Admins.php @@ -1,4 +1,4 @@ -output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -82,7 +104,7 @@ class Admins extends API_V1_Controller { { try { - // Insert the admin to the database. + // Insert the admin to the database. $request = new Request(); $admin = $request->getBody(); $this->parser->decode($admin); @@ -100,7 +122,7 @@ class Admins extends API_V1_Controller { $status = new NonEmptyText('201 Created'); $response->encode($this->parser)->singleEntry(TRUE)->output($status); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -115,7 +137,7 @@ class Admins extends API_V1_Controller { { try { - // Update the admin record. + // Update the admin record. $batch = $this->admins_model->get_batch('id = ' . $id); if ($id !== NULL && count($batch) === 0) @@ -135,7 +157,7 @@ class Admins extends API_V1_Controller { $response = new Response($batch); $response->encode($this->parser)->singleEntry($id)->output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -159,7 +181,7 @@ class Admins extends API_V1_Controller { $response->output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } diff --git a/application/controllers/api/v1/Appointments.php b/application/controllers/api/v1/Appointments.php index 81664a5c..c2f0fa54 100644 --- a/application/controllers/api/v1/Appointments.php +++ b/application/controllers/api/v1/Appointments.php @@ -1,4 +1,4 @@ -output(); } - catch (\Exception $exception) + catch (Exception $exception) { exit($this->_handleException($exception)); } @@ -108,7 +130,7 @@ class Appointments extends API_V1_Controller { $status = new NonEmptyText('201 Created'); $response->encode($this->parser)->singleEntry(TRUE)->output($status); } - catch (\Exception $exception) + catch (Exception $exception) { exit($this->_handleException($exception)); } @@ -143,7 +165,7 @@ class Appointments extends API_V1_Controller { $response = new Response($batch); $response->encode($this->parser)->singleEntry($id)->output(); } - catch (\Exception $exception) + catch (Exception $exception) { exit($this->_handleException($exception)); } @@ -167,7 +189,7 @@ class Appointments extends API_V1_Controller { $response->output(); } - catch (\Exception $exception) + catch (Exception $exception) { exit($this->_handleException($exception)); } diff --git a/application/controllers/api/v1/Availabilities.php b/application/controllers/api/v1/Availabilities.php index e50770b1..66e0e1c8 100644 --- a/application/controllers/api/v1/Availabilities.php +++ b/application/controllers/api/v1/Availabilities.php @@ -1,4 +1,4 @@ -set_content_type('application/json') ->set_output(json_encode($availableHours)); } - catch (\Exception $exception) + catch (Exception $exception) { exit($this->_handleException($exception)); } @@ -122,7 +144,8 @@ class Availabilities extends API_V1_Controller { $provider_id, $selected_date, $exclude_appointments = [] - ) { + ) + { $this->load->model('appointments_model'); $this->load->model('providers_model'); @@ -318,7 +341,8 @@ class Availabilities extends API_V1_Controller { $service_duration, $manage_mode = FALSE, $availabilities_type = 'flexible' - ) { + ) + { $this->load->model('settings_model'); $available_hours = []; @@ -358,7 +382,8 @@ class Availabilities extends API_V1_Controller { $selected_date, $service, $provider - ) { + ) + { $this->load->model('appointments_model'); $this->load->model('services_model'); $this->load->model('providers_model'); diff --git a/application/controllers/api/v1/Categories.php b/application/controllers/api/v1/Categories.php index b7d9d3b9..d3899a0e 100644 --- a/application/controllers/api/v1/Categories.php +++ b/application/controllers/api/v1/Categories.php @@ -1,4 +1,4 @@ -output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -82,7 +104,7 @@ class Categories extends API_V1_Controller { { try { - // Insert the category to the database. + // Insert the category to the database. $request = new Request(); $category = $request->getBody(); $this->parser->decode($category); @@ -100,7 +122,7 @@ class Categories extends API_V1_Controller { $status = new NonEmptyText('201 Created'); $response->encode($this->parser)->singleEntry(TRUE)->output($status); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -115,7 +137,7 @@ class Categories extends API_V1_Controller { { try { - // Update the category record. + // Update the category record. $batch = $this->services_model->get_all_categories('id = ' . $id); if ($id !== NULL && count($batch) === 0) @@ -135,7 +157,7 @@ class Categories extends API_V1_Controller { $response = new Response($batch); $response->encode($this->parser)->singleEntry($id)->output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -159,7 +181,7 @@ class Categories extends API_V1_Controller { $response->output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } diff --git a/application/controllers/api/v1/Customers.php b/application/controllers/api/v1/Customers.php index 7593b5ab..6e5f26d8 100644 --- a/application/controllers/api/v1/Customers.php +++ b/application/controllers/api/v1/Customers.php @@ -1,4 +1,4 @@ -output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -82,7 +104,7 @@ class Customers extends API_V1_Controller { { try { - // Insert the customer to the database. + // Insert the customer to the database. $request = new Request(); $customer = $request->getBody(); $this->parser->decode($customer); @@ -100,7 +122,7 @@ class Customers extends API_V1_Controller { $status = new NonEmptyText('201 Created'); $response->encode($this->parser)->singleEntry(TRUE)->output($status); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -115,7 +137,7 @@ class Customers extends API_V1_Controller { { try { - // Update the customer record. + // Update the customer record. $batch = $this->customers_model->get_batch('id = ' . $id); if ($id !== NULL && count($batch) === 0) @@ -135,7 +157,7 @@ class Customers extends API_V1_Controller { $response = new Response($batch); $response->encode($this->parser)->singleEntry($id)->output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -159,7 +181,7 @@ class Customers extends API_V1_Controller { $response->output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } diff --git a/application/controllers/api/v1/Providers.php b/application/controllers/api/v1/Providers.php index f2fb79e9..e641472a 100644 --- a/application/controllers/api/v1/Providers.php +++ b/application/controllers/api/v1/Providers.php @@ -1,4 +1,4 @@ -output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -100,7 +122,7 @@ class Providers extends API_V1_Controller { $status = new NonEmptyText('201 Created'); $response->encode($this->parser)->singleEntry(TRUE)->output($status); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -135,7 +157,7 @@ class Providers extends API_V1_Controller { $response = new Response($batch); $response->encode($this->parser)->singleEntry($id)->output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -159,7 +181,7 @@ class Providers extends API_V1_Controller { $response->output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } diff --git a/application/controllers/api/v1/Secretaries.php b/application/controllers/api/v1/Secretaries.php index ee6d31e3..ff5bfb80 100644 --- a/application/controllers/api/v1/Secretaries.php +++ b/application/controllers/api/v1/Secretaries.php @@ -1,4 +1,4 @@ -output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -82,7 +104,7 @@ class Secretaries extends API_V1_Controller { { try { - // Insert the secretary to the database. + // Insert the secretary to the database. $request = new Request(); $secretary = $request->getBody(); $this->parser->decode($secretary); @@ -100,7 +122,7 @@ class Secretaries extends API_V1_Controller { $status = new NonEmptyText('201 Created'); $response->encode($this->parser)->singleEntry(TRUE)->output($status); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -115,7 +137,7 @@ class Secretaries extends API_V1_Controller { { try { - // Update the secretary record. + // Update the secretary record. $batch = $this->secretaries_model->get_batch('id = ' . $id); if ($id !== NULL && count($batch) === 0) @@ -135,7 +157,7 @@ class Secretaries extends API_V1_Controller { $response = new Response($batch); $response->encode($this->parser)->singleEntry($id)->output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -159,7 +181,7 @@ class Secretaries extends API_V1_Controller { $response->output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } diff --git a/application/controllers/api/v1/Services.php b/application/controllers/api/v1/Services.php index 868237a4..2330519a 100644 --- a/application/controllers/api/v1/Services.php +++ b/application/controllers/api/v1/Services.php @@ -1,4 +1,4 @@ -output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -82,7 +104,7 @@ class Services extends API_V1_Controller { { try { - // Insert the service to the database. + // Insert the service to the database. $request = new Request(); $service = $request->getBody(); $this->parser->decode($service); @@ -100,7 +122,7 @@ class Services extends API_V1_Controller { $status = new NonEmptyText('201 Created'); $response->encode($this->parser)->singleEntry(TRUE)->output($status); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -115,7 +137,7 @@ class Services extends API_V1_Controller { { try { - // Update the service record. + // Update the service record. $batch = $this->services_model->get_batch('id = ' . $id); if ($id !== NULL && count($batch) === 0) @@ -135,7 +157,7 @@ class Services extends API_V1_Controller { $response = new Response($batch); $response->encode($this->parser)->singleEntry($id)->output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } @@ -159,7 +181,7 @@ class Services extends API_V1_Controller { $response->output(); } - catch (\Exception $exception) + catch (Exception $exception) { $this->_handleException($exception); } diff --git a/application/controllers/api/v1/Settings.php b/application/controllers/api/v1/Settings.php index a3dfb063..3acfb500 100644 --- a/application/controllers/api/v1/Settings.php +++ b/application/controllers/api/v1/Settings.php @@ -1,4 +1,4 @@ -output(); } - catch (\Exception $exception) + catch (Exception $exception) { exit($this->_handleException($exception)); } @@ -115,7 +137,7 @@ class Settings extends API_V1_Controller { ]); $response->encode($this->parser)->singleEntry($name)->output(); } - catch (\Exception $exception) + catch (Exception $exception) { exit($this->_handleException($exception)); } @@ -139,7 +161,7 @@ class Settings extends API_V1_Controller { $response->output(); } - catch (\Exception $exception) + catch (Exception $exception) { exit($this->_handleException($exception)); } diff --git a/application/controllers/api/v1/Unavailabilities.php b/application/controllers/api/v1/Unavailabilities.php index e1f2bcf4..9b34a37f 100644 --- a/application/controllers/api/v1/Unavailabilities.php +++ b/application/controllers/api/v1/Unavailabilities.php @@ -1,4 +1,4 @@ -output(); } - catch (\Exception $exception) + catch (Exception $exception) { exit($this->_handleException($exception)); } @@ -82,7 +104,7 @@ class Unavailabilities extends API_V1_Controller { { try { - // Insert the appointment to the database. + // Insert the appointment to the database. $request = new Request(); $unavailability = $request->getBody(); $this->parser->decode($unavailability); @@ -100,7 +122,7 @@ class Unavailabilities extends API_V1_Controller { $status = new NonEmptyText('201 Created'); $response->encode($this->parser)->singleEntry(TRUE)->output($status); } - catch (\Exception $exception) + catch (Exception $exception) { exit($this->_handleException($exception)); } @@ -115,7 +137,7 @@ class Unavailabilities extends API_V1_Controller { { try { - // Update the appointment record. + // Update the appointment record. $batch = $this->appointments_model->get_batch('id = ' . $id); if ($id !== NULL && count($batch) === 0) @@ -135,7 +157,7 @@ class Unavailabilities extends API_V1_Controller { $response = new Response($batch); $response->encode($this->parser)->singleEntry($id)->output(); } - catch (\Exception $exception) + catch (Exception $exception) { exit($this->_handleException($exception)); } @@ -159,7 +181,7 @@ class Unavailabilities extends API_V1_Controller { $response->output(); } - catch (\Exception $exception) + catch (Exception $exception) { exit($this->_handleException($exception)); } diff --git a/application/helpers/asset_helper.php b/application/helpers/asset_helper.php index de514082..b16af5dd 100644 --- a/application/helpers/asset_helper.php +++ b/application/helpers/asset_helper.php @@ -1,4 +1,4 @@ -config->item('cache_busting_token') : ''; + $debug = $framework->config->item('debug'); - if (strpos(basename($uri), '.js') !== FALSE && strpos(basename($uri), '.min.js') === FALSE && ! Config::DEBUG_MODE) + $cache_busting_token = ! $debug ? '?' . $framework->config->item('cache_busting_token') : ''; + + if (strpos(basename($uri), '.js') !== FALSE && strpos(basename($uri), '.min.js') === FALSE && ! $debug) { $uri = str_replace('.js', '.min.js', $uri); } - if (strpos(basename($uri), '.css') !== FALSE && strpos(basename($uri), '.min.css') === FALSE && ! Config::DEBUG_MODE) + if (strpos(basename($uri), '.css') !== FALSE && strpos(basename($uri), '.min.css') === FALSE && ! $debug) { $uri = str_replace('.css', '.min.css', $uri); } diff --git a/application/helpers/config_helper.php b/application/helpers/config_helper.php index 899afbcc..3776e0de 100644 --- a/application/helpers/config_helper.php +++ b/application/helpers/config_helper.php @@ -1,4 +1,4 @@ - @@ -55,35 +31,14 @@ function exceptionToHtml($exc)
' . $exc->getTraceAsString() . '+
' . $exception->getTraceAsString() . '