forked from mirrors/easyappointments
Add support for dynamic webhook definition in the settings page (#581)
This commit is contained in:
parent
80cc4f9d5d
commit
0d5e60cdb7
|
@ -71,6 +71,7 @@ define('PRIV_SERVICES', 'services');
|
|||
define('PRIV_USERS', 'users');
|
||||
define('PRIV_SYSTEM_SETTINGS', 'system_settings');
|
||||
define('PRIV_USER_SETTINGS', 'user_settings');
|
||||
define('PRIV_WEBHOOKS', 'webhooks');
|
||||
|
||||
define('DATE_FORMAT_DMY', 'DMY');
|
||||
define('DATE_FORMAT_MDY', 'MDY');
|
||||
|
@ -91,5 +92,33 @@ define('AVAILABILITIES_TYPE_FIXED', 'fixed');
|
|||
|
||||
define('EVENT_MINIMUM_DURATION', 5); // Minutes
|
||||
|
||||
define('DEFAULT_COMPANY_COLOR', '#ffffff');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Webhook Actions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| External application endpoints can subscribe to these webhook actions.
|
||||
|
|
||||
*/
|
||||
|
||||
define('WEBHOOK_APPOINTMENT_SAVE', 'appointment_save');
|
||||
define('WEBHOOK_APPOINTMENT_DELETE', 'appointment_delete');
|
||||
define('WEBHOOK_UNAVAILABILITY_SAVE', 'unavailability_save');
|
||||
define('WEBHOOK_UNAVAILABILITY_DELETE', 'unavailability_delete');
|
||||
define('WEBHOOK_CUSTOMER_SAVE', 'customer_save');
|
||||
define('WEBHOOK_CUSTOMER_DELETE', 'customer_delete');
|
||||
define('WEBHOOK_SERVICE_SAVE', 'service_save');
|
||||
define('WEBHOOK_SERVICE_DELETE', 'service_delete');
|
||||
define('WEBHOOK_CATEGORY_SAVE', 'category_save');
|
||||
define('WEBHOOK_CATEGORY_DELETE', 'category_delete');
|
||||
define('WEBHOOK_PROVIDER_SAVE', 'provider_save');
|
||||
define('WEBHOOK_PROVIDER_DELETE', 'provider_delete');
|
||||
define('WEBHOOK_SECRETARY_SAVE', 'secretary_save');
|
||||
define('WEBHOOK_SECRETARY_DELETE', 'secretary_delete');
|
||||
define('WEBHOOK_ADMIN_SAVE', 'admin_save');
|
||||
define('WEBHOOK_ADMIN_DELETE', 'admin_delete');
|
||||
|
||||
/* End of file constants.php */
|
||||
/* Location: ./application/config/constants.php */
|
||||
|
|
|
@ -122,6 +122,8 @@ route_api_resource($route, 'services', 'api/v1/');
|
|||
|
||||
route_api_resource($route, 'unavailabilities', 'api/v1/');
|
||||
|
||||
route_api_resource($route, 'webhooks', 'api/v1/');
|
||||
|
||||
$route['api/v1/settings']['get'] = 'api/v1/settings_api_v1/index';
|
||||
|
||||
$route['api/v1/settings/(:any)']['get'] = 'api/v1/settings_api_v1/show/$1';
|
||||
|
|
|
@ -31,6 +31,7 @@ class Admins extends EA_Controller {
|
|||
|
||||
$this->load->library('accounts');
|
||||
$this->load->library('timezones');
|
||||
$this->load->library('webhooks_client');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -145,6 +146,10 @@ class Admins extends EA_Controller {
|
|||
]);
|
||||
|
||||
$admin_id = $this->admins_model->save($admin);
|
||||
|
||||
$admin = $this->admins_model->find($admin_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_ADMIN_SAVE, $admin);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
|
@ -197,6 +202,10 @@ class Admins extends EA_Controller {
|
|||
|
||||
$admin_id = $this->admins_model->save($admin);
|
||||
|
||||
$admin = $this->admins_model->find($admin_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_ADMIN_SAVE, $admin);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $admin_id
|
||||
|
@ -222,8 +231,12 @@ class Admins extends EA_Controller {
|
|||
|
||||
$admin_id = request('admin_id');
|
||||
|
||||
$admin = $this->admins_model->find($admin_id);
|
||||
|
||||
$this->admins_model->delete($admin_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_ADMIN_DELETE, $admin);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
]);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* Appointments controller.
|
||||
*
|
||||
* Handles the appointments related operations.
|
||||
*
|
||||
*
|
||||
* Notice: This file used to have the booking page related code which since v1.5 has now moved to the Booking.php
|
||||
* controller for improved consistency.
|
||||
*
|
||||
|
@ -34,13 +34,14 @@ class Appointments extends EA_Controller {
|
|||
|
||||
$this->load->library('accounts');
|
||||
$this->load->library('timezones');
|
||||
$this->load->library('webhooks_client');
|
||||
}
|
||||
|
||||
/**
|
||||
* Support backwards compatibility for appointment links that still point to this URL.
|
||||
*
|
||||
* Support backwards compatibility for appointment links that still point to this URL.
|
||||
*
|
||||
* @param string $appointment_hash
|
||||
*
|
||||
*
|
||||
* @deprecated Since 1.5
|
||||
*/
|
||||
public function index(string $appointment_hash = '')
|
||||
|
@ -65,7 +66,7 @@ class Appointments extends EA_Controller {
|
|||
$order_by = 'name ASC';
|
||||
|
||||
$limit = request('limit', 1000);
|
||||
|
||||
|
||||
$offset = 0;
|
||||
|
||||
$appointments = $this->appointments_model->search($keyword, $limit, $offset, $order_by);
|
||||
|
@ -106,6 +107,10 @@ class Appointments extends EA_Controller {
|
|||
|
||||
$appointment_id = $this->appointments_model->save($appointment);
|
||||
|
||||
$appointment = $this->appointments_model->find($appointment);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_APPOINTMENT_SAVE, $appointment);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $appointment_id
|
||||
|
@ -170,9 +175,13 @@ class Appointments extends EA_Controller {
|
|||
}
|
||||
|
||||
$appointment_id = request('appointment_id');
|
||||
|
||||
$appointment = $this->appointments_model->find($appointment_id);
|
||||
|
||||
$this->appointments_model->delete($appointment_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_APPOINTMENT_DELETE, $appointment);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
]);
|
||||
|
|
|
@ -43,6 +43,7 @@ class Booking extends EA_Controller {
|
|||
$this->load->library('synchronization');
|
||||
$this->load->library('notifications');
|
||||
$this->load->library('availability');
|
||||
$this->load->library('webhooks_client');
|
||||
|
||||
$this->load->driver('cache', ['adapter' => 'file']);
|
||||
}
|
||||
|
@ -555,6 +556,8 @@ class Booking extends EA_Controller {
|
|||
|
||||
$this->notifications->notify_appointment_saved($appointment, $service, $provider, $customer, $settings, $manage_mode);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_APPOINTMENT_SAVE, $appointment);
|
||||
|
||||
$response = [
|
||||
'appointment_id' => $appointment['id'],
|
||||
'appointment_hash' => $appointment['hash']
|
||||
|
|
|
@ -33,6 +33,7 @@ class Booking_cancellation extends EA_Controller {
|
|||
|
||||
$this->load->library('synchronization');
|
||||
$this->load->library('notifications');
|
||||
$this->load->library('webhooks_client');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,6 +96,9 @@ class Booking_cancellation extends EA_Controller {
|
|||
$this->synchronization->sync_appointment_deleted($appointment, $provider);
|
||||
|
||||
$this->notifications->notify_appointment_deleted($appointment, $service, $provider, $customer, $settings);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_APPOINTMENT_DELETE, $appointment);
|
||||
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
|
|
|
@ -38,6 +38,7 @@ class Calendar extends EA_Controller {
|
|||
$this->load->library('notifications');
|
||||
$this->load->library('synchronization');
|
||||
$this->load->library('timezones');
|
||||
$this->load->library('webhooks_client');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -272,6 +273,8 @@ class Calendar extends EA_Controller {
|
|||
|
||||
$this->notifications->notify_appointment_saved($appointment, $service, $provider, $customer, $settings, $manage_mode);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_APPOINTMENT_SAVE, $appointment);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
]);
|
||||
|
@ -326,6 +329,8 @@ class Calendar extends EA_Controller {
|
|||
|
||||
$this->synchronization->sync_appointment_deleted($appointment, $provider);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_APPOINTMENT_DELETE, $appointment);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
]);
|
||||
|
@ -357,50 +362,13 @@ class Calendar extends EA_Controller {
|
|||
|
||||
$provider = $this->providers_model->find($unavailability['id_users_provider']);
|
||||
|
||||
// Add appointment
|
||||
|
||||
|
||||
|
||||
$unavailability['id'] = $this->unavailabilities_model->save($unavailability);
|
||||
$unavailability_id = $this->unavailabilities_model->save($unavailability);
|
||||
|
||||
$unavailability = $this->unavailabilities_model->find($unavailability['id']); // fetch all inserted data
|
||||
$unavailability = $this->unavailabilities_model->find($unavailability_id);
|
||||
|
||||
// Google Sync
|
||||
try
|
||||
{
|
||||
$google_sync = $this->providers_model->get_setting($unavailability['id_users_provider'], 'google_sync');
|
||||
$this->synchronization->sync_unavailability_saved($unavailability, $provider);
|
||||
|
||||
if ($google_sync)
|
||||
{
|
||||
$google_token = json_decode($this->providers_model->get_setting($unavailability['id_users_provider'], 'google_token'));
|
||||
|
||||
$this->google_sync->refresh_token($google_token->refresh_token);
|
||||
|
||||
if ($unavailability['id_google_calendar'] == NULL)
|
||||
{
|
||||
$google_event = $this->google_sync->add_unavailability($provider, $unavailability);
|
||||
$unavailability['id_google_calendar'] = $google_event->id;
|
||||
|
||||
$this->unavailabilities_model->only($unavailability, [
|
||||
'start_datetime',
|
||||
'end_datetime',
|
||||
'is_unavailability',
|
||||
'notes',
|
||||
'id_users_provider'
|
||||
]);
|
||||
|
||||
$this->unavailabilities_model->save($unavailability);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->google_sync->update_unavailability($provider, $unavailability);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
$warnings[] = $e;
|
||||
}
|
||||
$this->webhooks_client->trigger(WEBHOOK_UNAVAILABILITY_SAVE, $unavailability);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
|
@ -431,30 +399,14 @@ class Calendar extends EA_Controller {
|
|||
|
||||
$provider = $this->providers_model->find($unavailability['id_users_provider']);
|
||||
|
||||
$this->appointments_model->delete($unavailability['id']);
|
||||
$this->unavailabilities_model->delete($unavailability_id);
|
||||
|
||||
// Google Sync
|
||||
try
|
||||
{
|
||||
$google_sync = $this->providers_model->get_setting($provider['id'], 'google_sync');
|
||||
$this->synchronization->sync_appointment_deleted($unavailability, $provider);
|
||||
|
||||
if ($google_sync == TRUE)
|
||||
{
|
||||
$google_token = json_decode($this->providers_model->get_setting($provider['id'], 'google_token'));
|
||||
|
||||
$this->google_sync->refresh_token($google_token->refresh_token);
|
||||
|
||||
$this->google_sync->delete_unavailability($provider, $unavailability['id_google_calendar']);
|
||||
}
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
$warnings[] = $e;
|
||||
}
|
||||
$this->webhooks_client->trigger(WEBHOOK_UNAVAILABILITY_DELETE, $unavailability);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'warnings' => $warnings ?? []
|
||||
]);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
|
@ -626,7 +578,7 @@ class Calendar extends EA_Controller {
|
|||
}
|
||||
|
||||
$record_id = request('record_id');
|
||||
|
||||
|
||||
$filter_type = request('filter_type');
|
||||
|
||||
if ( ! $filter_type && $record_id !== FILTER_TYPE_ALL)
|
||||
|
@ -648,7 +600,9 @@ class Calendar extends EA_Controller {
|
|||
elseif ($filter_type === FILTER_TYPE_SERVICE)
|
||||
{
|
||||
$where_id = 'id_services';
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$where_id = $record_id;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ class Categories extends EA_Controller {
|
|||
|
||||
$this->load->library('accounts');
|
||||
$this->load->library('timezones');
|
||||
$this->load->library('webhooks_client');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -44,7 +45,7 @@ class Categories extends EA_Controller {
|
|||
session(['dest_url' => site_url('categories')]);
|
||||
|
||||
$user_id = session('user_id');
|
||||
|
||||
|
||||
if (cannot('view', PRIV_SERVICES))
|
||||
{
|
||||
if ($user_id)
|
||||
|
@ -116,7 +117,7 @@ class Categories extends EA_Controller {
|
|||
{
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
|
||||
$category = request('category');
|
||||
|
||||
$this->categories_model->only($category, [
|
||||
|
@ -126,6 +127,10 @@ class Categories extends EA_Controller {
|
|||
|
||||
$category_id = $this->categories_model->save($category);
|
||||
|
||||
$category = $this->categories_model->find($category_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_CATEGORY_SAVE, $category);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $category_id
|
||||
|
@ -159,6 +164,10 @@ class Categories extends EA_Controller {
|
|||
|
||||
$category_id = $this->categories_model->save($category);
|
||||
|
||||
$category = $this->categories_model->find($category_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_CATEGORY_SAVE, $category);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $category_id
|
||||
|
@ -184,8 +193,12 @@ class Categories extends EA_Controller {
|
|||
|
||||
$category_id = request('category_id');
|
||||
|
||||
$category = $this->categories_model->find($category_id);
|
||||
|
||||
$this->categories_model->delete($category_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_CATEGORY_DELETE, $category);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
]);
|
||||
|
|
|
@ -139,7 +139,7 @@ class Console extends EA_Controller {
|
|||
continue;
|
||||
}
|
||||
|
||||
Google::sync($provider['id']);
|
||||
Google::sync((string)$provider['id']);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ class Customers extends EA_Controller {
|
|||
$this->load->library('accounts');
|
||||
$this->load->library('permissions');
|
||||
$this->load->library('timezones');
|
||||
$this->load->library('webhook_client');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,6 +186,10 @@ class Customers extends EA_Controller {
|
|||
|
||||
$customer_id = $this->customers_model->save($customer);
|
||||
|
||||
$customer = $this->customers_model->find($customer_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_CUSTOMER_SAVE, $customer);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $customer_id
|
||||
|
@ -219,6 +224,10 @@ class Customers extends EA_Controller {
|
|||
|
||||
$customer_id = $this->customers_model->save($customer);
|
||||
|
||||
$customer = $this->customers_model->find($customer_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_CUSTOMER_SAVE, $customer);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $customer_id
|
||||
|
@ -251,8 +260,12 @@ class Customers extends EA_Controller {
|
|||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
$customer = $this->customers_model->find($customer_id);
|
||||
|
||||
$this->customers_model->delete($customer_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_CUSTOMER_DELETE, $customer);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
]);
|
||||
|
|
|
@ -32,6 +32,7 @@ class Providers extends EA_Controller {
|
|||
|
||||
$this->load->library('accounts');
|
||||
$this->load->library('timezones');
|
||||
$this->load->library('webhooks_client');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,6 +138,10 @@ class Providers extends EA_Controller {
|
|||
|
||||
$provider_id = $this->providers_model->save($provider);
|
||||
|
||||
$provider = $this->providers_model->find($provider_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_PROVIDER_SAVE, $provider);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $provider_id
|
||||
|
@ -164,6 +169,10 @@ class Providers extends EA_Controller {
|
|||
|
||||
$provider_id = $this->providers_model->save($provider);
|
||||
|
||||
$provider = $this->providers_model->find($provider_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_PROVIDER_SAVE, $provider);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $provider_id
|
||||
|
@ -189,8 +198,12 @@ class Providers extends EA_Controller {
|
|||
|
||||
$provider_id = request('provider_id');
|
||||
|
||||
$provider = $this->providers_model->find($provider_id);
|
||||
|
||||
$this->providers_model->delete($provider_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_PROVIDER_DELETE, $provider);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
]);
|
||||
|
|
|
@ -32,6 +32,7 @@ class Secretaries extends EA_Controller {
|
|||
|
||||
$this->load->library('accounts');
|
||||
$this->load->library('timezones');
|
||||
$this->load->library('webhooks_client');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,6 +138,10 @@ class Secretaries extends EA_Controller {
|
|||
|
||||
$secretary_id = $this->secretaries_model->save($secretary);
|
||||
|
||||
$secretary = $this->secretaries_model->find($secretary_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_SECRETARY_SAVE, $secretary);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $secretary_id
|
||||
|
@ -164,6 +169,10 @@ class Secretaries extends EA_Controller {
|
|||
|
||||
$secretary_id = $this->secretaries_model->save($secretary);
|
||||
|
||||
$secretary = $this->secretaries_model->find($secretary_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_SECRETARY_SAVE, $secretary);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $secretary_id
|
||||
|
@ -189,8 +198,12 @@ class Secretaries extends EA_Controller {
|
|||
|
||||
$secretary_id = request('secretary_id');
|
||||
|
||||
$secretary = $this->secretaries_model->find($secretary_id);
|
||||
|
||||
$this->secretaries_model->delete($secretary_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_SECRETARY_DELETE, $secretary);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
]);
|
||||
|
|
|
@ -31,6 +31,7 @@ class Services extends EA_Controller {
|
|||
|
||||
$this->load->library('accounts');
|
||||
$this->load->library('timezones');
|
||||
$this->load->library('webhooks_client');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,9 +121,13 @@ class Services extends EA_Controller {
|
|||
|
||||
$service = request('service');
|
||||
|
||||
$service['id_categories'] = $service['id_categories'] ?: null;
|
||||
$service['id_categories'] = $service['id_categories'] ?: NULL;
|
||||
|
||||
$service_id = $this->services_model->save($service);
|
||||
|
||||
$service = $this->services_model->find($service_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_SERVICE_SAVE, $service);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
|
@ -149,10 +154,14 @@ class Services extends EA_Controller {
|
|||
|
||||
$service = request('service');
|
||||
|
||||
$service['id_categories'] = $service['id_categories'] ?: null;
|
||||
$service['id_categories'] = $service['id_categories'] ?: NULL;
|
||||
|
||||
$service_id = $this->services_model->save($service);
|
||||
|
||||
$service = $this->services_model->find($service_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_SERVICE_SAVE, $service);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $service_id
|
||||
|
@ -178,8 +187,12 @@ class Services extends EA_Controller {
|
|||
|
||||
$service_id = request('service_id');
|
||||
|
||||
$service = $this->services_model->find($service_id);
|
||||
|
||||
$this->services_model->delete($service_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_SERVICE_DELETE, $service);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
]);
|
||||
|
|
|
@ -31,6 +31,7 @@ class Unavailabilities extends EA_Controller {
|
|||
|
||||
$this->load->library('accounts');
|
||||
$this->load->library('timezones');
|
||||
$this->load->library('webhooks_client');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,7 +51,7 @@ class Unavailabilities extends EA_Controller {
|
|||
$order_by = 'name ASC';
|
||||
|
||||
$limit = request('limit', 1000);
|
||||
|
||||
|
||||
$offset = 0;
|
||||
|
||||
$unavailabilities = $this->unavailabilities_model->search($keyword, $limit, $offset, $order_by);
|
||||
|
@ -75,10 +76,18 @@ class Unavailabilities extends EA_Controller {
|
|||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
$unavailability = json_decode(request('unavailability'), TRUE);
|
||||
$unavailability = request('unavailability');
|
||||
|
||||
$unavailability_id = $this->unavailabilities_model->save($unavailability);
|
||||
|
||||
$unavailability = $this->unavailabilities_model->find($unavailability_id);
|
||||
|
||||
$provider = $this->providers_model->find($unavailability['id_users_provider']);
|
||||
|
||||
$this->synchronization->sync_unavailability_saved($unavailability, $provider);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_UNAVAILABILITY_SAVE, $unavailability);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $unavailability_id
|
||||
|
@ -102,10 +111,18 @@ class Unavailabilities extends EA_Controller {
|
|||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
$unavailability = json_decode(request('unavailability'), TRUE);
|
||||
$unavailability = request('unavailability');
|
||||
|
||||
$unavailability_id = $this->unavailabilities_model->save($unavailability);
|
||||
|
||||
$unavailability = $this->unavailabilities_model->find($unavailability_id);
|
||||
|
||||
$provider = $this->providers_model->find($unavailability['id_users_provider']);
|
||||
|
||||
$this->synchronization->sync_unavailability_saved($unavailability, $provider);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_UNAVAILABILITY_SAVE, $unavailability);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $unavailability_id
|
||||
|
@ -131,8 +148,12 @@ class Unavailabilities extends EA_Controller {
|
|||
|
||||
$unavailability_id = request('unavailability_id');
|
||||
|
||||
$unavailability = $this->unavailabilities_model->find($unavailability_id);
|
||||
|
||||
$this->unavailabilities_model->delete($unavailability_id);
|
||||
|
||||
$this->webhooks_client->trigger(WEBHOOK_UNAVAILABILITY_DELETE, $unavailability);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
]);
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
<?php defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Easy!Appointments - Online Appointment Scheduler
|
||||
*
|
||||
* @package EasyAppointments
|
||||
* @author A.Tselegidis <alextselegidis@gmail.com>
|
||||
* @copyright Copyright (c) Alex Tselegidis
|
||||
* @license https://opensource.org/licenses/GPL-3.0 - GPLv3
|
||||
* @link https://easyappointments.org
|
||||
* @since v1.0.0
|
||||
* ---------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Webhooks controller.
|
||||
*
|
||||
* Handles the webhooks related operations.
|
||||
*
|
||||
* @package Controllers
|
||||
*/
|
||||
class Webhooks extends EA_Controller {
|
||||
/**
|
||||
* Webhooks constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->load->model('webhooks_model');
|
||||
$this->load->model('roles_model');
|
||||
|
||||
$this->load->library('accounts');
|
||||
$this->load->library('timezones');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the backend webhooks page.
|
||||
*
|
||||
* On this page admin users will be able to manage webhooks, which are eventually selected by customers during the
|
||||
* booking process.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
session(['dest_url' => site_url('webhooks')]);
|
||||
|
||||
$user_id = session('user_id');
|
||||
|
||||
if (cannot('view', PRIV_WEBHOOKS))
|
||||
{
|
||||
if ($user_id)
|
||||
{
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
redirect('login');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$role_slug = session('role_slug');
|
||||
|
||||
script_vars([
|
||||
'user_id' => $user_id,
|
||||
'role_slug' => $role_slug,
|
||||
]);
|
||||
|
||||
html_vars([
|
||||
'page_title' => lang('webhooks'),
|
||||
'active_menu' => PRIV_SYSTEM_SETTINGS,
|
||||
'user_display_name' => $this->accounts->get_user_display_name($user_id),
|
||||
'timezones' => $this->timezones->to_array(),
|
||||
'privileges' => $this->roles_model->get_permissions_by_slug($role_slug),
|
||||
'available_actions' => [
|
||||
WEBHOOK_APPOINTMENT_SAVE,
|
||||
WEBHOOK_APPOINTMENT_DELETE,
|
||||
WEBHOOK_UNAVAILABILITY_SAVE,
|
||||
WEBHOOK_UNAVAILABILITY_DELETE,
|
||||
WEBHOOK_CUSTOMER_SAVE,
|
||||
WEBHOOK_CUSTOMER_DELETE,
|
||||
WEBHOOK_SERVICE_SAVE,
|
||||
WEBHOOK_SERVICE_DELETE,
|
||||
WEBHOOK_CATEGORY_SAVE,
|
||||
WEBHOOK_CATEGORY_DELETE,
|
||||
WEBHOOK_PROVIDER_SAVE,
|
||||
WEBHOOK_PROVIDER_DELETE,
|
||||
WEBHOOK_SECRETARY_SAVE,
|
||||
WEBHOOK_SECRETARY_DELETE,
|
||||
WEBHOOK_ADMIN_SAVE,
|
||||
WEBHOOK_ADMIN_DELETE
|
||||
]
|
||||
]);
|
||||
|
||||
$this->load->view('pages/webhooks');
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter webhooks by the provided keyword.
|
||||
*/
|
||||
public function search()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cannot('view', PRIV_WEBHOOKS))
|
||||
{
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
$keyword = request('keyword', '');
|
||||
|
||||
$order_by = 'name ASC';
|
||||
|
||||
$limit = request('limit', 1000);
|
||||
|
||||
$offset = 0;
|
||||
|
||||
$webhooks = $this->webhooks_model->search($keyword, $limit, $offset, $order_by);
|
||||
|
||||
json_response($webhooks);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a webhook.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cannot('add', PRIV_WEBHOOKS))
|
||||
{
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
$webhook = request('webhook');
|
||||
|
||||
$this->webhooks_model->only($webhook, [
|
||||
'name',
|
||||
'url',
|
||||
'actions',
|
||||
'secret_token',
|
||||
'is_ssl_verified',
|
||||
'notes',
|
||||
]);
|
||||
|
||||
$webhook_id = $this->webhooks_model->save($webhook);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $webhook_id
|
||||
]);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a webhook.
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cannot('edit', PRIV_WEBHOOKS))
|
||||
{
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
$webhook = request('webhook');
|
||||
|
||||
$this->webhooks_model->only($webhook, [
|
||||
'id',
|
||||
'name',
|
||||
'url',
|
||||
'actions',
|
||||
'secret_token',
|
||||
'is_ssl_verified',
|
||||
'notes',
|
||||
]);
|
||||
|
||||
$webhook_id = $this->webhooks_model->save($webhook);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'id' => $webhook_id
|
||||
]);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a webhook.
|
||||
*/
|
||||
public function destroy()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cannot('delete', PRIV_WEBHOOKS))
|
||||
{
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
$webhook_id = request('webhook_id');
|
||||
|
||||
$this->webhooks_model->delete($webhook_id);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
]);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a webhook.
|
||||
*/
|
||||
public function find()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cannot('view', PRIV_WEBHOOKS))
|
||||
{
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
$webhook_id = request('webhook_id');
|
||||
|
||||
$webhook = $this->webhooks_model->find($webhook_id);
|
||||
|
||||
json_response($webhook);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
<?php defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Easy!Appointments - Online Appointment Scheduler
|
||||
*
|
||||
* @package EasyAppointments
|
||||
* @author A.Tselegidis <alextselegidis@gmail.com>
|
||||
* @copyright Copyright (c) Alex Tselegidis
|
||||
* @license https://opensource.org/licenses/GPL-3.0 - GPLv3
|
||||
* @link https://easyappointments.org
|
||||
* @since v1.5.0
|
||||
* ---------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Webhooks API v1 controller.
|
||||
*
|
||||
* @package Controllers
|
||||
*/
|
||||
class Webhooks_api_v1 extends EA_Controller {
|
||||
/**
|
||||
* Webhooks_api_v1 constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->load->model('webhooks_model');
|
||||
|
||||
$this->load->library('api');
|
||||
|
||||
$this->api->auth();
|
||||
|
||||
$this->api->model('webhooks_model');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a webhook collection.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
try
|
||||
{
|
||||
$keyword = $this->api->request_keyword();
|
||||
|
||||
$limit = $this->api->request_limit();
|
||||
|
||||
$offset = $this->api->request_offset();
|
||||
|
||||
$order_by = $this->api->request_order_by();
|
||||
|
||||
$fields = $this->api->request_fields();
|
||||
|
||||
$with = $this->api->request_with();
|
||||
|
||||
$webhooks = empty($keyword)
|
||||
? $this->webhooks_model->get(NULL, $limit, $offset, $order_by)
|
||||
: $this->webhooks_model->search($keyword, $limit, $offset, $order_by);
|
||||
|
||||
foreach ($webhooks as &$webhook)
|
||||
{
|
||||
$this->webhooks_model->api_encode($webhook);
|
||||
|
||||
if ( ! empty($fields))
|
||||
{
|
||||
$this->webhooks_model->only($webhook, $fields);
|
||||
}
|
||||
|
||||
if ( ! empty($with))
|
||||
{
|
||||
$this->webhooks_model->load($webhook, $with);
|
||||
}
|
||||
}
|
||||
|
||||
json_response($webhooks);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single webhook.
|
||||
*
|
||||
* @param int|null $id Webhook ID.
|
||||
*/
|
||||
public function show(int $id = NULL)
|
||||
{
|
||||
try
|
||||
{
|
||||
$fields = $this->api->request_fields();
|
||||
|
||||
$with = $this->api->request_with();
|
||||
|
||||
$webhook = $this->webhooks_model->find($id);
|
||||
|
||||
$this->webhooks_model->api_encode($webhook);
|
||||
|
||||
if ( ! empty($fields))
|
||||
{
|
||||
$this->webhooks_model->only($webhook, $fields);
|
||||
}
|
||||
|
||||
if ( ! empty($with))
|
||||
{
|
||||
$this->webhooks_model->load($webhook, $with);
|
||||
}
|
||||
|
||||
if ( ! $webhook)
|
||||
{
|
||||
response('', 404);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
json_response($webhook);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a webhook.
|
||||
*/
|
||||
public function store()
|
||||
{
|
||||
try
|
||||
{
|
||||
$webhook = request();
|
||||
|
||||
$this->webhooks_model->api_decode($webhook);
|
||||
|
||||
if (array_key_exists('id', $webhook))
|
||||
{
|
||||
unset($webhook['id']);
|
||||
}
|
||||
|
||||
$webhook_id = $this->webhooks_model->save($webhook);
|
||||
|
||||
$created_webhook = $this->webhooks_model->find($webhook_id);
|
||||
|
||||
$this->webhooks_model->api_encode($created_webhook);
|
||||
|
||||
json_response($created_webhook, 201);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a webhook.
|
||||
*
|
||||
* @param int $id Webhook ID.
|
||||
*/
|
||||
public function update(int $id)
|
||||
{
|
||||
try
|
||||
{
|
||||
$occurrences = $this->webhooks_model->get(['id' => $id]);
|
||||
|
||||
if (empty($occurrences))
|
||||
{
|
||||
response('', 404);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$original_webhook = $occurrences[0];
|
||||
|
||||
$webhook = request();
|
||||
|
||||
$this->webhooks_model->api_decode($webhook, $original_webhook);
|
||||
|
||||
$webhook_id = $this->webhooks_model->save($webhook);
|
||||
|
||||
$updated_webhook = $this->webhooks_model->find($webhook_id);
|
||||
|
||||
$this->webhooks_model->api_encode($updated_webhook);
|
||||
|
||||
json_response($updated_webhook);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a webhook.
|
||||
*
|
||||
* @param int $id Webhook ID.
|
||||
*/
|
||||
public function destroy(int $id)
|
||||
{
|
||||
try
|
||||
{
|
||||
$occurrences = $this->webhooks_model->get(['id' => $id]);
|
||||
|
||||
if (empty($occurrences))
|
||||
{
|
||||
response('', 404);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->webhooks_model->delete($id);
|
||||
|
||||
response('', 204);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,6 +51,7 @@
|
|||
* @property Settings_model $settings_model
|
||||
* @property Unavailabilities_model $unavailabilities_model
|
||||
* @property Users_model $users_model
|
||||
* @property Webhooks_model $webhooks_model
|
||||
*
|
||||
* @property Accounts $accounts
|
||||
* @property Api $api
|
||||
|
@ -64,6 +65,7 @@
|
|||
* @property Permissions $permissions
|
||||
* @property Synchronization $synchronization
|
||||
* @property Timezones $timezones
|
||||
* @property Webhooks_client $webhooks_client
|
||||
*/
|
||||
class EA_Controller extends CI_Controller {
|
||||
/**
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'Quin tipus d\'esdeveniment voleu afegir?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'Mis laadi sündmust soovid lisada?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -366,4 +366,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -367,4 +367,24 @@ $lang['what_kind_of_event'] = 'What kind of event would you like to add?';
|
|||
$lang['theme'] = 'Theme';
|
||||
$lang['limit_customer_access'] = 'Limit Customer Access';
|
||||
$lang['limit_customer_access_hint'] = 'If enabled, providers and secretaries will only be able to access customers they have an appointment with.';
|
||||
$lang['url'] = 'URL';
|
||||
$lang['secret_token'] = 'Secret Token';
|
||||
$lang['verify_ssl'] = 'Verify SSL';
|
||||
$lang['appointment_save'] = 'Appointment Save';
|
||||
$lang['appointment_delete'] = 'Appointment Delete';
|
||||
$lang['unavailability_save'] = 'Unavailability Save';
|
||||
$lang['unavailability_delete'] = 'Unavailability Delete';
|
||||
$lang['customer_save'] = 'Customer Save';
|
||||
$lang['customer_delete'] = 'Customer Delete';
|
||||
$lang['service_save'] = 'Service Save';
|
||||
$lang['service_delete'] = 'Service Delete';
|
||||
$lang['category_save'] = 'Category Save';
|
||||
$lang['category_delete'] = 'Category Delete';
|
||||
$lang['provider_save'] = 'Provider Save';
|
||||
$lang['provider_delete'] = 'Provider Delete';
|
||||
$lang['secretary_save'] = 'Secretary Save';
|
||||
$lang['secretary_delete'] = 'Secretary Delete';
|
||||
$lang['admin_save'] = 'Admin Save';
|
||||
$lang['admin_delete'] = 'Admin Delete';
|
||||
$lang['options'] = 'Options';
|
||||
// End
|
||||
|
|
|
@ -51,74 +51,160 @@ class Synchronization {
|
|||
{
|
||||
try
|
||||
{
|
||||
$google_sync = filter_var(
|
||||
$this->CI->providers_model->get_setting($appointment['id_users_provider'], 'google_sync'),
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
);
|
||||
|
||||
if ($google_sync === TRUE)
|
||||
if ( ! $provider['settings']['google_sync'])
|
||||
{
|
||||
$google_token = json_decode(
|
||||
$this->CI->providers_model->get_setting($appointment['id_users_provider'], 'google_token'));
|
||||
return;
|
||||
}
|
||||
|
||||
$this->CI->load->library('google_sync');
|
||||
if (empty($provider['settings']['google_token']))
|
||||
{
|
||||
throw new RuntimeException('No google token available for the provider: ' . $provider['id']);
|
||||
}
|
||||
|
||||
$this->CI->google_sync->refresh_token($google_token->refresh_token);
|
||||
$google_token = json_decode($provider['settings']['google_token'], TRUE);
|
||||
|
||||
if ($manage_mode === FALSE)
|
||||
{
|
||||
// Add appointment to Google Calendar.
|
||||
$google_event = $this->CI->google_sync->add_appointment($appointment, $provider,
|
||||
$service, $customer, $settings);
|
||||
$appointment['id_google_calendar'] = $google_event->id;
|
||||
$this->CI->appointments_model->add($appointment);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update appointment to Google Calendar.
|
||||
$appointment['id_google_calendar'] = $this->CI->appointments_model->value($appointment['id'], 'id_google_calendar');
|
||||
$this->CI->google_sync->refresh_token($google_token['refresh_token']);
|
||||
|
||||
$this->CI->google_sync->update_appointment($appointment, $provider,
|
||||
$service, $customer, $settings);
|
||||
}
|
||||
if (empty($appointment['id_google_calendar']))
|
||||
{
|
||||
$google_event = $this->CI->google_sync->add_appointment(
|
||||
$appointment,
|
||||
$provider,
|
||||
$webhook,
|
||||
$customer,
|
||||
$settings
|
||||
);
|
||||
|
||||
$appointment['id_google_calendar'] = $google_event->getId();
|
||||
|
||||
$this->CI->appointments_model->save($appointment);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->CI->google_sync->update_appointment(
|
||||
$appointment,
|
||||
$provider,
|
||||
$webhook,
|
||||
$customer,
|
||||
$settings
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (Exception $exception)
|
||||
catch (Throwable $e)
|
||||
{
|
||||
log_message('error', $exception->getMessage());
|
||||
log_message('error', $exception->getTraceAsString());
|
||||
log_message('error', $e->getMessage());
|
||||
log_message('error', $e->getTraceAsString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize removal of an appointment with external calendars.
|
||||
*
|
||||
* @param array $appointment Appointment data.
|
||||
* @param array $provider Provider data.
|
||||
* @param array $appointment Appointment record.
|
||||
* @param array $provider Provider record.
|
||||
*/
|
||||
public function sync_appointment_deleted(array $appointment, array $provider)
|
||||
{
|
||||
if ( ! empty($appointment['id_google_calendar']))
|
||||
try
|
||||
{
|
||||
try
|
||||
if ( ! $provider['settings']['google_sync'] || empty($appointment['id_google_calendar']))
|
||||
{
|
||||
$google_sync = filter_var(
|
||||
$this->CI->providers_model->get_setting($appointment['id_users_provider'], 'google_sync'),
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($google_sync === TRUE)
|
||||
{
|
||||
$google_token = json_decode($this->CI->providers_model->get_setting($provider['id'], 'google_token'));
|
||||
$this->CI->load->library('Google_sync');
|
||||
$this->CI->google_sync->refresh_token($google_token->refresh_token);
|
||||
$this->CI->google_sync->delete_appointment($provider, $appointment['id_google_calendar']);
|
||||
}
|
||||
}
|
||||
catch (Exception $exception)
|
||||
if (empty($provider['settings']['google_token']))
|
||||
{
|
||||
$exceptions[] = $exception;
|
||||
throw new RuntimeException('No google token available for the provider: ' . $provider['id']);
|
||||
}
|
||||
|
||||
$google_token = json_decode($provider['settings']['google_token'], TRUE);
|
||||
|
||||
$this->CI->google_sync->refresh_token($google_token['refresh_token']);
|
||||
|
||||
$this->CI->google_sync->delete_appointment($provider, $appointment['id_google_calendar']);
|
||||
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
log_message('error', $e->getMessage());
|
||||
log_message('error', $e->getTraceAsString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize changes made to the unavailability with external calendars.
|
||||
*
|
||||
* @param array $unavailability Unavailability record.
|
||||
* @param array $provider Provider record.
|
||||
*/
|
||||
public function sync_unavailability_saved(array $unavailability, array $provider)
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( ! $provider['settings']['google_sync'])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($provider['settings']['google_token']))
|
||||
{
|
||||
throw new RuntimeException('No google token available for the provider: ' . $provider['id']);
|
||||
}
|
||||
|
||||
$google_token = json_decode($provider['settings']['google_token'], TRUE);
|
||||
|
||||
$this->CI->google_sync->refresh_token($google_token['refresh_token']);
|
||||
|
||||
if (empty($unavailability['id_google_calendar']))
|
||||
{
|
||||
$google_event = $this->CI->google_sync->add_unavailability($provider, $unavailability);
|
||||
|
||||
$unavailability['id_google_calendar'] = $google_event->getId();
|
||||
|
||||
$this->CI->unavailabilities_model->save($unavailability);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->CI->google_sync->update_unavailability($provider, $unavailability);
|
||||
}
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
log_message('error', $e->getMessage());
|
||||
log_message('error', $e->getTraceAsString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize removal of an unavailability with external calendars.
|
||||
*
|
||||
* @param array $unavailability Unavailability record.
|
||||
* @param array $provider Provider record.
|
||||
*/
|
||||
public function sync_unavailability_deleted(array $unavailability, array $provider)
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( ! $provider['settings']['google_sync'] || empty($unavailability['id_google_calendar']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($provider['settings']['google_token']))
|
||||
{
|
||||
throw new RuntimeException('No google token available for the provider: ' . $provider['id']);
|
||||
}
|
||||
|
||||
$google_token = json_decode($provider['settings']['google_token'], TRUE);
|
||||
|
||||
$this->CI->google_sync->refresh_token($google_token['refresh_token']);
|
||||
|
||||
$this->CI->google_sync->delete_unavailability($provider, $unavailability['id_google_calendar']);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
log_message('error', $e->getMessage());
|
||||
log_message('error', $e->getTraceAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<?php defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Easy!Appointments - Open Source Web Scheduler
|
||||
*
|
||||
* @package EasyAppointments
|
||||
* @author A.Tselegidis <alextselegidis@gmail.com>
|
||||
* @copyright Copyright (c) 2013 - 2020, Alex Tselegidis
|
||||
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
|
||||
* @link http://easyappointments.org
|
||||
* @since v1.4.0
|
||||
* ---------------------------------------------------------------------------- */
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
/**
|
||||
* Webhooks client library.
|
||||
*
|
||||
* Handles the webhook HTTP related functionality.
|
||||
*
|
||||
* @package Libraries
|
||||
*/
|
||||
class Webhooks_client {
|
||||
/**
|
||||
* @var EA_Controller
|
||||
*/
|
||||
protected $CI;
|
||||
|
||||
/**
|
||||
* Webhook client constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->CI =& get_instance();
|
||||
|
||||
$this->CI->load->model('providers_model');
|
||||
$this->CI->load->model('secretaries_model');
|
||||
$this->CI->load->model('secretaries_model');
|
||||
$this->CI->load->model('admins_model');
|
||||
$this->CI->load->model('appointments_model');
|
||||
$this->CI->load->model('settings_model');
|
||||
$this->CI->load->model('webhooks_model');
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger the registered webhooks for the provided action.
|
||||
*
|
||||
* @param string $action Webhook action.
|
||||
* @param array $payload Payload data.
|
||||
*
|
||||
* @return void|null
|
||||
*/
|
||||
public function trigger(string $action, array $payload)
|
||||
{
|
||||
$webhooks = $this->CI->webhooks_model->get();
|
||||
|
||||
foreach ($webhooks as $webhook)
|
||||
{
|
||||
if (strpos($webhook['actions'], $action) !== FALSE)
|
||||
{
|
||||
$this->call($webhook, $action, $payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the provided webhook.
|
||||
*
|
||||
* @param array $webhook
|
||||
* @param string $action
|
||||
* @param array $payload
|
||||
*/
|
||||
private function call(array $webhook, string $action, array $payload)
|
||||
{
|
||||
try
|
||||
{
|
||||
$client = new Client();
|
||||
|
||||
$client->post($webhook['url'], [
|
||||
'verify' => $webhook['is_ssl_verified'],
|
||||
'json' => [
|
||||
'action' => $action,
|
||||
'payload' => $payload
|
||||
]
|
||||
]);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
log_message('error', 'Webhooks Client - The webhook (' . ($webhook['id'] ?? NULL) . ') request received an unexpected exception: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
<?php defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Easy!Appointments - Online Appointment Scheduler
|
||||
*
|
||||
* @package EasyAppointments
|
||||
* @author A.Tselegidis <alextselegidis@gmail.com>
|
||||
* @copyright Copyright (c) Alex Tselegidis
|
||||
* @license https://opensource.org/licenses/GPL-3.0 - GPLv3
|
||||
* @link https://easyappointments.org
|
||||
* @since v1.4.0
|
||||
* ---------------------------------------------------------------------------- */
|
||||
|
||||
class Migration_Create_webhooks_table extends EA_Migration {
|
||||
/**
|
||||
* Upgrade method.
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if ( ! $this->db->table_exists('webhooks'))
|
||||
{
|
||||
$this->dbforge->add_field([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'auto_increment' => TRUE
|
||||
],
|
||||
'create_datetime' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => TRUE
|
||||
],
|
||||
'update_datetime' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => TRUE
|
||||
],
|
||||
'delete_datetime' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => TRUE
|
||||
],
|
||||
'name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => '256',
|
||||
'null' => TRUE,
|
||||
],
|
||||
'url' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => TRUE,
|
||||
],
|
||||
'actions' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => TRUE,
|
||||
],
|
||||
'secret_token' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => '512',
|
||||
'null' => TRUE,
|
||||
],
|
||||
'is_ssl_verified' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => '4',
|
||||
'default' => TRUE,
|
||||
],
|
||||
'notes' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => TRUE,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->dbforge->add_key('id', TRUE);
|
||||
|
||||
$this->dbforge->create_table('webhooks', TRUE, ['engine' => 'InnoDB']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downgrade method.
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->table_exists('webhooks'))
|
||||
{
|
||||
$this->dbforge->drop_table('webhooks');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?php defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Easy!Appointments - Online Appointment Scheduler
|
||||
*
|
||||
* @package EasyAppointments
|
||||
* @author A.Tselegidis <alextselegidis@gmail.com>
|
||||
* @copyright Copyright (c) Alex Tselegidis
|
||||
* @license https://opensource.org/licenses/GPL-3.0 - GPLv3
|
||||
* @link https://easyappointments.org
|
||||
* @since v1.4.0
|
||||
* ---------------------------------------------------------------------------- */
|
||||
|
||||
class Migration_Add_webhooks_column_to_roles_table extends EA_Migration {
|
||||
/**
|
||||
* Upgrade method.
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if ( ! $this->db->field_exists('webhooks', 'roles'))
|
||||
{
|
||||
$fields = [
|
||||
'webhooks' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => '11',
|
||||
'null' => TRUE
|
||||
]
|
||||
];
|
||||
|
||||
$this->dbforge->add_column('roles', $fields);
|
||||
|
||||
$this->db->update('roles', ['webhooks' => '15'], ['slug' => 'admin']);
|
||||
|
||||
$this->db->update('roles', ['webhooks' => '0'], ['slug !=' => 'admin']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downgrade method.
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->field_exists('webhooks', 'roles'))
|
||||
{
|
||||
$this->dbforge->drop_column('roles', 'webhooks');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,323 @@
|
|||
<?php defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Easy!Appointments - Online Appointment Scheduler
|
||||
*
|
||||
* @package EasyAppointments
|
||||
* @author A.Tselegidis <alextselegidis@gmail.com>
|
||||
* @copyright Copyright (c) Alex Tselegidis
|
||||
* @license https://opensource.org/licenses/GPL-3.0 - GPLv3
|
||||
* @link https://easyappointments.org
|
||||
* @since v1.3.2
|
||||
* ---------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Webhooks model.
|
||||
*
|
||||
* Handles all the database operations of the webhook resource.
|
||||
*
|
||||
* @package Models
|
||||
*/
|
||||
class Webhooks_model extends EA_Model {
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'is_active' => 'boolean',
|
||||
'is_ssl_verified' => 'boolean',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $api_resource = [
|
||||
'id' => 'id',
|
||||
'name' => 'name',
|
||||
'url' => 'url',
|
||||
'action' => 'action',
|
||||
'secretToken' => 'secret_token',
|
||||
'isActive' => 'is_active',
|
||||
'isSslVerified' => 'is_ssl_verified',
|
||||
'notes' => 'notes',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Save (insert or update) a webhook.
|
||||
*
|
||||
* @param array $webhook Associative array with the webhook data.
|
||||
*
|
||||
* @return int Returns the webhook ID.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function save(array $webhook): int
|
||||
{
|
||||
$this->validate($webhook);
|
||||
|
||||
if (empty($webhook['id']))
|
||||
{
|
||||
return $this->insert($webhook);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->update($webhook);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate the webhook data.
|
||||
*
|
||||
* @param array $webhook Associative array with the webhook data.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function validate(array $webhook)
|
||||
{
|
||||
if (
|
||||
empty($webhook['name'])
|
||||
|| empty($webhook['url'])
|
||||
|| empty($webhook['actions'])
|
||||
)
|
||||
{
|
||||
throw new InvalidArgumentException('Not all required fields are provided: ' . print_r($webhook, TRUE));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new webhook into the database.
|
||||
*
|
||||
* @param array $webhook Associative array with the webhook data.
|
||||
*
|
||||
* @return int Returns the webhook ID.
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function insert(array $webhook): int
|
||||
{
|
||||
$webhook['create_datetime'] = date('Y-m-d H:i:s');
|
||||
$webhook['update_datetime'] = date('Y-m-d H:i:s');
|
||||
|
||||
if ( ! $this->db->insert('webhooks', $webhook))
|
||||
{
|
||||
throw new RuntimeException('Could not insert webhook.');
|
||||
}
|
||||
|
||||
return $this->db->insert_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing webhook.
|
||||
*
|
||||
* @param array $webhook Associative array with the webhook data.
|
||||
*
|
||||
* @return int Returns the webhook ID.
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function update(array $webhook): int
|
||||
{
|
||||
$webhook['update_datetime'] = date('Y-m-d H:i:s');
|
||||
|
||||
if ( ! $this->db->update('webhooks', $webhook, ['id' => $webhook['id']]))
|
||||
{
|
||||
throw new RuntimeException('Could not update webhook.');
|
||||
}
|
||||
|
||||
return $webhook['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an existing webhook from the database.
|
||||
*
|
||||
* @param int $webhook_id Webhook ID.
|
||||
* @param bool $force_delete Override soft delete.
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function delete(int $webhook_id, bool $force_delete = FALSE)
|
||||
{
|
||||
if ($force_delete)
|
||||
{
|
||||
$this->db->delete('webhooks', ['id' => $webhook_id]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->db->update('webhooks', ['delete_datetime' => date('Y-m-d H:i:s')], ['id' => $webhook_id]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific webhook from the database.
|
||||
*
|
||||
* @param int $webhook_id The ID of the record to be returned.
|
||||
* @param bool $with_trashed
|
||||
*
|
||||
* @return array Returns an array with the webhook data.
|
||||
*/
|
||||
public function find(int $webhook_id, bool $with_trashed = FALSE): array
|
||||
{
|
||||
if ( ! $with_trashed)
|
||||
{
|
||||
$this->db->where('delete_datetime IS NULL');
|
||||
}
|
||||
|
||||
$webhook = $this->db->get_where('webhooks', ['id' => $webhook_id])->row_array();
|
||||
|
||||
if ( ! $webhook)
|
||||
{
|
||||
throw new InvalidArgumentException('The provided webhook ID was not found in the database: ' . $webhook_id);
|
||||
}
|
||||
|
||||
$this->cast($webhook);
|
||||
|
||||
return $webhook;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific field value from the database.
|
||||
*
|
||||
* @param int $webhook_id Webhook ID.
|
||||
* @param string $field Name of the value to be returned.
|
||||
*
|
||||
* @return string Returns the selected webhook value from the database.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function value(int $webhook_id, string $field): string
|
||||
{
|
||||
if (empty($field))
|
||||
{
|
||||
throw new InvalidArgumentException('The field argument is cannot be empty.');
|
||||
}
|
||||
|
||||
if (empty($webhook_id))
|
||||
{
|
||||
throw new InvalidArgumentException('The webhook ID argument cannot be empty.');
|
||||
}
|
||||
|
||||
// Check whether the webhook exists.
|
||||
$query = $this->db->get_where('webhooks', ['id' => $webhook_id]);
|
||||
|
||||
if ( ! $query->num_rows())
|
||||
{
|
||||
throw new InvalidArgumentException('The provided webhook ID was not found in the database: ' . $webhook_id);
|
||||
}
|
||||
|
||||
// Check if the required field is part of the webhook data.
|
||||
$webhook = $query->row_array();
|
||||
|
||||
$this->cast($webhook);
|
||||
|
||||
if ( ! array_key_exists($field, $webhook))
|
||||
{
|
||||
throw new InvalidArgumentException('The requested field was not found in the webhook data: ' . $field);
|
||||
}
|
||||
|
||||
return $webhook[$field];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all webhooks that match the provided criteria.
|
||||
*
|
||||
* @param array|string $where Where conditions.
|
||||
* @param int|null $limit Record limit.
|
||||
* @param int|null $offset Record offset.
|
||||
* @param string|null $order_by Order by.
|
||||
* @param bool $with_trashed
|
||||
*
|
||||
* @return array Returns an array of webhooks.
|
||||
*/
|
||||
public function get($where = NULL, int $limit = NULL, int $offset = NULL, string $order_by = NULL, bool $with_trashed = FALSE): array
|
||||
{
|
||||
if ($where !== NULL)
|
||||
{
|
||||
$this->db->where($where);
|
||||
}
|
||||
|
||||
if ($order_by !== NULL)
|
||||
{
|
||||
$this->db->order_by($order_by);
|
||||
}
|
||||
|
||||
if ( ! $with_trashed)
|
||||
{
|
||||
$this->db->where('delete_datetime IS NULL');
|
||||
}
|
||||
|
||||
$webhooks = $this->db->get('webhooks', $limit, $offset)->result_array();
|
||||
|
||||
foreach ($webhooks as &$webhook)
|
||||
{
|
||||
$this->cast($webhook);
|
||||
}
|
||||
|
||||
return $webhooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query builder interface, configured for use with the webhooks table.
|
||||
*
|
||||
* @return CI_DB_query_builder
|
||||
*/
|
||||
public function query(): CI_DB_query_builder
|
||||
{
|
||||
return $this->db->from('webhooks');
|
||||
}
|
||||
|
||||
/**
|
||||
* Search webhooks by the provided keyword.
|
||||
*
|
||||
* @param string $keyword Search keyword.
|
||||
* @param int|null $limit Record limit.
|
||||
* @param int|null $offset Record offset.
|
||||
* @param string|null $order_by Order by.
|
||||
* @param bool $with_trashed
|
||||
*
|
||||
* @return array Returns an array of webhooks.
|
||||
*/
|
||||
public function search(string $keyword, int $limit = NULL, int $offset = NULL, string $order_by = NULL, bool $with_trashed = FALSE): array
|
||||
{
|
||||
if ( ! $with_trashed)
|
||||
{
|
||||
$this->db->where('delete_datetime IS NULL');
|
||||
}
|
||||
|
||||
$webhooks = $this
|
||||
->db
|
||||
->select()
|
||||
->from('webhooks')
|
||||
->group_start()
|
||||
->like('name', $keyword)
|
||||
->or_like('url', $keyword)
|
||||
->or_like('actions', $keyword)
|
||||
->group_end()
|
||||
->limit($limit)
|
||||
->offset($offset)
|
||||
->order_by($order_by)
|
||||
->get()
|
||||
->result_array();
|
||||
|
||||
foreach ($webhooks as &$webhook)
|
||||
{
|
||||
$this->cast($webhook);
|
||||
}
|
||||
|
||||
return $webhooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load related resources to a webhook.
|
||||
*
|
||||
* @param array $webhook Associative array with the webhook data.
|
||||
* @param array $resources Resource names to be attached.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function load(array &$webhook, array $resources)
|
||||
{
|
||||
// Webhooks do not currently have any related resources.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
<?php extend('layouts/backend_layout') ?>
|
||||
|
||||
<?php section('content') ?>
|
||||
|
||||
<div class="container-fluid backend-page" id="webhooks-page">
|
||||
<div class="row" id="webhooks">
|
||||
<div id="filter-webhooks" class="filter-records col col-12 col-md-5">
|
||||
<form class="mb-4">
|
||||
<div class="input-group">
|
||||
<input type="text" class="key form-control">
|
||||
|
||||
<button class="filter btn btn-outline-secondary" type="submit"
|
||||
data-tippy-content="<?= lang('filter') ?>">
|
||||
<i class="fas fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<h3><?= lang('webhooks') ?></h3>
|
||||
<div class="results"></div>
|
||||
</div>
|
||||
|
||||
<div class="record-details column col-12 col-md-5">
|
||||
<div class="btn-toolbar mb-4">
|
||||
<div class="add-edit-delete-group btn-group">
|
||||
<button id="add-webhook" class="btn btn-primary">
|
||||
<i class="fas fa-plus-square me-2"></i>
|
||||
<?= lang('add') ?>
|
||||
</button>
|
||||
<button id="edit-webhook" class="btn btn-outline-secondary" disabled="disabled">
|
||||
<i class="fas fa-edit me-2"></i>
|
||||
<?= lang('edit') ?>
|
||||
</button>
|
||||
<button id="delete-webhook" class="btn btn-outline-secondary" disabled="disabled">
|
||||
<i class="fas fa-trash-alt me-2"></i>
|
||||
<?= lang('delete') ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="save-cancel-group" style="display:none;">
|
||||
<button id="save-webhook" class="btn btn-primary">
|
||||
<i class="fas fa-check-square me-2"></i>
|
||||
<?= lang('save') ?>
|
||||
</button>
|
||||
<button id="cancel-webhook" class="btn btn-secondary">
|
||||
<?= lang('cancel') ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3><?= lang('details') ?></h3>
|
||||
|
||||
<div class="form-message alert" style="display:none;"></div>
|
||||
|
||||
<input type="hidden" id="id">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="name">
|
||||
<?= lang('name') ?>
|
||||
<span class="text-danger" hidden>*</span>
|
||||
</label>
|
||||
<input id="name" class="form-control required" maxlength="128" disabled>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="duration">
|
||||
<?= lang('url') ?>
|
||||
<span class="text-danger" hidden>*</span>
|
||||
</label>
|
||||
<input id="url" class="form-control required" disabled>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="secret-token">
|
||||
<?= lang('secret_token') ?>
|
||||
</label>
|
||||
|
||||
<input id="secret-token" class="form-control" disabled>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="notes">
|
||||
<?= lang('notes') ?>
|
||||
</label>
|
||||
<textarea id="notes" rows="4" class="form-control" disabled></textarea>
|
||||
</div>
|
||||
|
||||
<div class="border raounded mb-3 p-3">
|
||||
<label class="form-label mb-3" for="actions">
|
||||
<?= lang('actions') ?>
|
||||
</label>
|
||||
|
||||
<div id="actions">
|
||||
<?php foreach (vars('available_actions') as $available_action): ?>
|
||||
<div class="mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
id="include-<?= str_replace('_', '-', $available_action) ?>"
|
||||
data-action="<?= $available_action ?>">
|
||||
|
||||
<label class="form-check-label"
|
||||
for="include-<?= str_replace('_', '-', $available_action) ?>">
|
||||
<?= lang($available_action) ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border rounded mb-3 p-3">
|
||||
<label class="form-label mb-3">
|
||||
<?= lang('options') ?>
|
||||
</label>
|
||||
|
||||
<div class="">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" id="is-ssl-verified">
|
||||
|
||||
<label class="form-check-label" for="is-ssl-verified">
|
||||
<?= lang('verify_ssl') ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php section('content') ?>
|
||||
|
||||
<?php section('scripts') ?>
|
||||
|
||||
<script src="<?= asset_url('assets/js/utils/message.js') ?>"></script>
|
||||
<script src="<?= asset_url('assets/js/utils/validation.js') ?>"></script>
|
||||
<script src="<?= asset_url('assets/js/utils/url.js') ?>"></script>
|
||||
<script src="<?= asset_url('assets/js/http/webhooks_http_client.js') ?>"></script>
|
||||
<script src="<?= asset_url('assets/js/pages/webhooks.js') ?>"></script>
|
||||
|
||||
<?php section('scripts') ?>
|
|
@ -0,0 +1,133 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* Easy!Appointments - Online Appointment Scheduler
|
||||
*
|
||||
* @package EasyAppointments
|
||||
* @author A.Tselegidis <alextselegidis@gmail.com>
|
||||
* @copyright Copyright (c) Alex Tselegidis
|
||||
* @license https://opensource.org/licenses/GPL-3.0 - GPLv3
|
||||
* @link https://easyappointments.org
|
||||
* @since v1.5.0
|
||||
* ---------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Webhooks HTTP client.
|
||||
*
|
||||
* This module implements the webhooks related HTTP requests.
|
||||
*/
|
||||
App.Http.Webhooks = (function () {
|
||||
/**
|
||||
* Save (create or update) a webhook.
|
||||
*
|
||||
* @param {Object} webhook
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
function save(webhook) {
|
||||
return webhook.id ? update(webhook) : create(webhook);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an webhook.
|
||||
*
|
||||
* @param {Object} webhook
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
function create(webhook) {
|
||||
const url = App.Utils.Url.siteUrl('webhooks/create');
|
||||
|
||||
const data = {
|
||||
csrf_token: vars('csrf_token'),
|
||||
webhook: webhook
|
||||
};
|
||||
|
||||
return $.post(url, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an webhook.
|
||||
*
|
||||
* @param {Object} webhook
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
function update(webhook) {
|
||||
const url = App.Utils.Url.siteUrl('webhooks/update');
|
||||
|
||||
const data = {
|
||||
csrf_token: vars('csrf_token'),
|
||||
webhook: webhook
|
||||
};
|
||||
|
||||
return $.post(url, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an webhook.
|
||||
*
|
||||
* @param {Number} webhookId
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
function destroy(webhookId) {
|
||||
const url = App.Utils.Url.siteUrl('webhooks/destroy');
|
||||
|
||||
const data = {
|
||||
csrf_token: vars('csrf_token'),
|
||||
webhook_id: webhookId
|
||||
};
|
||||
|
||||
return $.post(url, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search webhooks by keyword.
|
||||
*
|
||||
* @param {String} keyword
|
||||
* @param {Number} limit
|
||||
* @param {Number} offset
|
||||
* @param {String} orderBy
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
function search(keyword, limit, offset, orderBy) {
|
||||
const url = App.Utils.Url.siteUrl('webhooks/search');
|
||||
|
||||
const data = {
|
||||
csrf_token: vars('csrf_token'),
|
||||
keyword,
|
||||
limit,
|
||||
offset,
|
||||
order_by: orderBy
|
||||
};
|
||||
|
||||
return $.post(url, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an webhook.
|
||||
*
|
||||
* @param {Number} webhookId
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
function find(webhookId) {
|
||||
const url = App.Utils.Url.siteUrl('webhooks/find');
|
||||
|
||||
const data = {
|
||||
csrf_token: vars('csrf_token'),
|
||||
webhook_id: webhookId
|
||||
};
|
||||
|
||||
return $.post(url, data);
|
||||
}
|
||||
|
||||
return {
|
||||
save,
|
||||
create,
|
||||
update,
|
||||
destroy,
|
||||
search,
|
||||
find
|
||||
};
|
||||
})();
|
|
@ -0,0 +1,383 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* Easy!Appointments - Online Appointment Scheduler
|
||||
*
|
||||
* @package EasyAppointments
|
||||
* @author A.Tselegidis <alextselegidis@gmail.com>
|
||||
* @copyright Copyright (c) Alex Tselegidis
|
||||
* @license https://opensource.org/licenses/GPL-3.0 - GPLv3
|
||||
* @link https://easyappointments.org
|
||||
* @since v1.5.0
|
||||
* ---------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Webhooks page.
|
||||
*
|
||||
* This module implements the functionality of the webhooks page.
|
||||
*/
|
||||
App.Pages.Webhooks = (function () {
|
||||
const $webhooks = $('#webhooks');
|
||||
const $id = $('#id');
|
||||
const $name = $('#name');
|
||||
const $url = $('#url');
|
||||
const $actions = $('#actions');
|
||||
const $secretToken = $('#secret-token');
|
||||
const $isSslVerified = $('#is-ssl-verified');
|
||||
const $notes = $('#notes');
|
||||
const $filterWebhooks = $('#filter-webhooks');
|
||||
let filterResults = {};
|
||||
let filterLimit = 20;
|
||||
|
||||
/**
|
||||
* Add page event listeners.
|
||||
*/
|
||||
function addEventListeners() {
|
||||
/**
|
||||
* Event: Filter Webhooks Form "Submit"
|
||||
*
|
||||
* @param {jQuery.Event} event
|
||||
*/
|
||||
$webhooks.on('submit', '#filter-webhooks form', (event) => {
|
||||
event.preventDefault();
|
||||
const key = $filterWebhooks.find('.key').val();
|
||||
$filterWebhooks.find('.selected').removeClass('selected');
|
||||
resetForm();
|
||||
filter(key);
|
||||
});
|
||||
|
||||
/**
|
||||
* Event: Filter Webhook Row "Click"
|
||||
*
|
||||
* Display the selected webhook data to the user.
|
||||
*/
|
||||
$webhooks.on('click', '.webhook-row', (event) => {
|
||||
if ($filterWebhooks.find('.filter').prop('disabled')) {
|
||||
$filterWebhooks.find('.results').css('color', '#AAA');
|
||||
return; // exit because we are on edit mode
|
||||
}
|
||||
|
||||
const webhookId = $(event.currentTarget).attr('data-id');
|
||||
|
||||
const webhook = filterResults.find((filterResult) => Number(filterResult.id) === Number(webhookId));
|
||||
|
||||
display(webhook);
|
||||
|
||||
$filterWebhooks.find('.selected').removeClass('selected');
|
||||
$(event.currentTarget).addClass('selected');
|
||||
$('#edit-webhook, #delete-webhook').prop('disabled', false);
|
||||
});
|
||||
|
||||
/**
|
||||
* Event: Add New Webhook Button "Click"
|
||||
*/
|
||||
$webhooks.on('click', '#add-webhook', () => {
|
||||
resetForm();
|
||||
$webhooks.find('.add-edit-delete-group').hide();
|
||||
$webhooks.find('.save-cancel-group').show();
|
||||
$webhooks.find('.record-details').find('input, select, textarea').prop('disabled', false);
|
||||
$webhooks.find('.record-details .form-label span').prop('hidden', false);
|
||||
$filterWebhooks.find('button').prop('disabled', true);
|
||||
$filterWebhooks.find('.results').css('color', '#AAA');
|
||||
});
|
||||
|
||||
/**
|
||||
* Event: Cancel Webhook Button "Click"
|
||||
*
|
||||
* Cancel add or edit of a webhook record.
|
||||
*/
|
||||
$webhooks.on('click', '#cancel-webhook', () => {
|
||||
const id = $id.val();
|
||||
|
||||
resetForm();
|
||||
|
||||
if (id !== '') {
|
||||
select(id, true);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Event: Save Webhook Button "Click"
|
||||
*/
|
||||
$webhooks.on('click', '#save-webhook', () => {
|
||||
const webhook = {
|
||||
name: $name.val(),
|
||||
url: $url.val(),
|
||||
actions: '',
|
||||
secret_token: $secretToken.val(),
|
||||
is_ssl_verified: Number($isSslVerified.prop('checked')),
|
||||
notes: $notes.val(),
|
||||
};
|
||||
|
||||
const actions = [];
|
||||
|
||||
$actions.find('input:checked').each((index, checkbox) => {
|
||||
var action = $(checkbox).data('action');
|
||||
actions.push(action);
|
||||
});
|
||||
|
||||
webhook.actions = actions.join(',');
|
||||
|
||||
if ($id.val() !== '') {
|
||||
webhook.id = $id.val();
|
||||
}
|
||||
|
||||
if (!validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
save(webhook);
|
||||
});
|
||||
|
||||
/**
|
||||
* Event: Edit Webhook Button "Click"
|
||||
*/
|
||||
$webhooks.on('click', '#edit-webhook', () => {
|
||||
$webhooks.find('.add-edit-delete-group').hide();
|
||||
$webhooks.find('.save-cancel-group').show();
|
||||
$webhooks.find('.record-details').find('input, select, textarea').prop('disabled', false);
|
||||
$webhooks.find('.record-details .form-label span').prop('hidden', false);
|
||||
$filterWebhooks.find('button').prop('disabled', true);
|
||||
$filterWebhooks.find('.results').css('color', '#AAA');
|
||||
});
|
||||
|
||||
/**
|
||||
* Event: Delete Webhook Button "Click"
|
||||
*/
|
||||
$webhooks.on('click', '#delete-webhook', () => {
|
||||
const webhookId = $id.val();
|
||||
const buttons = [
|
||||
{
|
||||
text: lang('cancel'),
|
||||
click: () => {
|
||||
$('#message-box').dialog('close');
|
||||
}
|
||||
},
|
||||
{
|
||||
text: lang('delete'),
|
||||
click: () => {
|
||||
remove(webhookId);
|
||||
$('#message-box').dialog('close');
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
App.Utils.Message.show(lang('delete_webhook'), lang('delete_record_prompt'), buttons);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Save webhook record to database.
|
||||
*
|
||||
* @param {Object} webhook Contains the webhook record data. If an 'id' value is provided
|
||||
* then the update operation is going to be executed.
|
||||
*/
|
||||
function save(webhook) {
|
||||
App.Http.Webhooks.save(webhook).then((response) => {
|
||||
App.Layouts.Backend.displayNotification(lang('webhook_saved'));
|
||||
resetForm();
|
||||
$filterWebhooks.find('.key').val('');
|
||||
filter('', response.id, true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a webhook record from database.
|
||||
*
|
||||
* @param {Number} id Record ID to be deleted.
|
||||
*/
|
||||
function remove(id) {
|
||||
App.Http.Webhooks.destroy(id).then(() => {
|
||||
App.Layouts.Backend.displayNotification(lang('webhook_deleted'));
|
||||
resetForm();
|
||||
filter($filterWebhooks.find('.key').val());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a webhook record.
|
||||
*
|
||||
* @return {Boolean} Returns the validation result.
|
||||
*/
|
||||
function validate() {
|
||||
$webhooks.find('.is-invalid').removeClass('is-invalid');
|
||||
$webhooks.find('.form-message').removeClass('alert-danger').hide();
|
||||
|
||||
try {
|
||||
// Validate required fields.
|
||||
let missingRequired = false;
|
||||
|
||||
$webhooks.find('.required').each((index, requiredField) => {
|
||||
if (!$(requiredField).val()) {
|
||||
$(requiredField).addClass('is-invalid');
|
||||
missingRequired = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (missingRequired) {
|
||||
throw new Error(lang('fields_are_required'));
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
$webhooks.find('.form-message').addClass('alert-danger').text(error.message).show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the webhook tab form back to its initial state.
|
||||
*/
|
||||
function resetForm() {
|
||||
$filterWebhooks.find('.selected').removeClass('selected');
|
||||
$filterWebhooks.find('button').prop('disabled', false);
|
||||
$filterWebhooks.find('.results').css('color', '');
|
||||
|
||||
$webhooks.find('.record-details').find('input, select, textarea').val('').prop('disabled', true);
|
||||
$webhooks.find('.record-details .form-label span').prop('hidden', true);
|
||||
$webhooks.find('.record-details h3 a').remove();
|
||||
|
||||
$webhooks.find('.add-edit-delete-group').show();
|
||||
$webhooks.find('.save-cancel-group').hide();
|
||||
$('#edit-webhook, #delete-webhook').prop('disabled', true);
|
||||
|
||||
$webhooks.find('.record-details .is-invalid').removeClass('is-invalid');
|
||||
$webhooks.find('.record-details .form-message').hide();
|
||||
|
||||
$actions.find('input:checkbox').prop('checked', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a webhook record into the webhook form.
|
||||
*
|
||||
* @param {Object} webhook Contains the webhook record data.
|
||||
*/
|
||||
function display(webhook) {
|
||||
$id.val(webhook.id);
|
||||
$name.val(webhook.name);
|
||||
$url.val(webhook.url);
|
||||
$secretToken.val(webhook.secret_token);
|
||||
$isSslVerified.prop('checked', Boolean(Number(webhook.is_ssl_verified)));
|
||||
|
||||
$actions.find('input:checkbox').prop('checked', false);
|
||||
|
||||
if (webhook.actions && webhook.actions.length) {
|
||||
const actions = webhook.actions.split(',');
|
||||
actions.forEach((action) => $(`[data-action="${action}"]`).prop('checked', true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters webhook records depending a string keyword.
|
||||
*
|
||||
* @param {String} keyword This is used to filter the webhook records of the database.
|
||||
* @param {Number} selectId Optional, if set then after the filter operation the record with this
|
||||
* ID will be selected (but not displayed).
|
||||
* @param {Boolean} show Optional (false), if true then the selected record will be displayed on the form.
|
||||
*/
|
||||
function filter(keyword, selectId = null, show = false) {
|
||||
App.Http.Webhooks.search(keyword, filterLimit).then((response) => {
|
||||
filterResults = response;
|
||||
|
||||
$filterWebhooks.find('.results').empty();
|
||||
|
||||
response.forEach((webhook) => {
|
||||
$filterWebhooks.find('.results').append(getFilterHtml(webhook)).append($('<hr/>'));
|
||||
});
|
||||
|
||||
if (response.length === 0) {
|
||||
$filterWebhooks.find('.results').append(
|
||||
$('<em/>', {
|
||||
'text': lang('no_records_found')
|
||||
})
|
||||
);
|
||||
} else if (response.length === filterLimit) {
|
||||
$('<button/>', {
|
||||
'type': 'button',
|
||||
'class': 'btn btn-outline-secondary w-100 load-more text-center',
|
||||
'text': lang('load_more'),
|
||||
'click': () => {
|
||||
filterLimit += 20;
|
||||
filter(keyword, selectId, show);
|
||||
}
|
||||
}).appendTo('#filter-webhooks .results');
|
||||
}
|
||||
|
||||
if (selectId) {
|
||||
select(selectId, show);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Filter HTML
|
||||
*
|
||||
* Get a webhook row HTML code that is going to be displayed on the filter results list.
|
||||
*
|
||||
* @param {Object} webhook Contains the webhook record data.
|
||||
*
|
||||
* @return {String} The HTML code that represents the record on the filter results list.
|
||||
*/
|
||||
function getFilterHtml(webhook) {
|
||||
const name = webhook.name;
|
||||
|
||||
const actionCount = webhook.actions && webhook.actions.length ? webhook.actions.split(',').length : 0;
|
||||
|
||||
const info = `${actionCount} ${lang('actions')}`;
|
||||
|
||||
return $('<div/>', {
|
||||
'class': 'webhook-row entry',
|
||||
'data-id': webhook.id,
|
||||
'html': [
|
||||
$('<strong/>', {
|
||||
'text': name
|
||||
}),
|
||||
$('<br/>'),
|
||||
$('<small/>', {
|
||||
'class': 'text-muted',
|
||||
'text': info
|
||||
}),
|
||||
$('<br/>')
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a specific record from the current filter results. If the webhook id does not exist
|
||||
* in the list then no record will be selected.
|
||||
*
|
||||
* @param {Number} id The record id to be selected from the filter results.
|
||||
* @param {Boolean} show Optional (false), if true then the method will display the record on the form.
|
||||
*/
|
||||
function select(id, show = false) {
|
||||
$filterWebhooks.find('.selected').removeClass('selected');
|
||||
|
||||
$filterWebhooks.find('.webhook-row[data-id="' + id + '"]').addClass('selected');
|
||||
|
||||
if (show) {
|
||||
const webhook = filterResults.find((filterResult) => Number(filterResult.id) === Number(id));
|
||||
|
||||
display(webhook);
|
||||
|
||||
$('#edit-webhook, #delete-webhook').prop('disabled', false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the module.
|
||||
*/
|
||||
function initialize() {
|
||||
resetForm();
|
||||
filter('');
|
||||
addEventListeners();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', initialize);
|
||||
|
||||
return {
|
||||
filter,
|
||||
save,
|
||||
remove,
|
||||
getFilterHtml,
|
||||
resetForm,
|
||||
select
|
||||
};
|
||||
})();
|
423
openapi.yml
423
openapi.yml
|
@ -27,6 +27,7 @@ tags:
|
|||
- name: services
|
||||
- name: settings
|
||||
- name: unavailabilities
|
||||
- name: webhooks
|
||||
paths:
|
||||
/availabilities:
|
||||
get:
|
||||
|
@ -62,8 +63,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/appointments:
|
||||
get:
|
||||
tags:
|
||||
|
@ -115,8 +116,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
post:
|
||||
tags:
|
||||
- appointments
|
||||
|
@ -144,8 +145,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/appointments/{appointmentId}:
|
||||
get:
|
||||
tags:
|
||||
|
@ -175,8 +176,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
put:
|
||||
tags:
|
||||
- appointments
|
||||
|
@ -212,8 +213,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
delete:
|
||||
tags:
|
||||
- appointments
|
||||
|
@ -238,8 +239,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/unavailabilities:
|
||||
get:
|
||||
tags:
|
||||
|
@ -312,8 +313,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/unavailabilities/{unavailabilityId}:
|
||||
get:
|
||||
tags:
|
||||
|
@ -343,8 +344,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
put:
|
||||
tags:
|
||||
- unavailabilities
|
||||
|
@ -380,8 +381,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
delete:
|
||||
tags:
|
||||
- unavailabilities
|
||||
|
@ -406,8 +407,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/customers:
|
||||
get:
|
||||
tags:
|
||||
|
@ -454,8 +455,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
post:
|
||||
tags:
|
||||
- customers
|
||||
|
@ -482,8 +483,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
x-codegen-request-body-name: body
|
||||
/customers/{customerId}:
|
||||
get:
|
||||
|
@ -514,8 +515,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
put:
|
||||
tags:
|
||||
- customers
|
||||
|
@ -551,8 +552,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
delete:
|
||||
tags:
|
||||
- customers
|
||||
|
@ -577,8 +578,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/services:
|
||||
get:
|
||||
tags:
|
||||
|
@ -625,8 +626,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
post:
|
||||
tags:
|
||||
- services
|
||||
|
@ -654,8 +655,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/services/{serviceId}:
|
||||
get:
|
||||
tags:
|
||||
|
@ -685,8 +686,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
put:
|
||||
tags:
|
||||
- services
|
||||
|
@ -722,8 +723,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
delete:
|
||||
tags:
|
||||
- services
|
||||
|
@ -748,8 +749,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/categories:
|
||||
get:
|
||||
tags:
|
||||
|
@ -796,8 +797,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
post:
|
||||
tags:
|
||||
- categories
|
||||
|
@ -825,8 +826,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/categories/{categoryId}:
|
||||
get:
|
||||
tags:
|
||||
|
@ -856,8 +857,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
put:
|
||||
tags:
|
||||
- categories
|
||||
|
@ -893,8 +894,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
delete:
|
||||
tags:
|
||||
- categories
|
||||
|
@ -919,8 +920,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/admins:
|
||||
get:
|
||||
tags:
|
||||
|
@ -967,8 +968,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
post:
|
||||
tags:
|
||||
- admins
|
||||
|
@ -996,8 +997,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/admins/{adminId}:
|
||||
get:
|
||||
tags:
|
||||
|
@ -1027,8 +1028,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
put:
|
||||
tags:
|
||||
- admins
|
||||
|
@ -1064,8 +1065,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
delete:
|
||||
tags:
|
||||
- admins
|
||||
|
@ -1090,8 +1091,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/providers:
|
||||
get:
|
||||
tags:
|
||||
|
@ -1138,8 +1139,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
post:
|
||||
tags:
|
||||
- providers
|
||||
|
@ -1167,8 +1168,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/providers/{providerId}:
|
||||
get:
|
||||
tags:
|
||||
|
@ -1198,8 +1199,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
put:
|
||||
tags:
|
||||
- providers
|
||||
|
@ -1235,8 +1236,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
delete:
|
||||
tags:
|
||||
- providers
|
||||
|
@ -1261,8 +1262,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/secretaries:
|
||||
get:
|
||||
tags:
|
||||
|
@ -1309,8 +1310,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
post:
|
||||
tags:
|
||||
- secretaries
|
||||
|
@ -1338,8 +1339,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/secretaries/{secretaryId}:
|
||||
get:
|
||||
tags:
|
||||
|
@ -1369,8 +1370,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
put:
|
||||
tags:
|
||||
- secretaries
|
||||
|
@ -1406,8 +1407,8 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
delete:
|
||||
tags:
|
||||
- secretaries
|
||||
|
@ -1426,8 +1427,8 @@ paths:
|
|||
'404':
|
||||
description: Not Found
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/settings:
|
||||
get:
|
||||
tags:
|
||||
|
@ -1474,8 +1475,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/settings/{settingName}:
|
||||
get:
|
||||
tags:
|
||||
|
@ -1505,8 +1506,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
put:
|
||||
tags:
|
||||
- settings
|
||||
|
@ -1542,8 +1543,179 @@ paths:
|
|||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: []
|
||||
- BasicAuth: []
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/webhooks:
|
||||
get:
|
||||
tags:
|
||||
- webhooks
|
||||
summary: Get all webhooks
|
||||
parameters:
|
||||
- name: page
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
- name: length
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
- name: sort
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
- name: q
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
- name: fields
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
- name: with
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/WebhookCollection'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
'500':
|
||||
description: Internal Server Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
post:
|
||||
tags:
|
||||
- webhooks
|
||||
summary: Create a webhook
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/WebhookPayload'
|
||||
required: true
|
||||
responses:
|
||||
'201':
|
||||
description: Created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/WebhookRecord'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
'500':
|
||||
description: Internal Server Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
/webhooks/{webhookId}:
|
||||
get:
|
||||
tags:
|
||||
- webhooks
|
||||
summary: Get a webhook
|
||||
parameters:
|
||||
- name: webhookId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/WebhookRecord'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
'404':
|
||||
description: Not Found
|
||||
'500':
|
||||
description: Internal Server Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
put:
|
||||
tags:
|
||||
- webhooks
|
||||
summary: Update a webhook
|
||||
parameters:
|
||||
- name: webhookId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/WebhookPayload'
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/WebhookRecord'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
'404':
|
||||
description: Not Found
|
||||
'500':
|
||||
description: Internal Server Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
x-codegen-request-body-name: body
|
||||
security:
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
delete:
|
||||
tags:
|
||||
- webhooks
|
||||
summary: Delete a webhook
|
||||
parameters:
|
||||
- name: webhookId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
responses:
|
||||
'204':
|
||||
description: No Content
|
||||
'401':
|
||||
description: Unauthorized
|
||||
'404':
|
||||
description: Not Found
|
||||
'500':
|
||||
description: Internal Server Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
security:
|
||||
- BearerToken: [ ]
|
||||
- BasicAuth: [ ]
|
||||
components:
|
||||
schemas:
|
||||
Availabilities:
|
||||
|
@ -2019,7 +2191,7 @@ components:
|
|||
notes: This is a test provider.
|
||||
timezone: UTC
|
||||
language: english
|
||||
services: []
|
||||
services: [ ]
|
||||
settings:
|
||||
username: chrisdoe
|
||||
password: Password@123
|
||||
|
@ -2035,23 +2207,23 @@ components:
|
|||
monday:
|
||||
start: '09:00'
|
||||
end: '17:00'
|
||||
breaks: []
|
||||
breaks: [ ]
|
||||
tuesday:
|
||||
start: '09:00'
|
||||
end: '17:00'
|
||||
breaks: []
|
||||
breaks: [ ]
|
||||
wednesday:
|
||||
start: '09:00'
|
||||
end: '17:00'
|
||||
breaks: []
|
||||
breaks: [ ]
|
||||
thursday:
|
||||
start: '09:00'
|
||||
end: '17:00'
|
||||
breaks: []
|
||||
breaks: [ ]
|
||||
friday:
|
||||
start: '09:00'
|
||||
end: '17:00'
|
||||
breaks: []
|
||||
breaks: [ ]
|
||||
saturday: null
|
||||
ProviderPayload:
|
||||
type: object
|
||||
|
@ -2118,7 +2290,7 @@ components:
|
|||
notes: This is a test provider.
|
||||
timezone: UTC
|
||||
language: english
|
||||
services: []
|
||||
services: [ ]
|
||||
settings:
|
||||
username: chrisdoe
|
||||
password: Password@123
|
||||
|
@ -2134,23 +2306,23 @@ components:
|
|||
monday:
|
||||
start: '09:00'
|
||||
end: '17:00'
|
||||
breaks: []
|
||||
breaks: [ ]
|
||||
tuesday:
|
||||
start: '09:00'
|
||||
end: '17:00'
|
||||
breaks: []
|
||||
breaks: [ ]
|
||||
wednesday:
|
||||
start: '09:00'
|
||||
end: '17:00'
|
||||
breaks: []
|
||||
breaks: [ ]
|
||||
thursday:
|
||||
start: '09:00'
|
||||
end: '17:00'
|
||||
breaks: []
|
||||
breaks: [ ]
|
||||
friday:
|
||||
start: '09:00'
|
||||
end: '17:00'
|
||||
breaks: []
|
||||
breaks: [ ]
|
||||
saturday: null
|
||||
ProviderCollection:
|
||||
type: array
|
||||
|
@ -2212,7 +2384,7 @@ components:
|
|||
notes: This is a test service.
|
||||
timezone: UTC
|
||||
language: english
|
||||
providers: []
|
||||
providers: [ ]
|
||||
settings:
|
||||
username: jessydoe
|
||||
password: Password@123
|
||||
|
@ -2271,7 +2443,7 @@ components:
|
|||
notes: This is a test service.
|
||||
timezone: UTC
|
||||
language: english
|
||||
providers: []
|
||||
providers: [ ]
|
||||
settings:
|
||||
username: jessydoe
|
||||
password: Password@123
|
||||
|
@ -2302,6 +2474,57 @@ components:
|
|||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/SettingRecord'
|
||||
WebhookRecord:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
actions:
|
||||
type: string
|
||||
secretToken:
|
||||
type: string
|
||||
isSslVerified:
|
||||
type: boolean
|
||||
notes:
|
||||
type: string
|
||||
example:
|
||||
id: 1
|
||||
name: Test Webhook
|
||||
url: https://example.org/webhook?withTestQueryParam=Value
|
||||
actions: appointment_create,appointment_update,customer_delete,category_create
|
||||
secretToken: SecureSecretTokenHere
|
||||
isSslVerified: true
|
||||
notes: This is a webhook.
|
||||
WebhookPayload:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
actions:
|
||||
type: string
|
||||
secretToken:
|
||||
type: string
|
||||
isSslVerified:
|
||||
type: boolean
|
||||
notes:
|
||||
type: string
|
||||
example:
|
||||
name: Test Webhook
|
||||
url: https://example.org/webhook?withTestQueryParam=Value
|
||||
actions: appointment_create,appointment_update,customer_delete,category_create
|
||||
secretToken: SecureSecretTokenHere
|
||||
isSslVerified: true
|
||||
notes: This is a webhook.
|
||||
WebhookCollection:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/WebhookRecord'
|
||||
ErrorResponse:
|
||||
type: object
|
||||
properties:
|
||||
|
|
Loading…
Reference in New Issue