diff --git a/Release Notes.txt b/Release Notes.txt index 090bc6d2..c5dccf95 100644 --- a/Release Notes.txt +++ b/Release Notes.txt @@ -6,10 +6,11 @@ Main - Javascript Google API usage from the customer's perspective. - Backend google calendar authentication Process. - Sync every appointment change made from E!A to Google Calendar. -- Display user friendly error messages. + Minor +- Display user friendly error messages. - Added sync exception to Google Sync library. \ No newline at end of file diff --git a/db/easy_appointments.sql b/db/easy_appointments.sql index a346be48..5dd8ad07 100644 --- a/db/easy_appointments.sql +++ b/db/easy_appointments.sql @@ -3,7 +3,7 @@ -- http://www.phpmyadmin.net -- -- Φιλοξενητής: localhost --- Χρόνος δημιουργίας: 08 Ιουν 2013 στις 12:49:21 +-- Χρόνος δημιουργίας: 19 Ιουν 2013 στις 22:27:32 -- Έκδοση διακομιστή: 5.5.24-log -- Έκδοση PHP: 5.4.3 @@ -36,18 +36,12 @@ CREATE TABLE IF NOT EXISTS `ea_appointments` ( `id_users_provider` bigint(20) unsigned NOT NULL, `id_users_customer` bigint(20) unsigned NOT NULL, `id_services` bigint(20) unsigned NOT NULL, + `id_google_calendar` text, PRIMARY KEY (`id`), KEY `id_users_customer` (`id_users_customer`), KEY `id_services` (`id_services`), KEY `id_users_provider` (`id_users_provider`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=43 ; - --- --- Άδειασμα δεδομένων του πίνακα `ea_appointments` --- - -INSERT INTO `ea_appointments` (`id`, `book_datetime`, `start_datetime`, `end_datetime`, `notes`, `hash`, `id_users_provider`, `id_users_customer`, `id_services`) VALUES -(10, NULL, '2013-06-07 15:30:00', '2013-06-07 15:50:00', '', 'c4baf9ea27dcd0fdc5449eb91b0ee2c5', 2, 20, 1); +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=88 ; -- -------------------------------------------------------- @@ -93,7 +87,7 @@ CREATE TABLE IF NOT EXISTS `ea_services` ( `id_service_categories` bigint(20) unsigned DEFAULT NULL, PRIMARY KEY (`id`), KEY `id_service_categories` (`id_service_categories`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=22 ; +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ; -- -- Άδειασμα δεδομένων του πίνακα `ea_services` @@ -156,7 +150,7 @@ CREATE TABLE IF NOT EXISTS `ea_settings` ( `name` varchar(512) DEFAULT NULL, `value` longtext, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=22 ; +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ; -- -- Άδειασμα δεδομένων του πίνακα `ea_settings` @@ -190,7 +184,7 @@ CREATE TABLE IF NOT EXISTS `ea_users` ( `id_roles` bigint(20) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `id_roles` (`id_roles`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=116 ; +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=154 ; -- -- Άδειασμα δεδομένων του πίνακα `ea_users` @@ -200,9 +194,7 @@ INSERT INTO `ea_users` (`id`, `first_name`, `last_name`, `email`, `mobile_number (1, '', '1', 'alextselegidis@gmail.com', '123456789', '1', '', '', NULL, '', 'This is me making Easy!Appointments', 1), (2, 'Γεώργιος', 'Παπαδόπουλος', 'alextselegidis@gmail.com', '1212121212', '1', '', '', NULL, '', 'This is a test provider', 2), (3, 'Νίκος', 'Αναστασίου', 'prov2@test.gr', '1313133113131', '32132165146', 'Some Street 3', NULL, NULL, NULL, NULL, 2), -(4, 'Ηρώ', 'Καριοφύλη', 'prov3@test.gr', '239203490', '029340923', 'John Doe 3 ', NULL, NULL, NULL, NULL, 2), -(20, 'Alex', 'Tselegidis', 'alextselegidis@yahoo.gr', NULL, '123456789', 'Some Str', 'Some City', NULL, '12345', NULL, 3), -(76, '', 'a', 'alextselegidis@yahoo.gr', NULL, 'a', '', '', NULL, '', NULL, 3); +(4, 'Ηρώ', 'Καριοφύλη', 'prov3@test.gr', '239203490', '029340923', 'John Doe 3 ', NULL, NULL, NULL, NULL, 2); -- -------------------------------------------------------- @@ -216,7 +208,8 @@ CREATE TABLE IF NOT EXISTS `ea_user_settings` ( `password` varchar(512) DEFAULT NULL, `working_plan` text, `notifications` text, - `google_sync` tinyint(4) DEFAULT NULL, + `google_sync` tinyint(4) DEFAULT '0', + `google_token` text, PRIMARY KEY (`id_users`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -224,10 +217,10 @@ CREATE TABLE IF NOT EXISTS `ea_user_settings` ( -- Άδειασμα δεδομένων του πίνακα `ea_user_settings` -- -INSERT INTO `ea_user_settings` (`id_users`, `username`, `password`, `working_plan`, `notifications`, `google_sync`) VALUES -(2, 'provider_1', 'provider_1', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 0), -(3, 'provider_2', 'provider_2', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 0), -(4, 'provider_3', 'provider_3', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 0); +INSERT INTO `ea_user_settings` (`id_users`, `username`, `password`, `working_plan`, `notifications`, `google_sync`, `google_token`) VALUES +(2, 'provider_1', 'provider_1', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 1, '{"access_token":"ya29.AHES6ZRsDBInIFSW1vdMEUt9N_teDoKPk6IVLS-mM41J7P0","token_type":"Bearer","expires_in":3600,"refresh_token":"1\\/9KusWyDci21Fv-PpgeZr3Yik56WnNQ7LDTcmeUhNTN8","created":1371639646}'), +(3, 'provider_2', 'provider_2', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 0, NULL), +(4, 'provider_3', 'provider_3', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 1, '{"access_token":"ya29.AHES6ZQLXwNinpRgyZ30VP4aNy2MctNkj3fc6oJid8-Gc-TEifJ6WA","token_type":"Bearer","expires_in":3600,"refresh_token":"1\\/bBPokd195S2UX2so9-jclC3E3gpzxgyDjGhJkJxmkHU","created":1371639504}'); -- -- Περιορισμοί για άχρηστους πίνακες diff --git a/src/application/config/config.php b/src/application/config/config.php index 90b302d6..641d7f3e 100644 --- a/src/application/config/config.php +++ b/src/application/config/config.php @@ -15,7 +15,7 @@ | */ require_once dirname(dirname(dirname(__FILE__))) . '/configuration.php'; -$config['base_url'] = SystemConfiguration::$base_url; //'http://localhost/dev/external/Easy!Appointments/trunk/src/WRONG'; +$config['base_url'] = SystemConfiguration::$base_url; /* |-------------------------------------------------------------------------- diff --git a/src/application/controllers/appointments.php b/src/application/controllers/appointments.php index 903e4945..d7524817 100644 --- a/src/application/controllers/appointments.php +++ b/src/application/controllers/appointments.php @@ -30,8 +30,11 @@ class Appointments extends CI_Controller { $manage_mode = TRUE; - $appointment_data = $this->Appointments_Model - ->get_batch(array('hash' => $appointment_hash))[0]; + $results = $this->Appointments_Model + ->get_batch(array('hash' => $appointment_hash)); + + $appointment_data = $results[0]; // Php 5.3 does not support treating a function as an array. + $provider_data = $this->Providers_Model ->get_row($appointment_data['id_users_provider']); $customer_data = $this->Customers_Model @@ -106,22 +109,22 @@ class Appointments extends CI_Controller { $appointment_data['id_users_provider']); if ($google_sync == TRUE) { - $google_token = $this->Providers_Model->get_setting('google_token', - $appointment_data['id_users_provider']); + $google_token = json_decode($this->Providers_Model->get_setting('google_token', + $appointment_data['id_users_provider'])); // Authenticate the token. If it isn't valid, the sync operation cannot // be completed. $this->load->library('google_sync'); + $this->google_sync->refresh_token($google_token->refresh_token); - if ($this->google_sync->authenticate($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']); - } + if ($post_data['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 success view. diff --git a/src/application/controllers/backend.php b/src/application/controllers/backend.php index ac5ecdca..9d0d93d2 100644 --- a/src/application/controllers/backend.php +++ b/src/application/controllers/backend.php @@ -95,6 +95,10 @@ class Backend extends CI_Controller { * appointment data. * @param array $_POST['customer_data'] (OPTIONAL) Array with the customer * data. + * + * @task Send email notifications to both provider and customer that changes + * have been made to the appointment. + * @task Sync changes with google calendar. */ public function ajax_save_appointment_changes() { try { @@ -102,6 +106,18 @@ class Backend extends CI_Controller { $appointment_data = json_decode(stripcslashes($_POST['appointment_data']), true); $this->load->model('Appointments_Model'); $this->Appointments_Model->add($appointment_data); + + if ($appointment_data['id_google_calendar'] != NULL) { + $this->load->model('Providers_Model'); + $provider_settings = json_decode($this->Providers_Model + ->get_setting('google_token', $appointment_data['id_users_provider'])); + + if ($provider_settings->google_sync == TRUE) { + $this->load->library('Google_Sync'); + $this->google_sync->refresh_token($provider_settings->refresh_token); + $this->google_sync->update_appointment($appointment_data['id']); + } + } } if (isset($_POST['customer_data'])) { @@ -113,11 +129,100 @@ class Backend extends CI_Controller { echo json_encode('SUCCESS'); } catch(Exception $exc) { - $js_error = array( + echo json_encode(array( 'error' => $exc->getMessage() - ); + )); + } + } + + /** + * [AJAX] 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. + * + * @param int $_POST['appointment_id'] The appointment id to be deleted. + * + * @task Sync action with GCal. + * @task Send email notifications to provider and customer. + */ + public function ajax_delete_appointment() { + try { + if (!isset($_POST['appointment_id'])) { + throw new Exception('No appointment id provided.'); + } - echo json_encode($js_error); + // :: STORE APPOINTMENT DATA FOR LATER USE IN THIS METHOD + $this->load->model('Appointments_Model'); + $this->load->model('Providers_Model'); + $this->load->model('Customers_Model'); + $this->load->model('Services_Model'); + + $appointment_data = $this->Appointments_Model->get_row($_POST['appointment_id']); + $provider_data = $this->Providers_Model->get_row($appointment_data['id_users_provider']); + $customer_data = $this->Customers_Model->get_row($appointment_data['id_users_customer']); + $service_data = $this->services_Model->get_row($appointment_data['id_services']); + + // :: DELETE APPOINTMENT RECORD FROM DATABASE. + $this->Appointments_Model->delete($_POST['appointment_id']); + + // :: SYNC CHANGE TO GOOGLE CALENDAR + $google_sync = $this->Providers_Model->get_setting('google_sync', + $provider_data['id']); + + if ($google_sync == TRUE) { + $google_token = json_decode($this->Providers_Model->get_setting('google_token', + $provider_data['id'])); + + $this->load->library('Google_Sync'); + $this->google_sync->refresh_token($google_token->refresh_token); + $this->google_sync->delete_appointment($appointment_data['id_google_calendar']); + } + + // :: SEND NOTIFICATION EMAILS TO PROVIDER AND CUSTOMER. + $this->load->library('Notifications'); + $this->notification->send_delete_appointment($appointment_data, $provider_data, + $service_data, $customer_data); + + echo json_encode('SUCCESS'); + + } catch(Exception $exc) { + echo json_encode(array( + 'error' => $exc->getMessage() + )); + } + } + + /** + * [AJAX] 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. + * + * @param string $_POST['provider_id'] The selected provider record id. + */ + public function ajax_disable_provider_sync() { + try { + if (!isset($_POST['provider_id'])) { + throw new Exception('Provider id not specified.'); + } + + $this->load->model('Providers_Model'); + + $this->Providers_Model->set_setting('google_sync', FALSE, + $_POST['provider_id']); + $this->Providers_Model->set_setting('google_token', NULL, + $_POST['provider_id']); + + echo json_encode('SUCCESS'); + + } catch(Exception $exc) { + echo json_encode(array( + 'error' => $exc->getMessage() + )); } } } diff --git a/src/application/controllers/google.php b/src/application/controllers/google.php index c0abd7e3..abec252b 100644 --- a/src/application/controllers/google.php +++ b/src/application/controllers/google.php @@ -12,9 +12,15 @@ class Google extends CI_Controller { * made. */ public function oauth($provider_id) { + // Store the provider id for use on the callback function. + if (!isset($_SESSION)) { + @session_start(); + } + $_SESSION['oauth_provider_id'] = $provider_id; + + // Redirect browser to google user content page. $this->load->library('Google_Sync'); - - // @task Create auth link and redirect browser window. + header('Location: ' . $this->google_sync->get_auth_url()); } /** @@ -29,10 +35,33 @@ class Google extends CI_Controller { * 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 the allowed redirect urls. + * included in an allowed redirect url. */ public function oauth_callback() { - // @task Store refresh token. + if (isset($_GET['code'])) { + $this->load->library('Google_Sync'); + $token = $this->google_sync->authenticate($_GET['code']); + + // Store the token into the database for future reference. + if (!isset($_SESSION)) { + @session_start(); + } + + if (isset($_SESSION['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']); + + } else { + echo '