Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #18 from Ioannis/act_as_feature
act_as_feature
aaschenbrener committed Apr 5, 2024
2 parents 9bbd03e + bf27f1e commit acf611e
Showing 22 changed files with 1,733 additions and 739 deletions.
25 changes: 25 additions & 0 deletions Config/Schema/schema.xml
@@ -51,4 +51,29 @@
<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;
}
}
2 changes: 1 addition & 1 deletion Controller/CoGrouperLiteWidgetsController.php
@@ -45,7 +45,7 @@ public function display($id) {
$cfg = $this->CoGrouperLiteWidget->getConfig();

$this->set('pl_grouperlite_index_url', Router::url([
'plugin' => "grouper_lite",
'plugin' => 'grouper_lite',
'controller' => 'grouper_groups',
'action' => 'index',
'co' => $this->cur_co['Co']['id'],

0 comments on commit acf611e

Please sign in to comment.