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: "= _txt('pl.grouperlite.message.flash.remove-subscriber-success') ?>", getSubscriberError: "= _txt('pl.grouperlite.message.flash.group-detail-members-failed') ?>", peoplePickerPlaceHolder: "= _txt('op.grm.add.placeholder') ?>", + memberships: "= _txt('pl.grouperlite.action.memberships') ?>", noaccess: "= _txt('pl.grouperlite.members.noaccess') ?>", empty: "= _txt('pl.grouperlite.members.empty') ?>", join: "= _txt('pl.grouperlite.action.join') ?>", @@ -129,6 +130,7 @@ add: "= $this->webroot ?>grouper_lite_widget/grouper_groups/addSubscriber/co:= $vv_coid ?>/glid:= $vv_config['CoGrouperLiteWidget']['id'] ?>", group: "= $this->webroot ?>grouper_lite_widget/grouper_groups/groupSubscribers/co:= $vv_coid ?>/glid:= $vv_config['CoGrouperLiteWidget']['id'] ?>", memberships: "= $this->webroot ?>grouper_lite_widget/grouper_groups/groupmemberapi/co:= $vv_coid ?>/glid:= $vv_config['CoGrouperLiteWidget']['id'] ?>", + managing: "= $this->webroot ?>grouper_lite_widget/grouper_groups/usermanagerapi/co:= $vv_coid ?>/glid:= $vv_config['CoGrouperLiteWidget']['id'] ?>", optin: "= $this->webroot ?>grouper_lite_widget/grouper_groups/groupoptinapi/co:= $vv_coid ?>/glid:= $vv_config['CoGrouperLiteWidget']['id'] ?>", owner: "= $this->webroot ?>grouper_lite_widget/grouper_groups/groupownerapi/co:= $vv_coid ?>/glid:= $vv_config['CoGrouperLiteWidget']['id'] ?>", }, 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"> {{ this.icon }} {{ 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 {