diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index bc41852..aab184b 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -155,16 +155,14 @@ public function groupSubscribers(): void $groupName = urldecode($this->request->query['groupname']); $subscribers = 0; - //Need to see if coming from AdHoc or from a WG (Working Group) - $groupNameFormatted = strpos($groupName, ':') === false ? 'ref:incommon-collab:' . $groupName . ':users' - : $groupName; +// //Need to see if coming from AdHoc or from a WG (Working Group) +// $groupNameFormatted = strpos($groupName, ':') === false ? 'ref:incommon-collab:' . $groupName . ':users' +// : $groupName; try { $subscribers = $this->GrouperGroup->getGrouperGroupMembers($this->userId, - $groupNameFormatted, + $groupName, $this->CoGrouperLiteWidget->getConfig()); - CakeLog::write('debug', __METHOD__ . '::response: ' . var_export($subscribers, true)); - } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); @@ -194,15 +192,14 @@ public function addSubscriber(): void $resultAdd = 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 { $resultAdd = $this->GrouperGroup->addGrouperGroupMember($this->userId, - $groupNameFormatted, + $groupName, $addUserId, $this->CoGrouperLiteWidget->getConfig()); - CakeLog::write('debug', __METHOD__ . '::response: ' . var_export($resultAdd, true)); } catch (Exception $e) { // $this->restResponse(HttpStatusCodesEnum::HTTP_UNAUTHORIZED, ErrorsEnum::NotAdded); CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); @@ -246,8 +243,6 @@ public function findSubscriber(): void * Remove a member from a group * Called from all pages via AJAX call * - * TODO: We should probably save extra metadata in a data attribute and then pass that attribute to the request and not - * the Human Readable name * TODO: We need to appropriately handle Unathenticated call. We have to bubble up the response and do something. */ public function removeSubscriber(): void @@ -265,8 +260,6 @@ public function removeSubscriber(): void $groupNameFormatted, $remUserId, $this->CoGrouperLiteWidget->getConfig()); - - CakeLog::write('debug', __METHOD__ . '::response: ' . var_export($resultRemove, true)); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); } @@ -304,7 +297,6 @@ public function groupOwnerApi() { $func = $scope['method']; $groupowners = $this->GrouperGroup->$func($scope, $this->CoGrouperLiteWidget->getConfig()); - CakeLog::write('debug', __METHOD__ . "::response: " . var_export($groupowners, true)); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . "::{$errorHint}: " . var_export($e->getMessage(), true)); $this->restResponse(HttpStatusCodesEnum::HTTP_INTERNAL_SERVER_ERROR, ErrorsEnum::Exception); diff --git a/Lib/GrouperApiAccess.php b/Lib/GrouperApiAccess.php index 0f1589e..c84e8de 100644 --- a/Lib/GrouperApiAccess.php +++ b/Lib/GrouperApiAccess.php @@ -206,36 +206,28 @@ public function createGroupWithTemplate(array $queryData): array * * Create or Update a Group where User is Admin/Owner * - * @param array $queryData Array of conditions and data adding new Grouper Group + * @param string $actAsUserId + * @param string $groupName + * @param string $stem + * @param string $groupDescription * * @return bool True if added or updated successful - * @throws GrouperLiteWidgetException|JsonException + * @throws GrouperLiteWidgetException + * @throws JsonException */ - public function createUpdateGroup(array $queryData) + public function createUpdateGroup(string $actAsUserId, string $groupName, string $stem, string $groupDescription ): bool { - - $groupName = htmlentities($queryData['name']); - $stemName = htmlentities($queryData['stem']); - $userId = $queryData['userId']; - $groupDescription = htmlentities($queryData['description']); - - //Group name may be in "friendly" format, so need to do some small conversions before saving. - $newGroupName = ucfirst(strtolower($groupName)); - $newGroupName = str_replace(' ', '', $newGroupName); - - $newGroupToSave = "$stemName:$newGroupName"; - //Build request logic $groupToSave = [ 'WsRestGroupSaveRequest' => [ 'actAsSubjectLookup' => [ - 'subjectId' => $userId + 'subjectId' => $actAsUserId ], 'wsGroupToSaves' => [ [ 'wsGroup' => [ 'description' => $groupDescription, - 'name' => $newGroupToSave, + 'name' => "{$stem}:{$groupName}", 'displayExtension' => $groupName ], 'wsGroupLookup' => [ @@ -322,14 +314,14 @@ public function deleteGroupWithTemplate(array $queryData) * * Grouper Group information plus a listing of attributes in Grouper for that given Group * - * @param array $queryData Array of conditions for querying + * @param string $groupName * * @return array Record of Grouper attributes for given GroupName - * @throws GrouperLiteWidgetException|JsonException + * @throws GrouperLiteWidgetException + * @throws JsonException */ - public function getGrouperGroupInfo(array $queryData) + public function getGrouperGroupInfo(string $groupName) { - $groupName = $queryData['groupName']; $groupInfo = []; //Build request logic @@ -436,7 +428,7 @@ public function getGrouperGroupMembers(string $actorUserId, string $groupName): // Parse out relevant records to send front end if(isset($results['WsGetMembersResults']['results'][0]['resultMetadata']['resultCode']) - && $results['WsGetMembersResults']['results'][0]['resultMetadata']['resultCode'] == 'GROUP_NOT_FOUND') { + && $results['WsGetMembersResults']['results'][0]['resultMetadata']['resultCode'] === GrouperResultCodesEnum::GROUP_NOT_FOUND) { return [ [ 'sourceId' => 'NoAccess', @@ -449,21 +441,77 @@ public function getGrouperGroupMembers(string $actorUserId, string $groupName): return $results['WsGetMembersResults']['results'][0]['wsSubjects'] ?? []; } + /** + * Used for requests made to Membership endpoint in Grouper WS + * + * @param string $userId + * @param string $groupType + * + * @return array Group records associated to calling method + * @throws GrouperLiteWidgetException + * @see getOwnedStems() + * @see getOptinGroups() + * @see getOptOutGroups() + * @see getOwnedGroups() + */ + private function getGrouperUserMemberships(string $userId, string $groupType): array + { + if (in_array($groupType, [ + GrouperGroupTypeEnum::OPTINS, + GrouperGroupTypeEnum::OPTOUTS], true) + ) { + $subjectId = 'GrouperAll'; + } elseif (in_array($groupType, [ + GrouperGroupTypeEnum::ADMIN, + GrouperGroupTypeEnum::UPDATE, + 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"); + } + + //Build request logic + $data = []; + $data['WsRestGetMembershipsRequest']['fieldName'] = $groupType; + $data['WsRestGetMembershipsRequest']['wsSubjectLookups'][0]['subjectId'] = $subjectId; + + if ($groupType == GrouperGroupTypeEnum::OPTINS + || $groupType == GrouperGroupTypeEnum::OPTOUTS) { + // Build request logic, 2 subjectId's, second is for when user in "Secret" Optin/Optout Group + $data['WsRestGetMembershipsRequest']['wsSubjectLookups'][1]['subjectId'] = $userId; + } + + $actionEndpoint = '/memberships'; + + try { + $results = $this->http->sendRequest('POST', + $actionEndpoint, + json_encode($data)); + } catch (Exception $e) { + CakeLog::write('error', __METHOD__ . ': An error occurred'); + throw $e; + } + + return $results; + } + /** * Gets all available Optin/OptOut groups in Grouper * * Returns Optin/OptOut groups that can be joined/left * - * @param array $queryData Array of conditions for querying + * @param string $userId + * @param string $groupType + * * @return array Optin groups from Grouper * @throws GrouperLiteWidgetException - * */ - public function getOptionalGroups(array $queryData) + public function getOptionalGroups(string $userId, string $groupType): array { - try { - $results = $this->useMembershipUrl($queryData); + $results = $this->getGrouperUserMemberships($userId, $groupType); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; @@ -474,21 +522,16 @@ public function getOptionalGroups(array $queryData) /** * Gets all groups in Grouper where user is an admin/owner or has update privs * - * @param array $queryData Array of conditions for querying - * @return array Array of groups from Grouper - * @throws GrouperLiteWidgetException + * @param string $userId * + * @return array Array of groups from Grouper + * @throws Exception */ - public function getOwnedGroups(array $queryData) + public function getOwnedGroups(string $userId): array { try { - $queryData['groupType'] = 'admin'; - $resultsAdmin = $this->useMembershipUrl($queryData); - CakeLog::write('debug', __METHOD__ . '::response admins: ' . var_export($resultsAdmin, true)); - - $queryData['groupType'] = 'update'; - $resultsUpdate = $this->useMembershipUrl($queryData); - CakeLog::write('debug', __METHOD__ . '::response updates: ' . var_export($resultsUpdate, true)); + $resultsAdmin = $this->getGrouperUserMemberships($userId, GrouperGroupTypeEnum::ADMIN); + $resultsUpdate = $this->getGrouperUserMemberships($userId, GrouperGroupTypeEnum::UPDATE); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; @@ -503,16 +546,15 @@ public function getOwnedGroups(array $queryData) * * Gets all Stems/Folders where User is admin/owner * - * @param array $queryData Array of conditions for querying + * @param string $userId + * * @return array Array of Stems/Folders from Grouper * @throws GrouperLiteWidgetException */ - public function getOwnedStems(array $queryData) + public function getOwnedStems(string $userId): array { - $queryData['groupType'] = 'stemAdmin'; - try { - $results = $this->useMembershipUrl($queryData); + $results = $this->getGrouperUserMemberships($userId, GrouperGroupTypeEnum::ADMIN); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; @@ -647,55 +689,4 @@ public function urlGrouperEncode(string $url): string $url = urlencode($url); return str_replace(':', '%3A', $url); } - - /** - * Used for requests made to Membership endpoint in Grouper WS - * - * @param array $queryData Array of conditions for querying - * @return array Group records associated to calling method - * @throws GrouperLiteWidgetException - * - * @see getOwnedStems() - * @see getOptinGroups() - * @see getOptOutGroups() - * @see getOwnedGroups() - */ - private function useMembershipUrl(array $queryData) - { - $groupType = $queryData['groupType']; - $userId = $queryData['userId']; - - if ($groupType == 'optins' || $groupType == 'optouts') { - $subjectId = 'GrouperAll'; - } elseif ($groupType == 'admin' || $groupType == 'update' || $groupType == 'stemAdmin') { - $subjectId = $userId; - } else { - CakeLog::write('error', __METHOD__ . ": Option of {$groupType} is not supported"); - throw new GrouperLiteWidgetException("Option of {$groupType} is not supported"); - } - - //Build request logic - $groupsToShow = []; - $groupsToShow['WsRestGetMembershipsRequest']['fieldName'] = $groupType; - $groupsToShow['WsRestGetMembershipsRequest']['wsSubjectLookups'][0]['subjectId'] = $subjectId; - - if ($groupType == 'optins' - || $groupType == 'optouts') { - // Build request logic, 2 subjectId's, second is for when user in "Secret" Optin/Optout Group - $groupsToShow['WsRestGetMembershipsRequest']['wsSubjectLookups'][1]['subjectId'] = $userId; - } - - $actionEndpoint = "/memberships"; - - try { - $results = $this->http->sendRequest('POST', - $actionEndpoint, - json_encode($groupsToShow)); - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); - throw $e; - } - - return $results; - } } diff --git a/Lib/enum.php b/Lib/enum.php index e430d7a..3d84546 100644 --- a/Lib/enum.php +++ b/Lib/enum.php @@ -27,4 +27,12 @@ class GrouperResultCodesEnum { const NO_SUCH_OBJECT = 'NO_SUCH_OBJECT'; const SUCCESS_NO_INFO = 'SUCCESS_NO_INFO'; const EXECUTE_FAILED = 'EXECUTE_FAILED'; +} + +class GrouperGroupTypeEnum { + const OPTINS = 'optins'; + const OPTOUTS = 'optouts'; + const ADMIN = 'admin'; + const UPDATE = 'update'; + const STEM_ADMIN = 'stemAdmin'; } \ No newline at end of file diff --git a/Model/GrouperGroup.php b/Model/GrouperGroup.php index f535a7a..d3f891a 100644 --- a/Model/GrouperGroup.php +++ b/Model/GrouperGroup.php @@ -61,25 +61,22 @@ class GrouperGroup extends GrouperLiteWidgetAppModel /** - * Verifies if user is an owner/admin of a group and then stores results in Session. + * Verifies if user is an owner/admin of a group. * Session variable is reset on Group Creation and Group Deletion * * @param string $userId Id of User * @return String T or F * @throws GrouperLiteWidgetException * - * @see GrouperGroup::resetUserOwner() - * * @since COmanage Registry v4.4.0 */ public function isUserOwner(string $userId, array $cfg) { $this->initApi($cfg); $args = array(); - $args['userId'] = $userId; try { - $ownGroups = $this->grouperAPI->getOwnedGroups($args); + $ownGroups = $this->grouperAPI->getOwnedGroups($userId); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; @@ -140,10 +137,8 @@ public function filteredMemberOfGroups(array $conditions, array $cfg) try { $memberOfGroups = $this->memberOfGroups($conditions['userId'], $conditions['userId'], $cfg); - - $conditions['groupType'] = 'optouts'; - // Determine which groups can be left by user, if want. - $optOutGroups = $this->grouperAPI->getOptionalGroups($conditions); + // Determine which groups can be left by user, if wanted. + $optOutGroups = $this->grouperAPI->getOptionalGroups($conditions['userId'], GrouperGroupTypeEnum::OPTOUTS); $optOutGroupsNames = Hash::combine($optOutGroups, '{n}.name', '{n}.displayExtension'); foreach ($memberOfGroups as &$memberOfGroup) { @@ -356,7 +351,7 @@ public function ownerGroups(array $conditions, array $cfg) $this->initApi($cfg); try { - return $this->grouperAPI->getOwnedGroups($conditions); + return $this->grouperAPI->getOwnedGroups($conditions['userId']); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; @@ -405,7 +400,7 @@ public function getGrouperGroupMembers(string $actorUserId, string $groupName, a /** * Add a member to a specific Grouper Group * - * @param string $userId Id of User + * @param string $actAsUserId Id of User * @param string $groupName * @param string $addUserId * @param array $cfg @@ -415,12 +410,12 @@ public function getGrouperGroupMembers(string $actorUserId, string $groupName, a * @throws JsonException * @since COmanage Registry v4.4.0 */ - public function addGrouperGroupMember(string $userId, string $groupName, string $addUserId, array $cfg) + public function addGrouperGroupMember(string $actAsUserId, string $groupName, string $addUserId, array $cfg) { $this->initApi($cfg); try { - return $this->grouperAPI->addGrouperGroupMember($userId, $groupName, $addUserId); + return $this->grouperAPI->addGrouperGroupMember($actAsUserId, $groupName, $addUserId); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; @@ -469,13 +464,15 @@ public function removeGrouperGroupMember(string $userId, string $groupName, stri public function optinGroups(array $conditions, array $cfg) { $this->initApi($cfg); - $conditions['groupType'] = 'optins'; try { // Groups the user can join or leave - $joinOrLeave = $this->grouperAPI->getOptionalGroups($conditions); + $joinOrLeave = $this->grouperAPI->getOptionalGroups($conditions['userId'], + GrouperGroupTypeEnum::OPTINS); // Groups the user is a member of - $userGroups = $this->memberOfGroups($conditions['userId'], $conditions['userId'], $cfg); + $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 @@ -522,35 +519,28 @@ public function isTemplateUser(string $userId, array $cfg) public function createGroupWithTemplate(string $userId, array $groupData, array $cfg) { $this->initApi($cfg); + //Need to massage incoming data to meet Grouper Template requirements + $fields = array( + 'gsh_input_isSympa', + 'gsh_input_isSympaModerated', + 'gsh_input_isOptin', + 'gsh_input_isConfluence', + 'gsh_input_isJira' + ); + // Template does not except true/false, so convert to string and send that way + foreach ($fields as $field) { + ($groupData[$field] == '0') ? $groupData[$field] = 'false' : $groupData[$field] = 'true'; + } + $args = array(); + $args['userId'] = $userId; + $args['data'] = $groupData; try { - //Need to massage incoming data to meet Grouper Template requirements - $fields = array( - 'gsh_input_isSympa', - 'gsh_input_isSympaModerated', - 'gsh_input_isOptin', - 'gsh_input_isConfluence', - 'gsh_input_isJira' - ); - // Template does not except true/false, so convert to string and send that way - foreach ($fields as $field) { - ($groupData[$field] == '0') ? $groupData[$field] = 'false' : $groupData[$field] = 'true'; - } - - $args = array(); - $args['userId'] = $userId; - $args['data'] = $groupData; - - // Reset Session variable that shows if User is an owner or not - $this->resetUserOwner(); - return $this->grouperAPI->createGroupWithTemplate($args); - } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } - } /** @@ -620,9 +610,6 @@ private function getFriendlyWorkingGroupName(array $groups, string $method) { $arrayIndex = 0; $workingGroups = array(); - - CakeLog::write('debug', __METHOD__ . '::raw groups: ', print_r($groups, true)); - //First need to loop through all groups and pull in all top levels $topLevelWG = array(); foreach ($groups as $group) {