From dd690decb23ed7f08b1888bafc868ed0606dac3f Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Sun, 20 Aug 2017 21:53:02 -0400 Subject: [PATCH] Editing categories possible, add security check --- api/ApplicationContext.php | 8 ++- .../Categories/CategoryHandler.php | 67 ++++++++++++++++--- .../Security/PermissionChecker.php | 23 +++++++ api/BusinessLogic/Security/UserPrivilege.php | 1 + .../Categories/CategoryController.php | 21 +++++- api/DataAccess/Categories/CategoryGateway.php | 38 +++++++++++ 6 files changed, 146 insertions(+), 12 deletions(-) create mode 100644 api/BusinessLogic/Security/PermissionChecker.php diff --git a/api/ApplicationContext.php b/api/ApplicationContext.php index 55cb52b7..9de65544 100644 --- a/api/ApplicationContext.php +++ b/api/ApplicationContext.php @@ -12,6 +12,7 @@ use BusinessLogic\Emails\EmailTemplateRetriever; use BusinessLogic\Emails\MailgunEmailSender; use BusinessLogic\Navigation\CustomNavElementHandler; use BusinessLogic\Security\BanRetriever; +use BusinessLogic\Security\PermissionChecker; use BusinessLogic\Security\UserContextBuilder; use BusinessLogic\Security\UserToTicketChecker; use BusinessLogic\Settings\ApiChecker; @@ -50,6 +51,9 @@ class ApplicationContext { function __construct() { $this->get = array(); + // Permissions + $this->get[PermissionChecker::class] = new PermissionChecker(); + // Settings $this->get[ModsForHeskSettingsGateway::class] = new ModsForHeskSettingsGateway(); @@ -74,7 +78,9 @@ class ApplicationContext { // Categories $this->get[CategoryGateway::class] = new CategoryGateway(); $this->get[CategoryRetriever::class] = new CategoryRetriever($this->get[CategoryGateway::class]); - $this->get[CategoryHandler::class] = new CategoryHandler($this->get[CategoryGateway::class]); + $this->get[CategoryHandler::class] = new CategoryHandler( + $this->get[CategoryGateway::class], + $this->get[PermissionChecker::class]); // Bans $this->get[BanGateway::class] = new BanGateway(); diff --git a/api/BusinessLogic/Categories/CategoryHandler.php b/api/BusinessLogic/Categories/CategoryHandler.php index 0cca431d..895f1b34 100644 --- a/api/BusinessLogic/Categories/CategoryHandler.php +++ b/api/BusinessLogic/Categories/CategoryHandler.php @@ -3,7 +3,10 @@ namespace BusinessLogic\Categories; +use BusinessLogic\Exceptions\AccessViolationException; use BusinessLogic\Exceptions\ValidationException; +use BusinessLogic\Security\PermissionChecker; +use BusinessLogic\Security\UserPrivilege; use BusinessLogic\ValidationModel; use DataAccess\Categories\CategoryGateway; @@ -11,8 +14,12 @@ class CategoryHandler { /* @var $categoryGateway CategoryGateway */ private $categoryGateway; - function __construct($categoryGateway) { + /* @var $permissionChecker PermissionChecker */ + private $permissionChecker; + + function __construct($categoryGateway, $permissionChecker) { $this->categoryGateway = $categoryGateway; + $this->permissionChecker = $permissionChecker; } /** @@ -22,27 +29,35 @@ class CategoryHandler { * @throws ValidationException When validation fails */ //TODO Test - function createCategory($category, $heskSettings) { - $validationModel = $this->validate($category, $heskSettings); + function createCategory($category, $userContext, $heskSettings) { + $validationModel = $this->validate($category, $userContext); if (count($validationModel->errorKeys) > 0) { throw new ValidationException($validationModel); } - $category->id = $this->categoryGateway->createCategory($category, $heskSettings); + $id = $this->categoryGateway->createCategory($category, $heskSettings); + + $allCategories = $this->categoryGateway->getAllCategories($heskSettings); - return $category; + return $allCategories[$id]; } /** * @param $category Category - * @param $heskSettings array + * @param $userContext * @param $creating bool * @return ValidationModel + * @throws AccessViolationException */ //TODO Test - private function validate($category, $heskSettings, $creating = true) { + private function validate($category, $userContext, $creating = true) { $validationModel = new ValidationModel(); + + if (!$this->permissionChecker->doesUserHavePermission($userContext, UserPrivilege::CAN_MANAGE_CATEGORIES)) { + throw new AccessViolationException('User cannot manage categories!'); + } + if (!$creating && $category->id < 1) { $validationModel->errorKeys[] = 'ID_MISSING'; } @@ -59,11 +74,47 @@ class CategoryHandler { $validationModel->errorKeys[] = 'NAME_MISSING'; } + if ($category->priority === null || intval($category->priority) < 0 || intval($category->priority) > 3) { + $validationModel->errorKeys[] = 'INVALID_PRIORITY'; + } + + if ($category->autoAssign === null || !is_bool($category->autoAssign)) { + $validationModel->errorKeys[] = 'INVALID_AUTOASSIGN'; + } + + if ($category->displayBorder === null || !is_bool($category->displayBorder)) { + $validationModel->errorKeys[] = 'INVALID_DISPLAY_BORDER'; + } + + if ($category->type === null || (intval($category->type) !== 0 && intval($category->type) !== 1)) { + $validationModel->errorKeys[] = 'INVALID_TYPE'; + } + + if ($category->type === null || intval($category->type) < 0 || intval($category->type) > 2) { + $validationModel->errorKeys[] = 'INVALID_TYPE'; + } + return $validationModel; } - function editCategory($category, $heskSettings) { + /** + * @param $category Category + * @param $heskSettings array + * @return Category + * @throws ValidationException + */ + function editCategory($category, $userContext, $heskSettings) { + $validationModel = $this->validate($category, $userContext, false); + + if (count($validationModel->errorKeys) > 0) { + throw new ValidationException($validationModel); + } + + $this->categoryGateway->updateCategory($category, $heskSettings); + $this->categoryGateway->resortAllCategories($heskSettings); + $allCategories = $this->categoryGateway->getAllCategories($heskSettings); + return $allCategories[$category->id]; } } \ No newline at end of file diff --git a/api/BusinessLogic/Security/PermissionChecker.php b/api/BusinessLogic/Security/PermissionChecker.php new file mode 100644 index 00000000..cf2b1a43 --- /dev/null +++ b/api/BusinessLogic/Security/PermissionChecker.php @@ -0,0 +1,23 @@ +admin) { + return true; + } + + if (in_array($permission, $userContext->permissions)) { + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/api/BusinessLogic/Security/UserPrivilege.php b/api/BusinessLogic/Security/UserPrivilege.php index ad6064cc..1e90ff70 100644 --- a/api/BusinessLogic/Security/UserPrivilege.php +++ b/api/BusinessLogic/Security/UserPrivilege.php @@ -14,4 +14,5 @@ class UserPrivilege { const CAN_REPLY_TO_TICKETS = 'can_reply_tickets'; const CAN_EDIT_TICKETS = 'can_edit_tickets'; const CAN_DELETE_TICKETS = 'can_del_tickets'; + const CAN_MANAGE_CATEGORIES = 'can_man_cat'; } \ No newline at end of file diff --git a/api/Controllers/Categories/CategoryController.php b/api/Controllers/Categories/CategoryController.php index a739ab45..90aa2882 100644 --- a/api/Controllers/Categories/CategoryController.php +++ b/api/Controllers/Categories/CategoryController.php @@ -48,13 +48,16 @@ class CategoryController { return output($category); } + /** + * @param $json + * @return Category + */ private function buildCategoryFromJson($json) { $category = new Category(); - $category->id = Helpers::safeArrayGet($json, 'id'); $category->autoAssign = Helpers::safeArrayGet($json, 'autoassign'); $category->backgroundColor = Helpers::safeArrayGet($json, 'backgroundColor'); - $category->catOrder = Helpers::safeArrayGet($json, 'order'); + $category->catOrder = Helpers::safeArrayGet($json, 'catOrder'); $category->description = Helpers::safeArrayGet($json, 'description'); $category->displayBorder = Helpers::safeArrayGet($json, 'displayBorder'); $category->foregroundColor = Helpers::safeArrayGet($json, 'foregroundColor'); @@ -68,7 +71,19 @@ class CategoryController { } function put($id) { - //-- TODO: Edit category + global $hesk_settings, $applicationContext; + + $data = JsonRetriever::getJsonData(); + + $category = $this->buildCategoryFromJson($data); + $category->id = $id; + + /* @var $categoryHandler CategoryHandler */ + $categoryHandler = $applicationContext->get[CategoryHandler::class]; + + $category = $categoryHandler->editCategory($category, $hesk_settings); + + return output($category); } function delete($id) { diff --git a/api/DataAccess/Categories/CategoryGateway.php b/api/DataAccess/Categories/CategoryGateway.php index 00d24edb..fbf518ec 100644 --- a/api/DataAccess/Categories/CategoryGateway.php +++ b/api/DataAccess/Categories/CategoryGateway.php @@ -73,9 +73,47 @@ class CategoryGateway extends CommonDao { return $id; } + /** + * @param $category Category + * @param $heskSettings array + */ function updateCategory($category, $heskSettings) { $this->init(); + $sql = "UPDATE `" . hesk_dbEscape($heskSettings['db_pfix']) . "categories` SET + `name` = '" . hesk_dbEscape($category->name) . "', + `cat_order` = " . intval($category->catOrder) . ", + `autoassign` = '" . ($category->autoAssign ? 1 : 0) . "', + `type` = '" . intval($category->type) . "', + `priority` = '" . intval($category->priority) . "', + `manager` = " . ($category->manager === null ? 0 : intval($category->manager)) . ", + `background_color` = '" . hesk_dbEscape($category->backgroundColor) . "', + `usage` = " . intval($category->usage) . ", + `foreground_color` = '" . hesk_dbEscape($category->foregroundColor) . "', + `display_border_outline` = '" . ($category->displayBorder ? 1 : 0) . "', + `mfh_description` = '" . hesk_dbEscape($category->description) . "' + WHERE `id` = " . intval($category->id); + + hesk_dbQuery($sql); + + $this->close(); + } + + function resortAllCategories($heskSettings) { + $this->init(); + + $rs = hesk_dbQuery("SELECT `id` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "categories` + ORDER BY `cat_order` ASC"); + + $sortValue = 10; + while ($row = hesk_dbFetchAssoc($rs)) { + hesk_dbQuery("UPDATE `" . hesk_dbEscape($heskSettings['db_pfix']) . "categories` + SET `cat_order` = " . intval($sortValue) . " + WHERE `id` = " . intval($row['id'])); + + $sortValue += 10; + } + $this->close(); } } \ No newline at end of file