From 758b2f5e66aa4c52581860e98fef233c95a0936a Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Wed, 28 Feb 2024 11:43:18 +0200 Subject: [PATCH 1/5] Simplify add/remove from group backend --- Controller/GrouperGroupsController.php | 52 +++++++------- Lib/GrouperApiAccess.php | 32 ++++----- Lib/GrouperHTTPWrapper.php | 41 ++++++++--- Lib/enum.php | 32 ++++++--- Model/GrouperGroup.php | 99 +++++++------------------- webroot/js/groups.js | 6 +- webroot/js/members.js | 12 ++-- 7 files changed, 127 insertions(+), 147 deletions(-) diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index 659496b..675b1f0 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -160,9 +160,9 @@ public function groupSubscribers(): void // : $groupName; try { - $subscribers = $this->GrouperGroup->getGrouperGroupMembers($this->userId, - $groupName, - $this->CoGrouperLiteWidget->getConfig()); + $subscribers = $this->GrouperGroup->getGroupMembers($this->userId, + $groupName, + $this->CoGrouperLiteWidget->getConfig()); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); @@ -184,31 +184,31 @@ public function groupSubscribers(): void * Add a new member to a group * Called from all pages via AJAX call * + * @throws JsonException + * @throws Exception */ public function addSubscriber(): void { $groupName = urldecode($this->request->query['group']); $addUserId = urldecode($this->request->query['userId']); - $resultAdd = false; - //Need to see if coming from AdHoc or from a WG (Working Group) + // Need to see if coming from AdHoc or from a WG (Working Group) + // todo: Investigate further + // XXX groupJoin is not using this formatted syntax??? // $groupNameFormatted = strpos($groupName, ':') === false ? 'ref:incommon-collab:' . $groupName . ':users' // : $groupName; try { - $resultAdd = $this->GrouperGroup->addGrouperGroupMember($this->userId, - $groupName, - $addUserId, - $this->CoGrouperLiteWidget->getConfig()); + $this->GrouperGroup->addGroupMember($this->userId, + $groupName, + $addUserId, + $this->CoGrouperLiteWidget->getConfig()); } catch (Exception $e) { -// $this->restResponse(HttpStatusCodesEnum::HTTP_UNAUTHORIZED, ErrorsEnum::NotAdded); CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); - $this->restResponse(HttpStatusCodesEnum::HTTP_NOT_FOUND, ErrorsEnum::Exception); + throw $e; } - $this->set(compact($resultAdd ? GrouperResultCodesEnum::SUCCESS : '')); - $this->set('_serialize', 'resultAdd'); - + $this->restResponse(HttpStatusCodesEnum::HTTP_OK); } /** @@ -255,10 +255,10 @@ public function removeSubscriber(): void : $groupName; try { - $resultRemove = $this->GrouperGroup->removeGrouperGroupMember($this->userId, - $groupNameFormatted, - $remUserId, - $this->CoGrouperLiteWidget->getConfig()); + $resultRemove = $this->GrouperGroup->removeGroupMember($this->userId, + $groupNameFormatted, + $remUserId, + $this->CoGrouperLiteWidget->getConfig()); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); } @@ -432,22 +432,22 @@ public function groupCreateTemplate() */ public function joinGroup(): void { + // todo: add Subscriber and joinGroup should accept the same query parameters. Currently the join Group + // accepts a GroupName, while the addSubscriber accepts a group parameter $name = urldecode($this->request->query['GroupName']); - $resultAdd = false; try { // Add myself - $resultAdd = $this->GrouperGroup->joinGroup($this->userId, - $name, - $this->CoGrouperLiteWidget->getConfig()); + $this->GrouperGroup->addGroupMember($this->userId, + $name, + $this->userId, + $this->CoGrouperLiteWidget->getConfig()); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); -// $this->restResponse(HttpStatusCodesEnum::HTTP_UNAUTHORIZED, ErrorsEnum::NotAdded); - $this->restResponse(HttpStatusCodesEnum::HTTP_NOT_FOUND, ErrorsEnum::Exception); + throw $e; } - $this->set(compact($resultAdd ? GrouperResultCodesEnum::SUCCESS : '')); - $this->set('_serialize', 'resultAdd'); + $this->restResponse(HttpStatusCodesEnum::HTTP_OK); } /** diff --git a/Lib/GrouperApiAccess.php b/Lib/GrouperApiAccess.php index c84e8de..867aafb 100644 --- a/Lib/GrouperApiAccess.php +++ b/Lib/GrouperApiAccess.php @@ -35,14 +35,11 @@ */ class GrouperApiAccess { - // Array for storing settings needed in call to Grouper - private $config; - // Instance of Grouper HTTP Wrapper class - private $http; + private GrouperHTTPWrapper $http; // String used to build out Grouper WS URL - private $_urlServlet = '/grouper-ws/servicesRest/'; + private string $_urlServlet = '/grouper-ws/servicesRest/'; /** * GrouperApiAccess constructor. @@ -84,9 +81,9 @@ public function __construct(array $cfg) * @throws GrouperLiteWidgetException * @throws JsonException */ - public function addGrouperGroupMember(string $actAsUserId, - string $groupName, - string $addUserId): bool + public function addGroupMember(string $actAsUserId, + string $groupName, + string $addUserId): bool { if(empty($actAsUserId) || empty($groupName) @@ -121,6 +118,11 @@ public function addGrouperGroupMember(string $actAsUserId, throw $e; } + if(isset($results['error']) && $results['error']) { + $cakeExceptionClass = $results['cakeException']; + throw new $cakeExceptionClass($results['message']); + } + return isset($results['WsAddMemberResults']['wsGroupAssigned']) && $results['WsAddMemberResults']['wsGroupAssigned']['name'] === urldecode($groupName); } @@ -262,7 +264,7 @@ public function createUpdateGroup(string $actAsUserId, string $groupName, string * @throws GrouperLiteWidgetException|JsonException * */ - public function deleteGroupWithTemplate(array $queryData) + public function deleteGroupWithTemplate(array $queryData): bool { $workingGroupExt = $queryData['workingGroupExt']; $userId = $queryData['userId']; @@ -320,7 +322,7 @@ public function deleteGroupWithTemplate(array $queryData) * @throws GrouperLiteWidgetException * @throws JsonException */ - public function getGrouperGroupInfo(string $groupName) + public function getGroupInfo(string $groupName): array { $groupInfo = []; @@ -371,7 +373,7 @@ public function getGrouperGroupInfo(string $groupName) * * @throws GrouperLiteWidgetException */ - public function getUserGrouperGroupMemberships(string $actorUserId, string $userId): array + public function getUserGroupMemberships(string $actorUserId, string $userId): array { if(empty($userId)) { return []; @@ -400,7 +402,7 @@ public function getUserGrouperGroupMemberships(string $actorUserId, string $user * @throws GrouperLiteWidgetException * @throws JsonException */ - public function getGrouperGroupMembers(string $actorUserId, string $groupName): array + public function getGroupMembers(string $actorUserId, string $groupName): array { //Build request logic $usersToShow = [ @@ -572,7 +574,7 @@ public function getOwnedStems(string $userId): array * * @throws GrouperLiteWidgetException */ - public function isMemberOfGrouperGroup(string $groupName, string $userId): bool + public function isMemberOfGroup(string $groupName, string $userId): bool { if(empty($userId) || empty($groupName)) { return []; @@ -636,9 +638,7 @@ public function removeDuplicates(array $arrOne, array $arrTwo) * @throws GrouperLiteWidgetException * @throws JsonException */ - public function removeGrouperGroupMember(string $actAsUserId, - string $groupName, - string $removeUserId): bool + public function removeGroupMember(string $actAsUserId, string $groupName, string $removeUserId): bool { if(empty($actAsUserId) || empty($groupName) diff --git a/Lib/GrouperHTTPWrapper.php b/Lib/GrouperHTTPWrapper.php index 727ae79..e9c025a 100644 --- a/Lib/GrouperHTTPWrapper.php +++ b/Lib/GrouperHTTPWrapper.php @@ -190,23 +190,46 @@ public function sendRequest(string $method, string $endPoint, string $body = '') $apiResults = $this->request($this->_request); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred: ' . var_export($e->getMessage(), true)); - throw new GrouperLiteWidgetException('An error occurred talking to Grouper WS'); + throw new RuntimeException(_txt('er.notfound-b', array( + _txt('pl.grouperlite.crumb.root')) + )); } - // Call may return non-200, which may be okay depending on call - if (!$apiResults->isOk()) { - CakeLog::write('error', __METHOD__ . ': Grouper WS returned non-200 of ' . var_export($apiResults->body(), true)); + $successHeader = $apiResults->getHeader('X-Grouper-success'); + if (empty($successHeader)) { + throw new RuntimeException('Web service did not even respond!'); } $payload = json_decode($apiResults->body(), true); - - CakeLog::write('debug', __METHOD__ . '::payload: ' . var_export($payload, true)); - $successHeader = $apiResults->getHeader('X-Grouper-success'); - if (empty($successHeader)) { - throw new RuntimeException('Web service did not even respond!'); + $code = $apiResults->code; + $reasonPhrase = $apiResults->reasonPhrase; + + // The request returned with Failed status + if($successHeader == 'F' && !empty($payload)) { + CakeLog::write('debug', __METHOD__ . '::body ' . var_export($apiResults->body(), true)); + CakeLog::write('debug', __METHOD__ . '::headers: ' . var_export($apiResults->headers, true)); + + // I need to pop the element since the key is request specific. + // For example, it is WsAddMemberResults for an Add request + $error_payload = array_pop($payload); + $constant_error = 'GrouperCodesToExceptionClassEnum::' . $error_payload['resultMetadata']['resultCode']; + $cakeException = defined($constant_error) ? constant($constant_error) : 'BadRequestException'; + if($code == HttpStatusCodesEnum::HTTP_UNAUTHORIZED) { + $cakeException = 'UnauthorizedException'; + } + + return [ + 'error' => true, + 'grouperCode' => $error_payload['resultMetadata']['resultCode'], + 'message' => $error_payload['resultMetadata']['resultMessage'], + 'reasonPhrase' => $reasonPhrase, + 'cakeException' => $cakeException + ]; } + CakeLog::write('debug', __METHOD__ . '::payload: ' . var_export($payload, true)); + return $payload; } } diff --git a/Lib/enum.php b/Lib/enum.php index 3d84546..c9799a6 100644 --- a/Lib/enum.php +++ b/Lib/enum.php @@ -1,11 +1,11 @@ 'ERROR', 'message' => 'EXCEPTION'); - const NotDeleted = array('status' => 'ERROR', 'message' => 'NOT DELETED'); - const NotAdded = array('status' => 'ERROR', 'message' => 'NOT ADDED'); - const Error = array('status' => 'ERROR', 'message' => 'ERROR'); - const NoAccess = array('status' => 'ERROR', 'message' => 'NO ACCESS'); + const Error = ['status' => 'ERROR', 'message' => 'ERROR']; + const Exception = ['status' => 'ERROR', 'message' => 'EXCEPTION']; + const NoAccess = ['status' => 'ERROR', 'message' => 'NO ACCESS']; + const NotAdded = ['status' => 'ERROR', 'message' => 'NOT ADDED']; + const NotDeleted = ['status' => 'ERROR', 'message' => 'NOT DELETED']; } class GrouperSpecialGroups { @@ -20,19 +20,29 @@ class GrouperSpecialGroups { } class GrouperResultCodesEnum { - const IS_MEMBER = 'IS_MEMBER'; - const SUCCESS = 'SUCCESS'; + const EXECUTE_FAILED = 'EXECUTE_FAILED'; const GROUP_NOT_FOUND = 'GROUP_NOT_FOUND'; - const SUBJECT_NOT_FOUND = 'SUBJECT_NOT_FOUND'; + const IS_MEMBER = 'IS_MEMBER'; const NO_SUCH_OBJECT = 'NO_SUCH_OBJECT'; + const PROBLEM_WITH_ASSIGNMENT = 'PROBLEM_WITH_ASSIGNMENT'; + const SUBJECT_NOT_FOUND = 'SUBJECT_NOT_FOUND'; + const SUCCESS = 'SUCCESS'; const SUCCESS_NO_INFO = 'SUCCESS_NO_INFO'; - const EXECUTE_FAILED = 'EXECUTE_FAILED'; +} + +class GrouperCodesToExceptionClassEnum { + const EXECUTE_FAILED = 'BadRequestException'; + const GROUP_NOT_FOUND = 'NotFoundException'; + const NO_SUCH_OBJECT = 'NotFoundException'; + const PROBLEM_WITH_ASSIGNMENT = 'BadRequestException'; + const SUBJECT_NOT_FOUND = 'NotFoundException'; + const SUCCESS_NO_INFO = 'MethodNotAllowedException'; } class GrouperGroupTypeEnum { + const ADMIN = 'admin'; const OPTINS = 'optins'; const OPTOUTS = 'optouts'; - const ADMIN = 'admin'; - const UPDATE = 'update'; const STEM_ADMIN = 'stemAdmin'; + const UPDATE = 'update'; } \ No newline at end of file diff --git a/Model/GrouperGroup.php b/Model/GrouperGroup.php index 2b52896..3a7c9b9 100644 --- a/Model/GrouperGroup.php +++ b/Model/GrouperGroup.php @@ -99,7 +99,7 @@ public function isGrouperVisible(string $userId, array $cfg): string $this->initApi($cfg); try { - $isMember = $this->grouperAPI->isMemberOfGrouperGroup(GrouperSpecialGroups::GROUPER_VISIBLE_GROUP, $userId); + $isMember = $this->grouperAPI->isMemberOfGroup(GrouperSpecialGroups::GROUPER_VISIBLE_GROUP, $userId); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; @@ -276,57 +276,7 @@ private function memberOfGroups(string $actorUserId, string $userId, array $cfg) $this->initApi($cfg); try { - return $this->grouperAPI->getUserGrouperGroupMemberships($actorUserId, $userId); - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); - throw $e; - } - } - - - /** - * Process for User to Leave a Group - * - * @param string $userId Id of User - * @param string $groupName Name of Group Leaving, do not confuse with DisplayName field! - * @param array $cfg the plugin configuration - * - * @return bool True|False - * @throws GrouperLiteWidgetException - * - * @since COmanage Registry v4.4.0 - */ - public function leaveGroup(string $userId, string $groupName, array $cfg): bool - { - $this->initApi($cfg); - - try { - return $this->grouperAPI->removeGrouperGroupMember($userId, - $groupName, - $userId // Remove myself from the Group - ); - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); - throw $e; - } - } - - /** - * Process for User to Join a Group - * - * @param string $userId Id of User - * @param string $groupName Name of Group Joining, do not confuse with DisplayName field! - * @return bool True|False - * @throws GrouperLiteWidgetException - * - * @since COmanage Registry v4.4.0 - */ - public function joinGroup(string $userId, string $groupName, array $cfg): bool - { - $this->initApi($cfg); - - try { - return $this->grouperAPI->addGrouperGroupMember($userId, $groupName, $userId); + return $this->grouperAPI->getUserGroupMemberships($actorUserId, $userId); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; @@ -368,12 +318,12 @@ public function ownerGroups(array $conditions, array $cfg) * @throws JsonException * @since COmanage Registry v4.4.0 */ - public function getGrouperGroupMembers(string $actorUserId, string $groupName, array $cfg): array + public function getGroupMembers(string $actorUserId, string $groupName, array $cfg): array { $this->initApi($cfg); try { - $groupMembers = $this->grouperAPI->getGrouperGroupMembers($actorUserId, $groupName); + $groupMembers = $this->grouperAPI->getGroupMembers($actorUserId, $groupName); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; @@ -406,16 +356,11 @@ public function getGrouperGroupMembers(string $actorUserId, string $groupName, a * @throws JsonException * @since COmanage Registry v4.4.0 */ - public function addGrouperGroupMember(string $actAsUserId, string $groupName, string $addUserId, array $cfg) + public function addGroupMember(string $actAsUserId, string $groupName, string $addUserId, array $cfg) { $this->initApi($cfg); - try { - return $this->grouperAPI->addGrouperGroupMember($actAsUserId, $groupName, $addUserId); - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); - throw $e; - } + return $this->grouperAPI->addGroupMember($actAsUserId, $groupName, $addUserId); } /** @@ -431,14 +376,17 @@ public function addGrouperGroupMember(string $actAsUserId, string $groupName, st * @throws JsonException Captured in Controller * @since COmanage Registry v4.4.0 */ - public function removeGrouperGroupMember(string $userId, string $groupName, string $removeUserId, array $cfg): bool + public function removeGroupMember(string $userId, + string $groupName, + string $removeUserId, + array $cfg): bool { $this->initApi($cfg); try { - return $this->grouperAPI->removeGrouperGroupMember($userId, - $groupName, - $removeUserId); + return $this->grouperAPI->removeGroupMember($userId, + $groupName, + $removeUserId); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; @@ -457,7 +405,7 @@ public function removeGrouperGroupMember(string $userId, string $groupName, stri * * @since COmanage Registry v4.4.0 */ - public function optinGroups(array $conditions, array $cfg) + public function optinGroups(array $conditions, array $cfg): array { $this->initApi($cfg); @@ -465,18 +413,19 @@ public function optinGroups(array $conditions, array $cfg) // Groups the user can join or leave $joinOrLeave = $this->grouperAPI->getOptionalGroups($conditions['userId'], GrouperGroupTypeEnum::OPTINS); - // Groups the user is a member of - $userGroups = $this->memberOfGroups($conditions['userId'], - $conditions['userId'], - $cfg); - // Extract the names of the Groups the user is a member of - $userGroupsNames = Hash::extract($userGroups, '{n}.name'); - // Return the groups the user can join and is not a member of - return array_filter($joinOrLeave, static fn($value) => !in_array($value['name'], $userGroupsNames)); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } + + // Groups the user is a member of + $userGroups = $this->memberOfGroups($conditions['userId'], + $conditions['userId'], + $cfg); + // Extract the names of the Groups the user is a member of + $userGroupsNames = Hash::extract($userGroups, '{n}.name'); + // Return the groups the user can join and is not a member of + return array_filter($joinOrLeave, static fn($value) => !in_array($value['name'], $userGroupsNames)); } /** @@ -493,7 +442,7 @@ public function isTemplateUser(string $userId, array $cfg) $this->initApi($cfg); try { - $isMember = $this->grouperAPI->isMemberOfGrouperGroup(GrouperSpecialGroups::TEMPLATE_CREATION_GROUP, $userId); + $isMember = $this->grouperAPI->isMemberOfGroup(GrouperSpecialGroups::TEMPLATE_CREATION_GROUP, $userId); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; diff --git a/webroot/js/groups.js b/webroot/js/groups.js index 3fa6393..c4cf3a4 100644 --- a/webroot/js/groups.js +++ b/webroot/js/groups.js @@ -76,10 +76,8 @@ export default { group.loading = true; const resp = await fetch(`${this.api.join}?GroupName=${group.name}&GroupDisplayName=${group.displayName}`, { headers: { - "Accept": "application/json", - // 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: "DELETE" + "Accept": "application/json" + } }); if (resp.ok) { this.loadGroups(this.apiPath, this.query, false); diff --git a/webroot/js/members.js b/webroot/js/members.js index c3634d5..959cb55 100644 --- a/webroot/js/members.js +++ b/webroot/js/members.js @@ -89,13 +89,12 @@ export default { const resp = await fetch(`${this.api.remove}?group=${(name)}&userId=${id}`, { method: "DELETE", headers: { - "Accept": "application/json", - // 'Content-Type': 'application/x-www-form-urlencoded', + "Accept": "application/json" } }); if (resp.ok) { this.subscribers = []; - this.loadGroupSubscribers(this.group); + await this.loadGroupSubscribers(this.group); generateFlash(`${label || subName} ${this.txt.removeSubscriberSuccess} ${(displayExtension)}`, 'success'); } else { this.disabled = [ ...this.disabled, id ]; @@ -115,15 +114,16 @@ export default { method: "POST", headers: { "Accept": "application/json", - // 'Content-Type': 'application/x-www-form-urlencoded', }, body: formData }); if (resp.ok) { - this.loadGroupSubscribers(this.group); + await this.loadGroupSubscribers(this.group); generateFlash(`${label} ${this.txt.addSubscriberSuccess} ${(displayExtension)}`, 'success'); } else { - generateFlash(this.txt.addSubscriberError, 'error'); + generateFlash(`${this.txt.addSubscriberError}`, 'error'); + let errorResponse = await resp.json(); + generateFlash(`Server Reported:${errorResponse.message}`, 'error'); } this.loading = false; From 076c938b0469d62f4fc6fb227de9407e45a463d1 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Wed, 28 Feb 2024 12:16:55 +0200 Subject: [PATCH 2/5] simplify add/remove to/from group --- Controller/GrouperGroupsController.php | 91 ++++++++------ Lib/GrouperApiAccess.php | 157 +++++++++---------------- Model/GrouperGroup.php | 71 ++++++++--- View/GrouperGroups/index.ctp | 3 +- webroot/js/members.js | 4 +- 5 files changed, 167 insertions(+), 159 deletions(-) diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index 675b1f0..7796d6b 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -107,7 +107,7 @@ public function beforeRender() { $this->set('vv_config', $cfg); $this->set('title', _txt('pl.grouperlite.title.groupmember')); - $this->set('vv_is_user_owner', $this->GrouperGroup->isUserOwner($this->userId ?? '', $cfg) ); + $this->set('vv_is_user_owner', $this->GrouperGroup->isUserGroupOwner($this->userId ?? '', $cfg) ); // $this->set('vv_is_template_user', $this->GrouperGroup->isTemplateUser($this->userId ?? '', $cfg) ); // $this->set('vv_is_grouper_visible', $this->GrouperGroup->isGrouperVisible($this->userId ?? '', $cfg)); $this->set('vv_coid', $this->cur_co['Co']['id']); @@ -189,6 +189,9 @@ public function groupSubscribers(): void */ public function addSubscriber(): void { + $this->layout = null; + $this->autoRender = false; + $groupName = urldecode($this->request->query['group']); $addUserId = urldecode($this->request->query['userId']); @@ -199,10 +202,14 @@ public function addSubscriber(): void // : $groupName; try { - $this->GrouperGroup->addGroupMember($this->userId, - $groupName, - $addUserId, - $this->CoGrouperLiteWidget->getConfig()); + if(!$this->GrouperGroup->addGroupMember($this->userId, + $groupName, + $addUserId, + $this->CoGrouperLiteWidget->getConfig())) { + // The Request returned unsuccessful, but we have not more infomration. In this case we will just return + // forbidden since we do not actually now what happened + $this->restResponse(HttpStatusCodesEnum::HTTP_FORBIDDEN); + } } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); throw $e; @@ -243,32 +250,35 @@ public function findSubscriber(): void * Called from all pages via AJAX call * * TODO: We need to appropriately handle Unathenticated call. We have to bubble up the response and do something. + * @throws JsonException */ public function removeSubscriber(): void { + $this->layout = null; + $this->autoRender = false; + $groupName = urldecode($this->request->query['group']); $remUserId = urldecode($this->request->query['userId']); - $resultRemove = false; //Need to see if coming from AdHoc or from a WG (Working Group) - $groupNameFormatted = (strpos($groupName, ':') === false) ? 'ref:incommon-collab:' . $groupName . ':users' - : $groupName; +// $groupNameFormatted = (strpos($groupName, ':') === false) ? 'ref:incommon-collab:' . $groupName . ':users' +// : $groupName; try { - $resultRemove = $this->GrouperGroup->removeGroupMember($this->userId, - $groupNameFormatted, - $remUserId, - $this->CoGrouperLiteWidget->getConfig()); + if(!$this->GrouperGroup->removeGroupMember($this->userId, + $groupName, + $remUserId, + $this->CoGrouperLiteWidget->getConfig())) { + // The Request returned unsuccessful, but we have not more infomration. In this case we will just return + // forbidden since we do not actually now what happened + $this->restResponse(HttpStatusCodesEnum::HTTP_FORBIDDEN); + } } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); + throw $e; } - if (!$resultRemove) { - $this->restResponse(HttpStatusCodesEnum::HTTP_NOT_FOUND, ErrorsEnum::Error); - } - - $this->set(compact($resultRemove ? GrouperResultCodesEnum::SUCCESS : '')); - $this->set('_serialize', 'resultRemove'); + $this->restResponse(HttpStatusCodesEnum::HTTP_OK); } /** @@ -289,7 +299,7 @@ public function groupOwnerApi() { $scope['searchpage'] = 'ownerGroups'; $errorHint = 'Search'; } else { - $scope['method'] = 'ownerGroups'; + $scope['method'] = 'getOwnedGroups'; $errorHint = ''; } try { @@ -429,19 +439,26 @@ public function groupCreateTemplate() /** * Process to join a group displayed on the "Optin" page * + * @throws Exception */ public function joinGroup(): void { + $this->layout = null; + $this->autoRender = false; // todo: add Subscriber and joinGroup should accept the same query parameters. Currently the join Group // accepts a GroupName, while the addSubscriber accepts a group parameter - $name = urldecode($this->request->query['GroupName']); + $groupName = urldecode($this->request->query['GroupName']); try { // Add myself - $this->GrouperGroup->addGroupMember($this->userId, - $name, - $this->userId, - $this->CoGrouperLiteWidget->getConfig()); + if(!$this->GrouperGroup->addGroupMember($this->userId, + $groupName, + $this->userId, + $this->CoGrouperLiteWidget->getConfig())) { + // The Request returned unsuccessful, but we have not more infomration. In this case we will just return + // forbidden since we do not actually now what happened + $this->restResponse(HttpStatusCodesEnum::HTTP_FORBIDDEN); + } } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); throw $e; @@ -456,25 +473,25 @@ public function joinGroup(): void */ public function leaveGroup(): void { - $name = urldecode($this->request->query['GroupName']); - $resultRemove = false; + $this->layout = null; + $this->autoRender = false; + $groupName = urldecode($this->request->query['GroupName']); try { - $resultRemove = $this->GrouperGroup->leaveGroup($this->userId, - $name, - $this->CoGrouperLiteWidget->getConfig()); + if(!$this->GrouperGroup->removeGroupMember($this->userId, + $groupName, + $this->userId, + $this->CoGrouperLiteWidget->getConfig())) { + // The Request returned unsuccessful, but we have not more infomration. In this case we will just return + // forbidden since we do not actually now what happened + $this->restResponse(HttpStatusCodesEnum::HTTP_FORBIDDEN); + } } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); + throw $e; } -// $this->restResponse(HttpStatusCodesEnum::HTTP_UNAUTHORIZED, ErrorsEnum::NotDeleted); - - if (!$resultRemove) { - $this->restResponse(HttpStatusCodesEnum::HTTP_NOT_FOUND, ErrorsEnum::Error); - } - - $this->set(compact($resultRemove ? GrouperResultCodesEnum::SUCCESS : '')); - $this->set('_serialize', 'resultRemove'); + $this->restResponse(HttpStatusCodesEnum::HTTP_OK); } /** diff --git a/Lib/GrouperApiAccess.php b/Lib/GrouperApiAccess.php index 867aafb..7c3b7b5 100644 --- a/Lib/GrouperApiAccess.php +++ b/Lib/GrouperApiAccess.php @@ -392,57 +392,6 @@ public function getUserGroupMemberships(string $actorUserId, string $userId): ar return $results['WsGetGroupsLiteResult']['wsGroups'] ?? []; } - /** - * Get members associated to a specific Grouper Group - * - * @param string $actorUserId - * @param string $groupName - * - * @return array Listing of Members belonging to Grouper Group - * @throws GrouperLiteWidgetException - * @throws JsonException - */ - public function getGroupMembers(string $actorUserId, string $groupName): array - { - //Build request logic - $usersToShow = [ - 'WsRestGetMembersRequest' => [ - 'actAsSubjectLookup' => [ - 'subjectId' => $actorUserId - ], - 'wsGroupLookups' => [ - ['groupName' => $groupName] - ], - 'subjectAttributeNames' => ['name'] - ] - ]; - - $actionEndpoint = "/groups"; - - try { - $results = $this->http->sendRequest('POST', - $actionEndpoint, - json_encode($usersToShow, JSON_THROW_ON_ERROR)); - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); - throw $e; - } - - // Parse out relevant records to send front end - if(isset($results['WsGetMembersResults']['results'][0]['resultMetadata']['resultCode']) - && $results['WsGetMembersResults']['results'][0]['resultMetadata']['resultCode'] === GrouperResultCodesEnum::GROUP_NOT_FOUND) { - return [ - [ - 'sourceId' => 'NoAccess', - 'name' => '', - 'id' => '' - ] - ]; - } - - return $results['WsGetMembersResults']['results'][0]['wsSubjects'] ?? []; - } - /** * Used for requests made to Membership endpoint in Grouper WS * @@ -456,7 +405,7 @@ public function getGroupMembers(string $actorUserId, string $groupName): array * @see getOptOutGroups() * @see getOwnedGroups() */ - private function getGrouperUserMemberships(string $userId, string $groupType): array + public function getGrouperUserMemberships(string $userId, string $groupType): array { if (in_array($groupType, [ GrouperGroupTypeEnum::OPTINS, @@ -500,47 +449,76 @@ private function getGrouperUserMemberships(string $userId, string $groupType): a } /** - * Gets all available Optin/OptOut groups in Grouper - * - * Returns Optin/OptOut groups that can be joined/left + * Get members associated to a specific Grouper Group * - * @param string $userId - * @param string $groupType + * @param string $actorUserId + * @param string $groupName * - * @return array Optin groups from Grouper + * @return array Listing of Members belonging to Grouper Group * @throws GrouperLiteWidgetException + * @throws JsonException */ - public function getOptionalGroups(string $userId, string $groupType): array + public function getGroupMembers(string $actorUserId, string $groupName): array { + //Build request logic + $usersToShow = [ + 'WsRestGetMembersRequest' => [ + 'actAsSubjectLookup' => [ + 'subjectId' => $actorUserId + ], + 'wsGroupLookups' => [ + ['groupName' => $groupName] + ], + 'subjectAttributeNames' => ['name'] + ] + ]; + + $actionEndpoint = "/groups"; + try { - $results = $this->getGrouperUserMemberships($userId, $groupType); + $results = $this->http->sendRequest('POST', + $actionEndpoint, + json_encode($usersToShow, JSON_THROW_ON_ERROR)); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } - return $results['WsGetMembershipsResults']['wsGroups'] ?? []; + + // Parse out relevant records to send front end + if(isset($results['WsGetMembersResults']['results'][0]['resultMetadata']['resultCode']) + && $results['WsGetMembersResults']['results'][0]['resultMetadata']['resultCode'] === GrouperResultCodesEnum::GROUP_NOT_FOUND) { + return [ + [ + 'sourceId' => 'NoAccess', + 'name' => '', + 'id' => '' + ] + ]; + } + + return $results['WsGetMembersResults']['results'][0]['wsSubjects'] ?? []; } /** - * Gets all groups in Grouper where user is an admin/owner or has update privs + * Gets all available Optin/OptOut groups in Grouper + * + * Returns Optin/OptOut groups that can be joined/left * * @param string $userId + * @param string $groupType * - * @return array Array of groups from Grouper - * @throws Exception + * @return array Optin groups from Grouper + * @throws GrouperLiteWidgetException */ - public function getOwnedGroups(string $userId): array + public function getOptionalGroups(string $userId, string $groupType): array { try { - $resultsAdmin = $this->getGrouperUserMemberships($userId, GrouperGroupTypeEnum::ADMIN); - $resultsUpdate = $this->getGrouperUserMemberships($userId, GrouperGroupTypeEnum::UPDATE); + $results = $this->getGrouperUserMemberships($userId, $groupType); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } - - return $this->removeDuplicates($resultsAdmin['WsGetMembershipsResults']['wsGroups'] ?? [], - $resultsUpdate['WsGetMembershipsResults']['wsGroups'] ?? []); + return $results['WsGetMembershipsResults']['wsGroups'] ?? []; } /** @@ -582,7 +560,7 @@ public function isMemberOfGroup(string $groupName, string $userId): bool $groupNameEncoded = $this->urlGrouperEncode($groupName); - $actionEndpoint = "/groups" + $actionEndpoint = '/groups' . "/{$groupNameEncoded}/members/{$userId}"; try { $results = $this->http->sendRequest('GET', $actionEndpoint); @@ -595,37 +573,6 @@ public function isMemberOfGroup(string $groupName, string $userId): bool && $results['WsHasMemberLiteResul']['resultMetadata']['resultCode'] === GrouperResultCodesEnum::IS_MEMBER; } - /** - * Removes duplicates where the user is the owner and the updater of the group. Just one line instead of two. - * - * @param array $arrOne - * @param array $arrTwo - * @return array - */ - public function removeDuplicates(array $arrOne, array $arrTwo) - { - //Determine which array is bigger and use as base - $countOne = count($arrOne); - $countTwo = count($arrTwo); - if ($countOne >= $countTwo) { - $arrL = $arrOne; - $arrS = $arrTwo; - } else { - $arrL = $arrTwo; - $arrS = $arrOne; - } - - foreach ($arrL as $large) { - foreach ($arrS as $key => $val) { - if ($large['uuid'] == $val['uuid']) { - unset($arrS[$key]); - } - } - } - - return array_merge_recursive($arrL, $arrS); - } - /** * Remove a member from a specific Grouper Group * @@ -672,7 +619,11 @@ public function removeGroupMember(string $actAsUserId, string $groupName, string throw $e; } - // Parse out relevant records to send front end + if(isset($results['error']) && $results['error']) { + $cakeExceptionClass = $results['cakeException']; + throw new $cakeExceptionClass($results['message']); + } + return isset($results['WsDeleteMemberResults']['resultMetadata']['resultCode']) && $results['WsDeleteMemberResults']['resultMetadata']['resultCode'] === GrouperResultCodesEnum::SUCCESS; } diff --git a/Model/GrouperGroup.php b/Model/GrouperGroup.php index 3a7c9b9..1a1f8b6 100644 --- a/Model/GrouperGroup.php +++ b/Model/GrouperGroup.php @@ -70,19 +70,24 @@ class GrouperGroup extends GrouperLiteWidgetAppModel * * @since COmanage Registry v4.4.0 */ - public function isUserOwner(string $userId, array $cfg) + public function isUserGroupOwner(string $userId, array $cfg): bool { $this->initApi($cfg); - $args = array(); + + if(empty($userId)) { + return false; + } try { - $ownGroups = $this->grouperAPI->getOwnedGroups($userId); + $resultsAdmin = $this->grouperAPI->getGrouperUserMemberships($userId, GrouperGroupTypeEnum::ADMIN); + $resultsUpdate = $this->grouperAPI->getGrouperUserMemberships($userId, GrouperGroupTypeEnum::UPDATE); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } - return count($ownGroups) > 0 ? 'T' : 'F'; + return count($resultsAdmin['WsGetMembershipsResults']['wsGroups'] ?? []) > 0 + || count($resultsUpdate['WsGetMembershipsResults']['wsGroups'] ?? []) > 0; } /** @@ -286,22 +291,31 @@ private function memberOfGroups(string $actorUserId, string $userId, array $cfg) /** * Return all Grouper Groups that the User has a role of owner/admin * - * @param array $conditions Listing of conditions for display of records, including UserId + * @param array $conditions Listing of conditions for display of records, including UserId + * @param array $cfg + * * @return array * @throws GrouperLiteWidgetException - * * @since COmanage Registry v4.4.0 */ - public function ownerGroups(array $conditions, array $cfg) + public function getOwnedGroups(array $conditions, array $cfg): array { + if(empty($conditions['userId'])) { + return false; + } + $this->initApi($cfg); try { - return $this->grouperAPI->getOwnedGroups($conditions['userId']); + $resultsAdmin = $this->grouperAPI->getGrouperUserMemberships($conditions['userId'], GrouperGroupTypeEnum::ADMIN); + $resultsUpdate = $this->grouperAPI->getGrouperUserMemberships($conditions['userId'], GrouperGroupTypeEnum::UPDATE); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } + + return $this->removeDuplicates($resultsAdmin['WsGetMembershipsResults']['wsGroups'] ?? [], + $resultsUpdate['WsGetMembershipsResults']['wsGroups'] ?? []); } /** @@ -383,14 +397,7 @@ public function removeGroupMember(string $userId, { $this->initApi($cfg); - try { - return $this->grouperAPI->removeGroupMember($userId, - $groupName, - $removeUserId); - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); - throw $e; - } + return $this->grouperAPI->removeGroupMember($userId, $groupName, $removeUserId); } @@ -674,4 +681,36 @@ private function getFriendlyWorkingGroupName(array $groups, string $method) { return $finalWorkingGroups; } + + + /** + * Removes duplicates where the user is the owner and the updater of the group. Just one line instead of two. + * + * @param array $arrOne + * @param array $arrTwo + * @return array + */ + public function removeDuplicates(array $arrOne, array $arrTwo) + { + //Determine which array is bigger and use as base + $countOne = count($arrOne); + $countTwo = count($arrTwo); + if ($countOne >= $countTwo) { + $arrL = $arrOne; + $arrS = $arrTwo; + } else { + $arrL = $arrTwo; + $arrS = $arrOne; + } + + foreach ($arrL as $large) { + foreach ($arrS as $key => $val) { + if ($large['uuid'] == $val['uuid']) { + unset($arrS[$key]); + } + } + } + + return array_merge_recursive($arrL, $arrS); + } } diff --git a/View/GrouperGroups/index.ctp b/View/GrouperGroups/index.ctp index 822086c..d3da24d 100644 --- a/View/GrouperGroups/index.ctp +++ b/View/GrouperGroups/index.ctp @@ -2,7 +2,6 @@ extend('/GrouperGroups/base'); ?> Html->script('GrouperLiteWidget.vue-router.js') ?> Html->addCrumb(_txt('pl.grouperlite.nav.memberships')); ?> -
Html->image('GrouperLiteWidget.Grouper.jpg', array('class' => 'img-fluid mr-2', 'style' => 'height: 50px')); ?> @@ -56,7 +55,7 @@ provide: { collapsed: , optAction: "", - owner: , + owner: , url: "", grouperUrl: "", view: "action; ?>", diff --git a/webroot/js/members.js b/webroot/js/members.js index 959cb55..4357086 100644 --- a/webroot/js/members.js +++ b/webroot/js/members.js @@ -99,6 +99,8 @@ export default { } else { this.disabled = [ ...this.disabled, id ]; generateFlash(this.txt.removeSubscriberError, 'error'); + let errorResponse = await resp.json(); + generateFlash(`${errorResponse.message}`, 'error'); } this.loading = false; @@ -123,7 +125,7 @@ export default { } else { generateFlash(`${this.txt.addSubscriberError}`, 'error'); let errorResponse = await resp.json(); - generateFlash(`Server Reported:${errorResponse.message}`, 'error'); + generateFlash(`${errorResponse.message}`, 'error'); } this.loading = false; From a6e11e600b762c9feeedfe75f28877d3e9ae9520 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Wed, 28 Feb 2024 18:21:02 +0200 Subject: [PATCH 3/5] logs comment out --- Lib/GrouperHTTPWrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/GrouperHTTPWrapper.php b/Lib/GrouperHTTPWrapper.php index e9c025a..8475837 100644 --- a/Lib/GrouperHTTPWrapper.php +++ b/Lib/GrouperHTTPWrapper.php @@ -228,7 +228,7 @@ public function sendRequest(string $method, string $endPoint, string $body = '') ]; } - CakeLog::write('debug', __METHOD__ . '::payload: ' . var_export($payload, true)); +// CakeLog::write('debug', __METHOD__ . '::payload: ' . var_export($payload, true)); return $payload; } From e3b6617c18bd5142d2ebac36dacfa64217d369d9 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Wed, 28 Feb 2024 20:34:57 +0200 Subject: [PATCH 4/5] refactor getGrouperUserMemberships --- Controller/GrouperGroupsController.php | 4 ++-- Lib/GrouperApiAccess.php | 28 ++++++++++++-------------- Lib/enum.php | 10 +++++++++ 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index 7796d6b..3baeed7 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -215,7 +215,7 @@ public function addSubscriber(): void throw $e; } - $this->restResponse(HttpStatusCodesEnum::HTTP_OK); + $this->restResponse(HttpStatusCodesEnum::HTTP_CREATED); } /** @@ -464,7 +464,7 @@ public function joinGroup(): void throw $e; } - $this->restResponse(HttpStatusCodesEnum::HTTP_OK); + $this->restResponse(HttpStatusCodesEnum::HTTP_CREATED); } /** diff --git a/Lib/GrouperApiAccess.php b/Lib/GrouperApiAccess.php index 7c3b7b5..bf5c9e8 100644 --- a/Lib/GrouperApiAccess.php +++ b/Lib/GrouperApiAccess.php @@ -407,29 +407,28 @@ public function getUserGroupMemberships(string $actorUserId, string $userId): ar */ public function getGrouperUserMemberships(string $userId, string $groupType): array { - if (in_array($groupType, [ + if(!in_array($groupType, [ GrouperGroupTypeEnum::OPTINS, - GrouperGroupTypeEnum::OPTOUTS], true) - ) { - $subjectId = 'GrouperAll'; - } elseif (in_array($groupType, [ + GrouperGroupTypeEnum::OPTOUTS, GrouperGroupTypeEnum::ADMIN, GrouperGroupTypeEnum::UPDATE, - GrouperGroupTypeEnum::STEM_ADMIN], true) + GrouperGroupTypeEnum::STEM_ADMIN + ], true) ) { - $subjectId = $userId; - } else { CakeLog::write('error', __METHOD__ . ": Option of {$groupType} is not supported"); - throw new GrouperLiteWidgetException("Option of {$groupType} is not supported"); + throw new BadRequestException("Option of {$groupType} is not supported"); } + $isOptinsOrOptouts = in_array($groupType, + [GrouperGroupTypeEnum::OPTINS, GrouperGroupTypeEnum::OPTOUTS], + true); + //Build request logic $data = []; $data['WsRestGetMembershipsRequest']['fieldName'] = $groupType; - $data['WsRestGetMembershipsRequest']['wsSubjectLookups'][0]['subjectId'] = $subjectId; + $data['WsRestGetMembershipsRequest']['wsSubjectLookups'][0]['subjectId'] = $isOptinsOrOptouts ? GrouperConfigEnums::ALL : $userId; - if ($groupType == GrouperGroupTypeEnum::OPTINS - || $groupType == GrouperGroupTypeEnum::OPTOUTS) { + if ($isOptinsOrOptouts) { // Build request logic, 2 subjectId's, second is for when user in "Secret" Optin/Optout Group $data['WsRestGetMembershipsRequest']['wsSubjectLookups'][1]['subjectId'] = $userId; } @@ -455,8 +454,7 @@ public function getGrouperUserMemberships(string $userId, string $groupType): ar * @param string $groupName * * @return array Listing of Members belonging to Grouper Group - * @throws GrouperLiteWidgetException - * @throws JsonException + * @throws GrouperLiteWidgetException|JsonException|NotFoundException */ public function getGroupMembers(string $actorUserId, string $groupName): array { @@ -473,7 +471,7 @@ public function getGroupMembers(string $actorUserId, string $groupName): array ] ]; - $actionEndpoint = "/groups"; + $actionEndpoint = '/groups'; try { $results = $this->http->sendRequest('POST', diff --git a/Lib/enum.php b/Lib/enum.php index c9799a6..815b144 100644 --- a/Lib/enum.php +++ b/Lib/enum.php @@ -20,14 +20,19 @@ class GrouperSpecialGroups { } class GrouperResultCodesEnum { + const SUCCESS_ALREADY_EXISTED = 'SUCCESS_ALREADY_EXISTED'; const EXECUTE_FAILED = 'EXECUTE_FAILED'; const GROUP_NOT_FOUND = 'GROUP_NOT_FOUND'; const IS_MEMBER = 'IS_MEMBER'; + const IS_NOT_MEMBER = 'IS_NOT_MEMBER'; const NO_SUCH_OBJECT = 'NO_SUCH_OBJECT'; const PROBLEM_WITH_ASSIGNMENT = 'PROBLEM_WITH_ASSIGNMENT'; const SUBJECT_NOT_FOUND = 'SUBJECT_NOT_FOUND'; const SUCCESS = 'SUCCESS'; + const SUCCESS_INSERTED = 'SUCCESS_INSERTED'; + const SUCCESS_NO_CHANGES_NEEDED = 'SUCCESS_NO_CHANGES_NEEDED'; const SUCCESS_NO_INFO = 'SUCCESS_NO_INFO'; + const SUCCESS_UPDATED = 'SUCCESS_UPDATED'; } class GrouperCodesToExceptionClassEnum { @@ -45,4 +50,9 @@ class GrouperGroupTypeEnum { const OPTOUTS = 'optouts'; const STEM_ADMIN = 'stemAdmin'; const UPDATE = 'update'; +} + +class GrouperConfigEnums { + // https://github.com/Internet2/grouper/blob/GROUPER_4_BRANCH/grouper/src/grouper/edu/internet2/middleware/grouper/cfg/GrouperConfig.java + const ALL = 'GrouperAll'; } \ No newline at end of file From 938e45bc69a54ac640c7827caf1784bb56781d01 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Wed, 28 Feb 2024 21:10:18 +0200 Subject: [PATCH 5/5] Refactor get groupSubscribers --- Controller/GrouperGroupsController.php | 13 +++---------- Lib/GrouperApiAccess.php | 20 ++++++-------------- Lib/enum.php | 1 + View/GrouperGroups/index.ctp | 1 + webroot/js/members.js | 6 +++++- 5 files changed, 16 insertions(+), 25 deletions(-) diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index 3baeed7..79d3515 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -149,11 +149,12 @@ public function groupOwner(): void * Show all members of a group * Called from all pages via AJAX call * + * @throws Exception */ public function groupSubscribers(): void { $groupName = urldecode($this->request->query['groupname']); - $subscribers = 0; + $subscribers = []; // //Need to see if coming from AdHoc or from a WG (Working Group) // $groupNameFormatted = strpos($groupName, ':') === false ? 'ref:incommon-collab:' . $groupName . ':users' @@ -165,15 +166,7 @@ public function groupSubscribers(): void $this->CoGrouperLiteWidget->getConfig()); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); - - $this->Flash->set(_txt('pl.grouperlite.message.flash.group-detail-members-failed'), array('key' => 'error')); - } - - if(count($subscribers) < 1){ - $this->restResponse(HttpStatusCodesEnum::HTTP_NOT_FOUND, ErrorsEnum::Error); - } elseif (count($subscribers) == 1 - && $subscribers[0]['sourceId'] === 'NoAccess') { - $this->restResponse(HttpStatusCodesEnum::HTTP_FORBIDDEN, ErrorsEnum::NoAccess); + throw $e; } $this->set(compact('subscribers')); diff --git a/Lib/GrouperApiAccess.php b/Lib/GrouperApiAccess.php index bf5c9e8..abf1726 100644 --- a/Lib/GrouperApiAccess.php +++ b/Lib/GrouperApiAccess.php @@ -60,7 +60,7 @@ public function __construct(array $cfg) || empty($cfg['CoGrouperLiteWidget']['conn_pass']) || empty($cfg['CoGrouperLiteWidget']['conn_ver']) ) { - throw new GrouperLiteWidgetException('No GrouperLite instance captured'); + throw new \http\Exception\RuntimeException('No GrouperLite instance captured'); } $this->http->setServiceUrl($cfg['CoGrouperLiteWidget']['conn_url'], $cfg['CoGrouperLiteWidget']['conn_ver']); @@ -78,8 +78,7 @@ public function __construct(array $cfg) * @param string $addUserId * * @return bool Requests success or not - * @throws GrouperLiteWidgetException - * @throws JsonException + * @throws GrouperLiteWidgetException|JsonException */ public function addGroupMember(string $actAsUserId, string $groupName, @@ -423,7 +422,7 @@ public function getGrouperUserMemberships(string $userId, string $groupType): ar [GrouperGroupTypeEnum::OPTINS, GrouperGroupTypeEnum::OPTOUTS], true); - //Build request logic + // Build request logic $data = []; $data['WsRestGetMembershipsRequest']['fieldName'] = $groupType; $data['WsRestGetMembershipsRequest']['wsSubjectLookups'][0]['subjectId'] = $isOptinsOrOptouts ? GrouperConfigEnums::ALL : $userId; @@ -482,16 +481,9 @@ public function getGroupMembers(string $actorUserId, string $groupName): array throw $e; } - // Parse out relevant records to send front end - if(isset($results['WsGetMembersResults']['results'][0]['resultMetadata']['resultCode']) - && $results['WsGetMembersResults']['results'][0]['resultMetadata']['resultCode'] === GrouperResultCodesEnum::GROUP_NOT_FOUND) { - return [ - [ - 'sourceId' => 'NoAccess', - 'name' => '', - 'id' => '' - ] - ]; + if(isset($results['error']) && $results['error']) { + $cakeExceptionClass = $results['cakeException']; + throw new $cakeExceptionClass($results['message']); } return $results['WsGetMembersResults']['results'][0]['wsSubjects'] ?? []; diff --git a/Lib/enum.php b/Lib/enum.php index 815b144..963dae1 100644 --- a/Lib/enum.php +++ b/Lib/enum.php @@ -27,6 +27,7 @@ class GrouperResultCodesEnum { const IS_NOT_MEMBER = 'IS_NOT_MEMBER'; const NO_SUCH_OBJECT = 'NO_SUCH_OBJECT'; const PROBLEM_WITH_ASSIGNMENT = 'PROBLEM_WITH_ASSIGNMENT'; + const PROBLEM_GETTING_MEMBERS = 'PROBLEM_GETTING_MEMBERS'; const SUBJECT_NOT_FOUND = 'SUBJECT_NOT_FOUND'; const SUCCESS = 'SUCCESS'; const SUCCESS_INSERTED = 'SUCCESS_INSERTED'; diff --git a/View/GrouperGroups/index.ctp b/View/GrouperGroups/index.ctp index d3da24d..b05e647 100644 --- a/View/GrouperGroups/index.ctp +++ b/View/GrouperGroups/index.ctp @@ -86,6 +86,7 @@ addSubscriberSuccess: "", removeSubscriberError: "", removeSubscriberSuccess: "", + getSubscriberError: "", searchTag: "", peoplePickerPlaceHolder: "", noaccess: "", diff --git a/webroot/js/members.js b/webroot/js/members.js index 4357086..2fa0a09 100644 --- a/webroot/js/members.js +++ b/webroot/js/members.js @@ -70,13 +70,17 @@ export default { const resp = await fetch(`${this.api.group}?groupname=${encodeURIComponent(name)}`, { headers: { "Accept": "application/json", - // 'Content-Type': 'application/x-www-form-urlencoded', }, method: "GET" }); if (resp.ok) { this.subscribers = await resp.json(); } else { + generateFlash( + `${this.txt.getSubscriberError.replace('this', `"${name}"`)}`, + 'error'); + let errorResponse = await resp.json(); + generateFlash(`${errorResponse.message}`, 'error'); this.error = resp; } this.loading = false;