From 1f5397c4a8511dfddd239000ab2c9bbcfc329b32 Mon Sep 17 00:00:00 2001 From: axman Date: Tue, 12 Oct 2021 10:23:33 -0700 Subject: [PATCH] ICPCO-173 and 174 --- Controller/GrouperGroupsController.php | 67 ++++------- Lib/GrouperApiAccess.php | 149 ++++++++++++++----------- Lib/GrouperHTTPWrapper.php | 35 +----- Model/GrouperGroup.php | 18 +-- 4 files changed, 125 insertions(+), 144 deletions(-) diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index e9baa80..eb50333 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -97,46 +97,20 @@ private function setConnection() { } /** - * No true Index page, so sent to default page of Optin + * No true Index page, so sent to default page of My Membership * - * @return CakeResponse Redirect to Optin page + * @return CakeResponse Redirect to MyMembership page */ public function index() { return $this->redirect( - array('controller' => 'grouper_groups', 'action' => 'groupoptin') + array('controller' => 'grouper_groups', 'action' => 'groupmember') ); } + /** - * Show all members of group in Grouper Group detail page - * Called from method GroupInfo - * - */ -// public function membersInGroup() { -// $groupName = urldecode($this->request->query['groupname']); -// -// //Set initial -// $scope = [ -// 'groupName' => $groupName -// ]; -// -// $details = []; -// -// try { -// $details = $this->GrouperGroup->membersInGroup($scope, $this->userId); -// -// } 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')); -// } -// -// return $details; -// } - - /** - * Show all members of group in Grouper Group detail page - * Called from method GroupInfo + * Show all members of a group + * Called from all pages via AJAX call * */ public function groupSubscribers() { @@ -376,13 +350,13 @@ public function groupOptin() { */ public function groupCreateTemplate() { if ($this->request->is('post')) { - if (!$this->GrouperGroup->createGroupWithTemplate($this->userId, $this->request->data)) { - $this->Flash->set("Error in creating group!", array('key' => 'error')); - return $this->redirect(array('action' => 'groupoptin')); + $status = $this->GrouperGroup->createGroupWithTemplate($this->userId, $this->request->data); + if ($status['status'] !== true) { + $this->Flash->set($status['message'], array('key' => 'error')); } else { $this->Flash->set("Success in creating group!", array('key' => 'success')); - return $this->redirect(array('action' => 'groupoptin')); } + return $this->redirect(array('action' => 'groupcreatetemplate')); } $this->set('title', _txt('pl.grouperlite.title.templatecreate')); } @@ -400,33 +374,39 @@ public function groupDeleteTemplate() { $this->set('title', _txt('pl.grouperlite.title.templatecreate')); } - + /** + * This method is currently not used. + * + * @return CakeResponse|void|null + */ public function groupCreate() { if ($this->request->is('post')) { if (!$this->GrouperGroup->createUpdateGroup($this->userId, $this->request->data)) { $this->Flash->set("Error in creating group!", array('key' => 'error')); - return $this->redirect(array('action' => 'groupOwner')); } else { $this->Flash->set("Your Group has been created!", array('key' => 'success')); - return $this->redirect(array('action' => 'groupOwner')); } + return $this->redirect(array('action' => 'groupOwner')); } $this->set('title', _txt('pl.grouperlite.title.groupcreate')); $this->set('grouperstems', $this->GrouperGroup->getOwnedStems($this->userId)); } - //TODO - Finish this call + + /** + * This method is currently not used. + * @return CakeResponse|null + */ public function groupDelete() { if (!$this->GrouperGroup->deleteGroup($this->userId, $this->request->data)) { $this->Flash->set("Error in deleting group!", array('key' => 'error')); - return $this->redirect(array('action' => 'groupOwner')); } else { $this->Flash->set("Your Group has been deleted!", array('key' => 'success')); - return $this->redirect(array('action' => 'groupOwner')); } $this->set('grouperstems', $this->GrouperGroup->getOwnedStems($this->userId)); + return $this->redirect(array('action' => 'groupOwner')); } @@ -449,7 +429,6 @@ public function joinGroup() { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); $this->Flash->set(_txt('pl.grouperlite.message.flash.join-group-error'), array('key' => 'error')); } - } else { $this->Flash->set(_txt('pl.grouperlite.message.flash.join-group-error')); } @@ -751,7 +730,6 @@ private function breakoutGroups(array $recordSet, $type = 'basic') { * */ private function hackDescription($description) { - //Verify description has period in it. if (strpos($description, ".") === false) { return $description; @@ -759,6 +737,5 @@ private function hackDescription($description) { $newString = substr($description, strpos($description, ".") + 1); return trim($newString); - } } diff --git a/Lib/GrouperApiAccess.php b/Lib/GrouperApiAccess.php index 33466a6..ab5fc15 100644 --- a/Lib/GrouperApiAccess.php +++ b/Lib/GrouperApiAccess.php @@ -73,6 +73,9 @@ public function __construct() { /** * Get Groups that User is a member of from Grouper. * + * Note: Params added at end make sure that the groups returned can only be viewed by the member logged into + * Grouper Lite + * * @param array $queryData Array of conditions for querying * @return array Membership records that User is a member of in Grouper * @throws GrouperLiteException @@ -81,7 +84,8 @@ public function getGrouperMemberOfGroups(array $queryData) { //Build request logic $userId = $queryData['userId']; - $connectionUrl = "{$this->config['fullUrl']}/subjects/{$userId}/groups"; + $connectionUrl = "{$this->config['fullUrl']}/subjects/$userId/groups?"; + $connectionUrl .= "wsLiteObjectType=WsRestGetGroupsLiteRequest&actAsSubjectSourceId=ldap&actAsSubjectId=$userId"; try { $results = $this->http->sendRequest('GET', $connectionUrl); @@ -91,7 +95,7 @@ public function getGrouperMemberOfGroups(array $queryData) { return $results['WsGetGroupsLiteResult']['wsGroups']; } } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); + CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } @@ -121,8 +125,8 @@ public function grouperGroupLeaveOrJoin(array $queryData) { $resultResponse = 'WsAddMemberResults'; $resultGroup = 'wsGroupAssigned'; } else { - CakeLog::write('error',__METHOD__ . ": Option of $groupLeaveOrJoin is not supported"); - throw new GrouperLiteException("Receved option of $groupLeaveOrJoin which is not supported"); + CakeLog::write('error', __METHOD__ . ": Option of $groupLeaveOrJoin is not supported"); + throw new GrouperLiteException("Received option of $groupLeaveOrJoin which is not supported"); } //Build request logic @@ -139,7 +143,7 @@ public function grouperGroupLeaveOrJoin(array $queryData) { ); $this->http->setHeader(array('Content-Type' => 'application/json', 'Accept' => 'application/json')); - $connectionUrl = "{$this->config['fullUrl']}/groups/{$groupName}/members"; + $connectionUrl = "{$this->config['fullUrl']}/groups/$groupName/members"; try { $results = $this->http->sendRequest('PUT', $connectionUrl, json_encode($groupCommand)); @@ -151,7 +155,7 @@ public function grouperGroupLeaveOrJoin(array $queryData) { } } } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); + CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } @@ -201,29 +205,26 @@ public function getOwnedGroups(array $queryData) { $resultsUpdate = $this->useMembershipUrl($queryData); if (isset($resultsAdmin['WsGetMembershipsResults']['wsGroups']) && $resultsAdmin['WsGetMembershipsResults']['wsGroups'] != NULL) { - $admins = $resultsAdmin['WsGetMembershipsResults']['wsGroups']; + $admins = $resultsAdmin['WsGetMembershipsResults']['wsGroups']; } else { $admins = array(); } if (isset($resultsUpdate['WsGetMembershipsResults']['wsGroups']) && $resultsUpdate['WsGetMembershipsResults']['wsGroups'] != NULL) { - $updaters = $resultsUpdate['WsGetMembershipsResults']['wsGroups']; + $updaters = $resultsUpdate['WsGetMembershipsResults']['wsGroups']; } else { $updaters = array(); } return $this->removeDuplicates($admins, $updaters); } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); + CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } - return array(); } - /** - * Currently not being used, but would be needed if Bill K does not want to show a group where - * the user is the admin and the updater. + * 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 @@ -234,7 +235,7 @@ 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) { + if ($countOne >= $countTwo) { $arrL = $arrOne; $arrS = $arrTwo; } else { @@ -250,11 +251,9 @@ public function removeDuplicates(array $arrOne, array $arrTwo) { } } - $results = array_merge_recursive($arrL, $arrS); - return $results; + return array_merge_recursive($arrL, $arrS); } - /** * Get members associated to a specific Grouper Group * @@ -264,32 +263,32 @@ public function removeDuplicates(array $arrOne, array $arrTwo) { */ public function getMembersInGroup(array $queryData) { - // First verify that user has read access to group - if ($this->verifyPrivileges($queryData, 'read') === false) { - return array( - array( - "sourceId" => "ldap", - "name" => "You do not have access to memberships" - ) - ); - } + try { + // First verify that user has read access to group + if ($this->verifyPrivileges($queryData, 'read') === false) { + return array( + array( + "sourceId" => "ldap", + "name" => "You do not have access to memberships" + ) + ); + } - //Build request logic - $usersToShow = array( - "WsRestGetMembersRequest" => array( - "wsGroupLookups" => array( - array("groupName" => $queryData['groupName']) - ), - "subjectAttributeNames" => array( - "name" + //Build request logic + $usersToShow = array( + "WsRestGetMembersRequest" => array( + "wsGroupLookups" => array( + array("groupName" => $queryData['groupName']) + ), + "subjectAttributeNames" => array( + "name" + ) ) - ) - ); + ); - $this->http->setHeader(array('Content-Type' => 'application/json', 'Accept' => 'application/json')); - $connectionUrl = "{$this->config['fullUrl']}/groups"; + $this->http->setHeader(array('Content-Type' => 'application/json', 'Accept' => 'application/json')); + $connectionUrl = "{$this->config['fullUrl']}/groups"; - try { $results = $this->http->sendRequest('POST', $connectionUrl, json_encode($usersToShow)); // Parse out relevant records to send front end @@ -297,13 +296,19 @@ public function getMembersInGroup(array $queryData) { return $results['WsGetMembersResults']['results'][0]['wsSubjects']; } } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); + CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } return array(); } + /** + * @param array $queryData Array of conditions for querying + * @param string $privilege attribute verifying user has set + * @return bool If user has said attribute correctly set + * @throws GrouperLiteException + */ public function verifyPrivileges(array $queryData, string $privilege) { //Build request logic $verifyPrivs = array( @@ -329,12 +334,11 @@ public function verifyPrivileges(array $queryData, string $privilege) { } } } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); + CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } - return array(); - + return false; } /** @@ -354,7 +358,7 @@ public function getOwnedStems(array $queryData) { return $results['WsGetMembershipsResults']['wsStems']; } } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); + CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } return array(); @@ -363,14 +367,14 @@ public function getOwnedStems(array $queryData) { /** * Used for requests made to Membership endpoint in Grouper WS * - * @see getOptinGroups() - * @see getOptOutGroups() - * @see getOwnedGroups() - * @see getOwnedStems() - * * @param array $queryData Array of conditions for querying * @return array Group records associated to calling method * @throws GrouperLiteException + * + * @see getOwnedStems() + * @see getOptinGroups() + * @see getOptOutGroups() + * @see getOwnedGroups() */ private function useMembershipUrl(array $queryData) { $groupType = $queryData['groupType']; @@ -381,7 +385,7 @@ private function useMembershipUrl(array $queryData) { } elseif ($groupType == 'admin' || $groupType == 'update' || $groupType == 'stemAdmin') { $subjectId = $userId; } else { - CakeLog::write('error', __METHOD__ . ": Option of $groupType is not supported"); + CakeLog::write('error', __METHOD__ . ": Option of $groupType is not supported"); throw new GrouperLiteException("Option of $groupType is not supported"); } @@ -414,22 +418,21 @@ private function useMembershipUrl(array $queryData) { try { return $this->http->sendRequest('POST', $connectionUrl, json_encode($groupsToShow)); } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); + CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } } - /** - * Method used to CREATE a new Group in Grouper via the Template method. + * Method used to CREATE a new Group in Grouper via the Working Group Template method. * * @param array $queryData Array of conditions and data adding new Grouper Group - * @return bool True if added successfully + * @return array status and error message, if applicable * @throws GrouperLiteException * */ public function createGroupWithTemplate(array $queryData) { - //Currently only supporting create group, need to test if update a group will work! + //Currently, only supporting create group, need to test if update a group will work! $data = $queryData['data']; $userId = $queryData['userId']; @@ -442,7 +445,7 @@ public function createGroupWithTemplate(array $queryData) { //Build request logic $inputFields = array(); - foreach($data as $key => $value) { + foreach ($data as $key => $value) { $inputFields[] = array('name' => $key, 'value' => $value); } @@ -464,19 +467,39 @@ public function createGroupWithTemplate(array $queryData) { $this->http->setHeader(array('Content-Type' => 'application/json', 'Accept' => 'application/json')); $connectionUrl = "{$this->config['fullUrl']}/gshTemplateExec"; + $status = true; + $message = ''; try { $results = $this->http->sendRequest('POST', $connectionUrl, json_encode($groupToSave)); if (isset($results['WsGshTemplateExecResult']['resultMetadata']['resultCode'])) { - if (stripos($results['WsGshTemplateExecResult']['resultMetadata']['resultCode'], "SUCCESS", 0) !== false) { - return true; + if (stripos($results['WsGshTemplateExecResult']['resultMetadata']['resultCode'], "INVALID", 0) !== false) { + // Need to see what error message is + if (isset($results['WsGshTemplateExecResult']['gshValidationLines'])) { + //Just grab first one, since do not want to overload the user with errors, plus they won't understand message + $errorMessage = $results['WsGshTemplateExecResult']['gshValidationLines'][0]['validationText']; + $status = false; + if (stripos($errorMessage, 'already exist', 0) !== false) { + $message = 'There already is a WG named: ' . $data['gsh_input_workingGroupExtension']; + } else { + $message = 'An error occurred, please try again later.'; + } + } else { + $status = false; + $message = 'An error occurred, please try again later.'; + } } } } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); + CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } - return false; + + return array( + 'status' => $status, + 'message' => $message + ); + } /** @@ -524,7 +547,7 @@ public function deleteGroupWithTemplate(array $queryData) { } } } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); + CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } return false; @@ -586,7 +609,7 @@ public function createUpdateGroup(array $queryData) { } } } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); + CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } return false; @@ -635,7 +658,7 @@ public function getGrouperGroupInfo(array $queryData) { return $groupInfo; } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); + CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } } diff --git a/Lib/GrouperHTTPWrapper.php b/Lib/GrouperHTTPWrapper.php index 3439d50..dbcd822 100644 --- a/Lib/GrouperHTTPWrapper.php +++ b/Lib/GrouperHTTPWrapper.php @@ -113,40 +113,17 @@ public function sendRequest(string $method, string $uri, string $body = ''): arr $this->_request['body'] = $body; try { - $results = $this->request($this->_request); + $apiResults = $this->request($this->_request); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred: ' . var_export($e->getMessage(), true)); throw new GrouperLiteException('An error occurred talking to Grouper WS'); } - return $this->_verifyResults($results); - } - /** - * Verify data from Grouper Web Service came back successfully, if not log error and send to front end. - * - * @param HttpSocketResponse $apiResults Results from Grouper WS - * @return array array of records | array with error message - * @throws GrouperLiteException If issue with Grouper WS data returned - */ - private function _verifyResults(HttpSocketResponse $apiResults): array { - - $resBody = array(); - if ($apiResults->isOk()) { - $resBody = json_decode($apiResults->body(), true); - - $mainKey = key($resBody); - $apiSuccess = $resBody[$mainKey]['resultMetadata']['resultCode']; - - // Had to add SUCCESS_NOT_ALLOWED and SUCCESS_ALLOWED for checking privs on a group for a user - if ($apiSuccess != 'SUCCESS' && $apiSuccess != 'SUCCESS_NOT_ALLOWED' && $apiSuccess != 'SUCCESS_ALLOWED') { - CakeLog::write('error', __METHOD__ . ': Result Code was ' . var_export($apiSuccess, true)); - CakeLog::write('error', __METHOD__ . ': Error of ' . var_export($apiResults->body(), true)); - throw new GrouperLiteException('Result from Grouper WS was' . var_export($apiSuccess, true)); - } - } else { - CakeLog::write('error', __METHOD__ . ': Verify error of ' . var_export($apiResults->body(), true)); - throw new GrouperLiteException('An error occurred while talking to Grouper WS'); + // 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)); } - return $resBody; + + return json_decode($apiResults->body(), true); } } diff --git a/Model/GrouperGroup.php b/Model/GrouperGroup.php index f566cd7..4352b22 100644 --- a/Model/GrouperGroup.php +++ b/Model/GrouperGroup.php @@ -299,9 +299,7 @@ public function ownerGroups(array $conditions) { $this->initApi(); try { - $ownGroups = $this->grouperAPI->getOwnedGroups($conditions); - - return $ownGroups; + return $this->grouperAPI->getOwnedGroups($conditions); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); @@ -464,7 +462,7 @@ public function isTemplateUser(string $userId) { * * @param string $userId Id of User * @param array $groupData Data needed to create new Grouper Group via Template - * @return bool True if successfully created record + * @return array status and error message, if applicable * @throws GrouperLiteException * */ @@ -667,11 +665,18 @@ public function paginate($conditions) { } + /** + * Process that parses the email list and makes it more user friendly + * @lists. + * + * @param array $groups - Array of email lists + * @param $method - User who is accessing, if plain member remove admin and owner email lists. + * @return array - Array of friendly email lists + */ private function getFriendlyEmailName(array $groups, $method) { $arrayIndex = 0; foreach ($groups as &$group) { - $appName = ''; if ($method == 'member') { if ($group['extension'] == 'admins' || $group['extension'] == 'owners') { unset($groups[$arrayIndex]); @@ -709,6 +714,7 @@ private function getFriendlyEmailName(array $groups, $method) { private function getFriendlyWorkingGroupName(array $groups, $method) { $arrayIndex = 0; + $workingGroups = array(); //First need to loop through all groups and pull in all top levels $topLevelWG = array(); @@ -783,7 +789,6 @@ private function getFriendlyWorkingGroupName(array $groups, $method) { } $arrayIndex += 1; } - $finalWorkingGroups = array(); foreach ($workingGroups as $workingGroup) { @@ -838,7 +843,6 @@ private function verifyAdHocStem(array $groups) { if (!$legit) { unset($groups[$key]); } - } return $groups;