Skip to content

Commit

Permalink
pkp#9771 Move ORCID functionality into core application
Browse files Browse the repository at this point in the history
  • Loading branch information
ewhanson committed Jun 20, 2024
1 parent 592f862 commit 96c8341
Show file tree
Hide file tree
Showing 118 changed files with 12,211 additions and 23 deletions.
178 changes: 178 additions & 0 deletions api/v1/orcid/OrcidController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<?php

/**
* @file api/v1/dois/OrcidController.php
*
* Copyright (c) 2024 Simon Fraser University
* Copyright (c) 2024 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class OrcidController
*
* @ingroup api_v1_orcid
*
* @brief Handle API requests for ORCID operations.
*
*/

namespace PKP\API\v1\orcid;

use APP\facades\Repo;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Route;
use PKP\core\PKPBaseController;
use PKP\jobs\orcid\SendAuthorMail;
use PKP\orcid\OrcidManager;
use PKP\security\Role;
use PKP\stageAssignment\StageAssignment;

class OrcidController extends PKPBaseController
{
/**
* @inheritDoc
*/
public function getHandlerPath(): string
{
return 'orcid';
}

/**
* @inheritDoc
*/
public function getRouteGroupMiddleware(): array
{
return [
'has.user',
'has.context',
self::roleAuthorizer([
Role::ROLE_ID_SITE_ADMIN,
Role::ROLE_ID_MANAGER,
Role::ROLE_ID_SUB_EDITOR,
]),
];
}

/**
* @inheritDoc
*/
public function getGroupRoutes(): void
{
Route::post('requestAuthorVerification/{authorId}', $this->requestAuthorVerification(...))
->name('orcid.requestAuthorVerification');
Route::post('deleteForAuthor/{authorId}', $this->deleteForAuthor(...))
->name('orcid.delete');
}

/**
* Send email request for author to link their ORCID to the submission in OJS
*
*/
public function requestAuthorVerification(Request $illuminateRequest): JsonResponse
{
$context = $this->getRequest()->getContext();
if (!OrcidManager::isEnabled($context)) {
return response()->json([
'error' => __('api.orcid.403.orcidNotEnabled'),
], Response::HTTP_FORBIDDEN);
}

$authorId = (int) $illuminateRequest->route('authorId');
$author = Repo::author()->get($authorId);

if (empty($author)) {
return response()->json([
'error' => __('api.orcid.404.authorNotFound'),
], Response::HTTP_NOT_FOUND);
}

$user = $this->getRequest()->getUser();
$currentRoles = array_map(
function (Role $role) {
return $role->getId();
},
$user->getRoles($context->getId())
);

if (!array_intersect([Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_MANAGER], $currentRoles)) {
$publicationId = $author->getData('publicationId');
$submissionId = Repo::publication()->get($publicationId)->getData('submissionId');

$editorAssignment = StageAssignment::withSubmissionIds([$submissionId])
->withRoleIds([Role::ROLE_ID_SUB_EDITOR])
->withUserId($user->getId())
->first();

if ($editorAssignment === null) {
return response()->json([
'error' => __('api.orcid.403.editWithoutPermission'),
], Response::HTTP_FORBIDDEN);
}
}

try {
dispatch(new SendAuthorMail($author, $context, true));
} catch (\Exception $exception) {
return response()->json([
'error' => __('api.orcid.404.contextRequired'),
], Response::HTTP_NOT_FOUND);
}

return response()->json([], Response::HTTP_OK);
}

/**
* Remove ORCID and access token data from submission author
*
*/
public function deleteForAuthor(Request $illuminateRequest): JsonResponse
{
$context = $this->getRequest()->getContext();
if (!OrcidManager::isEnabled($context)) {
return response()->json([
'error' => __('api.orcid.403.orcidNotEnabled'),
], Response::HTTP_FORBIDDEN);
}

$authorId = (int) $illuminateRequest->route('authorId');
$author = Repo::author()->get($authorId);

if (empty($author)) {
return response()->json([
'error' => __('api.orcid.404.authorNotFound'),
], Response::HTTP_NOT_FOUND);
}

$user = $this->getRequest()->getUser();
$currentRoles = array_map(
function (Role $role) {
return $role->getId();
},
$user->getRoles($context->getId())
);

if (!array_intersect([Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_MANAGER], $currentRoles)) {
$publicationId = $author->getData('publicationId');
$submissionId = Repo::publication()->get($publicationId)->getData('submissionId');

$editorAssignment = StageAssignment::withSubmissionIds([$submissionId])
->withRoleIds([Role::ROLE_ID_SUB_EDITOR])
->withUserId($user->getId())
->first();

if ($editorAssignment === null) {
return response()->json([
'error' => __('api.orcid.403.editWithoutPermission'),
], Response::HTTP_FORBIDDEN);
}
}

$author->setOrcid(null);
$author->setOrcidVerified(false);
OrcidManager::removeOrcidAccessToken($author);
Repo::author()->edit($author, []);

return response()->json([], Response::HTTP_OK);
}
}
3 changes: 3 additions & 0 deletions classes/author/maps/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ protected function mapByProperties(array $props, Author $item): array
case 'fullName':
$output[$prop] = $item->getFullName();
break;
case 'hasVerifiedOrcid':
$output[$prop] = $item->hasVerifiedOrcid();
break;
default:
$output[$prop] = $item->getData($prop);
break;
Expand Down
6 changes: 6 additions & 0 deletions classes/components/forms/Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ abstract class Field
/** @var mixed A default for this field when no value is specified. */
public $default;

/** @var bool Whether the field should be ignored when a form is submitted */
public bool $isInert = false;

/**
* Only show this field when the field named here is not empty. Match an exact
* value by passing an array:
Expand Down Expand Up @@ -128,6 +131,9 @@ public function getConfig()
if (isset($this->showWhen)) {
$config['showWhen'] = $this->showWhen;
}
if (isset($this->isInert)) {
$config['isInert'] = $this->isInert;
}

$config['value'] = $this->value ?? $this->default ?? null;

Expand Down
3 changes: 3 additions & 0 deletions classes/components/forms/FieldHTML.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ class FieldHTML extends Field
{
/** @copydoc Field::$component */
public $component = 'field-html';

/** @copydoc Field::$isInert */
public bool $isInert = true;
}
48 changes: 48 additions & 0 deletions classes/components/forms/FieldOrcid.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

/**
* @file classes/components/form/FieldOrcid.php
*
* Copyright (c) 2014-2024 Simon Fraser University
* Copyright (c) 2000-2024 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class FieldOrcid
*
* @ingroup classes_controllers_form
*
* @brief A component managing and displaying ORCIDs
*/

namespace PKP\components\forms;

class FieldOrcid extends Field
{
/** @copydoc Field::$component */
public $component = 'field-orcid';

/** @var string ORCID URL */
public string $orcid = '';

/** @var int Author ID associated with the ORCID */
public int $authorId = 0;

/** @var bool Whether the provided ORCID ID has been verified/authenticated by the author */
public bool $isVerified = false;

/** @copydoc Field::$isInert */
public bool $isInert = true;

/**
* @copydoc Field::getConfig()
*/
public function getConfig()
{
$config = parent::getConfig();
$config['orcid'] = $this->orcid;
$config['authorId'] = $this->authorId;
$config['isVerified'] = $this->isVerified;

return $config;
}
}
Loading

0 comments on commit 96c8341

Please sign in to comment.