diff --git a/app/config/schema/schema.json b/app/config/schema/schema.json index f7e5b234e..8a46da7f2 100644 --- a/app/config/schema/schema.json +++ b/app/config/schema/schema.json @@ -36,10 +36,7 @@ "id": {}, "description": {}, "table_name": { "type": "string", "size": 128, "notnull": true }, - "status": {}, - "referenceid_method": { "type": "string", "size": 2 }, - "referenceid_start": { "type": "integer" }, - "referenceid_prefix": { "type": "string", "size": 32 } + "status": {} }, "indexes": { "matchgrids_i1": { @@ -51,6 +48,23 @@ "changelog": false }, + "matchgrid_settings": { + "columns": { + "id": {}, + "matchgrid_id": {}, + "referenceid_method": { "type": "string", "size": 2 }, + "referenceid_start": { "type": "integer" }, + "referenceid_prefix": { "type": "string", "size": 32 }, + "notification_email": { "type": "string", "size": 80 } + }, + "indexes": { + "matchgrid_settings_i1": { + "columns": [ "matchgrid_id" ] + } + }, + "changelog": false + }, + "permissions": { "columns": { "id": {}, diff --git a/app/src/Controller/Component/AuthorizationComponent.php b/app/src/Controller/Component/AuthorizationComponent.php index f90259ab8..92bc94896 100644 --- a/app/src/Controller/Component/AuthorizationComponent.php +++ b/app/src/Controller/Component/AuthorizationComponent.php @@ -184,18 +184,19 @@ public function menuPermissions($username, $matchgridId=null) { return [ // Manage configuration of the current matchgrid - 'api_users' => $platformAdmin || $mgAdmin, - 'attribute_groups' => $platformAdmin || $mgAdmin, - 'attribute_maps' => $platformAdmin || $mgAdmin, - 'attributes' => $platformAdmin || $mgAdmin, - 'rules' => $platformAdmin || $mgAdmin, - 'systems_of_record' => $platformAdmin || $mgAdmin, + 'api_users' => $platformAdmin || $mgAdmin, + 'attribute_groups' => $platformAdmin || $mgAdmin, + 'attribute_maps' => $platformAdmin || $mgAdmin, + 'attributes' => $platformAdmin || $mgAdmin, + 'matchgrid_settings' => $platformAdmin || $mgAdmin, + 'rules' => $platformAdmin || $mgAdmin, + 'systems_of_record' => $platformAdmin || $mgAdmin, // Permissions specific to a matchgrid - 'gridroles' => $perms['matchgrids'], + 'gridroles' => $perms['matchgrids'], // Overall permission to manage the matchgrids - 'matchgrids' => $platformAdmin, + 'matchgrids' => $platformAdmin, // Overall permission to manage permissions - 'permissions' => $platformAdmin + 'permissions' => $platformAdmin ]; } } diff --git a/app/src/Controller/MatchgridSettingsController.php b/app/src/Controller/MatchgridSettingsController.php new file mode 100644 index 000000000..8ddaee495 --- /dev/null +++ b/app/src/Controller/MatchgridSettingsController.php @@ -0,0 +1,101 @@ + [ + 'MatchgridSetting.matchgrid_id' => 'asc' + ] + ]; + + /** + * Callback run prior to the view rendering. + * + * @since COmanage Match v1.0.0 + * @param Event $event Cake Event + */ + + public function beforeRender(\Cake\Event\Event $event) { + parent::beforeRender($event); + + // Override page title + if($this->request->getParam('action') == 'edit') { + $this->set('vv_title', __("match.op.edit.a", [__("match.ct.matchgrid_settings", 1)])); + } + } + + /** + * Handle an index request by checking for an existing CO Setting, + * creating it if not present, and then redirecting to edit. + * + * @since COmanage Match v1.0.0 + */ + + public function index() { + if(empty($this->cur_mg->id)) { + throw new RuntimeException(__("match.er.mgid")); + } + + // Let any exception pass up the stack + $id = $this->MatchgridSettings->getIdForMatchgrid($this->cur_mg->id); + + return $this->redirect(['action' => 'edit', $id]); + } + + /** + * Authorization for this Controller, called by Auth component + * - postcondition: $vv_permissions set with calculated permissions for this Controller + * + * @since COmanage Match v1.0.0 + * @param Array $user Array of user data + * @return Boolean True if authorized for the current action, false otherwise + */ + + public function isAuthorized(Array $user) { + $mgid = isset($this->cur_mg->id) ? $this->cur_mg->id : null; + + $platformAdmin = $this->Authorization->isPlatformAdmin($user['username']); + + $mgAdmin = $this->Authorization->isMatchAdmin($user['username'], $mgid); + + $p = [ + // No add or delete here + 'add' => false, + 'delete' => false, + 'edit' => $platformAdmin || $mgAdmin, + 'index' => $platformAdmin || $mgAdmin, + 'view' => false + ]; + + $this->set('vv_permissions', $p); + return $p[$this->request->getParam('action')]; + } +} \ No newline at end of file diff --git a/app/src/Lib/Identifier/Sequence.php b/app/src/Lib/Identifier/Sequence.php index 926d70881..aa4d855a8 100644 --- a/app/src/Lib/Identifier/Sequence.php +++ b/app/src/Lib/Identifier/Sequence.php @@ -41,13 +41,15 @@ class Sequence extends ReferenceIdService { */ public function generate(\App\Model\Entity\Matchgrid $mgConfig, \ADOConnection $dbc) { + $MatchgridSettings = TableRegistry::get('MatchgridSettings'); + // We'll use the matchgrid ID rather than name in the sequence name to avoid // issues if the matchgrid is renamed for some reason. $seq = "mg_seq_" . (string)$mgConfig->id; - $prefix = $mgConfig->referenceid_prefix ?: ""; + $prefix = $MatchgridSettings->getReferenceIdPrefix($mgConfig->id); - $refId = $prefix . (string)$dbc->genId($seq, $mgConfig->referenceid_start); + $refId = $prefix . (string)$dbc->genId($seq, $MatchgridSettings->getReferenceIdStart($mgConfig->id)); return $refId; } diff --git a/app/src/Lib/Match/MatchService.php b/app/src/Lib/Match/MatchService.php index c5243ba2e..8a5ac52ce 100644 --- a/app/src/Lib/Match/MatchService.php +++ b/app/src/Lib/Match/MatchService.php @@ -105,7 +105,9 @@ public function attachReferenceId(string $sor, string $sorid, AttributeManager $ */ protected function generateReferenceId() { - if($this->mgConfig->referenceid_method == ReferenceIdEnum::Sequence) { + $MatchgridSettings = TableRegistry::get('MatchgridSettings'); + + if($MatchgridSettings->getReferenceIdMethod($this->mgConfig->id) == ReferenceIdEnum::Sequence) { $IdService = new \App\Lib\Identifier\Sequence; } else { $IdService = new \App\Lib\Identifier\Uuid; diff --git a/app/src/Locale/en_US/default.po b/app/src/Locale/en_US/default.po index 7e81b0886..0171012c6 100644 --- a/app/src/Locale/en_US/default.po +++ b/app/src/Locale/en_US/default.po @@ -96,6 +96,9 @@ msgstr "{0,plural,=1{Attribute Map} other{Attribute Maps}}" msgid "match.ct.attributes" msgstr "{0,plural,=1{Attribute} other{Attributes}}" +msgid "match.ct.matchgrid_settings" +msgstr "{0,plural,=1{Matchgrid Settings} other{Matchgrid Settings}}" + msgid "match.ct.matchgrids" msgstr "{0,plural,=1{Matchgrid} other{Matchgrids}}" @@ -293,6 +296,15 @@ msgstr "Label" msgid "match.fd.name" msgstr "Name" +msgid "match.fd.notification_email" +msgstr "Notification Email" + +msgid "match.fd.notification_email.desc" +msgstr "On potential match, notify this address of the request requiring resolution" + +msgid "match.fd.MatchgridSettings.notification_email.desc" +msgstr "On potential match, notify this address of the request requiring resolution (used if no SOR specific value is set)" + msgid "match.fd.null_equivalents" msgstr "Null Equivalents" diff --git a/app/src/Model/Entity/MatchgridSetting.php b/app/src/Model/Entity/MatchgridSetting.php new file mode 100644 index 000000000..3d7c02e0f --- /dev/null +++ b/app/src/Model/Entity/MatchgridSetting.php @@ -0,0 +1,40 @@ + true, + 'id' => false, + 'slug' => false, + ]; +} \ No newline at end of file diff --git a/app/src/Model/Table/MatchgridSettingsTable.php b/app/src/Model/Table/MatchgridSettingsTable.php new file mode 100644 index 000000000..cdc595b01 --- /dev/null +++ b/app/src/Model/Table/MatchgridSettingsTable.php @@ -0,0 +1,215 @@ + null, + 'referenceid_method' => ReferenceIdEnum::UUID, + 'referenceid_start' => 1, + 'referenceid_prefix' => "", + ]; + + /** + * Perform Cake Model initialization. + * + * @since COmanage Match v1.0.0 + * @param array $config Configuration options passed to constructor + */ + + public function initialize(array $config) { + // Timestamp behavior handles created/modified updates + $this->addBehavior('Timestamp'); + + // Define associations + $this->belongsTo('Matchgrids'); + + $this->setDisplayField('matchgrid_id'); + + $this->setPrimaryLink('matchgrid_id'); + $this->setRequiresMatchgrid(true); + + $this->setAutoViewVars([ + 'referenceidMethods' => [ + 'type' => 'enum', + 'class' => 'ReferenceIdEnum' + ] + ]); + } + + /** + * Get the MatchgridSetting row ID for a given Matchgrid, creating it if not + * already present. + * + * @since COmanage Match v1.0.0 + * @param int $matchgridId Matchgrid ID + * @return int MatchgridSetting ID + */ + + public function getIdForMatchgrid(int $matchgridId) { + try { + $obj = $this->find()->where(["matchgrid_id" => $matchgridId])->firstOrFail(); + } + catch(\Cake\Datasource\Exception\RecordNotFoundException $e) { + // No current Matchgrid Settings object for this Matchgrid, create one + + $obj = $this->newEntity(["matchgrid_id" => $matchgridId]); + + $this->MatchgridSettings->save($obj); + } + + return $obj->id; + } + + /** + * Get the Matchgrid notification email. + * + * @since COmanage Match v1.0.0 + * @param int $matchgridId Matchgrid ID + */ + + public function getNotificationEmail(int $matchgridId) { + return $this->lookupValue($matchgridId, 'notification_email'); + } + + /** + * Get the Matchgrid Reference ID prefix. + * + * @since COmanage Match v1.0.0 + * @param int $matchgridId Matchgrid ID + */ + + public function getReferenceIdPrefix(int $matchgridId) { + return $this->lookupValue($matchgridId, 'referenceid_prefix'); + } + + /** + * Get the Matchgrid Reference ID start. + * + * @since COmanage Match v1.0.0 + * @param int $matchgridId Matchgrid ID + */ + + public function getReferenceIdStart(int $matchgridId) { + return $this->lookupValue($matchgridId, 'referenceid_start'); + } + + /** + * Get the Matchgrid Reference ID method. + * + * @since COmanage Match v1.0.0 + * @param int $matchgridId Matchgrid ID + */ + + public function getReferenceIdMethod(int $matchgridId) { + return $this->lookupValue($matchgridId, 'referenceid_method'); + } + + /** + * Obtain a single Matchgrid setting. + * + * @since COmanage Match v1.0.0 + * @param int $matchgridId Matchgrid ID + * @param string $field Field name to retrieve, corresponding to column/field name + */ + + protected function lookupValue(int $matchgridId, string $field) { + $value = null; + + try { + $settings = $this->find()->where(["matchgrid_id" => $matchgridId])->firstOrFail(); + + if(isset($settings->$field)) { + return $settings->$field; + } + } + catch(\Cake\Datasource\Exception\RecordNotFoundException $e) { + // No settings for this Matchgrid, use default value + } + // Let other exceptions pass up the stack + + return $this->defaultSettings[$field]; + } + + /** + * Set validation rules. + * + * @since COmanage Match v1.0.0 + * @param Validator $validator Validator + * @return $validator Validator + */ + + public function validationDefault(Validator $validator) { + $validator->add( + 'matchgrid_id', + 'content', + [ 'rule' => 'isInteger' ] + ); + $validator->notEmpty('matchgrid_id'); + + $validator->add( + 'referenceid_method', + 'content', + [ 'rule' => [ 'inList', [ + ReferenceIdEnum::Sequence, + ReferenceIdEnum::UUID + ] ] ] + ); + $validator->notEmpty('referenceid_method'); + + $validator->add( + 'referenceid_start', + 'content', + [ 'rule' => [ 'range', 1, null ] ] + ); + $validator->allowEmpty('referenceid_start'); + + $validator->add( + 'referenceid_prefix', + 'content', + [ 'rule' => [ 'maxLength', 32 ] ] + ); + $validator->allowEmpty('referenceid_prefix'); + + return $validator; + } +} \ No newline at end of file diff --git a/app/src/Model/Table/MatchgridsTable.php b/app/src/Model/Table/MatchgridsTable.php index 7835bfd2d..3cec24b1f 100644 --- a/app/src/Model/Table/MatchgridsTable.php +++ b/app/src/Model/Table/MatchgridsTable.php @@ -34,7 +34,6 @@ use Cake\Validation\Validator; use \App\Lib\Enum\ConfidenceModeEnum; -use \App\Lib\Enum\ReferenceIdEnum; use \App\Lib\Enum\StatusEnum; use \App\Lib\Match\MatchgridBuilder; @@ -60,6 +59,8 @@ public function initialize(array $config) { // since it uses deleteAll(). ->setCascadeCallbacks() loads associated data // and can therefore reach lower levels of association. This is pretty poorly // documented and explained. + $this->hasOne('MatchgridSettings') + ->setDependent(true); $this->hasMany('ApiUsers') ->setDependent(true); $this->hasMany('Attributes') @@ -83,10 +84,6 @@ public function initialize(array $config) { $this->setDisplayField('table_name'); $this->setAutoViewVars([ - 'referenceidMethods' => [ - 'type' => 'enum', - 'class' => 'ReferenceIdEnum' - ], 'statuses' => [ 'type' => 'enum', 'class' => 'StatusEnum' @@ -201,30 +198,6 @@ public function validationDefault(Validator $validator) { ); $validator->notEmpty('status'); - $validator->add( - 'referenceid_method', - 'content', - [ 'rule' => [ 'inList', [ - ReferenceIdEnum::Sequence, - ReferenceIdEnum::UUID - ] ] ] - ); - $validator->notEmpty('referenceid_method'); - - $validator->add( - 'referenceid_start', - 'content', - [ 'rule' => [ 'range', 1, null ] ] - ); - $validator->allowEmpty('referenceid_start'); - - $validator->add( - 'referenceid_prefix', - 'content', - [ 'rule' => [ 'maxLength', 32 ] ] - ); - $validator->allowEmpty('referenceid_prefix'); - return $validator; } } \ No newline at end of file diff --git a/app/src/Template/Element/menuMain.ctp b/app/src/Template/Element/menuMain.ctp index d357af8e1..5cefc0753 100644 --- a/app/src/Template/Element/menuMain.ctp +++ b/app/src/Template/Element/menuMain.ctp @@ -34,12 +34,13 @@ // Matchgrid specific models $models = [ - 'api_users' => 'vpn_key', - 'attributes' => 'edit', - 'attribute_groups' => 'storage', - 'attribute_maps' => 'swap_horiz', - 'rules' => 'assignment', - 'systems_of_record' => 'gavel', + 'matchgrid_settings' => 'settings', + 'api_users' => 'vpn_key', + 'attributes' => 'edit', + 'attribute_groups' => 'storage', + 'attribute_maps' => 'swap_horiz', + 'rules' => 'assignment', + 'systems_of_record' => 'gavel', ]; foreach($models as $model => $icon) { diff --git a/app/src/Template/Email/text/potential_match.ctp b/app/src/Template/Email/text/potential_match.ctp new file mode 100644 index 000000000..c3771f956 --- /dev/null +++ b/app/src/Template/Email/text/potential_match.ctp @@ -0,0 +1,38 @@ + + + + +?> +A new potential match is available for your review. You may access the +pending request at this URL: + + + \ No newline at end of file diff --git a/app/src/Template/MatchgridSettings/fields.inc b/app/src/Template/MatchgridSettings/fields.inc new file mode 100644 index 000000000..809c6f281 --- /dev/null +++ b/app/src/Template/MatchgridSettings/fields.inc @@ -0,0 +1,66 @@ + + +Field->control('referenceid_method', + ['empty' => true, + 'onChange' => 'fields_update_gadgets();']); + + print $this->Field->control('referenceid_start', + ['default' => 1001]); + + print $this->Field->control('referenceid_prefix', + [], + false); + + print $this->Field->control('notification_email', [], true); +} diff --git a/app/src/Template/Matchgrids/fields.inc b/app/src/Template/Matchgrids/fields.inc index d39a8e65b..e8e992c2a 100644 --- a/app/src/Template/Matchgrids/fields.inc +++ b/app/src/Template/Matchgrids/fields.inc @@ -25,30 +25,6 @@ * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) */ -use \App\Lib\Enum\ReferenceIdEnum; -?> - -Field->control('table_name'); @@ -57,15 +33,4 @@ if($action == 'add' || $action == 'edit') { print $this->Field->control('status', ['empty' => false]); - - print $this->Field->control('referenceid_method', - ['empty' => true, - 'onChange' => 'fields_update_gadgets();']); - - print $this->Field->control('referenceid_start', - ['default' => 1001]); - - print $this->Field->control('referenceid_prefix', - [], - false); }