Skip to content

Commit

Permalink
Add isUniqueChangelog rule. Fix OrcidSource token index issue.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ioannis committed Aug 25, 2025
1 parent bff5a2c commit 50c38cc
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 2 deletions.
3 changes: 1 addition & 2 deletions app/plugins/OrcidSource/config/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@
},
"indexes": {
"orcid_source_tokens_i1": {
"columns": [ "orcid_source_id", "orcid_identifier"],
"unique": true
"columns": [ "orcid_source_id", "orcid_identifier"]
},
"orcid_source_tokens_i2": { "columns": [ "orcid_identifier" ] },
"orcid_source_tokens_i3": { "needed": false, "columns": [ "orcid_source_id" ] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ msgstr "{0} was not found"
msgid "error.response.no_orcid"
msgstr "ORCID identifier missing from response."

msgid "error.exists"
msgstr "{0} already exists with this Identitifier"

msgid "field.OrcidSources.api_type"
msgstr "API Type"

Expand Down
27 changes: 27 additions & 0 deletions app/plugins/OrcidSource/src/Model/Table/OrcidTokensTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

namespace OrcidSource\Model\Table;

use App\Lib\Rules\IsUniqueChangelog;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Utility\Security;
use Cake\Validation\Validator;
Expand Down Expand Up @@ -119,6 +121,31 @@ public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayO

}

/**
* Define business rules.
*
* @since COmanage Registry v5.2.0
* @param RulesChecker $rules RulesChecker object
* @return RulesChecker
*/

public function buildRules(RulesChecker $rules): RulesChecker {
// We don't want to perform the uniqueness check until after then namespacing
// check in order to avoid information leakage. This requires more complicated
// rule building.

$rules->add(
new IsUniqueChangelog(["orcid_source_id", "orcid_identifier"]),
'_isUniqueChangelog',
[
'errorField' => 'orcid_identifier',
'message' => __d('orcid_source', 'error.exists', [__d('controller', 'OrcidTokens', [1])]),
]
);

return $rules;
}

/**
* Unencrypt a value previously encrypted using salt
*
Expand Down
124 changes: 124 additions & 0 deletions app/src/Lib/Rules/IsUniqueChangelog.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?php
declare(strict_types=1);

/**
* COmanage Registry Env Sources Table
*
* 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.2.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/
namespace App\Lib\Rules;

use Cake\Datasource\EntityInterface;
use Cake\Utility\Hash;
use Cake\Utility\Inflector;

/**
* Checks that a list of fields from an entity are unique in the table
*/
class IsUniqueChangelog
{
/**
* The list of fields to check
*
* @var array<string>
*/
protected $_fields;

/**
* The unique check options
*
* @var array<string, mixed>
*/
protected $_options = [
'allowMultipleNulls' => false,
];

/**
* Constructor.
*
* ### Options
*
* - `allowMultipleNulls` Allows any field to have multiple null values. Defaults to false.
*
* @param array<string> $fields The list of fields to check uniqueness for
* @param array<string, mixed> $options The options for unique checks.
*/
public function __construct(array $fields, array $options = [])
{
$this->_fields = $fields;
$this->_options = $options + $this->_options;
}

/**
* Performs the uniqueness check
*
* @param \Cake\Datasource\EntityInterface $entity The entity from where to extract the fields
* where the `repository` key is required.
* @param array<string, mixed> $options Options passed to the check,
* @return bool
*/
public function __invoke(EntityInterface $entity, array $options): bool
{
if (!$entity->extract($this->_fields, true)) {
return true;
}

$fields = $entity->extract($this->_fields);
if ($this->_options['allowMultipleNulls'] && array_filter($fields, 'is_null')) {
return true;
}

$alias = $options['repository']->getAlias();
$conditions = $this->_alias($alias, $fields);
// Changelog
$ascParentfk = Inflector::singularize($options['repository']->getTable()) . '_id';
$conditions["$alias.deleted !="] = true;
$conditions["$alias.$ascParentfk IS"] = null;
if ($entity->isNew() === false) {
$keys = (array)$options['repository']->getPrimaryKey();
$keys = $this->_alias($alias, $entity->extract($keys));
if (Hash::filter($keys)) {
$conditions['NOT'] = $keys;
}
}

return !$options['repository']->exists($conditions);
}

/**
* Add a model alias to all the keys in a set of conditions.
*
* @param string $alias The alias to add.
* @param array $conditions The conditions to alias.
* @return array<string, mixed>
*/
protected function _alias(string $alias, array $conditions): array
{
$aliased = [];
foreach ($conditions as $key => $value) {
$aliased["$alias.$key IS"] = $value;
}

return $aliased;
}
}

0 comments on commit 50c38cc

Please sign in to comment.