Skip to content

Commit

Permalink
ORCID Source search...
Browse files Browse the repository at this point in the history
  • Loading branch information
Ioannis committed May 4, 2025
1 parent 130d506 commit 23acf17
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ public function validationDefault(Validator $validator): Validator {
'provider' => 'table'
]
]);
$validator->allowEmptyString('scope');
$validator->notEmptyString('scope');

$validator->add('refresh_token', [
'content' => [
Expand Down
69 changes: 37 additions & 32 deletions app/plugins/OrcidSource/src/Model/Table/OrcidSourcesTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
namespace OrcidSource\Model\Table;

use App\Model\Entity\ExternalIdentitySource;
use Cake\Http\Client;
use Cake\ORM\Table;
use Cake\ORM\TableRegistry;
use Cake\Routing\Router;
use Cake\Validation\Validator;
use OrcidSource\Lib\Enum\{OrcidSourceApiEnum, OrcidSourceTierEnum};
use \App\Lib\Enum\EduPersonAffiliationEnum;
use \App\Lib\Enum\HttpStatusCodesEnum;
use \OrcidSource\Model\Entity\OrcidSource;

Expand Down Expand Up @@ -284,7 +284,7 @@ protected function resultToEntityData(

$eidata['names'][] = $name;

foreach($result['emails']["email"] as $m) {
foreach($result['emails']['email'] as $m) {
$eidata['email_addresses'][] = [
'mail' => $m['email'],
'type' => $this->EmailAddressTypes->getTypeLabel($OrcidSource->email_address_type_id),
Expand Down Expand Up @@ -342,6 +342,10 @@ public function retrieve(

/**
* Search the External Identity Source.
* The ORCID search will be triggered by the CO/Platform Admin. As a result, we want to use a privileged access key
* i.e. the one the CO Admin got in Oauth2Server setup page
*
* refrence: https://info.orcid.org/documentation/api-tutorials/api-tutorial-searching-the-orcid-registry/
*
* @param ExternalIdentitySource $source EIS Entity with instantiated plugin configuration
* @param array $searchAttrs Array of search attributes and values, as configured by searchAttributes()
Expand All @@ -364,22 +368,19 @@ public function search(

// We just let search exceptions pop up the stack

$this->orcidConnect($source);
$this->httpClient = $this->orcidConnect($source);

$records = $this->orcidRequest('/v3.0/search/', $searchAttrs);

// We can control pagination with query params, but the OIS search capability
// doesn't currently understand pagination.

if(isset($records->{'num-found'}) && $records->{'num-found'} > 0) {
foreach($records->result as $rec) {
if(!empty($rec->{'orcid-identifier'}->{'path'})) {
$orcid = $rec->{'orcid-identifier'}->{'path'};
if(isset($records['num-found']) && $records['num-found'] > 0) {
foreach($records['result'] as $rec) {
if(!empty($rec['orcid-identifier']['path'])) {
$orcid = $rec['orcid-identifier']['path'];

$orcidbio = $this->orcidRequest('/v3.0/' . $orcid . '/person');

if(!empty($orcidbio)) {
// $ret[ $orcid ] = $this->resultToOrgIdentity($orcid, $orcidbio);
$ret[ $orcid ] = $this->resultToEntityData($source->orcid_source, $orcidbio);
}
}
}
Expand All @@ -396,11 +397,7 @@ public function search(
*/

public function searchableAttributes(): array {
// By default, ORCID uses a free form search. It is possible to search on
// specific fields (eg: email), though for the initial implementation we
// won't support that.
return [
// XXX This really isn't the right language key, we want an fd.*
'q' => __d('operation', 'search')
];
}
Expand All @@ -419,11 +416,17 @@ public function searchableAttributes(): array {
*/
public function orcidRequest(string $urlPath, array $data=[], string $action="get"): array
{
// Get the user access_token. If none is provided, then throw an exception
$accessToken = match(true) {
$this->orcidToken?->access_token !== null => $this->orcidTokensTable->getUnencrypted($this->orcidToken->access_token),
$this->orcidSource?->server?->oauth2_server?->access_token !== null => $this->orcidSource->server->oauth2_server->access_token,
default => throw new \InvalidArgumentException(__d('orcid_source', 'error.token.none'))
};

$options = [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . ($this->orcidTokensTable->getUnencrypted($this->orcidToken->access_token)
?? $this->orcidSource->server->oauth2_server->access_token),
'Authorization' => 'Bearer ' . $accessToken,
'Content-Type' => 'application/orcid+json'
]
];
Expand Down Expand Up @@ -484,15 +487,14 @@ public function orcidUrl(string $api=OrcidSourceApiEnum::PUBLIC, string $tier=Or
/**
* Establish connection to ORCID API by configuring the HTTP client with appropriate credentials.
*
* @param int $exterrnalIdentitySourceId The external identity source ID to connect to
* @param string $orcidIdentifier The ORCID identifier to use for authentication
* @return \Cake\Http\Client Configured HTTP client for ORCID API requests
* @throws \InvalidArgumentException If OAuth2 server configuration or access token not found
* @param ExternalIdentitySource $exterrnalIdentitySource
* @param string|null $orcidIdentifier The ORCID identifier to use for authentication
* @return Client Configured HTTP client for ORCID API requests
* @since COmanage Registry v5.2.0
*/
protected function orcidConnect(
\App\Model\Entity\ExternalIdentitySource $exterrnalIdentitySource,
string $orcidIdentifier
?string $orcidIdentifier = null
): \Cake\Http\Client {
$this->orcidSource = $this->find()
->contain([
Expand Down Expand Up @@ -521,16 +523,19 @@ protected function orcidConnect(
throw new \InvalidArgumentException(__d('error', 'notfound', [__d('core_server', 'controller.Oauth2Servers')]));
}

$this->orcidToken = $this->orcidTokensTable
->find()
->where([
'orcid_source_id' => $this->orcidSource->id,
'orcid_identifier' => $orcidIdentifier,
])
->first();

if (empty($this->orcidToken->access_token)) {
throw new \InvalidArgumentException(__d('orcid_source', 'error.token.none'));
// Since this is null, we will use the master access token stored in Oauth2Server Configuration
if ($orcidIdentifier !== null) {
$this->orcidToken = $this->orcidTokensTable
->find()
->where([
'orcid_source_id' => $this->orcidSource->id,
'orcid_identifier' => $orcidIdentifier,
])
->first();

if (empty($this->orcidToken->access_token)) {
throw new \InvalidArgumentException(__d('orcid_source', 'error.token.none'));
}
}

return $this->oauth2ServersTable->createHttpClient($this->orcidSource->server->oauth2_server->id);
Expand Down

0 comments on commit 23acf17

Please sign in to comment.