diff --git a/application/controllers/settings/Legal_contents.php b/application/controllers/settings/Legal_contents.php
new file mode 100644
index 00000000..4d9c50f2
--- /dev/null
+++ b/application/controllers/settings/Legal_contents.php
@@ -0,0 +1,113 @@
+
+ * @copyright Copyright (c) 2013 - 2020, Alex Tselegidis
+ * @license https://opensource.org/licenses/GPL-3.0 - GPLv3
+ * @link https://easyappointments.org
+ * @since v1.5.0
+ * ---------------------------------------------------------------------------- */
+
+/**
+ * Client form controller.
+ *
+ * Handles legal contents settings related operations.
+ *
+ * @package Controllers
+ */
+class Legal_contents extends EA_Controller {
+ /**
+ * @var array
+ */
+ protected array $permissions;
+
+ /**
+ * Legal_contents constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->load->model('appointments_model');
+ $this->load->model('customers_model');
+ $this->load->model('services_model');
+ $this->load->model('providers_model');
+ $this->load->model('roles_model');
+ $this->load->model('settings_model');
+
+ $this->load->library('accounts');
+ $this->load->library('google_sync');
+ $this->load->library('notifications');
+ $this->load->library('synchronization');
+ $this->load->library('timezones');
+
+ $role_slug = session('role_slug');
+
+ if ($role_slug)
+ {
+ $this->permissions = $this->roles_model->get_permissions_by_slug($role_slug);
+ }
+ }
+
+ /**
+ * Render the settings page.
+ */
+ public function index()
+ {
+ session(['dest_url' => site_url('services')]);
+
+ if (cannot('view', 'services'))
+ {
+ show_error('Forbidden', 403);
+ }
+
+ $user_id = session('user_id');
+
+ $role_slug = session('role_slug');
+
+ $this->load->view('pages/settings/legal_contents/legal_contents_page', [
+ 'page_title' => lang('settings'),
+ 'active_menu' => PRIV_SYSTEM_SETTINGS,
+ 'user_display_name' => $this->accounts->get_user_display_name($user_id),
+ 'privileges' => $this->roles_model->get_permissions_by_slug($role_slug),
+ 'system_settings' => $this->settings_model->get(),
+ ]);
+ }
+
+ /**
+ * Save general settings.
+ */
+ public function save()
+ {
+ try
+ {
+ if ($this->permissions[PRIV_SYSTEM_SETTINGS]['edit'] == FALSE)
+ {
+ throw new Exception('You do not have the required permissions for this task.');
+ }
+
+ $settings = json_decode(request('settings', FALSE), TRUE);
+
+ foreach ($settings as $setting)
+ {
+ $existing_setting = $this->settings_model->query()->where('name', $setting['name'])->get()->row_array();
+
+ if ( ! empty($existing_setting))
+ {
+ $setting['id'] = $existing_setting['id'];
+ }
+
+ $this->settings_model->save($setting);
+ }
+
+ response();
+ }
+ catch (Throwable $e)
+ {
+ json_exception($e);
+ }
+ }
+}
diff --git a/application/views/pages/settings/legal_contents/legal_contents_page.php b/application/views/pages/settings/legal_contents/legal_contents_page.php
new file mode 100755
index 00000000..f507d564
--- /dev/null
+++ b/application/views/pages/settings/legal_contents/legal_contents_page.php
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/js/backend_settings_legal_contents.js b/assets/js/backend_settings_legal_contents.js
new file mode 100644
index 00000000..2bf125f0
--- /dev/null
+++ b/assets/js/backend_settings_legal_contents.js
@@ -0,0 +1,110 @@
+/* ----------------------------------------------------------------------------
+ * Easy!Appointments - Open Source Web Scheduler
+ *
+ * @package EasyAppointments
+ * @author A.Tselegidis
+ * @copyright Copyright (c) 2013 - 2020, Alex Tselegidis
+ * @license http://opensource.org/licenses/GPL-3.0 - GPLv3
+ * @link http://easyappointments.org
+ * @since v1.0.0
+ * ---------------------------------------------------------------------------- */
+
+window.BackendSettingsLegalContents = window.BackendSettingsLegalContents || {};
+
+/**
+ * Backend Settings
+ *
+ * Contains the functionality of the backend settings page. Can either work for system or user settings,
+ * but the actions allowed to the user are restricted to his role (only admin has full privileges).
+ *
+ * @module BackendSettingsLegalContents
+ */
+(function (exports) {
+ 'use strict';
+
+ // Constants
+ exports.SETTINGS_SYSTEM = 'SETTINGS_SYSTEM';
+
+ /**
+ * Use this WorkingPlan class instance to perform actions on the page's working plan tables.
+ *
+ * @type {WorkingPlan}
+ */
+ exports.wp = {};
+
+ /**
+ * Tab settings object.
+ *
+ * @type {Object}
+ */
+ var settings = {};
+
+ /**
+ * Initialize Page
+ *
+ * @param {bool} defaultEventHandlers Optional (true), determines whether to bind the default event handlers.
+ */
+ exports.initialize = function (defaultEventHandlers) {
+ defaultEventHandlers = defaultEventHandlers || true;
+
+ $('#cookie-notice-content, #terms-and-conditions-content, #privacy-policy-content').trumbowyg();
+
+ // Apply setting values from database.
+ var workingPlan = {};
+
+ GlobalVariables.settings.system.forEach(function (setting) {
+ $('input[data-field="' + setting.name + '"]').val(setting.value);
+ $('select[data-field="' + setting.name + '"]').val(setting.value);
+
+ if (setting.name === 'display_cookie_notice') {
+ $('#display-cookie-notice').prop('checked', Boolean(Number(setting.value)));
+ }
+
+ if (setting.name === 'cookie_notice_content') {
+ $('#cookie-notice-content').trumbowyg('html', setting.value);
+ }
+
+ if (setting.name === 'display_terms_and_conditions') {
+ $('#display-terms-and-conditions').prop('checked', Boolean(Number(setting.value)));
+ }
+
+ if (setting.name === 'terms_and_conditions_content') {
+ $('#terms-and-conditions-content').trumbowyg('html', setting.value);
+ }
+
+ if (setting.name === 'display_privacy_policy') {
+ $('#display-privacy-policy').prop('checked', Boolean(Number(setting.value)));
+ }
+
+ if (setting.name === 'privacy_policy_content') {
+ $('#privacy-policy-content').trumbowyg('html', setting.value);
+ }
+ });
+
+ // Set default settings helper.
+ settings = new SystemSettingsLegalContentsHelper();
+
+ if (defaultEventHandlers) {
+ bindEventHandlers();
+ }
+
+ Backend.placeFooterToBottom();
+ };
+
+ /**
+ * Bind the backend/settings default event handlers.
+ *
+ * This method depends on the backend/settings html, so do not use this method on a different page.
+ */
+ function bindEventHandlers() {
+ /**
+ * Event: Save Settings Button "Click"
+ *
+ * Store the setting changes into the database.
+ */
+ $('.save-settings').on('click', function () {
+ var data = settings.get();
+ settings.save(data);
+ });
+ }
+})(window.BackendSettingsLegalContents);
diff --git a/assets/js/backend_settings_legal_contents_helper.js b/assets/js/backend_settings_legal_contents_helper.js
new file mode 100644
index 00000000..1aba6c5f
--- /dev/null
+++ b/assets/js/backend_settings_legal_contents_helper.js
@@ -0,0 +1,124 @@
+/* ----------------------------------------------------------------------------
+ * Easy!Appointments - Open Source Web Scheduler
+ *
+ * @package EasyAppointments
+ * @author A.Tselegidis
+ * @copyright Copyright (c) 2013 - 2020, Alex Tselegidis
+ * @license http://opensource.org/licenses/GPL-3.0 - GPLv3
+ * @link http://easyappointments.org
+ * @since v1.0.0
+ * ---------------------------------------------------------------------------- */
+
+(function () {
+ 'use strict';
+
+ /**
+ * "System Settings" Tab Helper Class
+ *
+ * @class SystemSettingsLegalContentsHelper
+ */
+ var SystemSettingsLegalContentsHelper = function () {};
+
+ /**
+ * Save the system settings.
+ *
+ * This method is run after changes are detected on the tab input fields.
+ *
+ * @param {Array} settings Contains the system settings data.
+ */
+ SystemSettingsLegalContentsHelper.prototype.save = function (settings) {
+ if (!this.validate()) {
+ return; // Validation failed, do not proceed.
+ }
+
+ var url = GlobalVariables.baseUrl + '/index.php/settings/legal_contents/save';
+
+ var data = {
+ csrfToken: GlobalVariables.csrfToken,
+ settings: JSON.stringify(settings),
+ type: BackendSettingsLegalContents.SETTINGS_SYSTEM
+ };
+
+ $.post(url, data).done(function () {
+ Backend.displayNotification(EALang.settings_saved);
+ });
+ };
+
+ /**
+ * Prepare the system settings array.
+ *
+ * This method uses the DOM elements of the backend/settings page, so it can't be used in another page.
+ *
+ * @return {Array} Returns the system settings array.
+ */
+ SystemSettingsLegalContentsHelper.prototype.get = function () {
+ var settings = [];
+
+ // Legal Contents Tab
+
+ settings.push({
+ name: 'display_cookie_notice',
+ value: $('#display-cookie-notice').prop('checked') ? '1' : '0'
+ });
+
+ settings.push({
+ name: 'cookie_notice_content',
+ value: $('#cookie-notice-content').trumbowyg('html')
+ });
+
+ settings.push({
+ name: 'display_terms_and_conditions',
+ value: $('#display-terms-and-conditions').prop('checked') ? '1' : '0'
+ });
+
+ settings.push({
+ name: 'terms_and_conditions_content',
+ value: $('#terms-and-conditions-content').trumbowyg('html')
+ });
+
+ settings.push({
+ name: 'display_privacy_policy',
+ value: $('#display-privacy-policy').prop('checked') ? '1' : '0'
+ });
+
+ settings.push({
+ name: 'privacy_policy_content',
+ value: $('#privacy-policy-content').trumbowyg('html')
+ });
+
+ return settings;
+ };
+
+ /**
+ * Validate the settings data.
+ *
+ * If the validation fails then display a message to the user.
+ *
+ * @return {Boolean} Returns the validation result.
+ */
+ SystemSettingsLegalContentsHelper.prototype.validate = function () {
+ $('#legal-contents .has-error').removeClass('has-error');
+
+ try {
+ // Validate required fields.
+ var missingRequired = false;
+ $('#general .required').each(function (index, requiredField) {
+ if (!$(requiredField).val()) {
+ $(requiredField).closest('.form-group').addClass('has-error');
+ missingRequired = true;
+ }
+ });
+
+ if (missingRequired) {
+ throw new Error(EALang.fields_are_required);
+ }
+
+ return true;
+ } catch (error) {
+ Backend.displayNotification(error.message);
+ return false;
+ }
+ };
+
+ window.SystemSettingsLegalContentsHelper = SystemSettingsLegalContentsHelper;
+})();