From 83727b0cca1a53bb024d77b35c02423302fab80d Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Thu, 7 Mar 2024 21:44:56 +0200 Subject: [PATCH] Backend work, frontend loader and disable action button. --- Controller/GrouperGroupsController.php | 101 ++++++++++++++++++------- Lib/lang.php | 1 + Model/GrouperGroup.php | 49 ++++++++++++ View/GrouperGroups/index.ctp | 2 + webroot/js/autocomplete.js | 10 +-- webroot/js/members.js | 2 +- webroot/js/page/UserManager.js | 50 +++++------- 7 files changed, 150 insertions(+), 65 deletions(-) diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index 7800d23..1657acd 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -40,7 +40,7 @@ class GrouperGroupsController extends GrouperLiteWidgetAppController public $helpers = array('Html', 'Form', 'Flash'); // Dynamic properties are deprecated, so we will define the property here - protected $userId = null; + private $userId = null; public $uses = array( 'GrouperLiteWidget.GrouperGroup', @@ -146,6 +146,14 @@ public function beforeRender() { $this->set('vv_coid', $this->cur_co['Co']['id']); } + /** + * @return null + */ + public function getUserId() + { + return $this->userId; + } + /** * Perform a "keyword" search for CO People, sort of like the CO Dashboard * cross controller search, but intended specifically for "people finder" @@ -234,7 +242,7 @@ public function groupSubscribers(): void /** * Listing of all Grouper Groups owned/admin by User Or search those Grouper Groups */ - public function groupOwnerApi() { + public function groupOwnerApi(): void { //Set initial setting $arguments = [ 'userId' => $this->userId, @@ -261,7 +269,7 @@ public function groupOwnerApi() { CakeLog::write('error', __METHOD__ . "::{$errorHint}: " . var_export($e->getMessage(), true)); $this->restResponse(HttpStatusCodesEnum::HTTP_INTERNAL_SERVER_ERROR, ErrorsEnum::Exception); - $this->set('groupsowners', []); + $this->set('groupowners', []); $this->Flash->set(_txt('pl.grouperlite.message.flash.owner-group-failed'), array('key' => 'error')); return; } @@ -275,7 +283,7 @@ public function groupOwnerApi() { * This includes self-joined Optin Groups, as well as required Groups User cannot leave * */ - public function groupMemberApi() { + public function groupMemberApi(): void { //Set initial setting $arguments = [ 'userId' => $this->userId, @@ -404,7 +412,7 @@ public function index(): void * @return array|bool Permissions * @since COmanage Registry v3.2.0 */ - function isAuthorized(): array|bool + public function isAuthorized(): array|bool { $roles = $this->Role->calculateCMRoles(); $cfg = $this->CoGrouperLiteWidget->getConfig(); @@ -420,32 +428,32 @@ function isAuthorized(): array|bool && is_array($identifiers) && isset($identifiers['Identifier']['identifier']) ) { - $this->userId = $identifiers['Identifier']['identifier']; + $this->setUserId($identifiers['Identifier']['identifier']); } // Determine what operations this user can perform // Construct the permission set for this user, which will also be passed to the view. - //Note: Leaving in current format, in case need to restrict certain pages, can just remove true and add params. - $p = array(); - - $p['index'] = true; - $p['groupowner'] = true; - $p['groupownerapi'] = true; - $p['groupoptin'] = true; - $p['groupoptinapi'] = true; - $p['groupmember'] = true; - $p['groupmemberapi'] = true; - $p['getBaseConfig'] = true; - $p['groupSubscribers'] = true; - $p['addSubscriber'] = true; - $p['findSubscriber'] = true; - $p['usermanager'] = true; - $p['removeSubscriber'] = true; - - $p['groupCreate'] = true; - $p['joinGroup'] = true; - $p['leaveGroup'] = true; - $p['groupcreatetemplate'] = true; + $p = []; + + $p['index'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['groupowner'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['groupownerapi'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['groupoptin'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['groupoptinapi'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['groupmember'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['groupmemberapi'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['getBaseConfig'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['groupSubscribers'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['addSubscriber'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['findSubscriber'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['usermanager'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['usermanagerapi'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['removeSubscriber'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + + $p['groupCreate'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['joinGroup'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['leaveGroup'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); + $p['groupcreatetemplate'] = ($roles['cmadmin'] || $roles['coadmin'] || $roles['comember']); $this->set('permissions', $p); @@ -597,6 +605,14 @@ public function restResponse(int $status, $this->response->send(); } + /** + * @param null $userId + */ + private function setUserId($userId): void + { + $this->userId = $userId; + } + /** * UserManager vue route for rendering * @@ -607,6 +623,37 @@ public function userManager(): void $this->render('index'); } + /** + * Display all Groups for the user i manage + */ + public function userManagerApi(): void + { + //Set initial setting + $cfg = $this->CoGrouperLiteWidget->getConfig(); + + if (!isset($this->request->query['memberid'])) { + $this->restResponse(HttpStatusCodesEnum::HTTP_BAD_REQUEST, ErrorsEnum::Exception); + } + + $memberId = urldecode($this->request->query['memberid']); + + try { + $groupsimanage = $this->GrouperGroup->getManagedUsers($this->userId, + $memberId, + $cfg); + } catch (Exception $e) { + CakeLog::write('error', __METHOD__ . '::get Managed Users: ' . var_export($e->getMessage(), true)); + $this->restResponse(HttpStatusCodesEnum::HTTP_INTERNAL_SERVER_ERROR, ErrorsEnum::Exception); + + $this->set('groupsimanage', []); + return; + } + + $this->set(compact('groupsimanage')); + $this->set('_serialize', 'groupsimanage'); + + } + /** * Override the default sanity check performed in AppController * diff --git a/Lib/lang.php b/Lib/lang.php index 43afa4e..d5e490b 100644 --- a/Lib/lang.php +++ b/Lib/lang.php @@ -121,6 +121,7 @@ 'pl.grouperlite.action.view-members' => 'View members', 'pl.grouperlite.action.grouper' => 'Grouper', 'pl.grouperlite.action.members' => 'Members', + 'pl.grouperlite.action.memberships' => 'Memberships', 'pl.grouperlite.action.close' => 'Close', 'pl.grouperlite.action.clear' => 'Clear', 'pl.grouperlite.action.add-user' => 'Add', diff --git a/Model/GrouperGroup.php b/Model/GrouperGroup.php index 49172c6..e32c589 100644 --- a/Model/GrouperGroup.php +++ b/Model/GrouperGroup.php @@ -318,6 +318,55 @@ public function getOwnedGroups(string $userId, array $cfg): array return $this->removeDuplicates($resultsAdmin, $resultsUpdate); } + /** + * Return all Grouper Groups that + * - the User(me) has a role of owner/admin + * - the User(member User) is a member + * + * @param string $userId + * @param string $memberId + * @param array $cfg + * + * @return array + * @throws GrouperLiteWidgetException + * @since COmanage Registry v4.4.0 + */ + public function getManagedUsers(string $managerId, string $memberId, array $cfg): array { + if(empty($managerId) || empty($memberId)) { + return false; + } + + $this->initApi($cfg); + + try { + $resultsManagerAdmin = $this->grouperAPI->getUserMemberships($managerId, $managerId, GrouperGroupTypeEnum::ADMIN); + $resultsManagerUpdate = $this->grouperAPI->getUserMemberships($managerId, $managerId, GrouperGroupTypeEnum::UPDATE); + } catch (Exception $e) { + CakeLog::write('error', __METHOD__ . ': An error occurred'); + throw $e; + } + + $managerGroupSet = $this->removeDuplicates($resultsManagerAdmin, $resultsManagerUpdate); + + try { + // Groups the user is a member of + $membersGroup = $this->grouperAPI->getUserGroups($memberId, $memberId); + } catch (Exception $e) { + CakeLog::write('error', __METHOD__ . ': An error occurred'); + throw $e; + } + + // Extract the names of the Groups the member-user is a member of + $memberGroupNames = Hash::extract($membersGroup, '{n}.name'); + // Return the groups the user can join and is not a member of + return array_values( // Restart indexing from 0(zero) on the final array + array_filter( // Return the groups the member-user is a member + $managerGroupSet, + static fn($value) => in_array($value['name'], $memberGroupNames) + ) + ); + } + /** * Potential use was for creating adhoc group by a user, not associated to WG. * diff --git a/View/GrouperGroups/index.ctp b/View/GrouperGroups/index.ctp index f22b2e9..138e8a3 100644 --- a/View/GrouperGroups/index.ctp +++ b/View/GrouperGroups/index.ctp @@ -93,6 +93,7 @@ removeSubscriberSuccess: "", getSubscriberError: "", peoplePickerPlaceHolder: "", + memberships: "", noaccess: "", empty: "", join: "", @@ -129,6 +130,7 @@ add: "webroot ?>grouper_lite_widget/grouper_groups/addSubscriber/co:/glid:", group: "webroot ?>grouper_lite_widget/grouper_groups/groupSubscribers/co:/glid:", memberships: "webroot ?>grouper_lite_widget/grouper_groups/groupmemberapi/co:/glid:", + managing: "webroot ?>grouper_lite_widget/grouper_groups/usermanagerapi/co:/glid:", optin: "webroot ?>grouper_lite_widget/grouper_groups/groupoptinapi/co:/glid:", owner: "webroot ?>grouper_lite_widget/grouper_groups/groupownerapi/co:/glid:", }, diff --git a/webroot/js/autocomplete.js b/webroot/js/autocomplete.js index 8fb8a54..c86d92f 100644 --- a/webroot/js/autocomplete.js +++ b/webroot/js/autocomplete.js @@ -2,10 +2,6 @@ export default { props: { - group: { - type: String, - default: "" - }, action: { type: String, default: "addUser" @@ -13,6 +9,10 @@ export default { icon: { type: String, default: 'add' + }, + activeBtn: { + type: Boolean, + default: true } }, inject: ['txt', 'api'], @@ -86,7 +86,7 @@ export default { class=" btn btn-grouper btn-primary px-4 border-0" type="button" @click="performAction()" - :disabled="true"> + :disabled="activeBtn"> {{ btnTxt }} diff --git a/webroot/js/members.js b/webroot/js/members.js index 4900d03..c031bd1 100644 --- a/webroot/js/members.js +++ b/webroot/js/members.js @@ -163,7 +163,7 @@ export default {
- +
diff --git a/webroot/js/page/UserManager.js b/webroot/js/page/UserManager.js index 2c14fb8..cbc874d 100644 --- a/webroot/js/page/UserManager.js +++ b/webroot/js/page/UserManager.js @@ -13,32 +13,31 @@ export default { Pagination, GroupsTable, Members, - Autocomplete + Autocomplete, + Loader + }, + data() { + return { + loading: false, + result: [], + } }, inject: ['api', 'txt'], methods: { - showSubscribers(group) { - this.$refs.members.show(group); - }, - async findUserMemberships(user) { + async findManagedUsers(user) { const { identifier: id, label } = user; this.loading = true; - const { displayExtension, name } = this.group; - const formData = new FormData(); - formData.append("userId", id); - formData.append("group", name); - const resp = await fetch(`${this.api.add}?group=${name}&userId=${id}`, { - method: "POST", + const resp = await fetch(`${this.api.managing}?memberid=${id}`, { headers: { "Accept": "application/json", }, - body: formData + method: "GET" }); if (resp.ok) { - await this.loadGroupSubscribers(this.group); - generateFlash(`${label} ${this.txt.findUserMembershipsSuccess} ${(displayExtension)}`, 'success'); + this.result = await resp.json(); + console.log('result', this.result) + generateFlash(`${id} has ${this.result.length} ${this.txt.memberships}`, 'success'); } else { - generateFlash(`${this.txt.findUserMembershipsError}`, 'error'); let errorResponse = await resp.json(); generateFlash(`${errorResponse.message}`, 'error'); } @@ -47,24 +46,11 @@ export default { } }, template: /*html*/` - - - - - - - - - - - - - - - - + ` } \ No newline at end of file