Skip to content

Commit

Permalink
Merge branch 'citationField-724' into 'main'
Browse files Browse the repository at this point in the history
Obtém citação do documento original a partir do DOI

See merge request softwares-pkp/plugins_ojs/scieloTranslationsFields!2
  • Loading branch information
JhonathanLepidus committed Dec 4, 2024
2 parents 79d6061 + 760208e commit 5106a3f
Show file tree
Hide file tree
Showing 15 changed files with 464 additions and 16 deletions.
3 changes: 2 additions & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ include:
ref: main
file:
- 'templates/groups/pkp_plugin.yml'
- 'templates/groups/ops/cypress_tests.yml'
- 'templates/groups/ops/cypress_tests.yml'
- 'templates/groups/ops/unit_tests.yml'
54 changes: 46 additions & 8 deletions ScieloTranslationsFieldsPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
use PKP\plugins\GenericPlugin;
use APP\core\Application;
use APP\pages\submission\SubmissionHandler;
use APP\plugins\generic\scieloTranslationsFields\api\v1\translationsFields\TranslationsFieldsHandler;
use APP\plugins\generic\scieloTranslationsFields\classes\components\forms\TranslationDataForm;
use APP\plugins\generic\scieloTranslationsFields\classes\DoiValidator;

class ScieloTranslationsFieldsPlugin extends GenericPlugin
{
Expand All @@ -36,6 +38,7 @@ public function register($category, $path, $mainContextId = null)
Hook::add('Template::Workflow', [$this, 'removeRelationsFromWorkflow']);
Hook::add('TemplateManager::display', [$this, 'addResourcesToWorkflow']);
Hook::add('Template::Workflow::Publication', [$this, 'addTranslationDataTabToWorkflow']);
Hook::add('Dispatcher::dispatch', [$this, 'setupTranslationsFieldsHandler']);
Hook::add('Schema::get::publication', [$this, 'addOurFieldsToPublicationSchema']);
}

Expand Down Expand Up @@ -66,6 +69,11 @@ public function addOurFieldsToPublicationSchema($hookName, $params)
'apiSummary' => true,
'validation' => ['nullable'],
];
$schema->properties->{'originalDocumentCitation'} = (object) [
'type' => 'string',
'apiSummary' => true,
'validation' => ['nullable'],
];

return Hook::CONTINUE;
}
Expand Down Expand Up @@ -120,19 +128,19 @@ private function removeRelationsSection($stepSections)
return $editedSections;
}

private function getTranslationDataForm($submission, $request)
private function getTranslationDataForm($submission, $request, $placedOn)
{
$context = $request->getContext();
$publication = $submission->getLatestPublication();
$publicationEndpoint = 'submissions/' . $submission->getId() . '/publications/' . $publication->getId();
$saveFormUrl = $request->getDispatcher()->url($request, Application::ROUTE_API, $context->getPath(), $publicationEndpoint);
$saveFormUrl = $request
->getDispatcher()
->url($request, Application::ROUTE_API, $context->getPath(), "translationsFields/saveTranslationFields", null, null, ['submissionId' => $submission->getId()]);

return new TranslationDataForm($saveFormUrl, $submission);
return new TranslationDataForm($saveFormUrl, $submission, $placedOn);
}

private function addTranslationDataSection($stepSections, $submission, $request)
{
$translationDataForm = $this->getTranslationDataForm($submission, $request);
$translationDataForm = $this->getTranslationDataForm($submission, $request, 'submissionWizard');

$stepSections[] = [
'id' => 'translationData',
Expand Down Expand Up @@ -174,10 +182,18 @@ public function validateSubmissionFields($hookName, $params)
$submission = $params[1];
$publication = $submission->getCurrentPublication();

if (is_null($publication->getData('originalDocumentHasDoi'))) {
$originalDocumentHasDoi = $publication->getData('originalDocumentHasDoi');
if (is_null($originalDocumentHasDoi)) {
$errors['originalDocumentHasDoi'] = [__('plugins.generic.scieloTranslationsFields.error.originalDocumentHasDoi.required')];
}

$doiValidator = new DoiValidator();
$originalDocumentDoi = $publication->getData('originalDocumentDoi');

if ($originalDocumentHasDoi && !$doiValidator->validate($originalDocumentDoi)) {
$errors['originalDocumentDoi'] = [__('plugins.generic.scieloTranslationsFields.originalDocumentDoi.invalidDoi')];
}

return Hook::CONTINUE;
}

Expand Down Expand Up @@ -218,7 +234,7 @@ public function addResourcesToWorkflow($hookName, $params)
return Hook::CONTINUE;
}

$translationDataForm = $this->getTranslationDataForm($submission, $request);
$translationDataForm = $this->getTranslationDataForm($submission, $request, 'workflow');
$components = $templateMgr->getState('components');
$components[$translationDataForm->id] = $translationDataForm->getConfig();

Expand All @@ -236,6 +252,28 @@ public function addTranslationDataTabToWorkflow($hookName, $params)

return Hook::CONTINUE;
}

public function setupTranslationsFieldsHandler($hookName, $params)
{
$request = $params[0];
$router = $request->getRouter();

if (!($router instanceof \PKP\core\APIRouter)) {
return;
}

if (str_contains($request->getRequestPath(), 'api/v1/translationsFields')) {
$handler = new TranslationsFieldsHandler();
}

if (!isset($handler)) {
return;
}

$router->setHandler($handler);
$handler->getApp()->run();
exit;
}
}

if (!PKP_STRICT_MODE) {
Expand Down
102 changes: 102 additions & 0 deletions api/v1/translationsFields/TranslationsFieldsHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

namespace APP\plugins\generic\scieloTranslationsFields\api\v1\translationsFields;

use PKP\handler\APIHandler;
use PKP\security\Role;
use PKP\security\authorization\PolicySet;
use PKP\security\authorization\RoleBasedHandlerOperationPolicy;
use PKP\db\DAORegistry;
use APP\facades\Repo;
use APP\plugins\generic\scieloTranslationsFields\classes\clients\DoiClient;
use APP\plugins\generic\scieloTranslationsFields\classes\DoiValidator;

class TranslationsFieldsHandler extends APIHandler
{
public function __construct()
{
$this->_handlerPath = 'translationsFields';
$roles = [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_AUTHOR];
$this->_endpoints = [
'PUT' => [
[
'pattern' => $this->getEndpointPattern() . '/saveTranslationFields',
'handler' => [$this, 'saveTranslationFields'],
'roles' => $roles
],
],
];
parent::__construct();
}

public function authorize($request, &$args, $roleAssignments)
{
$rolePolicy = new PolicySet(PolicySet::COMBINING_PERMIT_OVERRIDES);

foreach ($roleAssignments as $role => $operations) {
$rolePolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, $role, $operations));
}
$this->addPolicy($rolePolicy);

return parent::authorize($request, $args, $roleAssignments);
}

private function getSubmission($slimRequest)
{
$queryParams = $slimRequest->getQueryParams();
$submissionId = (int) $queryParams['submissionId'];

return Repo::submission()->get($submissionId);
}

private function validateOriginalDoi($originalDocumentDoi)
{
$doiValidator = new DoiValidator();
return $doiValidator->validate($originalDocumentDoi);
}

public function saveTranslationFields($slimRequest, $response, $args)
{
$requestParams = $slimRequest->getParsedBody();
$placedOn = $slimRequest->getQueryParams()['placedOn'];
$submission = $this->getSubmission($slimRequest);
$publication = $submission->getCurrentPublication();

$originalDocumentHasDoi = $requestParams['originalDocumentHasDoi'];
$originalDocumentDoi = $requestParams['originalDocumentDoi'];
$originalDocumentCitation = null;

if ($originalDocumentHasDoi) {
if ($this->validateOriginalDoi($originalDocumentDoi)) {
$doiClient = new DoiClient();
$originalDocumentCitation = $doiClient->getApaCitation($originalDocumentDoi);
} elseif ($placedOn == 'workflow') {
return $response->withStatus(400)->withJson([
'originalDocumentDoi' => [__('plugins.generic.scieloTranslationsFields.originalDocumentDoi.invalidDoi')]
]);
}
}

Repo::publication()->edit($publication, [
'originalDocumentHasDoi' => $originalDocumentHasDoi,
'originalDocumentDoi' => $originalDocumentDoi,
'originalDocumentCitation' => $originalDocumentCitation
]);

$submission = Repo::submission()->get($submission->getId());
$publication = $submission->getCurrentPublication();

$contextId = $submission->getData('contextId');
$userGroups = Repo::userGroup()->getCollector()
->filterByContextIds([$contextId])
->getMany();

$genreDao = DAORegistry::getDAO('GenreDAO');
$genres = $genreDao->getByContextId($contextId)->toArray();

return $response->withJson(
Repo::publication()->getSchemaMap($submission, $userGroups, $genres)->map($publication),
200
);
}
}
11 changes: 11 additions & 0 deletions classes/DoiValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace APP\plugins\generic\scieloTranslationsFields\classes;

class DoiValidator
{
public function validate(string $doi): bool
{
return (preg_match('/^10\.\d{4,9}\/[-._;()\/:A-Z0-9]+$/i', $doi) === 1);
}
}
43 changes: 43 additions & 0 deletions classes/clients/DoiClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace APP\plugins\generic\scieloTranslationsFields\classes\clients;

use APP\core\Application;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Exception\ClientException;

class DoiClient
{
private $guzzleClient;

public const DOI_URL = 'https://doi.org/';

public function __construct($guzzleClient = null)
{
if (!is_null($guzzleClient)) {
$this->guzzleClient = $guzzleClient;
} else {
$this->guzzleClient = Application::get()->getHttpClient();
}
}

public function getApaCitation(string $doi): ?string
{
$doiUrl = self::DOI_URL . $doi;

try {
$response = $this->guzzleClient->request('GET', $doiUrl, [
'headers' => [
'Accept' => 'text/x-bibliography; style=apa'
],
]);

return $response->getBody()->getContents();
} catch (ClientException $e) {
$errorMsg = $e->getResponse()->getBody()->getContents();
error_log("Error while getting DOI citation: $errorMsg");
}

return null;
}
}
22 changes: 19 additions & 3 deletions classes/components/forms/TranslationDataForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@
use PKP\components\forms\FormComponent;
use PKP\components\forms\FieldOptions;
use PKP\components\forms\FieldText;
use PKP\components\forms\FieldHTML;

class TranslationDataForm extends FormComponent
{
public $id = 'translationData';
public $method = 'PUT';

public function __construct($action, $submission)
public function __construct($action, $submission, $placedOn)
{
$publication = $submission->getCurrentPublication();
$originalDocumentDoi = $publication->getData('originalDocumentDoi');

$this->action = $action;
$this->action = $action . "&placedOn=$placedOn";
$this->addField(new FieldOptions('originalDocumentHasDoi', [
'label' => __('plugins.generic.scieloTranslationsFields.originalDocumentHasDoi'),
'description' => __('plugins.generic.scieloTranslationsFields.originalDocumentHasDoi.description'),
Expand All @@ -37,8 +39,22 @@ public function __construct($action, $submission)
'label' => __('plugins.generic.scieloTranslationsFields.originalDocumentDoi'),
'description' => __('plugins.generic.scieloTranslationsFields.originalDocumentDoi.description'),
'isMultilingual' => false,
'value' => $publication->getData('originalDocumentDoi'),
'value' => $originalDocumentDoi,
'showWhen' => ['originalDocumentHasDoi', 1]
]));

if (!empty($originalDocumentDoi) && $placedOn == 'workflow') {
$originalDocumentCitation = $publication->getData('originalDocumentCitation');

if (empty($originalDocumentCitation)) {
$originalDocumentCitation = __('plugins.generic.scieloTranslationsFields.originalDocumentCitation.couldntRetrieve');
}

$this->addField(new FieldHTML('originalDocumentDoi', [
'label' => __('plugins.generic.scieloTranslationsFields.originalDocumentCitation'),
'description' => "<p style=\"text-align: justify\">{$originalDocumentCitation}</p>",
'showWhen' => ['originalDocumentHasDoi', 1]
]));
}
}
}
15 changes: 14 additions & 1 deletion cypress/tests/Test2_originalDoiField.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,14 @@ describe('SciELO Translations Fields - Original DOI features', function () {
cy.get('input[name="originalDocumentHasDoi"][value="1"]').check();
cy.contains('label', 'DOI');
cy.contains('Please insert the DOI of the original document this submission is translating');
cy.get('input[name="originalDocumentDoi"]').type(submissionData.originalDoi, {delay: 0});
cy.get('input[name="originalDocumentDoi"]').type('Invalid DOI', {delay: 0});
Cypress._.times(4, () => {
cy.contains('button', 'Continue').click();
});
cy.contains('The DOI entered is invalid. Please include only the identifier (e.g. "10.1234/ExampleDOI")');

cy.contains('.pkpSteps__step__label', 'Details').click();
cy.get('input[name="originalDocumentDoi"]').clear().type(submissionData.originalDoi, {delay: 0});
Cypress._.times(4, () => {
cy.contains('button', 'Continue').click();
});
Expand All @@ -117,5 +124,11 @@ describe('SciELO Translations Fields - Original DOI features', function () {
cy.get('input[name="originalDocumentHasDoi"][value="1"]').should('be.checked');
cy.contains('DOI')
cy.get('input[name="originalDocumentDoi"]').should('have.value', submissionData.originalDoi);

cy.get('input[name="originalDocumentDoi"]').clear().type('Invalid DOI', {delay: 0});
cy.get('#translationData').within(() => {
cy.contains('button', 'Save').click();
});
cy.contains('The DOI entered is invalid. Please include only the identifier (e.g. "10.1234/ExampleDOI")');
});
});
Loading

0 comments on commit 5106a3f

Please sign in to comment.