Skip to content

Feb2024 #23

Merged
merged 75 commits into from Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
69c66ad
Refactoring backend.Naming conventions.CAKEPHPism and COmanage confor…
Ioannis Feb 15, 2024
d4c2cf8
Add authorized users group configuration.Improved/Simplified existing…
Ioannis Feb 16, 2024
9d82e9d
Further simplify the code. Added test requests.
Ioannis Feb 19, 2024
6233090
Move debug message in HttpWrapper
Ioannis Feb 19, 2024
88ba44e
Move json content header to constructor
Ioannis Feb 19, 2024
aa6e2df
move service url in GrouperHTTPWrapper
Ioannis Feb 19, 2024
0da100c
add the READMD.md file
Ioannis Feb 20, 2024
07e6ef7
Merge pull request #8 from Ioannis/spring_semester2024
aaschenbrener Feb 20, 2024
9ab198d
Remove GrouperWidget folder.Add missing glid and coid url named param…
Ioannis Feb 21, 2024
8505de5
Merge pull request #9 from Ioannis/Remove_duplicates_fix_missing_glid…
aaschenbrener Feb 21, 2024
a953284
Improve code readability. Remove non-intuitive code.
Ioannis Feb 22, 2024
ddfccf7
Rename and cleanup GrouperAPI methods
Ioannis Feb 22, 2024
ee6bc31
Add people picker spinner. Fix people picker add button alignment.
Ioannis Feb 22, 2024
a411bfc
use loader component. Add small margin amgong text and icon in a button.
Ioannis Feb 23, 2024
7459512
Clean up autocomplete module.Fixed data object bindings on select.
Ioannis Feb 23, 2024
a522187
Merge pull request #10 from Ioannis/Improve_people_picker
aaschenbrener Feb 23, 2024
758b2f5
Simplify add/remove from group backend
Ioannis Feb 28, 2024
076c938
simplify add/remove to/from group
Ioannis Feb 28, 2024
a6e11e6
logs comment out
Ioannis Feb 28, 2024
e3b6617
refactor getGrouperUserMemberships
Ioannis Feb 28, 2024
938e45b
Refactor get groupSubscribers
Ioannis Feb 28, 2024
b33433d
Merge pull request #11 from Ioannis/Code_cleanup
aaschenbrener Feb 28, 2024
e0092a6
Cleanup. Add comments to API methods.
Ioannis Feb 29, 2024
79e7904
Merge pull request #12 from Ioannis/Clean_up_add_comments
aaschenbrener Feb 29, 2024
974cebd
Remove obsolete code
Ioannis Mar 1, 2024
73cb251
restore security for actions
Ioannis Mar 1, 2024
27396bf
Merge pull request #13 from Ioannis/Remove_obsolete_code
aaschenbrener Mar 1, 2024
93ee86f
revert security unlocked actions
Ioannis Mar 5, 2024
70b6458
Merge pull request #14 from Ioannis/Revert_security_unlocked_actions
aaschenbrener Mar 5, 2024
f2774dd
Fix buggy optin list of groups
Ioannis Mar 6, 2024
636c3ba
Merge pull request #15 from Ioannis/Fix_empty_groupoptins_list
aaschenbrener Mar 6, 2024
70d4480
Add the Users i manage tab
Ioannis Mar 6, 2024
a3da55e
Make autocomplete component fully dynamic
Ioannis Mar 7, 2024
a7e076f
add people picker element
Ioannis Mar 7, 2024
d2fe650
add user manager view
Ioannis Mar 7, 2024
83727b0
Backend work, frontend loader and disable action button.
Ioannis Mar 7, 2024
cf20425
autocomplete people picker improvements
Ioannis Mar 8, 2024
0f2c895
autocomplete improvements.Other improvements and minor fixes.
Ioannis Mar 8, 2024
6af044c
pass userManagerId to getUserGroups API Call
Ioannis Mar 13, 2024
060b668
Present data in table.Add and test action.
Ioannis Mar 14, 2024
feddde9
Merge pull request #16 from Ioannis/Users_i_manage
aaschenbrener Mar 18, 2024
29196ea
Initiate searching for groups as soon as i select the user from the d…
Ioannis Mar 18, 2024
9bbd03e
Merge pull request #17 from Ioannis/Fetch_members_on_user_selection
aaschenbrener Mar 18, 2024
11d4582
Refactoring. Add GrouperLiteActASPerson model
Ioannis Apr 1, 2024
a0c059a
remove base-css element
Ioannis Apr 1, 2024
700f48c
Code improvements
Ioannis Apr 1, 2024
2911ca0
ui improvements
Ioannis Apr 1, 2024
9b4f884
add action sidebar
Ioannis Apr 1, 2024
2a69807
added peoplepicker module
Ioannis Apr 2, 2024
6c86851
action act as ui improvements
Ioannis Apr 2, 2024
23ca0d4
render action sidebar if the user belongs to the appropriate group
Ioannis Apr 2, 2024
3d6efd2
implemented ActAsPerson add action
Ioannis Apr 2, 2024
86c4691
Add,Delete act as user
Ioannis Apr 3, 2024
9c121b4
Fix autocomplete unique id
Ioannis Apr 3, 2024
864a2aa
Fix autocomplete unique id
Ioannis Apr 3, 2024
8bd174c
Move code at sidebar.ctp file
Ioannis Apr 3, 2024
b0042c7
Add focus on people autocomplete on collapse open
Ioannis Apr 3, 2024
8e98e52
Do not allow act as duplicates in database
Ioannis Apr 3, 2024
29082fe
show spinner on act as user add.
Ioannis Apr 3, 2024
d4aa2fc
moved delete and act as use preview in a vue app.
Ioannis Apr 4, 2024
0dd1e70
Upsert and delete on ActAsPerson Model
Ioannis Apr 4, 2024
865bbb3
Apply act as user
Ioannis Apr 4, 2024
4e0b92e
check if the co_person_id has a value before executing the query.
Ioannis Apr 5, 2024
bf27f1e
pass all locales in the dom
Ioannis Apr 5, 2024
acf611e
Merge pull request #18 from Ioannis/act_as_feature
aaschenbrener Apr 5, 2024
61f2552
Fully impersonate a user
Ioannis Apr 5, 2024
eaf2117
Merge pull request #19 from Ioannis/fully_impersonate_user
aaschenbrener Apr 5, 2024
166bca7
User the self userId when calculating the permissions
Ioannis Apr 6, 2024
30f2806
Disable buttons on ActAs mode
Ioannis Apr 6, 2024
2a37569
revoke permission on edit actions when on actAs mode
Ioannis Apr 6, 2024
2bd1a43
Merge pull request #20 from Ioannis/Fixes
aaschenbrener Apr 8, 2024
fbf35bf
pass the correct parameters to getManagedUsers
Ioannis Apr 8, 2024
460b331
Merge pull request #21 from Ioannis/Fix_users_i_manage_params
aaschenbrener Apr 8, 2024
ec77b6c
Return a non-associative array
Ioannis Apr 9, 2024
c80d2c5
Merge pull request #22 from Ioannis/Fix_error_in_serialize
aaschenbrener Apr 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Empty file removed Config/Schema/empty
Empty file.
31 changes: 29 additions & 2 deletions Config/Schema/schema.xml
Expand Up @@ -25,7 +25,7 @@
must be specified in raw SQL, which needs the prefixed table name.
-->
<schema version="0.3">
<table name="co_grouper_lites">
<table name="co_grouper_lite_widgets">
<field name="id" type="I">
<key />
<autoincrement />
Expand All @@ -34,8 +34,10 @@
<constraint>REFERENCES cm_co_dashboard_widgets(id)</constraint>
</field>
<field name="conn_url" type="C" size="256" />
<field name="identifier_type" type="C" size="32" />
<field name="conn_ver" type="C" size="256" />
<field name="grouper_url" type="C" size="256" />
<field name="act_as_grp_name" type="C" size="512" />
<field name="conn_user" type="C" size="64" />
<field name="conn_pass" type="C" size="64" />
<field name="adhoc_heading" type="C" size="64" />
Expand All @@ -44,9 +46,34 @@
<field name="created" type="T" />
<field name="modified" type="T" />

<index name="co_grouper_lites_i1">
<index name="co_grouper_lite_widgets_i1">
<col>co_dashboard_widget_id</col>
<unique />
</index>
</table>

<table name="act_as_people">
<field name="id" type="I">
<key />
<autoincrement />
</field>
<field name="co_grouper_lite_widget_id" type="I">
<constraint>REFERENCES cm_co_grouper_lite_widgets(id)</constraint>
</field>
<field name="act_as_co_person_id" type="I">
<constraint>REFERENCES cm_co_people(id)</constraint>
</field>
<field name="co_person_id" type="I">
<constraint>REFERENCES cm_co_people(id)</constraint>
</field>
<field name="created" type="T" />
<field name="modified" type="T" />

<index name="grouper_lite_act_as_people_i1">
<col>co_grouper_lite_widget_id</col>
</index>
<index name="grouper_lite_act_as_people_i2">
<col>co_person_id</col>
</index>
</table>
</schema>
292 changes: 292 additions & 0 deletions Controller/ActAsPeopleController.php
@@ -0,0 +1,292 @@
<?php

App::uses('Validator', 'Vendor/cakephp/Validation');
App::uses('CoGrouperLite', 'GrouperLiteWidget.Model/');
App::uses('ActAsPerson', 'GrouperLiteWidget.Model/');
App::uses('GrouperGroup', 'GrouperLiteWidget.Model/');


App::uses('Identifier', 'Model');

class ActAsPeopleController extends GrouperLiteWidgetAppController
{
public $helpers = ['Html', 'Form', 'Flash'];

// Dynamic properties are deprecated, so we will define the property here
private $userId;

public $requires_person = true;

public $uses = [
'GrouperLiteWidget.ActAsPerson',
'GrouperLiteWidget.CoGrouperLiteWidget',
'GrouperLiteWidget.GrouperGroup',
'Identifier',
'CoPerson'
];

public $components = [
'Flash',
'RequestHandler',
'Security' => [
'validatePost' => false,
'csrfUseOnce' => false
]
];


public $name = 'ActAsPeople';

/**
* Overrides parent beforeFilter to verify that Session contains the correct API settings.
*
* @return void
*/
public function beforeFilter()
{
parent::beforeFilter();

if(empty($this->request->params['named']['glid'])) {
throw new InvalidArgumentException(_txt('er.grouperlite.glid'),
HttpStatusCodesEnum::HTTP_BAD_REQUEST);
}
$this->response->disableCache();
$this->RequestHandler->addInputType('json', ['json_decode', true]);

$this->Security->unlockedActions = [
'delete',
'upsert',
];

// Get the config
$args = array();
$args['conditions']['CoGrouperLiteWidget.id'] = $this->request->params['named']['glid'];
$args['contain'] = false;
$cfg = $this->CoGrouperLiteWidget->find('first', $args);
// Set the config so that everybody can access it
$this->CoGrouperLiteWidget->setConfig($cfg);
}

/**
* Update or Insert an ActAs user
*
* @since COmanage Registry v4.4.0
*/

public function upsert(): void
{
$this->request->allowMethod('ajax');
$this->layout = 'ajax';

if(!$this->request->is('restful')
&& !$this->request->is('ajax')) {
throw new RuntimeException('HTTP Method Not Allowed', HttpStatusCodesEnum::HTTP_METHOD_NOT_ALLOWED);
}

$data = $this->request->data;

$fullName = $data['fullname'];
unset($data['fullname']);

$args = [];
$args['conditions']['ActAsPerson.co_person_id'] = $data['co_person_id'];
if(!empty($this->request->named['actrecordId'])) {
$args['conditions']['ActAsPerson.id'] = $this->request->named['actrecordId'];
}
$args['conditions']['ActAsPerson.act_as_co_person_id'] = $data['act_as_co_person_id'];
$args['contain'] = false;
if(!empty($this->ActAsPerson->find('first', $args))) {
$this->Api->restResultHeader(HttpStatusCodesEnum::HTTP_CONFLICT, 'Already Exists');
$error = ErrorsEnum::Conflict;
$this->set(compact('error'));
$this->set('_serialize', 'error');
return;
}

// We will update
if(!empty($this->request->named['actrecordId'])) {
$this->ActAsPerson->id = $this->request->named['actrecordId'];
}

try {
$ret = $this->ActAsPerson->save($data);
}
catch(Exception $e) {
$err = filter_var($e->getMessage(),FILTER_SANITIZE_SPECIAL_CHARS);
$this->Flash->set($err, ['key' => 'error']);
}

if($ret) {
$this->Api->restResultHeader(HttpStatusCodesEnum::HTTP_CREATED, 'Added');
// I am registering a flash message. It will render after the frontend triggers a reload
$this->Flash->set("Act As {$fullName} Enabled" , ['key' => 'success']);

$args = [];
$args['conditions']['ActAsPerson.id'] = $this->ActAsPerson->id;
$args['contain'] = false;
$data = $this->ActAsPerson->find('first', $args);

$resp = [
'ActAsPerson' => $data['ActAsPerson']
];
$this->set(compact('resp'));
$this->set('_serialize', 'resp');
} else {
$fs = $this->ActAsPerson->invalidFields();

if(!empty($fs)) {
$this->Api->restResultHeader(HttpStatusCodesEnum::HTTP_BAD_REQUEST, 'Invalid Fields');
$this->Flash->set('Invalid Fields', ['key' => 'error']);
$this->set(compact('fs'));
$this->set('_serialize', 'fs');
} elseif ($e
&& isset(_txt('en.http.status.codes')[$e->getCode()]) ) {
$this->Api->restResultHeader($e->getCode(), _txt('en.http.status.codes')[$e->getCode()]);
if(!empty($e->getMessage())) {
$vv_error = $e->getMessage();
$this->set(compact('vv_error'));
$this->set('_serialize', 'vv_error');
$this->Flash->set($e->getMessage(), ['key' => 'error']);
}
} else {
$this->Api->restResultHeader(HttpStatusCodesEnum::HTTP_INTERNAL_SERVER_ERROR, 'Other Error');
$error = ErrorsEnum::Error;
$this->set(compact('error'));
$this->set('_serialize', 'error');
}
}
}

/**
* Handle an Act As Person Delete request.
*
* @since COmanage Registry v4.4.0
*/

public function delete():void
{
$this->request->allowMethod('ajax');
$this->layout = 'ajax';

if(!$this->request->is('delete')
&& !$this->request->is('ajax')
) {
throw new RuntimeException('HTTP Method Not Allowed', HttpStatusCodesEnum::HTTP_METHOD_NOT_ALLOWED);
}

if(empty($this->request->named['copersonid'])
|| empty($this->request->named['act_as_copersonid'])) {
$this->log(__METHOD__ . '::message: Named Parameter missing', LOG_ERROR);
throw new BadRequestException('Named Parameter missing');
}

try {
$conditions = [
'ActAsPerson.co_person_id' => $this->request->named['copersonid'],
'ActAsPerson.act_as_co_person_id' => $this->request->named['act_as_copersonid']
];

$ret = $this->ActAsPerson->deleteAll($conditions, true, true);
} catch(Exception $e) {
$error = filter_var($e->getMessage(),FILTER_SANITIZE_SPECIAL_CHARS);
$this->Api->restResultHeader(HttpStatusCodesEnum::HTTP_INTERNAL_SERVER_ERROR, 'Other Error');
$this->set(compact('error'));
$this->set('_serialize', 'error');
return;
}

// Set flash message
if(!$ret) {
$error = ErrorsEnum::NotDeleted;
$this->Api->restResultHeader(HttpStatusCodesEnum::HTTP_BAD_REQUEST, 'Bad Request');
$this->set(compact('error'));
$this->set('_serialize', 'error');
return;
}

// We will register a Flash message here. The frontend will reload and it will be rendered
$this->Flash->set('Act As Disabled', ['key' => 'success']);

// We do not redirect but we pass data back to the frontend because we
// want to keep the view structure as simple as possible. If we redirect we will
// have to add more JSON view infrastructure. We will let the frontend
// handle the redirect
$this->Api->restResultHeader(HttpStatusCodesEnum::HTTP_OK, 'Success');
$success = ['status' => 'Success', 'message' => 'Succeeded'];
$this->set(compact('success'));
$this->set('_serialize', 'success');
}


/**
* NOTE: All permissions will be done on the Grouper side. All Authenticated users will be able to
* use this plugin for self-admin of groups.
*
* Authorization for this Controller, called by Auth component
* - precondition: Session.Auth holds data used for authz decisions
* - postcondition: $permissions set with calculated permissions
*
* @return array|bool Permissions
* @since COmanage Registry v4.4.0
*/
public function isAuthorized(): array|bool
{
$roles = $this->Role->calculateCMRoles();
$this->set('roles', $roles);

$pids = $this->parsePersonID($this->request->data);

$cfg = $this->CoGrouperLiteWidget->getConfig();
// Find the identifier
$args = array();
$args['conditions']['Identifier.type'] = $cfg['CoGrouperLiteWidget']['identifier_type'];
$args['conditions']['Identifier.status'] = SuspendableStatusEnum::Active;
$args['conditions']['Identifier.co_person_id'] = !empty($roles['copersonid']) ? $roles['copersonid'] : $pids['copersonid'];
$args['contain'] = false;

$identifiers = $this->Identifier->find('first', $args);
if(!empty($identifiers)
&& is_array($identifiers)
&& isset($identifiers['Identifier']['identifier'])
) {
$this->setUserId($identifiers['Identifier']['identifier']);
}

// Find if the user belongs to Group
$eligibleGroup = $cfg['CoGrouperLiteWidget']['act_as_grp_name'];
$isActAsEligibilityGroupmember = false;

if(!empty($eligibleGroup)) {
$isActAsEligibilityGroupmember = $this->GrouperGroup
->isGroupMember($this->getUserId(), $eligibleGroup, $cfg);
}

// Determine what operations this user can perform
// Construct the permission set for this user, which will also be passed to the view.
$p = [];

$p['delete'] = $isActAsEligibilityGroupmember;
$p['upsert'] = $isActAsEligibilityGroupmember;

$this->set('permissions', $p);

return ($p[$this->action]);
}

/**
* @return null
*/
public function getUserId()
{
return $this->userId;
}


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