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 all 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';
}