From fcf58a7cf25f1ab94833432b982ea2cfbb9d2e93 Mon Sep 17 00:00:00 2001 From: "alextselegidis@gmail.com" Date: Mon, 10 Jun 2013 15:51:23 +0000 Subject: [PATCH] =?UTF-8?q?-=20=CE=91=CE=BB=CE=BB=CE=B1=CE=B3=CE=AE=20?= =?UTF-8?q?=CF=84=CE=BF=CF=85=20=CF=84=CF=81=CF=8C=CF=80=CE=BF=CF=85=20?= =?UTF-8?q?=CF=80=CF=81=CE=BF=CF=83=CE=B8=CE=AE=CE=BA=CE=B7=CF=82=20=CE=B5?= =?UTF-8?q?=CE=BD=CF=8C=CF=82=20=CE=BD=CE=AD=CE=BF=CF=85=20=CF=81=CE=B1?= =?UTF-8?q?=CE=BD=CF=84=CE=B5=CE=B2=CE=BF=CF=8D=20=CF=83=CF=84=CE=BF=20Goo?= =?UTF-8?q?gle=20Calendar=20=CF=84=CE=BF=CF=85=20=CF=80=CE=B5=CE=BB=CE=AC?= =?UTF-8?q?=CF=84=CE=B7=20(=CF=87=CF=81=CE=AE=CF=83=CE=B7=20javascript=20?= =?UTF-8?q?=CE=BA=CE=B1=CE=B9=20popup).=20-=20=CE=91=CE=BB=CE=BB=CE=B1?= =?UTF-8?q?=CE=B3=CE=AD=CF=82=20=CF=83=CF=84=CE=BF=20=CE=B1=CF=81=CF=87?= =?UTF-8?q?=CE=B5=CE=AF=CE=BF=20google=5Fsync.php?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/application/controllers/appointments.php | 74 ++++---- src/application/controllers/google.php | 34 ---- src/application/libraries/google_sync.php | 146 +++++++-------- src/application/models/providers_model.php | 15 +- src/application/views/appointments/book.php | 3 +- .../views/appointments/book_success.php | 170 ++++++++++++++++-- src/application/views/appointments/cancel.php | 11 +- .../views/appointments/google_sync.php | 52 ------ src/assets/js/frontend/book_appointment.js | 27 +++ src/assets/js/general_functions.js | 18 ++ 10 files changed, 336 insertions(+), 214 deletions(-) delete mode 100644 src/application/controllers/google.php delete mode 100644 src/application/views/appointments/google_sync.php diff --git a/src/application/controllers/appointments.php b/src/application/controllers/appointments.php index 0ab27540..529cdb2f 100644 --- a/src/application/controllers/appointments.php +++ b/src/application/controllers/appointments.php @@ -66,6 +66,9 @@ class Appointments extends CI_Controller { $this->load->model('Customers_Model'); $this->load->model('Appointments_Model'); + $this->load->model('Services_Model'); + $this->load->model('Providers_Model'); + $this->load->model('Settings_Model'); $customer_id = $this->Customers_Model->add($customer_data); $appointment_data['id_users_customer'] = $customer_id; @@ -96,9 +99,41 @@ class Appointments extends CI_Controller { . 'you can restore them later.

Error:
' . $not_exc->getMessage() . ''; } + + // Synchronize the appointment with the providers plan, if the + // google sync option is enabled. + $this->load->library('google_sync'); + $google_sync = $this->Providers_Model->get_setting('google_sync', + $appointment_data['id_users_provider']); + + if ($google_sync == TRUE) { + $google_token = $this->Providers_Model->get_setting('google_token', + $appointment_data['id_users_provider']); + // Validate the token. If it isn't valid, the sync operation cannot + // be completed. + if ($this->google_sync->validate_token($google_token) === TRUE) { + if ($manage_mode === FALSE) { + // Add appointment to Google Calendar. + $this->google_sync->add_appointment($appointment_data['id']); + } else { + // Update appointment to Google Calendar. + $this->google_sync->update_appointment($appointment_data['id']); + } + } + } // Load the book appointment view. - $view_data['appointment_id'] = $appointment_data['id']; + $service_data = $this->Services_Model->get_row($appointment_data['id_services']); + $provider_data = $this->Providers_Model->get_row($appointment_data['id_users_provider']); + $company_name = $this->Settings_Model->get_setting('company_name'); + + $view_data = array( + 'appointment_data' => $appointment_data, + 'service_data' => $service_data, + 'provider_data' => $provider_data, + 'company_name' => $company_name + ); + $this->load->view('appointments/book_success', $view_data); } } @@ -143,6 +178,12 @@ class Appointments extends CI_Controller { $this->notifications->send_cancel_appointment($appointment_data, $provider_email); $this->notifications->send_cancel_appointment($appointment_data, $customer_email); + // Delete the appointment from Google Calendar, if it is synced. + if ($appointment_data['id_google_calendar'] != NULL) { + $this->load->library('google_sync'); + $this->google_sync->delete_appointment($appointment_data['id']); + } + } catch(Exception $exc) { // Display the error message to the customer. $view_data['error_message'] = $exc->getMessage(); @@ -179,8 +220,8 @@ class Appointments extends CI_Controller { $reserved_appointments = $this->Appointments_Model->get_batch($where_clause); if ($_POST['manage_mode'] === 'true') { - // Current record id shouldn't be included as reserved time, - // whent the manage mode is true. + // Current record id shouldn't be included as reserved time, when the + // manage mode is true. foreach($reserved_appointments as $index=>$appointment) { if ($appointment['id'] == $_POST['appointment_id']) { unset($reserved_appointments[$index]); @@ -339,33 +380,6 @@ class Appointments extends CI_Controller { echo json_encode($available_hours); } - - /** - * Synchronize appointment with its' providers google calendar. - * - * This method syncs the registered appointment with the - * google calendar of the user. - * - * @task This method needs to be changed. Everytime a customer - * books a new appointment the synchronization process must be - * executed. - */ - public function google_sync($appointment_id) { - try { - $this->load->library('Google_Sync'); - $this->google_sync->sync_appointment($appointment_id); - $view_data['message'] = 'Your appointment has been successfully added' - . 'to Google Calendar!'; - $view_data['image'] = 'success.png'; - } catch (Exception $exc) { - $view_data['message'] = 'An unexpected error occured during the sync ' - . 'operation:
' . $exc->getMessage() . '
' - . $exc->getTraceAsString() . '
'; - $view_data['image'] = 'error.png'; - } - - $this->load->view('appointments/google_sync', $view_data); - } } /* End of file appointments.php */ diff --git a/src/application/controllers/google.php b/src/application/controllers/google.php deleted file mode 100644 index 6c9d8fe9..00000000 --- a/src/application/controllers/google.php +++ /dev/null @@ -1,34 +0,0 @@ -config->base_url() . 'appointments/google_sync/' - . $_SESSION['sync_appointment_id'] . '?code=' . $_GET['code']); - } else { - echo 'An error occured during the Google Calendar API authorization process.'; - } - } -} - -/* End of file google.php */ -/* Location: ./application/controllers/google.php */ \ No newline at end of file diff --git a/src/application/libraries/google_sync.php b/src/application/libraries/google_sync.php index e725a89c..a1d3b091 100644 --- a/src/application/libraries/google_sync.php +++ b/src/application/libraries/google_sync.php @@ -5,6 +5,12 @@ require_once dirname(__FILE__) . '/external/google-api-php-client/Google_Client. require_once dirname(__FILE__) . '/external/google-api-php-client/contrib/Google_CalendarService.php'; require_once dirname(dirname(dirname(__FILE__))) . '/configuration.php'; +/** + * Google Synchronization Class + * + * This class implements all the core synchronization between the Google Calendar + * and the Easy!Appointments system. + */ class Google_Sync { private $client; private $service; @@ -12,8 +18,8 @@ class Google_Sync { /** * Class Constructor * - * This method initializes the google client and the calendar service - * so that they can be used by the other methods. + * This method initializes the Google client class and the Calendar service + * class so that they can be used by the other methods. */ public function __construct() { session_start(); @@ -26,117 +32,113 @@ class Google_Sync { $this->client->setClientId(SystemConfiguration::$google_client_id); $this->client->setClientSecret(SystemConfiguration::$google_client_secret); $this->client->setDeveloperKey(SystemConfiguration::$google_api_key); - $this->client->setRedirectUri($CI->config->item('base_url') . 'google/api_auth'); + $this->client->setRedirectUri('http://localhost/oauth_callback'); $this->service = new Google_CalendarService($this->client); } /** - * Authorize google calendar api. + * Validate the Google API access token of a provider. * - * Before the system is able to use the google calendar api - * it must be authorized to access the users appointment. This - * method checks where an authorization token exists in the - * session cookie and handles the necessary actions. + * In order to manage a Google user's data, one need a valid access token. + * This token is provided when the user grants the permission to a system + * to access his Google account data. So before making any action we need + * to make sure that the available token is still valid. * - * IMPORTANT This method must be called every - * time before the usage of the google api. + * IMPORTANT! Always use this method before anything else + * in order to make sure that the token is being set and still valid. + * + * @param string $access_token This token is normally stored in the database. + * @return bool Returns the validation result. */ - public function authorize_api() { - // USE ONLY FOR RESETTING THE TOKEN - DEBUGGING - //unset($_SESSION['google_api_token']); - - // If the user is logged out there shouldn't be a token - // entry to the session array. - if (isset($_GET['logout'])) { - unset($_SESSION['google_api_token']); - } - - // If there is a 'code' entry available, authenticate the api. - if (isset($_GET['code'])) { - $this->client->authenticate($_GET['code']); - $_SESSION['google_api_token'] = $this->client->getAccessToken(); - header('Location: http://' . $_SERVER['HTTP_HOST'] - . $_SERVER['PHP_SELF']); // refreshes current url - } - - // If there is an active token then assign it to the client object. - if (isset($_SESSION['google_api_token'])) { - $this->client->setAccessToken($_SESSION['google_api_token']); - } - - if (!$this->client->getAccessToken()) { - $authUrl = $this->client->createAuthUrl(); - header('Location: ' . $authUrl); - } + public function validate_token($access_token) { + $this->client->setAccessToken($access_token); + return $this->client->isAccessTokenExpired(); } /** - * Synchronize a sigle appointment with Google Calendar. + * Add an appointment record to its providers Google Calendar account. * - * This method syncs an existing appointment with its' providers - * google calendar account. + * This method checks whether the appointment's provider has enabled the Google + * Sync utility of Easy!Appointments and the stored access token is still valid. + * If yes, the selected appointment record is going to be added to the Google + * Calendar account. * - * @expectedException Exception An error has occured during - * the sync operation. + * IMPORTANT! If the access token is not valid anymore the + * appointment cannot be added to the Google Calendar. A notification warning + * must be sent to the provider in order to authorize the E!A again, and store + * the new access token to the database. * - * @param int $appointment_id The appointments database id. + * @param int $appointment_id The record id of the appointment that is going to + * be added to the database. * @return Google_Event Returns the Google_Event class object. */ - public function sync_appointment($appointment_id) { - // Store the appointment id in the session cookies in case that - // we need to redirect to the authorization page of google. - $_SESSION['sync_appointment_id'] = $appointment_id; - - // Before procceeding to the sync operation we must authorize - // the user must authorize the application. - $this->authorize_api(); - - // Load the models and retrieve the necessary data from db. + public function add_appointment($appointment_id) { $CI =& get_instance(); $CI->load->model('Appointments_Model'); + $CI->load->model('Service_Model'); + $CI->load->model('Provider_Model'); $CI->load->model('Customers_Model'); - $CI->load->model('Providers_Model'); - $CI->load->model('Services_Model'); $CI->load->model('Settings_Model'); - $appointment = $CI->Appointments_Model->get_row($appointment_id); - $customer = $CI->Customers_Model->get_row($appointment['id_users_customer']); - $provider = $CI->Providers_Model->get_row($appointment['id_users_provider']); - $service = $CI->Services_Model->get_row($appointment['id_services']); + $appointment_data = $CI->Appointments_Model->get_row($appointment_id); + $provider_data = $CI->Providers_Model->get_row($appointment_data['id_users_provider']); + $customer_data = $CI->Customers_Model->get_row($appointment_data['id_users_customer']); + $service_data = $CI->Services_Model->get_row($appointment_data['id_services']); + $company_name = $CI->Settings_Model->get_setting('company_name'); - // Add a new event to the user's google calendar. $CI->load->helper('general'); $event = new Google_Event(); - $event->setSummary($service['name']); - $event->setLocation($CI->Settings_Model->get_setting('company_name')); + $event->setSummary($service_data['name']); + $event->setLocation($company_name); $start = new Google_EventDateTime(); - $start->setDateTime(date3339(strtotime($appointment['start_datetime']))); + $start->setDateTime(date3339(strtotime($appointment_data['start_datetime']))); $event->setStart($start); $end = new Google_EventDateTime(); - $end->setDateTime(date3339(strtotime($appointment['end_datetime']))); + $end->setDateTime(date3339(strtotime($appointment_data['end_datetime']))); $event->setEnd($end); $eventProvider = new Google_EventAttendee(); - $eventProvider->setDisplayName($provider['first_name'] . ' ' . $provider['last_name']); - //$eventProvider->setSelf(true); - $eventProvider->setEmail($provider['email']); + $eventProvider->setDisplayName($provider_data['first_name'] . ' ' + . $provider_data['last_name']); + $eventProvider->setEmail($provider_data['email']); $eventCustomer = new Google_EventAttendee(); - $eventCustomer->setDisplayName($customer['first_name'] . ' ' . $customer['last_name']); - $eventCustomer->setEmail($customer['email']); + $eventCustomer->setDisplayName($customer_data['first_name'] . ' ' + . $customer_data['last_name']); + $eventCustomer->setEmail($customer_data['email']); - $event->attendees = array ($eventProvider, $eventCustomer); + $event->attendees = array( + $eventProvider, + $eventCustomer + ); + // Add the new event to the "primary" calendar. $created_event = $this->service->events->insert('primary', $event); - unset($_SESSION['sync_appointment_id']); - return $created_event; } + + /** + * Update an existing appointment that is already synced with Google Calendar. + * + * @param int $appointment_id + */ + public function update_appointment($appointment_id) { + + } + + /** + * Delete an existing appointment from Google Calendar. + * + * @param type $appointment_id + */ + public function delete_appointment($appointment_id) { + + } } /* End of file google_sync.php */ diff --git a/src/application/models/providers_model.php b/src/application/models/providers_model.php index fb33ec43..2ed92f02 100644 --- a/src/application/models/providers_model.php +++ b/src/application/models/providers_model.php @@ -18,7 +18,8 @@ class Providers_Model extends CI_Model { */ public function get_row($provider_id) { if (!is_numeric($provider_id)) { - throw new InvalidArgumentException('$provider_id argument is not an integer : ' . $provider_id); + throw new InvalidArgumentException('$provider_id argument is not an integer : ' + . $provider_id); } return $this->db->get_where('ea_users', array('id' => $provider_id))->row_array(); } @@ -135,6 +136,18 @@ class Providers_Model extends CI_Model { return $this->db->get_where('ea_user_settings', array('id_users' => $provider_id)) ->row_array()[$setting_name]; } + + /** + * Set a provider's setting value in the database. + * + * @param string $setting_name The setting's name. + * @param string $value The setting's value. + * @param numeric $provider_id The selected provider id. + */ + public function set_setting($setting_name, $value, $provider_id) { + $this->db->where(array('id_users' => $provider_id)); + return $this->db->update('ea_user_settings', array($setting_name => $value)); + } } /* End of file providers_model.php */ diff --git a/src/application/views/appointments/book.php b/src/application/views/appointments/book.php index 3634f58d..4c8f8317 100644 --- a/src/application/views/appointments/book.php +++ b/src/application/views/appointments/book.php @@ -132,7 +132,8 @@ Press the "Cancel" button to remove the appointment from the company schedule.

-
diff --git a/src/application/views/appointments/book_success.php b/src/application/views/appointments/book_success.php index 8cacb44b..9f946617 100644 --- a/src/application/views/appointments/book_success.php +++ b/src/application/views/appointments/book_success.php @@ -6,9 +6,17 @@ - + src="config->base_url(); ?>assets/js/libs/jquery/jquery.min.js"> + + + + + + +
- -

Your appointment has been successfully registered.

-

An email with the appointment details has been sented to you.

- - - Sync with Google Calendar - - + +

Your appointment has been successfully registered!

+

An email with the appointment details has been sent to you.

+ + + @@ -50,7 +49,7 @@
-

Your appointment has been successfully cancelled

+

Your appointment has been successfully cancelled!

- - - - - - - - - - - - - - -
- -

Google Calendar Sync

-

-
- - \ No newline at end of file diff --git a/src/assets/js/frontend/book_appointment.js b/src/assets/js/frontend/book_appointment.js index 4dac8de8..056571ba 100644 --- a/src/assets/js/frontend/book_appointment.js +++ b/src/assets/js/frontend/book_appointment.js @@ -182,6 +182,33 @@ var bookAppointment = { $(this).addClass('selected-hour'); bookAppointment.updateConfirmFrame(); }); + + if (bookAppointment.manageMode) { + /** + * Event: Cancel Appointment Button "Click" + * + * When the user clicks the "Cancel" button this form is going to + * be submitted. We need the user to confirm this action because + * once the appointment is cancelled, it will be delete from the + * database. + */ + $('#cancel-appointment').click(function() { + event.preventDefault(); + + var dialogButtons = { + 'Yes' : function() { + $('#cancel-appointment-form').submit(); + }, + 'No' : function() { + $('#message_box').dialog('close'); + } + }; + + GeneralFunctions.displayMessageBox('Cancel Appointment', 'Are you sure ' + + 'that you want to cancel this appointment? This action can\'t ' + + 'be undone.', dialogButtons); + }); + } }, /** diff --git a/src/assets/js/general_functions.js b/src/assets/js/general_functions.js index 93839c7d..0e5433c8 100644 --- a/src/assets/js/general_functions.js +++ b/src/assets/js/general_functions.js @@ -102,4 +102,22 @@ GeneralFunctions.getUrlParameter = function(url, parameterName) { return ""; else return results[1]; +} + +/** + * This function creates a RFC 3339 date string. This string is needed + * by the Google Calendar API in order to pass dates as parameters. + * + * @param {date} dt The given date that will be transformed + * @returns {String} Returns the transformed string. + */ +GeneralFunctions.ISODateString = function(dt){ + function pad(n){return n<10 ? '0'+n : n} + + return dt.getUTCFullYear()+'-' + + pad(dt.getUTCMonth()+1)+'-' + + pad(dt.getUTCDate())+'T' + + pad(dt.getUTCHours())+':' + + pad(dt.getUTCMinutes())+':' + + pad(dt.getUTCSeconds())+'Z' } \ No newline at end of file