Ολοκλήρωση της διαδικασίας OAuth της Google. Συχρονισμός των ραντεβού που προστίθονται από τους πελάτες στο ημερολόγιο του αντίστοιχου πάροχου.
This commit is contained in:
parent
fc53817e81
commit
dc586ecefb
12 changed files with 442 additions and 110 deletions
|
@ -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.
|
||||
|
|
@ -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}');
|
||||
|
||||
--
|
||||
-- Περιορισμοί για άχρηστους πίνακες
|
||||
|
|
|
@ -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;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 '<h1>Sync provider id not specified!</h1>';
|
||||
}
|
||||
|
||||
} else {
|
||||
echo '<h1>Authorization Failed!</h1>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ require_once dirname(dirname(dirname(__FILE__))) . '/configuration.php';
|
|||
* and the Easy!Appointments system.
|
||||
*/
|
||||
class Google_Sync {
|
||||
private $CI;
|
||||
private $client;
|
||||
private $service;
|
||||
|
||||
|
@ -21,10 +22,12 @@ class Google_Sync {
|
|||
* 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();
|
||||
public function __construct() {
|
||||
$this->CI =& get_instance();
|
||||
|
||||
$CI =& get_instance();
|
||||
if (!isset($_SESSION)) {
|
||||
@session_start();
|
||||
}
|
||||
|
||||
// Initialize google client and calendar service.
|
||||
$this->client = new Google_Client();
|
||||
|
@ -32,13 +35,40 @@ 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('http://localhost/oauth_callback');
|
||||
$this->client->setRedirectUri($this->CI->config->item('base_url') . 'google/oauth_callback');
|
||||
$this->service = new Google_CalendarService($this->client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Google OAuth authorization url.
|
||||
*
|
||||
* This url must be used to redirect the user to the Google user consent page,
|
||||
* where the user grants access to his data for the Easy!Appointments app.
|
||||
*/
|
||||
public function get_auth_url() {
|
||||
// "max_auth_age" is needed because the user needs to always log in
|
||||
// and not use an existing session.
|
||||
return $this->client->createAuthUrl() . '&max_auth_age=0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the Google API usage.
|
||||
*
|
||||
* When the user grants consent for his data usage, google is going to redirect
|
||||
* the browser back to the given redirect url. There a authentication code is
|
||||
* provided. Using this code, we can authenticate the API usage and store the
|
||||
* token information to the database.
|
||||
*
|
||||
* @see Google Controller
|
||||
*/
|
||||
public function authenticate($auth_code) {
|
||||
$this->client->authenticate($auth_code);
|
||||
return $this->client->getAccessToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the Google Client access token.
|
||||
*
|
||||
* This method must be executed every time we need to make actions on a
|
||||
* provider's Google Calendar account. A new token is necessary and the
|
||||
* only way to get it is to use the stored refresh token that was provided
|
||||
|
@ -48,10 +78,9 @@ class Google_Sync {
|
|||
* @param string $refresh_token The provider's refresh token. This value is
|
||||
* stored in the database and used every time we need to make actions to his
|
||||
* Google Caledar account.
|
||||
* @return bool Returns the authenticate operation result.
|
||||
*/
|
||||
public function authenticate($refresh_token) {
|
||||
|
||||
public function refresh_token($refresh_token) {
|
||||
$this->client->refreshToken($refresh_token);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,23 +99,24 @@ class Google_Sync {
|
|||
* @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.
|
||||
*
|
||||
* @task This library should not use the models. The data must be provided from
|
||||
* the controllers (same for notification library).
|
||||
*/
|
||||
public function add_appointment($appointment_id) {
|
||||
$CI =& get_instance();
|
||||
$this->CI->load->model('Appointments_Model');
|
||||
$this->CI->load->model('Providers_Model');
|
||||
$this->CI->load->model('Services_Model');
|
||||
$this->CI->load->model('Customers_Model');
|
||||
$this->CI->load->model('Settings_Model');
|
||||
|
||||
$CI->load->model('Appointments_Model');
|
||||
$CI->load->model('Service_Model');
|
||||
$CI->load->model('Provider_Model');
|
||||
$CI->load->model('Customers_Model');
|
||||
$CI->load->model('Settings_Model');
|
||||
$appointment_data = $this->CI->Appointments_Model->get_row($appointment_id);
|
||||
$provider_data = $this->CI->Providers_Model->get_row($appointment_data['id_users_provider']);
|
||||
$customer_data = $this->CI->Customers_Model->get_row($appointment_data['id_users_customer']);
|
||||
$service_data = $this->CI->Services_Model->get_row($appointment_data['id_services']);
|
||||
$company_name = $this->CI->Settings_Model->get_setting('company_name');
|
||||
|
||||
$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');
|
||||
|
||||
$CI->load->helper('general');
|
||||
$this->CI->load->helper('general');
|
||||
|
||||
$event = new Google_Event();
|
||||
$event->setSummary($service_data['name']);
|
||||
|
@ -118,25 +148,44 @@ class Google_Sync {
|
|||
// Add the new event to the "primary" calendar.
|
||||
$created_event = $this->service->events->insert('primary', $event);
|
||||
|
||||
// Set the Google Calendar event id to the E!A database record.
|
||||
$appointment_data['id_google_calendar'] = $created_event['id'];
|
||||
$this->CI->Appointments_Model->add($appointment_data);
|
||||
|
||||
return $created_event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing appointment that is already synced with Google Calendar.
|
||||
*
|
||||
* @param int $appointment_id
|
||||
* @param int $appointment_id The appointment record id.
|
||||
*/
|
||||
public function update_appointment($appointment_id) {
|
||||
public function update_appointment($appointment_data, $provider_data,
|
||||
$service_data, $customer_data) {
|
||||
$this->CI->load->model('Appointments_Model');
|
||||
$this->CI->load->model('Services_Model');
|
||||
$this->CI->load->model('Providers_Model');
|
||||
$this->CI->load->model('Customers_Model');
|
||||
$this->CI->load->model('Settings_Model');
|
||||
|
||||
$appointment_data = $this->CI->Appointments_Model->get_row($appointment_id);
|
||||
$provider_data = $this->CI->Providers_Model->get_row($appointment_data['id_users_provider']);
|
||||
$customer_data = $this->CI->Customers_Model->get_row($appointment_data['id_users_customer']);
|
||||
$service_data = $this->CI->Services_Model->get_row($appointment_data['id_services']);
|
||||
$company_name = $this->CI->Settings_Model->get_setting('company_name');
|
||||
|
||||
$this->CI->load->helper('general');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing appointment from Google Calendar.
|
||||
*
|
||||
* @param type $appointment_id
|
||||
* @param string $google_calendar_id The Google Calendar event id to
|
||||
* be deleted.
|
||||
*/
|
||||
public function delete_appointment($appointment_id) {
|
||||
|
||||
public function delete_appointment($google_calendar_id) {
|
||||
$this->service->events->delete('primary', $google_calendar_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -201,6 +201,19 @@ class Notifications {
|
|||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send delete appointment notification.
|
||||
*
|
||||
* This method should be called after the appointment has been deleted.
|
||||
*
|
||||
* <strong>IMPORTANT!</strong> This method's arguments should be taken
|
||||
* from database before the appointment record is deleted.
|
||||
*/
|
||||
public function send_delete_appointment($appointment_data, $provider_data,
|
||||
$service_data, $customer_data) {
|
||||
// @task Implement sending delete appointment notification.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed.');
|
||||
|
||||
class Providers_Model extends CI_Model {
|
||||
/**
|
||||
|
@ -96,6 +96,7 @@ class Providers_Model extends CI_Model {
|
|||
|
||||
$providers = $this->db->get()->result_array();
|
||||
|
||||
// :: GET PROVIDER SERVICES
|
||||
// Return also an array with the services that each provider can provide
|
||||
// to the customers.
|
||||
foreach($providers as &$provider) {
|
||||
|
@ -115,6 +116,16 @@ class Providers_Model extends CI_Model {
|
|||
}
|
||||
}
|
||||
|
||||
// :: GET PROVIDER SETTINGS
|
||||
foreach($providers as &$provider) {
|
||||
$this->db
|
||||
->select('*')
|
||||
->from('ea_user_settings')
|
||||
->where('id_users', $provider['id']);
|
||||
$provider['settings'] = $this->db->get()->row_array();
|
||||
unset($provider['settings']['id_users']); // Do not need it.
|
||||
}
|
||||
|
||||
return $providers;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Book Appointment | <?php echo $company_name; ?></title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
|
||||
<?php
|
||||
|
|
|
@ -29,30 +29,34 @@
|
|||
<select id="select-filter-item"></select>
|
||||
</div>
|
||||
|
||||
<div id="calendar-actions" class="btn-group">
|
||||
<button id="google-sync" class="btn btn-primary"
|
||||
title="Trigger the Google Calendar synchronization process.">
|
||||
<i class="icon-refresh icon-white"></i>
|
||||
Synchronize
|
||||
</button>
|
||||
<div id="calendar-actions">
|
||||
<div class="btn-group">
|
||||
<button id="google-sync" class="btn btn-primary"
|
||||
title="Trigger the Google Calendar synchronization process.">
|
||||
<i class="icon-refresh icon-white"></i>
|
||||
<span>Synchronize</span>
|
||||
</button>
|
||||
|
||||
<button id="enable-sync" class="btn" data-toggle="button"
|
||||
title="Enable appointment synchronization with provider's Google Calendar account.">
|
||||
<i class="icon-calendar"></i>
|
||||
<span>Enable Sync</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button id="enable-sync" class="btn" data-toggle="button"
|
||||
title="Enable appointment synchronization with provider's Google Calendar account.">
|
||||
<i class="icon-calendar"></i>
|
||||
Enable Sync
|
||||
</button>
|
||||
|
||||
<button id="insert-new-appointment" class="btn"
|
||||
title="Create a new appointment and store it into the database.">
|
||||
<i class="icon-plus"></i>
|
||||
New Appointment
|
||||
</button>
|
||||
|
||||
<button id="insert-unavailable-period" class="btn"
|
||||
title="During unavailalbe period the provider won't accept new appointments.">
|
||||
<i class="icon-ban-circle"></i>
|
||||
Unavailable
|
||||
</button>
|
||||
<div class="btn-group">
|
||||
<button id="insert-appointment" class="btn"
|
||||
title="Create a new appointment and store it into the database.">
|
||||
<i class="icon-plus"></i>
|
||||
<span>Appointment</span>
|
||||
</button>
|
||||
|
||||
<button id="insert-unavailable" class="btn"
|
||||
title="During unavailalbe period the provider won't accept new appointments.">
|
||||
<i class="icon-ban-circle"></i>
|
||||
<span>Unavailable</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -60,8 +60,12 @@ var BackendCalendar = {
|
|||
// :: FILL THE SELECT ELEMENTS OF THE PAGE
|
||||
var optgroupHtml = '<optgroup label="Providers">';
|
||||
$.each(GlobalVariables.availableProviders, function(index, provider) {
|
||||
var hasGoogleSync = (provider['settings']['google_sync'] === '1')
|
||||
? 'true' : 'false';
|
||||
|
||||
optgroupHtml += '<option value="' + provider['id'] + '" ' +
|
||||
'type="' + BackendCalendar.FILTER_TYPE_PROVIDER + '">' +
|
||||
'type="' + BackendCalendar.FILTER_TYPE_PROVIDER + '" ' +
|
||||
'google-sync="' + hasGoogleSync + '">' +
|
||||
provider['first_name'] + ' ' + provider['last_name'] + '</option>';
|
||||
});
|
||||
optgroupHtml += '</optgroup>';
|
||||
|
@ -112,6 +116,20 @@ var BackendCalendar = {
|
|||
} else {
|
||||
$('#google-sync, #enable-sync, #insert-unavailable-period')
|
||||
.prop('disabled', false);
|
||||
// If the user has already the sync enabled then apply the proper
|
||||
// style changes.
|
||||
if ($('#select-filter-item option:selected').attr('google-sync')
|
||||
=== 'true') {
|
||||
$('#enable-sync').addClass('btn-success enabled');
|
||||
$('#enable-sync i').addClass('icon-white');
|
||||
$('#enable-sync span').text('Disable Sync');
|
||||
$('#google-sync').prop('disabled', false);
|
||||
} else {
|
||||
$('#enable-sync').removeClass('btn-success enabled');
|
||||
$('#enable-sync i').removeClass('icon-white');
|
||||
$('#enable-sync span').text('Enable Sync');
|
||||
$('#google-sync').prop('disabled', true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -201,6 +219,52 @@ var BackendCalendar = {
|
|||
$('#manage-appointment').modal('show');
|
||||
});
|
||||
|
||||
/**
|
||||
* Event: Delete Popover Button "Click"
|
||||
*
|
||||
* Displays a prompt on whether the user wants the appoinmtent to be
|
||||
* deleted. If he confirms the deletion then an ajax call is made to
|
||||
* the server and deletes the appointment from the database.
|
||||
*/
|
||||
$(document).on('click', '.delete-popover', function() {
|
||||
$(this).parents().eq(2).remove(); // Hide the popover
|
||||
|
||||
var messageButtons = {
|
||||
'Delete' : function() {
|
||||
var postUrl = GlobalVariables.baseUrl + 'backend/ajax_delete_appointment';
|
||||
|
||||
var postData = {
|
||||
'appointment_id' : BackendCalendar.lastFocusedEventData.data['id']
|
||||
};
|
||||
|
||||
$.post(postUrl, postData, function(response) {
|
||||
/////////////////////////////////////////////////////////
|
||||
console.log('Delete Appointment Response :', response);
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
if (response.error) {
|
||||
GeneralFunctions.displayMessageBox('Delete Appointment Error',
|
||||
'An unexpected error occured during the deletion of the '
|
||||
+ 'appointment. Please try again.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Close dialog and refresh calendar events.
|
||||
$('#message_box').dialog('close');
|
||||
$('#select-filter-item').trigger('change');
|
||||
|
||||
}, 'json');
|
||||
},
|
||||
'Cancel' : function() {
|
||||
$('#message_box').dialog('close');
|
||||
}
|
||||
};
|
||||
|
||||
GeneralFunctions.displayMessageBox('Delete Appointment', 'Are you sure '
|
||||
+ 'that you want to delete this appointment? This action cannot '
|
||||
+ 'be undone.', messageButtons);
|
||||
});
|
||||
|
||||
/**
|
||||
* Event: Manage Appointments Dialog Cancel Button "Click"
|
||||
*
|
||||
|
@ -289,30 +353,60 @@ var BackendCalendar = {
|
|||
});
|
||||
|
||||
/**
|
||||
* Event: Enable Synchronization Button "Click"
|
||||
* Event: Enable - Disable Synchronization Button "Click"
|
||||
*
|
||||
* When the user clicks on the "Enable Sync" button, a popup should appear
|
||||
* that is going to follow the web server authorization flow of OAuth.
|
||||
*
|
||||
* @task Check whether the selected provider has already enabled the sync
|
||||
* or not.
|
||||
*/
|
||||
$('#enable-sync').click(function() {
|
||||
var authUrl = GlobalVariables.baseUrl + 'google/oauth/'
|
||||
+ $('#select-filter-item').val();
|
||||
var redirectUrl = GlobalVariables.baseUrl + 'google/oauth_callback';
|
||||
|
||||
var windowHandle = window.open(authUrl, 'Authorize Easy!Appointments',
|
||||
'width=800, height=600');
|
||||
|
||||
var authInterval = window.setInterval(function() {
|
||||
if (windowHandle.document.URL.indexOf(redirectUrl) !== -1) {
|
||||
// The user has granted access to his data.
|
||||
windowHandle.close();
|
||||
window.clearInterval(authInterval);
|
||||
$('#enable-sync').addClass('btn-success');
|
||||
}
|
||||
}, 100);
|
||||
if ($('#enable-sync').hasClass('enabled') === false) {
|
||||
// :: ENABLE SYNCHRONIZATION FOR SELECTED PROVIDER
|
||||
var authUrl = GlobalVariables.baseUrl + 'google/oauth/'
|
||||
+ $('#select-filter-item').val();
|
||||
|
||||
var redirectUrl = GlobalVariables.baseUrl + 'google/oauth_callback';
|
||||
|
||||
var windowHandle = window.open(authUrl, 'Authorize Easy!Appointments',
|
||||
'width=800, height=600');
|
||||
|
||||
var authInterval = window.setInterval(function() {
|
||||
// When the browser redirects to the google user consent page the
|
||||
// "window.document" variable becomes "undefined" and when it comes
|
||||
// back to the redirect url it changes back. So check whether the
|
||||
// variable is undefined to avoid javascript errors.
|
||||
if (windowHandle.document !== undefined) {
|
||||
if (windowHandle.document.URL.indexOf(redirectUrl) !== -1) {
|
||||
// The user has granted access to his data.
|
||||
windowHandle.close();
|
||||
window.clearInterval(authInterval);
|
||||
$('#enable-sync').addClass('btn-success enabled');
|
||||
$('#enable-sync i').addClass('icon-white');
|
||||
$('#enable-sync span').text('Disable Sync');
|
||||
$('#google-sync').prop('disabled', false);
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
|
||||
} else {
|
||||
// :: DISABLE SYNCHRONIZATION FOR SELECTED PROVIDER
|
||||
// Update page elements and make an ajax call to remove the google
|
||||
// sync setting of the selected provider.
|
||||
$.each(GlobalVariables.availableProviders, function(index, provider) {
|
||||
if (provider['id'] == $('#select-filter-item').val()) {
|
||||
provider['settings']['google_sync'] = '0';
|
||||
provider['settings']['google_token'] = null;
|
||||
|
||||
BackendCalendar.disableProviderSync(provider['id']);
|
||||
|
||||
$('#enable-sync').removeClass('btn-success enabled');
|
||||
$('#enable-sync i').removeClass('icon-white');
|
||||
$('#enable-sync span').text('Enable Sync');
|
||||
$('#google-sync').prop('disabled', true);
|
||||
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -556,6 +650,7 @@ var BackendCalendar = {
|
|||
+ '<hr>' +
|
||||
'<center>' +
|
||||
'<button class="edit-popover btn btn-primary">Edit</button>' +
|
||||
'<button class="delete-popover btn btn-danger">Delete</button>' +
|
||||
'<button class="close-popover btn" data-po=' + jsEvent.target + '>Close</button>' +
|
||||
'</center>';
|
||||
|
||||
|
@ -674,5 +769,33 @@ var BackendCalendar = {
|
|||
$('.fv-events').each(function(index, eventHandle) {
|
||||
$(eventHandle).popover();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* This method disables the google synchronization for a specific provider.
|
||||
*
|
||||
* @param {int} providerId The selected provider record id.
|
||||
*/
|
||||
disableProviderSync: function(providerId) {
|
||||
// Make an ajax call to the server in order to disable the setting
|
||||
// from the database.
|
||||
var postUrl = GlobalVariables.baseUrl + 'backend/ajax_disable_provider_sync';
|
||||
|
||||
var postData = {
|
||||
'provider_id' : providerId
|
||||
};
|
||||
|
||||
$.post(postUrl, postData, function(response) {
|
||||
////////////////////////////////////////////////////////////
|
||||
//console.log('Disable Provider Sync Response :', response);
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
if (response.error) {
|
||||
GeneralFunctions.displayMessageBox('Disable Sync Error', 'An unexpected ' +
|
||||
'error occured during the disable provider sync operation : ' +
|
||||
response.error);
|
||||
}
|
||||
|
||||
}, 'json');
|
||||
}
|
||||
};
|
Loading…
Reference in a new issue