From c241338fbef4c14cb18d81f20fac2fbc883dbeba Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Sun, 5 Nov 2017 12:00:41 -0500 Subject: [PATCH 01/74] Couple small QoL changes --- admin/calendar.php | 20 +++++++++++--------- calendar.php | 6 +++++- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/admin/calendar.php b/admin/calendar.php index a3256299..679bfd21 100644 --- a/admin/calendar.php +++ b/admin/calendar.php @@ -551,16 +551,18 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php'); +
-

-

-

-

-

-

-

-

-

+
-

\ No newline at end of file From c985f80452f62b485af56556acf9bc953364b767 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Thu, 9 Nov 2017 13:04:10 -0500 Subject: [PATCH 02/74] Working on moving service messages to an API endpoint --- admin/service_messages.php | 16 +------ .../ServiceMessages/ServiceMessage.php | 33 ++++++++++++++ .../ServiceMessages/ServiceMessageHandler.php | 22 ++++++++++ .../ServiceMessages/ServiceMessageStyle.php | 44 +++++++++++++++++++ .../ServiceMessagesController.php | 38 ++++++++++++++++ .../ServiceMessagesGateway.php | 43 ++++++++++++++++++ 6 files changed, 181 insertions(+), 15 deletions(-) create mode 100644 api/BusinessLogic/ServiceMessages/ServiceMessage.php create mode 100644 api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php create mode 100644 api/BusinessLogic/ServiceMessages/ServiceMessageStyle.php create mode 100644 api/Controllers/ServiceMessages/ServiceMessagesController.php create mode 100644 api/DataAccess/ServiceMessages/ServiceMessagesGateway.php diff --git a/admin/service_messages.php b/admin/service_messages.php index 580d0012..9ba0b9a9 100644 --- a/admin/service_messages.php +++ b/admin/service_messages.php @@ -687,21 +687,7 @@ function new_sm() exit; } - // Get the latest service message order - $res = hesk_dbQuery("SELECT `order` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages` ORDER BY `order` DESC LIMIT 1"); - $row = hesk_dbFetchRow($res); - $my_order = intval($row[0]) + 10; - - // Insert service message into database - hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages` (`author`,`title`,`message`,`style`,`type`,`order`, `icon`) VALUES ( - '" . intval($_SESSION['id']) . "', - '" . hesk_dbEscape($title) . "', - '" . hesk_dbEscape($message) . "', - '{$style}', - '{$type}', - '{$my_order}', - '{$icon}' - )"); + $_SESSION['smord'] = hesk_dbInsertID(); hesk_process_messages($hesklang['sm_added'], 'service_messages.php', 'SUCCESS'); diff --git a/api/BusinessLogic/ServiceMessages/ServiceMessage.php b/api/BusinessLogic/ServiceMessages/ServiceMessage.php new file mode 100644 index 00000000..1951b672 --- /dev/null +++ b/api/BusinessLogic/ServiceMessages/ServiceMessage.php @@ -0,0 +1,33 @@ +serviceMessageGateway = $serviceMessagesGateway; + } + + function createServiceMessage($serviceMessage, $heskSettings) { + // TODO Validate + + return $this->serviceMessageGateway->createServiceMessage($serviceMessage, $heskSettings); + } +} \ No newline at end of file diff --git a/api/BusinessLogic/ServiceMessages/ServiceMessageStyle.php b/api/BusinessLogic/ServiceMessages/ServiceMessageStyle.php new file mode 100644 index 00000000..4dc3e388 --- /dev/null +++ b/api/BusinessLogic/ServiceMessages/ServiceMessageStyle.php @@ -0,0 +1,44 @@ + self::NONE, + 1 => self::SUCCESS, + 2 => self::INFO, + 3 => self::NOTICE, + 4 => self::ERROR + ); + + if (!isset($styles[$id])) { + throw new \Exception("Style {$id} is not a valid service message style."); + } + + return $styles[$id]; + } + + static function getIdForStyle($style) { + $styles = array( + self::NONE => 0, + self::SUCCESS => 1, + self::INFO => 2, + self::NOTICE => 3, + self::ERROR => 4 + ); + + if (!isset($styles[$style])) { + throw new \Exception("Style {$style} is not a valid service message style."); + } + + return $styles[$style]; + } +} \ No newline at end of file diff --git a/api/Controllers/ServiceMessages/ServiceMessagesController.php b/api/Controllers/ServiceMessages/ServiceMessagesController.php new file mode 100644 index 00000000..2e9e83c8 --- /dev/null +++ b/api/Controllers/ServiceMessages/ServiceMessagesController.php @@ -0,0 +1,38 @@ +get(ServiceMessageHandler::clazz()); + + $data = JsonRetriever::getJsonData(); + $element = $handler->createServiceMessage($this->buildElementModel($data, $userContext), $hesk_settings); + + return output($element, 201); + } + + /** + * @param $data array + * @param $userContext UserContext + * @return ServiceMessage + */ + private function buildElementModel($data, $userContext) { + $serviceMessage = new ServiceMessage(); + $serviceMessage->createdBy = $userContext->id; + $serviceMessage->icon = $data['icon']; + $serviceMessage->message = $data['message']; + $serviceMessage->published = $data['published']; + $serviceMessage->style = $data['style']; + + return $serviceMessage; + } +} \ No newline at end of file diff --git a/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php b/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php new file mode 100644 index 00000000..9e6adc39 --- /dev/null +++ b/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php @@ -0,0 +1,43 @@ +init(); + + // Get the latest service message order + $res = hesk_dbQuery("SELECT `order` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages` ORDER BY `order` DESC LIMIT 1"); + $row = hesk_dbFetchRow($res); + $myOrder = intval($row[0]) + 10; + + $style = ServiceMessageStyle::getIdForStyle($serviceMessage->style); + $type = $serviceMessage->published ? 0 : 1; + + // Insert service message into database + hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages` (`author`,`title`,`message`,`style`,`type`,`order`, `icon`) VALUES ( + '" . intval($serviceMessage->createdBy) . "', + '" . hesk_dbEscape($serviceMessage->title) . "', + '" . hesk_dbEscape($serviceMessage->message) . "', + '" . hesk_dbEscape($style) . "', + '{$type}', + '{$myOrder}', + '" . hesk_dbEscape($serviceMessage->icon) . "' + )"); + + $serviceMessage->id = hesk_dbInsertID(); + + $this->close(); + + return $serviceMessage; + } +} \ No newline at end of file From d305ccf9b3a162210ac68ab09a7108acf334ad87 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Thu, 9 Nov 2017 22:02:26 -0500 Subject: [PATCH 03/74] Add POST endpoint for creating service messages --- .../ServiceMessages/ServiceMessageHandler.php | 37 ++++++++++++++++++- api/index.php | 2 + 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php b/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php index 474beb51..a1563807 100644 --- a/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php +++ b/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php @@ -4,6 +4,8 @@ namespace BusinessLogic\ServiceMessages; // TODO Test +use BusinessLogic\Exceptions\ValidationException; +use BusinessLogic\ValidationModel; use DataAccess\ServiceMessages\ServiceMessagesGateway; class ServiceMessageHandler extends \BaseClass { @@ -15,8 +17,41 @@ class ServiceMessageHandler extends \BaseClass { } function createServiceMessage($serviceMessage, $heskSettings) { - // TODO Validate + $this->validate($serviceMessage); return $this->serviceMessageGateway->createServiceMessage($serviceMessage, $heskSettings); } + + /** + * @param $serviceMessage ServiceMessage + * @throws ValidationException + */ + private function validate($serviceMessage) { + $validationModel = new ValidationModel(); + if ($serviceMessage->createdBy < 1) { + $validationModel->errorKeys[] = 'MISSING_CREATOR'; + } + if ($serviceMessage->icon === null || trim($serviceMessage->icon) === '') { + $validationModel->errorKeys[] = 'MISSING_ICON'; + } + if ($serviceMessage->message === null || trim($serviceMessage->message) === '') { + $validationModel->errorKeys[] = 'MISSING_MESSAGE'; + } + if ($serviceMessage->title === null || trim($serviceMessage->title) === '') { + $validationModel->errorKeys[] = 'MISSING_TITLE'; + } + if ($serviceMessage->style === null || trim($serviceMessage->style) === '') { + $validationModel->errorKeys[] = 'MISSING_STYLE'; + } + try { + ServiceMessageStyle::getIdForStyle($serviceMessage->style); + } catch (\Exception $e) { + $validationModel->errorKeys[] = 'INVALID_STYLE'; + } + + if (count($validationModel->errorKeys) > 0) { + // Validation failed + throw new ValidationException($validationModel); + } + } } \ No newline at end of file diff --git a/api/index.php b/api/index.php index 4766701c..6700fa56 100644 --- a/api/index.php +++ b/api/index.php @@ -202,6 +202,8 @@ Link::all(array( '/v1/statuses' => action(\Controllers\Statuses\StatusController::clazz(), RequestMethod::all()), // Settings '/v1/settings' => action(\Controllers\Settings\SettingsController::clazz(), RequestMethod::all()), + // Service Messages + '/v1/service-messages' => action(\Controllers\ServiceMessages\ServiceMessagesController::clazz(), array(RequestMethod::POST)), /* Internal use only routes */ // Resend email response From 311a48487d1081a5b20eb7c14bddca043882dbfa Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Sat, 11 Nov 2017 16:33:43 -0500 Subject: [PATCH 04/74] Add POST service-messages endpoint --- .../ServiceMessages/ServiceMessageHandler.php | 23 ++++++++++++++++--- .../ServiceMessagesController.php | 1 + .../ServiceMessagesGateway.php | 8 +++++++ inc/common.inc.php | 3 ++- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php b/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php index a1563807..88bcd978 100644 --- a/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php +++ b/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php @@ -19,6 +19,26 @@ class ServiceMessageHandler extends \BaseClass { function createServiceMessage($serviceMessage, $heskSettings) { $this->validate($serviceMessage); + if ($serviceMessage->icon === null) { + switch ($serviceMessage->style) { + case ServiceMessageStyle::NONE: + $serviceMessage->icon = ''; + break; + case ServiceMessageStyle::INFO: + $serviceMessage->icon = 'fa fa-comment'; + break; + case ServiceMessageStyle::NOTICE: + $serviceMessage->icon = 'fa fa-exclamation-triangle'; + break; + case ServiceMessageStyle::ERROR: + $serviceMessage->icon = 'fa fa-times-circle'; + break; + case ServiceMessageStyle::SUCCESS: + $serviceMessage->icon = 'fa fa-check-circle'; + break; + } + } + return $this->serviceMessageGateway->createServiceMessage($serviceMessage, $heskSettings); } @@ -31,9 +51,6 @@ class ServiceMessageHandler extends \BaseClass { if ($serviceMessage->createdBy < 1) { $validationModel->errorKeys[] = 'MISSING_CREATOR'; } - if ($serviceMessage->icon === null || trim($serviceMessage->icon) === '') { - $validationModel->errorKeys[] = 'MISSING_ICON'; - } if ($serviceMessage->message === null || trim($serviceMessage->message) === '') { $validationModel->errorKeys[] = 'MISSING_MESSAGE'; } diff --git a/api/Controllers/ServiceMessages/ServiceMessagesController.php b/api/Controllers/ServiceMessages/ServiceMessagesController.php index 2e9e83c8..d6960764 100644 --- a/api/Controllers/ServiceMessages/ServiceMessagesController.php +++ b/api/Controllers/ServiceMessages/ServiceMessagesController.php @@ -28,6 +28,7 @@ class ServiceMessagesController extends \BaseClass { private function buildElementModel($data, $userContext) { $serviceMessage = new ServiceMessage(); $serviceMessage->createdBy = $userContext->id; + $serviceMessage->title = $data['title']; $serviceMessage->icon = $data['icon']; $serviceMessage->message = $data['message']; $serviceMessage->published = $data['published']; diff --git a/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php b/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php index 9e6adc39..82d9e6b8 100644 --- a/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php +++ b/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php @@ -3,6 +3,7 @@ namespace DataAccess\ServiceMessages; +use BusinessLogic\DateTimeHelpers; use BusinessLogic\ServiceMessages\ServiceMessage; use BusinessLogic\ServiceMessages\ServiceMessageStyle; use DataAccess\CommonDao; @@ -36,6 +37,13 @@ class ServiceMessagesGateway extends CommonDao { $serviceMessage->id = hesk_dbInsertID(); + // Get the autogenerated fields + $rs = hesk_dbQuery("SELECT `dt`, `order` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages` + WHERE `id` = " . intval($serviceMessage->id)); + $row = hesk_dbFetchAssoc($rs); + $serviceMessage->dateCreated = $row['dt']; + $serviceMessage->order = $row['order']; + $this->close(); return $serviceMessage; diff --git a/inc/common.inc.php b/inc/common.inc.php index be8f07eb..802e44da 100644 --- a/inc/common.inc.php +++ b/inc/common.inc.php @@ -185,7 +185,8 @@ function hesk_service_message($sm) ?>
'; ?> - +
+

Date: Sat, 11 Nov 2017 22:16:25 -0500 Subject: [PATCH 05/74] Add more endpoints for service messages --- .../ServiceMessages/ServiceMessageHandler.php | 35 +++++++++++- .../ServiceMessagesController.php | 34 +++++++++++- .../ServiceMessagesGateway.php | 54 ++++++++++++++++++- api/index.php | 2 +- 4 files changed, 119 insertions(+), 6 deletions(-) diff --git a/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php b/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php index 88bcd978..d70f142f 100644 --- a/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php +++ b/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php @@ -42,13 +42,44 @@ class ServiceMessageHandler extends \BaseClass { return $this->serviceMessageGateway->createServiceMessage($serviceMessage, $heskSettings); } + function getServiceMessages($heskSettings) { + return $this->serviceMessageGateway->getServiceMessages($heskSettings); + } + + function editServiceMessage($serviceMessage, $heskSettings) { + $this->validate($serviceMessage, false); + + if ($serviceMessage->icon === null) { + switch ($serviceMessage->style) { + case ServiceMessageStyle::NONE: + $serviceMessage->icon = ''; + break; + case ServiceMessageStyle::INFO: + $serviceMessage->icon = 'fa fa-comment'; + break; + case ServiceMessageStyle::NOTICE: + $serviceMessage->icon = 'fa fa-exclamation-triangle'; + break; + case ServiceMessageStyle::ERROR: + $serviceMessage->icon = 'fa fa-times-circle'; + break; + case ServiceMessageStyle::SUCCESS: + $serviceMessage->icon = 'fa fa-check-circle'; + break; + } + } + + return $this->serviceMessageGateway->updateServiceMessage($serviceMessage, $heskSettings); + } + /** * @param $serviceMessage ServiceMessage + * @param bool $isNew * @throws ValidationException */ - private function validate($serviceMessage) { + private function validate($serviceMessage, $isNew = true) { $validationModel = new ValidationModel(); - if ($serviceMessage->createdBy < 1) { + if ($isNew && $serviceMessage->createdBy < 1) { $validationModel->errorKeys[] = 'MISSING_CREATOR'; } if ($serviceMessage->message === null || trim($serviceMessage->message) === '') { diff --git a/api/Controllers/ServiceMessages/ServiceMessagesController.php b/api/Controllers/ServiceMessages/ServiceMessagesController.php index d6960764..f17d6e14 100644 --- a/api/Controllers/ServiceMessages/ServiceMessagesController.php +++ b/api/Controllers/ServiceMessages/ServiceMessagesController.php @@ -8,6 +8,15 @@ use BusinessLogic\ServiceMessages\ServiceMessageHandler; use Controllers\JsonRetriever; class ServiceMessagesController extends \BaseClass { + function get() { + global $applicationContext, $hesk_settings; + + /* @var $handler ServiceMessageHandler */ + $handler = $applicationContext->get(ServiceMessageHandler::clazz()); + + return output($handler->getServiceMessages($hesk_settings)); + } + function post() { global $applicationContext, $userContext, $hesk_settings; @@ -20,14 +29,35 @@ class ServiceMessagesController extends \BaseClass { return output($element, 201); } + function put() { + global $applicationContext, $hesk_settings; + + /* @var $handler ServiceMessageHandler */ + $handler = $applicationContext->get(ServiceMessageHandler::clazz()); + + $data = JsonRetriever::getJsonData(); + $element = $handler->editServiceMessage($this->buildElementModel($data, null, false), $hesk_settings); + + return output($element); + } + /** * @param $data array * @param $userContext UserContext * @return ServiceMessage */ - private function buildElementModel($data, $userContext) { + private function buildElementModel($data, $userContext, $creating = true) { $serviceMessage = new ServiceMessage(); - $serviceMessage->createdBy = $userContext->id; + + if (!$creating) { + $serviceMessage->id = $data['id']; + $serviceMessage->order = $data['order']; + } + + if ($creating) { + $serviceMessage->createdBy = $userContext->id; + } + $serviceMessage->title = $data['title']; $serviceMessage->icon = $data['icon']; $serviceMessage->message = $data['message']; diff --git a/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php b/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php index 82d9e6b8..9dfb1796 100644 --- a/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php +++ b/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php @@ -42,7 +42,59 @@ class ServiceMessagesGateway extends CommonDao { WHERE `id` = " . intval($serviceMessage->id)); $row = hesk_dbFetchAssoc($rs); $serviceMessage->dateCreated = $row['dt']; - $serviceMessage->order = $row['order']; + $serviceMessage->order = intval($row['order']); + + $this->close(); + + return $serviceMessage; + } + + function getServiceMessages($heskSettings) { + $this->init(); + + $serviceMessages = array(); + + $rs = hesk_dbQuery("SELECT * FROM `". hesk_dbEscape($heskSettings['db_pfix']) . "service_messages` ORDER BY `id`"); + while ($row = hesk_dbFetchAssoc($rs)) { + $serviceMessage = new ServiceMessage(); + $serviceMessage->id = $row['id']; + $serviceMessage->published = intval($row['type']) !== 1; + $serviceMessage->createdBy = intval($row['author']); + $serviceMessage->order = intval($row['order']); + $serviceMessage->dateCreated = $row['dt']; + $serviceMessage->title = $row['title']; + $serviceMessage->message = $row['message']; + $serviceMessage->style = ServiceMessageStyle::getStyleById($row['style']); + $serviceMessage->icon = $row['icon']; + $serviceMessages[] = $serviceMessage; + } + + $this->close(); + + return $serviceMessages; + } + + function updateServiceMessage($serviceMessage, $heskSettings) { + $this->init(); + + $style = ServiceMessageStyle::getIdForStyle($serviceMessage->style); + $type = $serviceMessage->published ? 0 : 1; + + hesk_dbQuery("UPDATE `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages` + SET `title` = '" . hesk_dbEscape($serviceMessage->title) . "', + `message` = '" . hesk_dbEscape($serviceMessage->message) . "', + `style` = '" . intval($style) . "', + `type` = " . intval($type) . ", + `icon` = '" . hesk_dbEscape($serviceMessage->icon) . "' + WHERE `id` = " . intval($serviceMessage->id)); + + $otherFieldsRs = hesk_dbQuery("SELECT `dt`, `author`, `order` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages` + WHERE `id` = " . intval($serviceMessage->id)); + $otherFields = hesk_dbFetchAssoc($otherFieldsRs); + + $serviceMessage->order = intval($otherFields['order']); + $serviceMessage->createdBy = intval($otherFields['author']); + $serviceMessage->dateCreated = $otherFields['dt']; $this->close(); diff --git a/api/index.php b/api/index.php index 6700fa56..afa70f70 100644 --- a/api/index.php +++ b/api/index.php @@ -203,7 +203,7 @@ Link::all(array( // Settings '/v1/settings' => action(\Controllers\Settings\SettingsController::clazz(), RequestMethod::all()), // Service Messages - '/v1/service-messages' => action(\Controllers\ServiceMessages\ServiceMessagesController::clazz(), array(RequestMethod::POST)), + '/v1/service-messages' => action(\Controllers\ServiceMessages\ServiceMessagesController::clazz(), array(RequestMethod::GET, RequestMethod::POST, RequestMethod::PUT)), /* Internal use only routes */ // Resend email response From c00d5641e426b37145135bbe60e5121018917297 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Sun, 12 Nov 2017 22:22:28 -0500 Subject: [PATCH 06/74] Service messages page can now retrieve service messages via AJAX --- admin/service_messages.php | 870 +++++------------- .../ServiceMessages/ServiceMessageHandler.php | 40 +- .../ServiceMessagesController.php | 12 + .../ServiceMessagesGateway.php | 32 +- api/autoload.php | 1 + api/index.php | 10 +- internal-api/js/service-messages.js | 362 ++++++++ 7 files changed, 706 insertions(+), 621 deletions(-) create mode 100644 internal-api/js/service-messages.js diff --git a/admin/service_messages.php b/admin/service_messages.php index 9ba0b9a9..b83d9378 100644 --- a/admin/service_messages.php +++ b/admin/service_messages.php @@ -15,6 +15,7 @@ define('IN_SCRIPT', 1); define('HESK_PATH', '../'); define('PAGE_TITLE', 'ADMIN_SERVICE_MESSAGES'); define('MFH_PAGE_LAYOUT', 'TOP_ONLY'); +define('EXTRA_JS', ''); /* Get all the required files and functions */ require(HESK_PATH . 'hesk_settings.inc.php'); @@ -31,26 +32,8 @@ hesk_isLoggedIn(); hesk_checkPermission('can_service_msg'); // Define required constants -define('LOAD_TABS', 1); define('WYSIWYG', 1); -// What should we do? -if ($action = hesk_REQUEST('a')) { - if ($action == 'edit_sm') { - edit_sm(); - } elseif (defined('HESK_DEMO')) { - hesk_process_messages($hesklang['ddemo'], 'service_messages.php', 'NOTICE'); - } elseif ($action == 'new_sm') { - new_sm(); - } elseif ($action == 'save_sm') { - save_sm(); - } elseif ($action == 'order_sm') { - order_sm(); - } elseif ($action == 'remove_sm') { - remove_sm(); - } -} - /* Print header */ require_once(HESK_PATH . 'inc/headerAdmin.inc.php'); @@ -60,638 +43,293 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
+
+

+ +

+
+ +
+
-
- var users = [];'; +$usersRs = hesk_dbQuery("SELECT `id`, `name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` WHERE `active` = '1'"); +$users = array(); +while ($row = hesk_dbFetchAssoc($usersRs)) { + $users[] = $row; + echo "users[" . $row['id'] . "] = { + id: ".$row['id'].", + name: '".$row['name']."' + }\n"; +} +echo ''; +?> + + + -hesk_cleanSessionVars(array('new_sm', 'preview_sm', 'edit_sm')); + 4 || $style < 0) { - $style = 0; - } - - $type = empty($_POST['type']) ? 0 : 1; - $icon = hesk_POST('icon'); - $title = hesk_input(hesk_POST('title')) or $hesk_error_buffer[] = $hesklang['sm_e_title']; - $message = hesk_getHTML(hesk_POST('message')); - - // Clean the HTML code - require(HESK_PATH . 'inc/htmlpurifier/HeskHTMLPurifier.php'); - $purifier = new HeskHTMLPurifier($hesk_settings['cache_dir']); - $message = $purifier->heskPurify($message); - - // Any errors? - if (count($hesk_error_buffer)) { - $_SESSION['edit_sm'] = true; - - $_SESSION['new_sm'] = array( - 'id' => $id, - 'style' => $style, - 'type' => $type, - 'title' => $title, - 'icon' => $icon, - 'message' => hesk_input(hesk_POST('message')), - ); - - $tmp = ''; - foreach ($hesk_error_buffer as $error) { - $tmp .= "
  • $error
  • \n"; - } - $hesk_error_buffer = $tmp; - - $hesk_error_buffer = $hesklang['rfm'] . '

      ' . $hesk_error_buffer . '
    '; - hesk_process_messages($hesk_error_buffer, 'service_messages.php'); - } - - // Just preview the message? - if (isset($_POST['sm_preview'])) { - $_SESSION['preview_sm'] = true; - $_SESSION['edit_sm'] = true; - - $_SESSION['new_sm'] = array( - 'id' => $id, - 'style' => $style, - 'type' => $type, - 'title' => $title, - 'message' => $message, - 'icon' => $icon, - ); - - header('Location: service_messages.php'); - exit; - } - - // Update the service message in the database - hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages` SET - `author` = '" . intval($_SESSION['id']) . "', - `title` = '" . hesk_dbEscape($title) . "', - `message` = '" . hesk_dbEscape($message) . "', - `style` = '{$style}', - `type` = '{$type}', - `icon` = '{$icon}' - WHERE `id`={$id}"); - - $_SESSION['smord'] = $id; - hesk_process_messages($hesklang['sm_mdf'], 'service_messages.php', 'SUCCESS'); - -} // End save_sm() - - -function edit_sm() -{ - global $hesk_settings, $hesklang; - - // Get service messageID - $id = intval(hesk_GET('id')) or hesk_error($hesklang['sm_e_id']); - - // Get details from the database - $res = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages` WHERE `id`={$id} LIMIT 1"); - if (hesk_dbNumRows($res) != 1) { - hesk_error($hesklang['sm_not_found']); - } - $sm = hesk_dbFetchAssoc($res); - - $_SESSION['new_sm'] = $sm; - $_SESSION['edit_sm'] = true; - -} // End edit_sm() - - -function order_sm() -{ - global $hesk_settings, $hesklang; - - // A security check - hesk_token_check(); - - // Get ID and move parameters - $id = intval(hesk_GET('id')) or hesk_error($hesklang['sm_e_id']); - $move = intval(hesk_GET('move')); - $_SESSION['smord'] = $id; - - // Update article details - hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages` SET `order`=`order`+" . intval($move) . " WHERE `id`={$id}"); - - // Update order of all service messages - update_sm_order(); - - // Finish - header('Location: service_messages.php'); - exit(); - -} // End order_sm() - - -function update_sm_order() -{ - global $hesk_settings, $hesklang; - - // Get list of current service messages - $res = hesk_dbQuery("SELECT `id` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages` ORDER BY `order` ASC"); - - // Update database - $i = 10; - while ($sm = hesk_dbFetchAssoc($res)) { - hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages` SET `order`=" . intval($i) . " WHERE `id`='" . intval($sm['id']) . "'"); - $i += 10; - } - - return true; - -} // END update_sm_order() - - -function remove_sm() -{ - global $hesk_settings, $hesklang; - - // A security check - hesk_token_check(); - - // Get ID - $id = intval(hesk_GET('id')) or hesk_error($hesklang['sm_e_id']); - - // Delete the service message - hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages` WHERE `id`={$id}"); - - // Were we successful? - if (hesk_dbAffectedRows() == 1) { - hesk_process_messages($hesklang['sm_deleted'], './service_messages.php', 'SUCCESS'); - } else { - hesk_process_messages($hesklang['sm_not_found'], './service_messages.php'); - } - -} // End remove_sm() - - -function new_sm() -{ - global $hesk_settings, $hesklang, $listBox; - global $hesk_error_buffer; - - // A security check - # hesk_token_check('POST'); - - $hesk_error_buffer = array(); - - $style = intval(hesk_POST('style', 0)); - if ($style > 4 || $style < 0) { - $style = 0; - } - - $type = empty($_POST['type']) ? 0 : 1; - $icon = hesk_POST('icon'); - $title = hesk_input(hesk_POST('title')) or $hesk_error_buffer[] = $hesklang['sm_e_title']; - $message = hesk_getHTML(hesk_POST('message')); - - // Clean the HTML code - require(HESK_PATH . 'inc/htmlpurifier/HeskHTMLPurifier.php'); - $purifier = new HeskHTMLPurifier($hesk_settings['cache_dir']); - $message = $purifier->heskPurify($message); - - // Any errors? - if (count($hesk_error_buffer)) { - $_SESSION['new_sm'] = array( - 'style' => $style, - 'type' => $type, - 'title' => $title, - 'icon' => $icon, - 'message' => hesk_input(hesk_POST('message')), - ); - - $tmp = ''; - foreach ($hesk_error_buffer as $error) { - $tmp .= "
  • $error
  • \n"; - } - $hesk_error_buffer = $tmp; - - $hesk_error_buffer = $hesklang['rfm'] . '

      ' . $hesk_error_buffer . '
    '; - hesk_process_messages($hesk_error_buffer, 'service_messages.php'); - } - - // Just preview the message? - if (isset($_POST['sm_preview'])) { - $_SESSION['preview_sm'] = true; - - $_SESSION['new_sm'] = array( - 'style' => $style, - 'type' => $type, - 'title' => $title, - 'icon' => $icon, - 'message' => $message, - ); - - header('Location: service_messages.php'); - exit; - } - - - - $_SESSION['smord'] = hesk_dbInsertID(); - hesk_process_messages($hesklang['sm_added'], 'service_messages.php', 'SUCCESS'); - -} // End new_sm() - ?> diff --git a/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php b/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php index d70f142f..9e70ceda 100644 --- a/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php +++ b/api/BusinessLogic/ServiceMessages/ServiceMessageHandler.php @@ -5,6 +5,7 @@ namespace BusinessLogic\ServiceMessages; // TODO Test use BusinessLogic\Exceptions\ValidationException; +use BusinessLogic\Navigation\Direction; use BusinessLogic\ValidationModel; use DataAccess\ServiceMessages\ServiceMessagesGateway; @@ -17,7 +18,7 @@ class ServiceMessageHandler extends \BaseClass { } function createServiceMessage($serviceMessage, $heskSettings) { - $this->validate($serviceMessage); + $this->validate($serviceMessage, $heskSettings); if ($serviceMessage->icon === null) { switch ($serviceMessage->style) { @@ -47,7 +48,7 @@ class ServiceMessageHandler extends \BaseClass { } function editServiceMessage($serviceMessage, $heskSettings) { - $this->validate($serviceMessage, false); + $this->validate($serviceMessage, $heskSettings, false); if ($serviceMessage->icon === null) { switch ($serviceMessage->style) { @@ -72,19 +73,52 @@ class ServiceMessageHandler extends \BaseClass { return $this->serviceMessageGateway->updateServiceMessage($serviceMessage, $heskSettings); } + function deleteServiceMessage($id, $heskSettings) { + $this->serviceMessageGateway->deleteServiceMessage($id, $heskSettings); + } + + function sortServiceMessage($id, $direction, $heskSettings) { + $serviceMessages = $this->serviceMessageGateway->getServiceMessages($heskSettings); + $serviceMessage = null; + foreach ($serviceMessages as $innerServiceMessage) { + if ($innerServiceMessage->id === intval($id)) { + $serviceMessage = $innerServiceMessage; + break; + } + } + + if ($serviceMessage === null) { + throw new \BaseException("Could not find category with ID {$id}!"); + } + + if ($direction === Direction::UP) { + $serviceMessage->order -= 15; + } else { + $serviceMessage->order += 15; + } + + $this->serviceMessageGateway->updateServiceMessage($serviceMessage, $heskSettings); + $this->serviceMessageGateway->resortAllServiceMessages($heskSettings); + } + /** * @param $serviceMessage ServiceMessage * @param bool $isNew * @throws ValidationException */ - private function validate($serviceMessage, $isNew = true) { + private function validate($serviceMessage, $heskSettings, $isNew = true) { $validationModel = new ValidationModel(); if ($isNew && $serviceMessage->createdBy < 1) { $validationModel->errorKeys[] = 'MISSING_CREATOR'; } + if ($serviceMessage->message === null || trim($serviceMessage->message) === '') { $validationModel->errorKeys[] = 'MISSING_MESSAGE'; + } else { + $htmlPurifier = new \HeskHTMLPurifier($heskSettings['cache_dir']); + $serviceMessage->message = $htmlPurifier->heskPurify($serviceMessage->message); } + if ($serviceMessage->title === null || trim($serviceMessage->title) === '') { $validationModel->errorKeys[] = 'MISSING_TITLE'; } diff --git a/api/Controllers/ServiceMessages/ServiceMessagesController.php b/api/Controllers/ServiceMessages/ServiceMessagesController.php index f17d6e14..94ff9776 100644 --- a/api/Controllers/ServiceMessages/ServiceMessagesController.php +++ b/api/Controllers/ServiceMessages/ServiceMessagesController.php @@ -6,6 +6,7 @@ use BusinessLogic\Security\UserContext; use BusinessLogic\ServiceMessages\ServiceMessage; use BusinessLogic\ServiceMessages\ServiceMessageHandler; use Controllers\JsonRetriever; +use Symfony\Component\EventDispatcher\Tests\Service; class ServiceMessagesController extends \BaseClass { function get() { @@ -41,6 +42,17 @@ class ServiceMessagesController extends \BaseClass { return output($element); } + function delete($id) { + global $applicationContext, $hesk_settings; + + /* @var $handler ServiceMessageHandler */ + $handler = $applicationContext->get(ServiceMessageHandler::clazz()); + + $handler->deleteServiceMessage($id, $hesk_settings); + + return http_response_code(204); + } + /** * @param $data array * @param $userContext UserContext diff --git a/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php b/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php index 9dfb1796..b2539d12 100644 --- a/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php +++ b/api/DataAccess/ServiceMessages/ServiceMessagesGateway.php @@ -3,7 +3,6 @@ namespace DataAccess\ServiceMessages; -use BusinessLogic\DateTimeHelpers; use BusinessLogic\ServiceMessages\ServiceMessage; use BusinessLogic\ServiceMessages\ServiceMessageStyle; use DataAccess\CommonDao; @@ -49,6 +48,10 @@ class ServiceMessagesGateway extends CommonDao { return $serviceMessage; } + /** + * @param $heskSettings + * @return ServiceMessage[] + */ function getServiceMessages($heskSettings) { $this->init(); @@ -100,4 +103,31 @@ class ServiceMessagesGateway extends CommonDao { return $serviceMessage; } + + function deleteServiceMessage($id, $heskSettings) { + $this->init(); + + hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages` + WHERE `id` = " . intval($id)); + + $this->close(); + } + + function resortAllServiceMessages($heskSettings) { + $this->init(); + + $rs = hesk_dbQuery("SELECT `id` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages` + ORDER BY `order` ASC"); + + $sortValue = 10; + while ($row = hesk_dbFetchAssoc($rs)) { + hesk_dbQuery("UPDATE `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages` + SET `order` = " . intval($sortValue) . " + WHERE `id` = " . intval($row['id'])); + + $sortValue += 10; + } + + $this->close(); + } } \ No newline at end of file diff --git a/api/autoload.php b/api/autoload.php index 0f14ff20..cf548485 100644 --- a/api/autoload.php +++ b/api/autoload.php @@ -12,6 +12,7 @@ require_once(__DIR__ . '/Core/output.php'); require_once(__DIR__ . '/../hesk_settings.inc.php'); require_once(__DIR__ . '/http_response_code.php'); require_once(__DIR__ . '/../inc/admin_functions.inc.php'); +require_once(__DIR__ . '/../inc/htmlpurifier/HeskHTMLPurifier.php'); hesk_load_api_database_functions(); diff --git a/api/index.php b/api/index.php index afa70f70..9c4b3e35 100644 --- a/api/index.php +++ b/api/index.php @@ -203,7 +203,15 @@ Link::all(array( // Settings '/v1/settings' => action(\Controllers\Settings\SettingsController::clazz(), RequestMethod::all()), // Service Messages - '/v1/service-messages' => action(\Controllers\ServiceMessages\ServiceMessagesController::clazz(), array(RequestMethod::GET, RequestMethod::POST, RequestMethod::PUT)), + '/v1/service-messages' => action(\Controllers\ServiceMessages\ServiceMessagesController::clazz(), + array(RequestMethod::GET, RequestMethod::POST, RequestMethod::PUT), + SecurityHandler::INTERNAL_OR_AUTH_TOKEN), + '/v1/service-messages/{i}' => action(\Controllers\ServiceMessages\ServiceMessagesController::clazz(), + array(RequestMethod::DELETE), + SecurityHandler::INTERNAL_OR_AUTH_TOKEN), + '/v1/service-messages/{i}/sort/{s}' => action(\Controllers\ServiceMessages\ServiceMessagesController::clazz() . '::sort', + array(RequestMethod::POST), + SecurityHandler::INTERNAL), /* Internal use only routes */ // Resend email response diff --git a/internal-api/js/service-messages.js b/internal-api/js/service-messages.js new file mode 100644 index 00000000..a2c3f950 --- /dev/null +++ b/internal-api/js/service-messages.js @@ -0,0 +1,362 @@ +var serviceMessages = []; + +$(document).ready(function() { + loadTable(); + bindEditModal(); + bindModalCancelCallback(); + bindFormSubmit(); + bindDeleteButton(); + bindCreateModal(); + bindSortButtons(); +}); + + +function loadTable() { + $('#overlay').show(); + var heskUrl = $('p#hesk-path').text(); + var $tableBody = $('#table-body'); + + $.ajax({ + method: 'GET', + url: heskUrl + 'api/index.php/v1/service-messages', + headers: { 'X-Internal-Call': true }, + success: function(data) { + $tableBody.html(''); + + if (data.length === 0) { + // TODO "No Service Messages Found" + $('#overlay').hide(); + return; + } + + var first = true; + var lastElement = null; + $.each(data, function() { + var $template = $($('#service-message-template').html()); + + $template.find('span[data-property="id"]').attr('data-value', this.id); + $template.find('span[data-property="title"]').html( + getFormattedTitle(this.icon, this.title, this.style)); + $template.find('span[data-property="author"]').text(users[this.createdBy].name); + if (this.published) { + $template.find('span[data-property="type"]').text(mfhLang.text('sm_published')); + } else { + $template.find('span[data-property="type"]').text(mfhLang.text('sm_draft')); + } + + $tableBody.append($template); + + serviceMessages[this.id] = this; + + lastElement = this; + + if (first) { + $template.find('[data-direction="up"]').css('visibility', 'hidden'); + first = false; + } + }); + + if (lastElement) { + //-- Hide the down arrow on the last element + $('[data-value="' + lastElement.id + '"]').parent().parent() + .find('[data-direction="down"]').css('visibility', 'hidden'); + } + }, + error: function(data) { + mfhAlert.errorWithLog(mfhLang.text('error_retrieving_categories'), data.responseJSON); + console.error(data); + }, + complete: function() { + refreshBackgroundVolatileItems(); + $('[data-toggle="popover"]').popover({ + trigger: 'hover', + container: 'body' + }); + $('#overlay').hide(); + } + }); +} + +function getFormattedTitle(icon, title, style) { + var $template = $($('#service-message-title-template').html()); + + var alertClass = 'none'; + switch (style) { + case 'ERROR': + alertClass = 'alert alert-danger'; + break; + case 'NOTICE': + alertClass = 'alert alert-warning'; + break; + case 'INFO': + alertClass = 'alert alert-info'; + break; + case 'SUCCESS': + alertClass = 'alert alert-success'; + break; + } + $template.addClass(alertClass) + .find('[data-property="icon"]').addClass(icon).end() + .find('[data-property="title"]').text(title); + + return $template; +} + +function getServiceMessagePreview(icon, title, message, style) { + var $template = $('#service-message-preview-template').html(); + + var alertClass = 'none'; + switch (style) { + case 'ERROR': + alertClass = 'alert alert-danger'; + break; + case 'NOTICE': + alertClass = 'alert alert-warning'; + break; + case 'INFO': + alertClass = 'alert alert-info'; + break; + case 'SUCCESS': + alertClass = 'alert alert-success'; + break; + } + $template = $template.replace('none', alertClass) + .replace('{{TITLE}}', title) + .replace('{{MESSAGE}}', message); + $template = $($template); + if (icon !== '') { + $template.find('i.fa').removeClass('fa').addClass(icon); + } + + return $template; +} + +function bindEditModal() { + $(document).on('click', '[data-action="edit"]', function() { + var element = categories[$(this).parent().parent().find('[data-property="id"]').text()]; + var $modal = $('#category-modal'); + + $modal.find('#edit-label').show(); + $modal.find('#create-label').hide(); + + $modal.find('input[name="name"]').val(element.name).end() + .find('select[name="priority"]').val(element.priority).end() + .find('select[name="manager"]').val(element.manager === null ? 0 : element.manager).end() + .find('input[name="id"]').val(element.id).end() + .find('select[name="usage"]').val(element.usage).end() + .find('input[name="display-border"][value="' + (element.displayBorder ? 1 : 0) + '"]') + .prop('checked', 'checked').end(); + + var backgroundColor = element.backgroundColor; + var foregroundColor = element.foregroundColor; + var colorpickerOptions = { + format: 'hex', + color: backgroundColor + }; + $modal.find('input[name="background-color"]') + .colorpicker(colorpickerOptions).end().modal('show'); + + colorpickerOptions = { + format: 'hex' + }; + if (foregroundColor != '' && foregroundColor !== 'AUTO') { + colorpickerOptions.color = foregroundColor; + } + + $modal.find('input[name="foreground-color"]') + .colorpicker(colorpickerOptions).end().modal('show'); + + if (foregroundColor === '' || foregroundColor === 'AUTO') { + $modal.find('input[name="foreground-color"]').colorpicker('setValue', '#fff'); + $modal.find('input[name="foreground-color"]').val(''); + } + + $modal.find('input[name="cat-order"]').val(element.catOrder); + $modal.find('input[name="autoassign"][value="' + (element.autoAssign ? 1 : 0) + '"]') + .prop('checked', 'checked'); + $modal.find('input[name="type"][value="' + (element.type ? 1 : 0) + '"]') + .prop('checked', 'checked'); + $modal.find('textarea[name="description"]').val(element.description === null ? '' : element.description); + + $modal.modal('show'); + }); +} + +function bindCreateModal() { + $('#create-button').click(function() { + var $modal = $('#category-modal'); + $modal.find('#edit-label').hide(); + $modal.find('#create-label').show(); + + $modal.find('input[name="name"]').val(''); + $modal.find('select[name="priority"]').val(3); // Low priority + $modal.find('select[name="usage"]').val(0); // Tickets and events + $modal.find('input[name="id"]').val(-1); + $modal.find('textarea[name="description"]').val(''); + $modal.find('input[name="cat-order"]').val(''); + $modal.find('input[name="type"][value="0"]').prop('checked', 'checked'); + $modal.find('input[name="autoassign"][value="0"]').prop('checked', 'checked'); + $modal.find('input[name="display-border"][value="0"]') + .prop('checked', 'checked'); + + var colorpickerOptions = { + format: 'hex', + color: '#fff' + }; + $modal.find('input[name="background-color"]') + .colorpicker(colorpickerOptions).end().modal('show'); + $modal.find('input[name="background-color"]').val(''); + $modal.find('input[name="foreground-color"]') + .colorpicker(colorpickerOptions).end().modal('show'); + $modal.find('input[name="foreground-color"]').val(''); + + $modal.modal('show'); + }); +} + +function bindModalCancelCallback() { + $('.cancel-callback').click(function() { + var $editCategoryModal = $('#category-modal'); + + $editCategoryModal.find('input[name="background-color"]').val('').colorpicker('destroy').end(); + $editCategoryModal.find('input[name="foreground-color"]').val('').colorpicker('destroy').end(); + $editCategoryModal.find('input[name="display-border"][value="1"]').prop('checked'); + $editCategoryModal.find('input[name="display-border"][value="0"]').prop('checked'); + $editCategoryModal.find('input[name="autoassign"][value="1"]').prop('checked'); + $editCategoryModal.find('input[name="autoassign"][value="0"]').prop('checked'); + }); +} + +function bindFormSubmit() { + $('form#manage-category').submit(function(e) { + e.preventDefault(); + var heskUrl = $('p#hesk-path').text(); + + var $modal = $('#category-modal'); + + var foregroundColor = $modal.find('input[name="foreground-color"]').val(); + var manager = parseInt($modal.find('select[name="manager"]').val()); + var data = { + autoassign: $modal.find('input[name="autoassign"]').val() === 'true', + backgroundColor: $modal.find('input[name="background-color"]').val(), + description: $modal.find('textarea[name="description"]').val(), + displayBorder: $modal.find('input[name="display-border"]:checked').val() === '1', + foregroundColor: foregroundColor === '' ? 'AUTO' : foregroundColor, + name: $modal.find('input[name="name"]').val(), + priority: parseInt($modal.find('select[name="priority"]').val()), + manager: manager === 0 ? null : manager, + type: parseInt($modal.find('input[name="type"]:checked').val()), + usage: parseInt($modal.find('select[name="usage"]').val()), + catOrder: parseInt($modal.find('input[name="cat-order"]').val()) + }; + + var url = heskUrl + 'api/index.php/v1/categories/'; + var method = 'POST'; + + var categoryId = parseInt($modal.find('input[name="id"]').val()); + if (categoryId !== -1) { + url += categoryId; + method = 'PUT'; + } + + $modal.find('#action-buttons').find('.cancel-button').attr('disabled', 'disabled'); + $modal.find('#action-buttons').find('.save-button').attr('disabled', 'disabled'); + + $.ajax({ + method: 'POST', + url: url, + headers: { + 'X-Internal-Call': true, + 'X-HTTP-Method-Override': method + }, + data: JSON.stringify(data), + success: function(data) { + var format = undefined; + if (categoryId === -1) { + format = mfhLang.html('cat_name_added'); + mfhAlert.success(format.replace('%s', data.name)); + } else { + format = mfhLang.html('category_updated'); + mfhAlert.success(format.replace('%s', data.name)); + } + $modal.modal('hide'); + loadTable(); + }, + error: function(data) { + mfhAlert.errorWithLog(mfhLang.text('error_saving_updating_category'), data.responseJSON); + console.error(data); + }, + complete: function(data) { + $modal.find('#action-buttons').find('.cancel-button').removeAttr('disabled'); + $modal.find('#action-buttons').find('.save-button').removeAttr('disabled'); + } + }); + }); +} + +function bindDeleteButton() { + $(document).on('click', '[data-action="delete"]', function() { + $('#overlay').show(); + + var heskUrl = $('p#hesk-path').text(); + var element = categories[$(this).parent().parent().find('[data-property="id"]').text()]; + + $.ajax({ + method: 'POST', + url: heskUrl + 'api/index.php/v1/categories/' + element.id, + headers: { + 'X-Internal-Call': true, + 'X-HTTP-Method-Override': 'DELETE' + }, + success: function() { + mfhAlert.success(mfhLang.text('cat_removed')); + loadTable(); + }, + error: function(data) { + $('#overlay').hide(); + mfhAlert.errorWithLog(mfhLang.text('error_deleting_category'), data.responseJSON); + console.error(data); + } + }); + }); +} + +function bindGenerateLinkModal() { + var $modal = $('#generate-link-modal'); + + $modal.find('.input-group-addon').click(function() { + clipboard.copy($modal.find('input[type="text"]').val()); + mfhAlert.success(mfhLang.text('copied_to_clipboard')); + }); + + $(document).on('click', '[data-property="generate-link"] i.fa-code', function () { + var heskUrl = $('p#hesk-url').text(); + + var url = heskUrl + '/index.php?a=add&catid=' + $(this).parent().data('category-id'); + + $modal.find('input[type="text"]').val(url).end().modal('show'); + }); +} + +function bindSortButtons() { + $(document).on('click', '[data-action="sort"]', function() { + $('#overlay').show(); + var heskUrl = $('p#hesk-path').text(); + var direction = $(this).data('direction'); + var element = categories[$(this).parent().parent().parent().find('[data-property="id"]').text()]; + + $.ajax({ + method: 'POST', + url: heskUrl + 'api/index.php/v1-internal/categories/' + element.id + '/sort/' + direction, + headers: { 'X-Internal-Call': true }, + success: function() { + loadTable(); + }, + error: function(data) { + mfhAlert.errorWithLog(mfhLang.text('error_sorting_categories'), data.responseJSON); + console.error(data); + $('#overlay').hide(); + } + }) + }); +} \ No newline at end of file From a8abfcd4a11216a3af59e205c3398a7b7e69338d Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Mon, 13 Nov 2017 13:07:19 -0500 Subject: [PATCH 07/74] More progress on service messages --- admin/service_messages.php | 301 +++++++++--------- .../ServiceMessagesController.php | 1 - internal-api/js/service-messages.js | 56 +--- language/en/text.php | 3 + 4 files changed, 161 insertions(+), 200 deletions(-) diff --git a/admin/service_messages.php b/admin/service_messages.php index b83d9378..6368b572 100644 --- a/admin/service_messages.php +++ b/admin/service_messages.php @@ -57,6 +57,12 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
    +
    + +
    -
    -
    -

    -
    -
    -
    -
    - +
    +
    +
    +
    + +
    +
    + +
    + diff --git a/language/en/text.php b/language/en/text.php index 0de8b91c..a994fc6c 100644 --- a/language/en/text.php +++ b/language/en/text.php @@ -2238,6 +2238,7 @@ $hesklang['show_event_start_time_help'] = 'Always show the start time on event t $hesklang['highlight_ticket_rows_based_on_priority'] = 'Highlight ticket rows based on priority'; $hesklang['highlight_ticket_rows_based_on_priority_help'] = 'If enabled, each ticket on the tickets page will be highlighted based on priority. If disabled, only * Critical * and High priority tickets will be highlighted.'; $hesklang['highlight_ticket_rows_based_on_priority_descr'] = 'Highlight all ticket rows based on priority'; +$hesklang['protected_group'] = 'This is a protected group; you cannot change accessible categories / features.'; // DO NOT CHANGE BELOW if (!defined('IN_SCRIPT')) die('PHP syntax OK!'); From 48b28fc3cdfdcb7d27ce39c2599a3947d66a5397 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Wed, 7 Feb 2018 22:03:55 -0500 Subject: [PATCH 59/74] Only modify permissions the user has access to --- admin/manage_permission_groups.php | 36 +++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/admin/manage_permission_groups.php b/admin/manage_permission_groups.php index 4220ea3d..9eb410a0 100644 --- a/admin/manage_permission_groups.php +++ b/admin/manage_permission_groups.php @@ -365,7 +365,6 @@ function save() WHERE `id` = " . intval($templateId)); $row = hesk_dbFetchAssoc($res); - // Add 'can ban emails' if 'can unban emails' is set (but not added). Same with 'can ban ips' $catArray = hesk_POST_array('categories'); $featArray = hesk_POST_array('features'); @@ -380,6 +379,41 @@ function save() $features = implode(',', $featArray); $name = hesk_POST('name'); + // Only allow users to add what they are allowed to add + // Admins can handle anything + if (!$_SESSION['isadmin']) { + // Update categories based on user visibility + $originalCategories = explode(',', $row['categories']); + $newCategories = array(); + foreach ($originalCategories as $innerCategory) { + if (in_array($innerCategory, $catArray) && in_array($innerCategory, $_SESSION['categories'])) { + $newCategories[] = $innerCategory; + } elseif (!in_array($innerCategory, $catArray) && !in_array($innerCategory, $_SESSION['categories'])) { + // The user can't modify this, so keep it in + $newCategories[] = $innerCategory; + } + // If neither, the user removed it. + } + + // Update features based on user visibility + $originalFeatures = explode(',', $row['features']); + $newFeatures = array(); + foreach ($originalFeatures as $innerFeature) { + if (in_array($innerFeature, $featArray) && strpos($_SESSION['heskprivileges'], $innerFeature) !== false) { + $newFeatures[] = $innerFeature; + } elseif (!in_array($innerFeature, $featArray) && strpos($_SESSION['heskprivileges'], $innerFeature) === false) { + // The user can't modify this, so keep it in + $newFeatures[] = $innerFeature; + } + // If neither, the user removed it. + } + + $categories = implode(',', $newCategories); + $features = implode(',', $newFeatures); + } + + + hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates` SET `categories` = '" . hesk_dbEscape($categories) . "', `heskprivileges` = '" . hesk_dbEscape($features) . "', `name` = '" . hesk_dbEscape($name) . "' From 35ed664dfdef0ea48600b134a8030c08196a35d4 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Sun, 11 Feb 2018 22:00:44 -0500 Subject: [PATCH 60/74] Only allow users to modify permissions that they have access to --- admin/manage_permission_groups.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/admin/manage_permission_groups.php b/admin/manage_permission_groups.php index 9eb410a0..9b9449ac 100644 --- a/admin/manage_permission_groups.php +++ b/admin/manage_permission_groups.php @@ -198,7 +198,7 @@ function createEditModal($template, $features, $categories) $disabled = ' disabled'; }?> - +