Skip to content

CFM-194_Application_Preferences #268

Merged
merged 7 commits into from Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
16 changes: 15 additions & 1 deletion app/config/bootstrap.php
Expand Up @@ -241,4 +241,18 @@
/*
* Define some constants
*/
define('DEF_GLOBAL_SEARCH_LIMIT', 500);
define("DEF_COMANAGE_CO_NAME", "COmanage");
// Default invitation validity, in minutes (used in various places, should probably be moved elsewhere)
define("DEF_INV_VALIDITY", 1440);

// Default window for reprovisioning on group validity change
define("DEF_GROUP_SYNC_WINDOW", 1440);

// Default window for Garbage Collection
define("DEF_GARBAGE_COLLECT_INTERVAL", 1440);

// Default global search limit
define("DEF_GLOBAL_SEARCH_LIMIT", 500);

// Default Search block limit
define("DEF_SEARCH_LIMIT", 25);
10 changes: 6 additions & 4 deletions app/config/schema/schema.json
Expand Up @@ -874,14 +874,16 @@
"application_states": {
"columns": {
"id": {},
"co_id": {},
"person_id": {},
"tag": { "type": "string", "size": 128 },
"username": { "type": "string", "size": 512 },
"tag": { "type": "string", "size": 128 },
"value": { "type": "string", "size": 256 }
},
"indexes": {
"application_states_i1": { "columns": [ "person_id" ] }
},
"changelog": false
"application_states_i1": { "columns": [ "co_id" ] },
"application_states_i2": { "columns": [ "person_id" ] }
}
}
},

Expand Down
9 changes: 6 additions & 3 deletions app/resources/locales/en_US/error.po
Expand Up @@ -229,9 +229,6 @@ msgstr "Provided value is not an integer"
msgid "Jobs.plugin.parameter.invalid"
msgstr "Invalid parameter"

msgid "Jobs.plugin.parameter.required"
msgstr "Required parameter not provided"

msgid "Jobs.plugin.parameter.select"
msgstr "Provided value is not a valid choice"

Expand Down Expand Up @@ -289,6 +286,9 @@ msgstr "Notification status {0} is not a valid resolution"
msgid "notprov"
msgstr "{0} not provided"

msgid "notsupported"
msgstr "Not supported"

msgid "ordr.unique"
msgstr "Each {0} must have a unique order"

Expand All @@ -298,6 +298,9 @@ msgstr "Page number may not be larger than {0}"
msgid "pagenum.nan"
msgstr "Page number must be an integer"

msgid "Parameter.required"
msgstr "Required parameter '{0}' not provided"

msgid "perm"
msgstr "Permission Denied"

Expand Down
3 changes: 3 additions & 0 deletions app/resources/locales/en_US/information.po
Expand Up @@ -135,6 +135,9 @@ msgstr "This plugin requires no configuration."
msgid "plugin.inactive"
msgstr "Inactive"

msgid "state.info"
msgstr "{0} successfully {1} to {2}"

msgid "record"
msgstr "Record"

Expand Down
21 changes: 18 additions & 3 deletions app/src/Controller/ApiV2Controller.php
Expand Up @@ -29,6 +29,7 @@

namespace App\Controller;

use Cake\Controller\Controller;
use InvalidArgumentException;
use Cake\Chronos\Chronos;
use Cake\Http\Exception\BadRequestException;
Expand All @@ -47,7 +48,6 @@ class ApiV2Controller extends AppController {
* Perform Cake Controller initialization.
*
* @since COmanage Registry v5.0.0
* @param array $config Configuration options passed to constructor
*/

public function initialize(): void {
Expand Down Expand Up @@ -100,7 +100,7 @@ public function add() {
$results[] = ['id' => $obj->id];

// Trigger provisioning, letting errors bubble up (AR-GMR-5)
if(method_exists($this->modelsName, "requestProvisioning")) {
if(method_exists($this->$modelsName, "requestProvisioning")) {
$this->llog('rule', "AR-GMR-5 Requesting provisioning for $modelsName " . $obj->id);
$table->requestProvisioning(id: $obj->id, context: ProvisioningContextEnum::Automatic);
}
Expand All @@ -121,7 +121,22 @@ public function add() {
// Let the view render
$this->render('/Standard/api/v2/json/add-edit');
}


/**
* beforeFilter callback.
*
* @param \Cake\Event\EventInterface $event Event.
* @return \Cake\Http\Response|null|void
*/
public function beforeFilter(\Cake\Event\EventInterface $event)
{
parent::beforeFilter($event);

if ($this->request->is('ajax') && $this->request->is(['post', 'put'])) {
$this->FormProtection->setConfig('validate', false);
}
}

/**
* Callback run prior to the request rendering.
*
Expand Down
40 changes: 36 additions & 4 deletions app/src/Controller/AppController.php
Expand Up @@ -99,7 +99,7 @@ public function initialize(): void {
*
* In general, we don't need these protections for transactional API calls.
*/
$this->loadComponent('Security');
$this->loadComponent('FormProtection');

// CSRF Protection is enabled via in Middleware via Application.php.
}
Expand Down Expand Up @@ -141,8 +141,15 @@ public function beforeFilter(\Cake\Event\EventInterface $event) {
// We need to populate this in beforeFilter (rather than beforeRender)
// so it's available to CosController::select
$this->populateAvailableCos();

// Get Person ID
if($this->RegistryAuth->getAuthenticatedUser() !== null && $this->getCOID() !== null) {
$this->set('vv_person_id', $this->RegistryAuth->getPersonId($this->getCOID()));
}
}


$this->getAppPrefs();

return parent::beforeFilter($event);
}

Expand All @@ -154,7 +161,6 @@ public function beforeFilter(\Cake\Event\EventInterface $event) {
*/

public function beforeRender(\Cake\Event\EventInterface $event) {
// $this->name = Models
$modelsName = $this->name;

// Views can also inspect the request object to determine the current
Expand All @@ -169,7 +175,7 @@ public function beforeRender(\Cake\Event\EventInterface $event) {
// Provide the user's application roles to the views.
$this->set('vv_user_roles', $this->RegistryAuth->getApplicationUserRoles($this->getCOID()));
}

return parent::beforeRender($event);
}

Expand Down Expand Up @@ -368,6 +374,32 @@ protected function primaryLinkLookup(): void
}
}

/**
* Get a user's Application State
* - postcondition: Application Preferences variable set
* @since COmanage Registry v5.1.0
*/
protected function getAppPrefs() {
$request = $this->getRequest();
$session = $request->getSession();

$username = $session->read('Auth.external.user');
$appPrefs = null;

// Get preferences if we have an Auth.User.co_person_id
if(!empty($username)) {
$ApplicationStates = $this->fetchTable('ApplicationStates');
$appPrefs = $ApplicationStates->retrieveAll(
username: $username,
// If we have not selected a CO yet, there will be no co_id
coid: $this->getCOID(),
personid: $this->viewBuilder()->getVar('vv_person_id')
);
}

$this->set('vv_app_prefs', $appPrefs);
}

/**
* Collect information about the Standard Object's Primary Link, if set.
* The $vv_primary_link view variable is also set.
Expand Down
14 changes: 8 additions & 6 deletions app/src/Controller/Component/RegistryAuthComponent.php
Expand Up @@ -597,11 +597,11 @@ public function getAuthenticatedUser(): ?string {
}

/**
* Obtain permissions suitable for menu rendering, specifically by
* Get permissions suitable for menu rendering, specifically by
* templates/element/menuMain.php.
*
* @since COmanage Registry v5.0.0
* @param int $coId Current CO ID, if known
* @param int|null $coId Current CO ID, if known
* @return array Array of permissions
*/

Expand Down Expand Up @@ -633,6 +633,7 @@ public function getMenuPermissions(?int $coId): array {
* @since COmanage Registry v5.0.0
* @param int $coId CO ID
* @throws RuntimeException
* @throws RecordNotFoundException
*/

public function getPersonID(int $coId): ?int {
Expand All @@ -649,10 +650,11 @@ public function getPersonID(int $coId): ?int {
$Identifiers = TableRegistry::getTableLocator()->get('Identifiers');

try {
return $Identifiers->lookupPersonByLogin($coId, $this->authenticatedUser);
}
catch(Cake\Datasource\Exception\RecordNotFoundException $e) {
return null;
$personId = (int)$Identifiers->lookupPersonByLogin($coId, $this->authenticatedUser);
} catch(RecordNotFoundException) {
$personId = null;
} finally {
return $personId;
}
}

Expand Down
15 changes: 11 additions & 4 deletions app/src/Controller/StandardController.php
Expand Up @@ -29,17 +29,21 @@

namespace App\Controller;

use App\Lib\Enum\ApplicationStateEnum;
use App\Lib\Traits\ApplicationStatesTrait;
use App\Lib\Traits\IndexQueryTrait;
use Cake\Database\Expression\QueryExpression;
use Cake\ORM\TableRegistry;
use InvalidArgumentException;
use \Cake\Http\Exception\BadRequestException;
use Cake\Utility\Inflector;
use InvalidArgumentException;
use \App\Lib\Enum\ProvisioningContextEnum;
use \App\Lib\Enum\SuspendableStatusEnum;
use \App\Lib\Util\{StringUtilities, FunctionUtilities};
use \Cake\Http\Exception\BadRequestException;

class StandardController extends AppController {
use \App\Lib\Traits\IndexQueryTrait;
use IndexQueryTrait;
use ApplicationStatesTrait;

// Pagination defaults should be set in each controller
public $pagination = [];
Expand Down Expand Up @@ -628,7 +632,10 @@ public function index() {
}

// Fetch the data and paginate
$resultSet = $this->paginate($query);
$paginationLimit = $this->getValue(ApplicationStateEnum::PaginationLimit, DEF_SEARCH_LIMIT);
$resultSet = $this->paginate($query, [
'limit' => (int)$paginationLimit
]);

// Pass vars to the View
$this->set($tableName, $resultSet);
Expand Down
38 changes: 38 additions & 0 deletions app/src/Lib/Enum/ApplicationStateEnum.php
@@ -0,0 +1,38 @@
<?php
/**
* COmanage Registry Applications State Enum
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* UCAID licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @link https://www.internet2.edu/comanage COmanage Project
* @package registry
* @since COmanage Registry v5.1.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/

declare(strict_types = 1);

namespace App\Lib\Enum;

class ApplicationStateEnum extends StandardEnum {
const UiDrawerState = 'UD';
const SearchBlockOptions = 'SO';
const PaginationLimit = 'PL';
const ProfileDarkMode = 'PM';
const ProfileDensity = 'PD';
}
36 changes: 36 additions & 0 deletions app/src/Lib/Enum/DarkModesEnum.php
@@ -0,0 +1,36 @@
<?php
/**
* COmanage Registry Dark Modes Enum
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* UCAID licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @link https://www.internet2.edu/comanage COmanage Project
* @package registry
* @since COmanage Registry v5.1.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/

declare(strict_types = 1);

namespace App\Lib\Enum;

class DarkModesEnum extends StandardEnum {
const Dark = 'DR';
const Light = 'LG';
const Auto = 'AU';
}
36 changes: 36 additions & 0 deletions app/src/Lib/Enum/DensityStatesEnum.php
@@ -0,0 +1,36 @@
<?php
/**
* COmanage Registry Density States Enum
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* UCAID licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @link https://www.internet2.edu/comanage COmanage Project
* @package registry
* @since COmanage Registry v5.1.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/

declare(strict_types = 1);

namespace App\Lib\Enum;

class DensityStatesEnum extends StandardEnum {
const Small = 'SM';
const Medium = 'MD';
const Large = 'LG';
}