Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #16 from Ioannis/Users_i_manage
Users i manage
  • Loading branch information
aaschenbrener committed Mar 18, 2024
2 parents 636c3ba + 060b668 commit feddde9
Showing 15 changed files with 401 additions and 77 deletions.
114 changes: 86 additions & 28 deletions 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',
@@ -67,8 +67,8 @@ public function addSubscriber(): void
$this->layout = null;
$this->autoRender = false;

$groupName = urldecode($this->request->query['group']);
$addUserId = urldecode($this->request->query['userId']);
$groupName = $this->request->data['group'];
$addUserId = $this->request->data['userId'];

// Need to see if coming from AdHoc or from a WG (Working Group)
$groupNameFormatted = strpos($groupName, ':') === false ? 'ref:incommon-collab:' . $groupName . ':users'
@@ -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,31 +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['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);

@@ -596,6 +605,55 @@ public function restResponse(int $status,
$this->response->send();
}

/**
* @param null $userId
*/
private function setUserId($userId): void
{
$this->userId = $userId;
}

/**
* UserManager vue route for rendering
*
* @return void
*/
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
*
3 changes: 2 additions & 1 deletion 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',
@@ -163,7 +164,7 @@
'pl.grouperlite.form.template.value.positive' => 'Yes',
'pl.grouperlite.form.template.value.negative' => 'No',

'pl.grouperlite.search.tags.text' => 'Search',
'pl.grouperlite.title.search' => 'Search',

'pl.grouperlite.pagination.counter' => 'Viewing {:start}-{:end} of {:count}',
'pl.grouperlite.attributes.zero-state' => 'No Attributes Associated to this Group.',
61 changes: 59 additions & 2 deletions Model/GrouperGroup.php
@@ -217,8 +217,10 @@ public function findForPicker(int $coId, string $mode, ?string $term): array
$idArr = $p['Identifier'];
$emailArr = $p['EmailAddress'];
$email = '';
$email_short = '';
$emailLabel = '';
$id = '';
$id_short = '';
$idLabel = '';

// Iterate over the email array
@@ -228,6 +230,7 @@ public function findForPicker(int $coId, string $mode, ?string $term): array
foreach($emailArr as $e) {
if($e['type'] == $pickerEmailType) {
$email = $e['mail'];
$email_short = mb_strimwidth($e['mail'], 0, 30, '...');
break;
}
}
@@ -243,7 +246,8 @@ public function findForPicker(int $coId, string $mode, ?string $term): array
}
foreach($idArr as $i) {
if($i['type'] == $pickerIdentifierType) {
$id = mb_strimwidth($i['identifier'], 0, 30, '...');
$id_short = mb_strimwidth($i['identifier'], 0, 30, '...');
$id = $i['identifier'];
break;
}
}
@@ -255,9 +259,13 @@ public function findForPicker(int $coId, string $mode, ?string $term): array
'value' => $p['CoPerson']['id'],
'label' => $label,
'email' => $email,
'emailShort' => $email_short,
'emailLabel' => $emailLabel,
'emailType' => $pickerEmailType,
'identifier' => $id,
'identifierLabel' => $idLabel
'identifierShort' => $id_short,
'identifierLabel' => $idLabel,
'identifierType' => $pickerIdentifierType
);
}
}
@@ -318,6 +326,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 $managerId
* @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($managerId, $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.
*
12 changes: 12 additions & 0 deletions View/CoGrouperLiteWidgets/display.ctp
@@ -91,6 +91,18 @@ $idsuffix = rand();
'glid' => $glid
)
); ?>"
},
{
label: "<?php echo _txt('pl.grouperlite.nav.users-presided'); ?>",
url: "<?php print $this->Html->url(
array(
'plugin' => $pl,
'controller' => 'grouper_groups',
'action' => 'usermanager',
'co' => $coid,
'glid' => $glid
)
); ?>"
}
]
}
1 change: 1 addition & 0 deletions View/GrouperGroups/base.ctp
@@ -16,6 +16,7 @@ echo $this->Html->meta(
array('inline' => false)
);

print $this->Html->script('GrouperLiteWidget.autocomplete.grouperplugin') . PHP_EOL;
print $this->element('GrouperLiteWidget.base-styles');
print $this->Html->css('GrouperLiteWidget.co-grouper-plugin') . PHP_EOL;

9 changes: 8 additions & 1 deletion View/GrouperGroups/index.ctp
@@ -14,6 +14,7 @@
import GroupMember from '<?= $this->webroot ?>grouper_lite_widget/js/page/GroupMember.js<?= $suffix ?>';
import GroupOptin from '<?= $this->webroot ?>grouper_lite_widget/js/page/GroupOptin.js<?= $suffix ?>';
import GroupOwner from '<?= $this->webroot ?>grouper_lite_widget/js/page/GroupOwner.js<?= $suffix ?>';
import UserManager from '<?= $this->webroot ?>grouper_lite_widget/js/page/UserManager.js<?= $suffix ?>';

<?php
$baseUrl = $vv_config['CoGrouperLiteWidget']['grouper_url'];
@@ -40,6 +41,10 @@
{
path: '/groupowner/co:co/glid:glid',
component: GroupOwner
},
{
path: '/usermanager/co:co/glid:glid',
component: UserManager
}
]
},
@@ -87,8 +92,8 @@
removeSubscriberError: "<?= _txt('pl.grouperlite.message.flash.remove-subscriber-failed') ?>",
removeSubscriberSuccess: "<?= _txt('pl.grouperlite.message.flash.remove-subscriber-success') ?>",
getSubscriberError: "<?= _txt('pl.grouperlite.message.flash.group-detail-members-failed') ?>",
searchTag: "<?= _txt('pl.grouperlite.search.tags.text') ?>",
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') ?>",
@@ -102,6 +107,7 @@
memberships: "<?= _txt('pl.grouperlite.nav.memberships') ?>",
optin: "<?= _txt('pl.grouperlite.nav.groups-can-join') ?>",
owner: "<?= _txt('pl.grouperlite.nav.groups-presided') ?>",
manager: "<?= _txt('pl.grouperlite.nav.users-presided') ?>",
},
columns: <?php print_r(json_encode(array(
'name' => _txt('pl.grouperlite.table.name'),
@@ -124,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'] ?>",
},
8 changes: 8 additions & 0 deletions webroot/css/co-grouper-plugin.css
@@ -327,4 +327,12 @@ a.list-group-item-action:hover .fa {
right: 38px;
bottom: 10px;
margin-right: -26px;
}

.grouper_groups #co-loading span,
.grouper_groups #co-loading-redirect span,
.grouper_groups .co-loading-mini span {
animation: 1.2s linear infinite both loading;
background-color: var(--teal);
display: inline-block;
}

0 comments on commit feddde9

Please sign in to comment.