From eef07aa5ef73c5eb20f4fe55f39f07b496911a4f Mon Sep 17 00:00:00 2001 From: Thiago Brasil Date: Fri, 17 Jan 2025 15:51:30 -0400 Subject: [PATCH 1/8] Added biblys/isbn composer depedence to validate ISBN Issue: documentacao-e-tarefas/desenvolvimento_e_infra#928 Signed-off-by: Thiago Brasil --- .gitignore | 1 + composer.json | 8 ++++++ composer.lock | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 .gitignore create mode 100644 composer.json create mode 100644 composer.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..52577b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +lib/vendor \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..6334702 --- /dev/null +++ b/composer.json @@ -0,0 +1,8 @@ +{ + "require": { + "biblys/isbn": "~3.0" + }, + "config": { + "vendor-dir": "lib/vendor" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..45da6ea --- /dev/null +++ b/composer.lock @@ -0,0 +1,78 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "30bd5da4e33de53f4f7c5b93d76d158f", + "packages": [ + { + "name": "biblys/isbn", + "version": "3.2.9", + "source": { + "type": "git", + "url": "https://github.com/biblys/isbn.git", + "reference": "4e7d3779d35d62bd335d3c77b20fbd14d0b98560" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/biblys/isbn/zipball/4e7d3779d35d62bd335d3c77b20fbd14d0b98560", + "reference": "4e7d3779d35d62bd335d3c77b20fbd14d0b98560", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "ext-json": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^7.0", + "phpunit/phpunit": "^6 || ^7 || ^8 || ^11" + }, + "type": "library", + "autoload": { + "psr-0": { + "Biblys": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Clement Latzarus", + "email": "hello@clemlatz.dev" + } + ], + "description": "A PHP library to convert and validate ISBNs", + "homepage": "https://github.com/biblys/isbn", + "keywords": [ + "ISBN", + "book", + "ean", + "gtin" + ], + "support": { + "issues": "https://github.com/biblys/isbn/issues", + "source": "https://github.com/biblys/isbn/tree/3.2.9" + }, + "funding": [ + { + "url": "https://liberapay.com/clemlatz", + "type": "liberapay" + } + ], + "time": "2022-11-26T00:00:00+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.6.0" +} From 46ba5b1794fdd3f638af7ababc35eb407c500620 Mon Sep 17 00:00:00 2001 From: Thiago Brasil Date: Fri, 17 Jan 2025 15:55:14 -0400 Subject: [PATCH 2/8] Created class to validate submission metadata Issue: documentacao-e-tarefas/desenvolvimento_e_infra#928 Signed-off-by: Thiago Brasil --- classes/ThothValidator.inc.php | 58 +++++++++++++++++++++ tests/classes/ThothValidatorTest.php | 76 ++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 classes/ThothValidator.inc.php create mode 100644 tests/classes/ThothValidatorTest.php diff --git a/classes/ThothValidator.inc.php b/classes/ThothValidator.inc.php new file mode 100644 index 0000000..051dc2a --- /dev/null +++ b/classes/ThothValidator.inc.php @@ -0,0 +1,58 @@ +getApprovedByPublicationId($submission->getData('currentPublicationId')) + ->toArray(); + + $publicationFormats = array_filter($publicationFormats, function ($publicationFormat) { + return $publicationFormat->getIsAvailable(); + }); + + $errors = array_merge($errors, self::validateIsbn($publicationFormats)); + + return $errors; + } + + public static function validateIsbn($publicationFormats) + { + $errors = []; + foreach ($publicationFormats as $publicationFormat) { + try { + $isbn = ThothService::publication()->getIsbnByPublicationFormat($publicationFormat); + Isbn::validateAsIsbn13($isbn); + } catch (Exception $e) { + $errors[] = __('plugins.generic.thoth.validation.isbn', [ + 'isbn' => $isbn, + 'formatName' => $publicationFormat->getLocalizedName() + ]); + } + } + + return $errors; + } +} diff --git a/tests/classes/ThothValidatorTest.php b/tests/classes/ThothValidatorTest.php new file mode 100644 index 0000000..14c41a2 --- /dev/null +++ b/tests/classes/ThothValidatorTest.php @@ -0,0 +1,76 @@ +newDataObject(); + $identificationCode1->setCode('15'); + $identificationCode1->setValue('978395796140'); + + $mockResult1 = $this->getMockBuilder(DAOResultFactory::class) + ->setMethods(['toArray']) + ->disableOriginalConstructor() + ->getMock(); + $mockResult1->expects($this->any()) + ->method('toArray') + ->will($this->returnValue([$identificationCode1])); + + $identificationCode2 = DAORegistry::getDAO('IdentificationCodeDAO')->newDataObject(); + $identificationCode2->setCode('24'); + $identificationCode2->setValue('9783957961'); + + $mockResult2 = $this->getMockBuilder(DAOResultFactory::class) + ->setMethods(['toArray']) + ->disableOriginalConstructor() + ->getMock(); + $mockResult2->expects($this->any()) + ->method('toArray') + ->will($this->returnValue([$identificationCode2])); + + $publicationFormat = $this->getMockBuilder(PublicationFormat::class) + ->setMethods(['getIdentificationCodes']) + ->getMock(); + $publicationFormat->expects($this->any()) + ->method('getIdentificationCodes') + ->will($this->returnValue($mockResult1)); + + $publicationFormats[] = $publicationFormat; + + $publicationFormat = $this->getMockBuilder(PublicationFormat::class) + ->setMethods(['getIdentificationCodes']) + ->getMock(); + $publicationFormat->expects($this->any()) + ->method('getIdentificationCodes') + ->will($this->returnValue($mockResult2)); + + $publicationFormats[] = $publicationFormat; + + $errors = ThothValidator::validateIsbn($publicationFormats); + + $this->assertEquals([ + '##plugins.generic.thoth.validation.isbn##', + '##plugins.generic.thoth.validation.isbn##' + ], $errors); + } +} From 246c2557ab1248d8cccd70d1b3ed7dd7fd111ac3 Mon Sep 17 00:00:00 2001 From: Thiago Brasil Date: Fri, 17 Jan 2025 15:56:38 -0400 Subject: [PATCH 3/8] Validates ISBN before metadata submit Issue: documentacao-e-tarefas/desenvolvimento_e_infra#928 Signed-off-by: Thiago Brasil --- ThothPlugin.inc.php | 2 +- classes/ThothRegister.inc.php | 75 +++++++++++-------- .../services/ThothPublicationService.inc.php | 25 +------ locale/en_US/locale.po | 6 ++ locale/es_ES/locale.po | 6 ++ locale/pt_BR/locale.po | 6 ++ 6 files changed, 65 insertions(+), 55 deletions(-) diff --git a/ThothPlugin.inc.php b/ThothPlugin.inc.php index 8845d80..5b1695d 100644 --- a/ThothPlugin.inc.php +++ b/ThothPlugin.inc.php @@ -31,7 +31,7 @@ public function register($category, $path, $mainContextId = null) if ($success && $this->getEnabled()) { $thothRegister = new ThothRegister($this); HookRegistry::register('Schema::get::submission', [$thothRegister, 'addWorkIdToSchema']); - HookRegistry::register('Form::config::before', [$thothRegister, 'addImprintField']); + HookRegistry::register('Form::config::before', [$thothRegister, 'addThothField']); HookRegistry::register('Publication::validatePublish', [$thothRegister, 'validateRegister']); HookRegistry::register('TemplateManager::display', [$thothRegister, 'addResources']); HookRegistry::register('Publication::publish', [$thothRegister, 'registerOnPublish']); diff --git a/classes/ThothRegister.inc.php b/classes/ThothRegister.inc.php index a75d78f..d1f2c52 100644 --- a/classes/ThothRegister.inc.php +++ b/classes/ThothRegister.inc.php @@ -14,6 +14,7 @@ */ import('plugins.generic.thoth.classes.facades.ThothService'); +import('plugins.generic.thoth.classes.ThothValidator'); class ThothRegister { @@ -35,9 +36,8 @@ public function addWorkIdToSchema($hookName, $args) return false; } - public function addImprintField($hookName, $form) + public function addThothField($hookName, $form) { - if ($form->id !== 'publish' || !empty($form->errors)) { return; } @@ -48,48 +48,63 @@ public function addImprintField($hookName, $form) return; } + $errors = []; + try { $thothClient = $this->plugin->getThothClient($submission->getData('contextId')); $publishers = $thothClient->linkedPublishers(); $imprints = $thothClient->imprints(['publishers' => array_column($publishers, 'publisherId')]); + } catch (ThothException $e) { + $errors[] = __('plugins.generic.thoth.connectionError'); + error_log($e->getMessage()); + } - $imprintOptions = []; - foreach ($imprints as $imprint) { - $imprintOptions[] = [ - 'value' => $imprint['imprintId'], - 'label' => $imprint['imprintName'] - ]; - } + if (empty($errors)) { + $errors = ThothValidator::validate($submission); + } - $form->addField(new \PKP\components\forms\FieldOptions('registerConfirmation', [ - 'label' => __('plugins.generic.thoth.register.label'), - 'options' => [ - ['value' => true, 'label' => __('plugins.generic.thoth.register.confirmation')] - ], - 'value' => false, - 'groupId' => 'default', - ])) - ->addField(new \PKP\components\forms\FieldSelect('imprint', [ - 'label' => __('plugins.generic.thoth.imprint'), - 'options' => $imprintOptions, - 'required' => true, - 'showWhen' => 'registerConfirmation', - 'groupId' => 'default', - 'value' => $imprints[0]['imprintId'] ?? null - ])); - } catch (ThothException $e) { - $warningIconHtml = ''; - $noticeMsg = __('plugins.generic.thoth.connectionError'); - $msg = '
' . $warningIconHtml . $noticeMsg . '
'; + if (!empty($errors)) { + $msg = '
'; + $msg .= __('plugins.generic.thoth.register.warning'); + $msg .= '
    '; + foreach ($errors as $error) { + $msg .= '
  • ' . $error . '
  • '; + } + $msg .= '
'; $form->addField(new \PKP\components\forms\FieldHTML('registerNotice', [ 'description' => $msg, 'groupId' => 'default', ])); - error_log($e->getMessage()); + return false; } + $imprintOptions = []; + foreach ($imprints as $imprint) { + $imprintOptions[] = [ + 'value' => $imprint['imprintId'], + 'label' => $imprint['imprintName'] + ]; + } + + $form->addField(new \PKP\components\forms\FieldOptions('registerConfirmation', [ + 'label' => __('plugins.generic.thoth.register.label'), + 'options' => [ + ['value' => true, 'label' => __('plugins.generic.thoth.register.confirmation')] + ], + 'value' => false, + 'groupId' => 'default', + ])) + ->addField(new \PKP\components\forms\FieldSelect('imprint', [ + 'label' => __('plugins.generic.thoth.imprint'), + 'options' => $imprintOptions, + 'required' => true, + 'showWhen' => 'registerConfirmation', + 'groupId' => 'default', + 'value' => $imprints[0]['imprintId'] ?? null + ])); + return false; } diff --git a/classes/services/ThothPublicationService.inc.php b/classes/services/ThothPublicationService.inc.php index 3871ca6..9d47f78 100644 --- a/classes/services/ThothPublicationService.inc.php +++ b/classes/services/ThothPublicationService.inc.php @@ -169,33 +169,10 @@ public function getIsbnByPublicationFormat($publicationFormat) $identificationCodes = $publicationFormat->getIdentificationCodes()->toArray(); foreach ($identificationCodes as $identificationCode) { if ($identificationCode->getCode() == "15" || $identificationCode->getCode() == "24") { - $isbn = $identificationCode->getValue(); - return $this->convertToIsbn13($isbn); + return $identificationCode->getValue(); } } return null; } - - private function convertToIsbn13($isbnString) - { - if (preg_match('/(?=.{17}$)97(?:8|9)([ -])\d{1,5}\1\d{1,7}\1\d{1,6}\1\d$/', $isbnString)) { - return $isbnString; - } - - $isbnNumber = preg_replace('/\D/', '', $isbnString); - - if (strlen($isbnNumber) != 13) { - return $isbnString; - } - - return sprintf( - '%s-%s-%s-%s-%s', - substr($isbnNumber, 0, 3), - substr($isbnNumber, 3, 1), - substr($isbnNumber, 4, 2), - substr($isbnNumber, 6, 6), - substr($isbnNumber, 12, 1) - ); - } } diff --git a/locale/en_US/locale.po b/locale/en_US/locale.po index 33eeeb1..7897aeb 100644 --- a/locale/en_US/locale.po +++ b/locale/en_US/locale.po @@ -48,6 +48,12 @@ msgstr "Register" msgid "plugins.generic.thoth.register.label" msgstr "Thoth registration" +msgid "plugins.generic.thoth.register.warning" +msgstr "The submission metadata can not be submitted to Thoth because of the following errors:" + +msgid "plugins.generic.thoth.validation.isbn" +msgstr "\"{$isbn}\" of \"{$formatName}\" publication format is not a valid ISBN-13. A valid ISBN-13 must be exactly 17 characters (numbers and hyphens)." + msgid "plugins.generic.thoth.register.confirmation" msgstr "Do you want to register in Thoth the metadata related to this submission?" diff --git a/locale/es_ES/locale.po b/locale/es_ES/locale.po index 4a23595..1632c05 100644 --- a/locale/es_ES/locale.po +++ b/locale/es_ES/locale.po @@ -48,6 +48,12 @@ msgstr "Registrar" msgid "plugins.generic.thoth.register.label" msgstr "Registro en Thoth" +msgid "plugins.generic.thoth.register.warning" +msgstr "Los metadatos de envio no pueden ser enviados a Thoth debido a los siguientes errores:" + +msgid "plugins.generic.thoth.validation.isbn" +msgstr "\"{$isbn}\" del formato de publicación \"{$formatName}\" no es un ISBN-13 válido. Un ISBN-13 válido debe tener exactamente 17 caracteres (números y guiones)." + msgid "plugins.generic.thoth.register.confirmation" msgstr "¿Desea registrar en Thoth los metadatos relacionados con este envío?" diff --git a/locale/pt_BR/locale.po b/locale/pt_BR/locale.po index 293ec00..4db8476 100644 --- a/locale/pt_BR/locale.po +++ b/locale/pt_BR/locale.po @@ -48,6 +48,12 @@ msgstr "Registrar" msgid "plugins.generic.thoth.register.label" msgstr "Registro em Thoth" +msgid "plugins.generic.thoth.register.warning" +msgstr "Os metadados da submissão não podem ser enviados para Thoth devido aos seguintes erros:" + +msgid "plugins.generic.thoth.validation.isbn" +msgstr "\"{$isbn}\" do formato de publicação \"{$formatName}\" não é um ISBN-13 válido. Um ISBN-13 válido deve ter exatamente 17 caracteres (números e hífens)." + msgid "plugins.generic.thoth.register.confirmation" msgstr "Deseja realmente registrar na Thoth os metadados relacionados a essa submissão?" From 3df7e9c28423da9799818de4dd6548c682769284 Mon Sep 17 00:00:00 2001 From: Thiago Brasil Date: Fri, 17 Jan 2025 15:59:12 -0400 Subject: [PATCH 4/8] Validates ISBN before metadata submit of published submissions Issue: documentacao-e-tarefas/desenvolvimento_e_infra#928 Signed-off-by: Thiago Brasil --- classes/components/forms/RegisterForm.inc.php | 16 ++++++++++------ controllers/modal/RegisterHandler.inc.php | 2 ++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/classes/components/forms/RegisterForm.inc.php b/classes/components/forms/RegisterForm.inc.php index 6a3aaa0..28fc9af 100644 --- a/classes/components/forms/RegisterForm.inc.php +++ b/classes/components/forms/RegisterForm.inc.php @@ -39,14 +39,18 @@ public function __construct($action, $imprints, $errors) 'pageId' => 'default', ]); + $msg = '
'; + $msg .= __('plugins.generic.thoth.register.warning'); + $msg .= '
    '; foreach ($errors as $error) { - $warningIconHtml = ''; - $msg = '
    ' . $warningIconHtml . $error . '
    '; - $this->addField(new \PKP\components\forms\FieldHTML('registerNotice', [ - 'description' => $msg, - 'groupId' => 'default', - ])); + $msg .= '
  • ' . $error . '
  • '; } + $msg .= '
'; + + $this->addField(new \PKP\components\forms\FieldHTML('registerNotice', [ + 'description' => $msg, + 'groupId' => 'default', + ])); return; } diff --git a/controllers/modal/RegisterHandler.inc.php b/controllers/modal/RegisterHandler.inc.php index a4ff872..3ead2cc 100644 --- a/controllers/modal/RegisterHandler.inc.php +++ b/controllers/modal/RegisterHandler.inc.php @@ -86,6 +86,8 @@ public function register($args, $request) $thothClient = $plugin->getThothClient($submissionContext->getId()); $publishers = $thothClient->linkedPublishers(); $imprints = $thothClient->imprints(['publishers' => array_column($publishers, 'publisherId')]); + + $errors = array_merge(ThothValidator::validate($this->submission), $errors); } catch (ThothException $e) { $errors[] = __('plugins.generic.thoth.connectionError'); error_log($e->getMessage()); From 37b97f63810633006cfba71cb3550d49ef7b99be Mon Sep 17 00:00:00 2001 From: Thiago Brasil Date: Fri, 17 Jan 2025 16:06:13 -0400 Subject: [PATCH 5/8] Installs composer dependencies in GitLab CI Issue: documentacao-e-tarefas/desenvolvimento_e_infra#928 Signed-off-by: Thiago Brasil --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0605aa5..1219fc7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,3 +12,4 @@ include: before_script: - rm -rf lib/APIKeyEncryption - git submodule update --init --depth 1 + - composer install From 8b44ebf9ff43f61eb136259b850309d7742a54bc Mon Sep 17 00:00:00 2001 From: Thiago Brasil Date: Fri, 17 Jan 2025 16:22:38 -0400 Subject: [PATCH 6/8] Changes composer dir Issue: documentacao-e-tarefas/desenvolvimento_e_infra#928 Signed-off-by: Thiago Brasil --- .gitignore | 2 +- classes/ThothValidator.inc.php | 2 +- composer.json | 5 +---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 52577b3..5657f6e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -lib/vendor \ No newline at end of file +vendor \ No newline at end of file diff --git a/classes/ThothValidator.inc.php b/classes/ThothValidator.inc.php index 051dc2a..d5ba06f 100644 --- a/classes/ThothValidator.inc.php +++ b/classes/ThothValidator.inc.php @@ -13,7 +13,7 @@ * @brief Validate submission metadata to Thoth submit */ -require_once(__DIR__ . '/../lib/vendor/autoload.php'); +require_once(__DIR__ . '/../vendor/autoload.php'); use Biblys\Isbn\Isbn; diff --git a/composer.json b/composer.json index 6334702..84515fe 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,5 @@ { "require": { "biblys/isbn": "~3.0" - }, - "config": { - "vendor-dir": "lib/vendor" - } + } } From da9006b77428c06409ac9a516101044a195d20c7 Mon Sep 17 00:00:00 2001 From: Thiago Brasil Date: Fri, 17 Jan 2025 16:30:09 -0400 Subject: [PATCH 7/8] Installs composer dependencies to generate package Issue: documentacao-e-tarefas/desenvolvimento_e_infra#928 Signed-off-by: Thiago Brasil --- .github/workflows/generate-package.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/generate-package.yml b/.github/workflows/generate-package.yml index e0d702c..76f8d7a 100644 --- a/.github/workflows/generate-package.yml +++ b/.github/workflows/generate-package.yml @@ -34,6 +34,8 @@ jobs: mkdir $PLUGIN_NAME shopt -s extglob cp -r !($PLUGIN_NAME|.git*|.|..|tests) $PLUGIN_NAME + wget -O composer.phar https://getcomposer.org/composer-stable.phar + php composer.phar install -d ${PLUGIN_NAME} tar -zcvf $PLUGIN_NAME.tar.gz $PLUGIN_NAME shell: bash - name: Create the release @@ -47,7 +49,7 @@ jobs: draft: false prerelease: false - name: Upload the package as release asset - id: upload-release-asset + id: upload-release-asset uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 8532020c823ed80ac833023490141b62e3c1e5b9 Mon Sep 17 00:00:00 2001 From: Thiago Brasil Date: Fri, 17 Jan 2025 16:37:42 -0400 Subject: [PATCH 8/8] Update version.xml Issue: documentacao-e-tarefas/desenvolvimento_e_infra#928 Signed-off-by: Thiago Brasil --- version.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.xml b/version.xml index 83624f1..5979522 100644 --- a/version.xml +++ b/version.xml @@ -3,8 +3,8 @@ thoth plugins.generic - 0.1.3.4 - 2025-01-15 + 0.1.4.0 + 2025-01-17 1 ThothPlugin