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 }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5657f6e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vendor \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 633bf25..3807210 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,3 +7,7 @@ include: file: - 'templates/groups/pkp_plugin.yml' - 'templates/groups/omp/unit_tests.yml' + +.unit_test_template: + before_script: + - composer install diff --git a/ThothPlugin.inc.php b/ThothPlugin.inc.php index 47274c4..db1525d 100644 --- a/ThothPlugin.inc.php +++ b/ThothPlugin.inc.php @@ -36,7 +36,7 @@ public function register($category, $path, $mainContextId = null) $thothRegister = new ThothRegister($this); HookRegistry::register('Schema::get::submission', [$thothRegister, 'addWorkIdToSchema']); HookRegistry::register('Schema::get::eventLog', [$thothRegister, 'addReasonToSchema']); - 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 b0f1d0e..ad0a240 100644 --- a/classes/ThothRegister.inc.php +++ b/classes/ThothRegister.inc.php @@ -20,6 +20,7 @@ use PKP\security\Role; import('plugins.generic.thoth.classes.facades.ThothService'); +import('plugins.generic.thoth.classes.ThothValidator'); class ThothRegister { @@ -52,7 +53,7 @@ public function addReasonToSchema($hookName, $args) return false; } - public function addImprintField($hookName, $form) + public function addThothField($hookName, $form) { if ($form->id !== 'publish' || !empty($form->errors)) { @@ -65,48 +66,107 @@ 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 .= '
'; $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; + + // try { + // $thothClient = $this->plugin->getThothClient($submission->getData('contextId')); + // $publishers = $thothClient->linkedPublishers(); + // $imprints = $thothClient->imprints(['publishers' => array_column($publishers, 'publisherId')]); + + // $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 + // ])); + // } catch (ThothException $e) { + // $warningIconHtml = ''; + // $noticeMsg = __('plugins.generic.thoth.connectionError'); + // $msg = '
' . $warningIconHtml . $noticeMsg . '
'; + + // $form->addField(new \PKP\components\forms\FieldHTML('registerNotice', [ + // 'description' => $msg, + // 'groupId' => 'default', + // ])); + + // error_log($e->getMessage()); + // } + return false; } diff --git a/classes/ThothValidator.inc.php b/classes/ThothValidator.inc.php new file mode 100644 index 0000000..99950d4 --- /dev/null +++ b/classes/ThothValidator.inc.php @@ -0,0 +1,59 @@ +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/classes/components/forms/RegisterForm.inc.php b/classes/components/forms/RegisterForm.inc.php index ccd000b..8ee19a1 100644 --- a/classes/components/forms/RegisterForm.inc.php +++ b/classes/components/forms/RegisterForm.inc.php @@ -40,14 +40,18 @@ public function __construct($action, $imprints, $errors) 'pageId' => 'default', ]); + $msg = '
'; + $msg .= __('plugins.generic.thoth.register.warning'); + $msg .= '
'; + + $this->addField(new \PKP\components\forms\FieldHTML('registerNotice', [ + 'description' => $msg, + 'groupId' => 'default', + ])); return; } diff --git a/classes/services/ThothPublicationService.inc.php b/classes/services/ThothPublicationService.inc.php index 22cd755..559b511 100644 --- a/classes/services/ThothPublicationService.inc.php +++ b/classes/services/ThothPublicationService.inc.php @@ -176,33 +176,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; } - - public 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/composer.json b/composer.json new file mode 100644 index 0000000..84515fe --- /dev/null +++ b/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "biblys/isbn": "~3.0" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..2ac77c3 --- /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": "88decabdccce7eed3f298f826e3365a00f895a05" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/biblys/isbn/zipball/88decabdccce7eed3f298f826e3365a00f895a05", + "reference": "88decabdccce7eed3f298f826e3365a00f895a05", + "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" +} diff --git a/controllers/modal/RegisterHandler.inc.php b/controllers/modal/RegisterHandler.inc.php index 4488efb..b36a8bc 100644 --- a/controllers/modal/RegisterHandler.inc.php +++ b/controllers/modal/RegisterHandler.inc.php @@ -22,6 +22,7 @@ use PKP\security\Role; import('classes.handler.Handler'); +import('plugins.generic.thoth.classes.ThothValidator'); class RegisterHandler extends Handler { @@ -90,6 +91,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()); diff --git a/locale/en/locale.po b/locale/en/locale.po index 33eeeb1..7897aeb 100644 --- a/locale/en/locale.po +++ b/locale/en/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/locale.po b/locale/es/locale.po index 4a23595..1632c05 100644 --- a/locale/es/locale.po +++ b/locale/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?" diff --git a/tests/classes/ThothValidateTest.php b/tests/classes/ThothValidateTest.php new file mode 100644 index 0000000..597b847 --- /dev/null +++ b/tests/classes/ThothValidateTest.php @@ -0,0 +1,89 @@ +makePartial() + ->shouldReceive('getLocalizedName') + ->withAnyArgs() + ->andReturn('PDF') + ->shouldReceive('getIdentificationCodes') + ->withAnyArgs() + ->andReturn( + Mockery::mock(\PKP\db\DAOResultFactory::class) + ->makePartial() + ->shouldReceive('toArray') + ->withAnyArgs() + ->andReturn([ + Mockery::mock(\APP\publicationFormat\IdentificationCode::class) + ->makePartial() + ->shouldReceive('getCode') + ->withAnyArgs() + ->andReturn('24') + ->shouldReceive('getValue') + ->withAnyArgs() + ->andReturn('97-83-9-579-61') + ->getMock() + ]) + ->getMock() + ) + ->getMock(), + Mockery::mock(\APP\publicationFormat\PublicationFormat::class) + ->makePartial() + ->shouldReceive('getLocalizedName') + ->withAnyArgs() + ->andReturn('EPUB') + ->shouldReceive('getIdentificationCodes') + ->withAnyArgs() + ->andReturn( + Mockery::mock(\PKP\db\DAOResultFactory::class) + ->makePartial() + ->shouldReceive('toArray') + ->withAnyArgs() + ->andReturn([ + Mockery::mock(\APP\publicationFormat\IdentificationCode::class) + ->makePartial() + ->shouldReceive('getCode') + ->withAnyArgs() + ->andReturn('15') + ->shouldReceive('getValue') + ->withAnyArgs() + ->andReturn('978395796140') + ->getMock() + ]) + ->getMock() + ) + ->getMock(), + ]; + + $errors = ThothValidator::validateIsbn($publicationFormats); + + $this->assertEquals([ + '##plugins.generic.thoth.validation.isbn##', + '##plugins.generic.thoth.validation.isbn##' + ], $errors); + } +} diff --git a/version.xml b/version.xml index 4dc3d8e..4a4cacc 100644 --- a/version.xml +++ b/version.xml @@ -3,8 +3,8 @@ thoth plugins.generic - 0.2.1.5 - 2025-01-15 + 0.2.2.0 + 2025-01-18 1 ThothPlugin