Skip to content

Commit d8056c2

Browse files
Merge pull request #63 from lepidus/main
Add publication accessibility metadata (OMP 3.5.0)
2 parents a4cb5f4 + 810d0fe commit d8056c2

25 files changed

Lines changed: 1313 additions & 282 deletions

classes/components/forms/config/PublishFormConfig.php

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use APP\plugins\generic\thoth\classes\facades\ThothService;
2222
use APP\plugins\generic\thoth\classes\notification\ThothNotification;
2323
use APP\submission\Submission;
24+
use Exception;
2425
use ThothApi\GraphQL\Models\Work as ThothWork;
2526

2627
class PublishFormConfig
@@ -32,18 +33,17 @@ public function addConfig($hookName, $form)
3233
}
3334

3435
$publication = $form->publication;
35-
$submission = Repo::submission()->get($publication->getData('submissionId'));
36+
$submission = $this->getSubmission($publication);
3637

3738
if ($submission->getData('thothWorkId')) {
3839
return;
3940
}
4041

4142
try {
42-
$errors = ThothService::book()->validate($publication);
43+
$errors = $this->validatePublication($publication);
4344

4445
if (empty($errors)) {
45-
$publishers = ThothRepository::account()->getLinkedPublishers();
46-
$imprints = ThothRepository::imprint()->getMany(array_column($publishers, 'publisherId'));
46+
$imprints = $this->getImprints();
4747
}
4848
} catch (Exception $e) {
4949
error_log($e->getMessage());
@@ -60,6 +60,22 @@ public function addConfig($hookName, $form)
6060
return false;
6161
}
6262

63+
protected function getSubmission($publication)
64+
{
65+
return Repo::submission()->get($publication->getData('submissionId'));
66+
}
67+
68+
protected function validatePublication($publication): array
69+
{
70+
return ThothService::book()->validate($publication);
71+
}
72+
73+
protected function getImprints(): array
74+
{
75+
$publishers = ThothRepository::account()->getLinkedPublishers();
76+
return ThothRepository::imprint()->getMany(array_column($publishers, 'publisherId'));
77+
}
78+
6379
private function addFields($form, $imprints, $workType)
6480
{
6581
$imprintOptions = [];

classes/container/providers/ThothRepositoryProvider.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,13 @@ public function register($container)
8383
});
8484

8585
$container->set('accountRepository', function ($container) {
86-
return new ThothAccountRepository($container->get('client'));
86+
$config = $container->get('config');
87+
$httpConfig = [];
88+
if ($config['customThothApi'] && $config['customThothApiUrl']) {
89+
$httpConfig['base_uri'] = trim($config['customThothApiUrl']);
90+
}
91+
92+
return new ThothAccountRepository($container->get('client'), $httpConfig, $config['token']);
8793
});
8894

8995
$container->set('abstractRepository', function ($container) {

classes/factories/ThothPublicationFactory.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@
2020

2121
class ThothPublicationFactory
2222
{
23+
private const ACCESSIBILITY_FIELDS = [
24+
'accessibilityStandard',
25+
'accessibilityAdditionalStandard',
26+
'accessibilityException',
27+
'accessibilityReportUrl',
28+
];
29+
2330
private const PHYSICAL_PUBLICATION_TYPE_MAPPING = [
2431
'BC' => ThothPublication::PUBLICATION_TYPE_PAPERBACK,
2532
'BB' => ThothPublication::PUBLICATION_TYPE_HARDBACK,
@@ -76,10 +83,19 @@ class ThothPublicationFactory
7683

7784
public function createFromPublicationFormat($publicationFormat, $submissionFile = null)
7885
{
79-
return new ThothPublication([
86+
$publicationData = [
8087
'publicationType' => $this->getPublicationTypeByPublicationFormat($publicationFormat, $submissionFile),
81-
'isbn' => $this->getIsbnByPublicationFormat($publicationFormat)
82-
]);
88+
'isbn' => $this->getIsbnByPublicationFormat($publicationFormat),
89+
];
90+
91+
foreach (self::ACCESSIBILITY_FIELDS as $fieldName) {
92+
$fieldValue = $publicationFormat->getData($fieldName);
93+
if ($fieldValue !== null && $fieldValue !== '') {
94+
$publicationData[$fieldName] = $fieldValue;
95+
}
96+
}
97+
98+
return new ThothPublication($publicationData);
8399
}
84100

85101
private function getPublicationTypeByPublicationFormat($publicationFormat, $submissionFile = null)

classes/hooks/HookRegistrant.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public function register(): void
4242
{
4343
$this->registerSchema();
4444
$this->registerFormConfigs();
45+
$this->registerLegacyForms();
4546
$this->registerListeners();
4647
$this->registerEndpoints();
4748
$this->registerTemplateHooks();
@@ -64,6 +65,19 @@ private function registerFormConfigs(): void
6465
Hook::add('Form::config::before', (new ContributorFormConfig())->addConfig(...));
6566
}
6667

68+
private function registerLegacyForms(): void
69+
{
70+
$publicationFormatFormHandler = new PublicationFormatFormHandler($this->plugin);
71+
Hook::add(
72+
'publicationformatdao::getAdditionalFieldNames',
73+
$publicationFormatFormHandler->addAccessibilityFieldNames(...)
74+
);
75+
Hook::add('publicationformatform::display', $publicationFormatFormHandler->addAccessibilityFields(...));
76+
Hook::add('publicationformatform::readuservars', $publicationFormatFormHandler->addAccessibilityUserVars(...));
77+
Hook::add('publicationformatform::validate', $publicationFormatFormHandler->validateAccessibilityFields(...));
78+
Hook::add('publicationformatform::execute', $publicationFormatFormHandler->saveAccessibilityFields(...));
79+
}
80+
6781
private function registerListeners(): void
6882
{
6983
$publicationPublishListener = new PublicationPublishListener();
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
3+
/**
4+
* @file plugins/generic/thoth/classes/hooks/PublicationFormatFormHandler.php
5+
*
6+
* Copyright (c) 2024-2026 Lepidus Tecnologia
7+
* Copyright (c) 2024-2026 Thoth
8+
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
9+
*
10+
* @class PublicationFormatFormHandler
11+
*
12+
* @ingroup plugins_generic_thoth
13+
*
14+
* @brief Handles Thoth accessibility metadata in OMP publication format forms
15+
*/
16+
17+
namespace APP\plugins\generic\thoth\classes\hooks;
18+
19+
use APP\plugins\generic\thoth\classes\templateFilters\PublicationFormatTemplateFilter;
20+
use APP\template\TemplateManager;
21+
use PKP\plugins\GenericPlugin;
22+
23+
class PublicationFormatFormHandler
24+
{
25+
public const ACCESSIBILITY_FIELDS = [
26+
'accessibilityStandard',
27+
'accessibilityAdditionalStandard',
28+
'accessibilityException',
29+
'accessibilityReportUrl',
30+
];
31+
32+
private GenericPlugin $plugin;
33+
34+
public function __construct(GenericPlugin $plugin)
35+
{
36+
$this->plugin = $plugin;
37+
}
38+
39+
public function addAccessibilityFields($hookName, $args): bool
40+
{
41+
$form = $args[0];
42+
$templateMgr = TemplateManager::getManager();
43+
$publicationFormat = $form->getPublicationFormat();
44+
45+
foreach (self::ACCESSIBILITY_FIELDS as $fieldName) {
46+
if ($publicationFormat && $form->getData($fieldName) === null) {
47+
$form->setData($fieldName, $publicationFormat->getData($fieldName));
48+
}
49+
}
50+
51+
$templateMgr->assign([
52+
'thothAccessibilityStandardOptions' => $this->getAccessibilityStandardOptions(),
53+
'thothAccessibilityExceptionOptions' => $this->getAccessibilityExceptionOptions(),
54+
]);
55+
56+
(new PublicationFormatTemplateFilter($this->plugin))->register($templateMgr);
57+
58+
return false;
59+
}
60+
61+
public function addAccessibilityFieldNames($hookName, $dao, &$fieldNames): bool
62+
{
63+
$fieldNames = array_values(array_unique(array_merge($fieldNames, self::ACCESSIBILITY_FIELDS)));
64+
65+
return false;
66+
}
67+
68+
public function addAccessibilityUserVars($hookName, $args): bool
69+
{
70+
$vars = & $args[1];
71+
$vars = array_unique(array_merge($vars, self::ACCESSIBILITY_FIELDS));
72+
73+
return false;
74+
}
75+
76+
public function validateAccessibilityFields($hookName, $args): bool
77+
{
78+
$form = $args[0];
79+
$reportUrl = trim((string) $form->getData('accessibilityReportUrl'));
80+
81+
if ($reportUrl !== '' && filter_var($reportUrl, FILTER_VALIDATE_URL) === false) {
82+
$form->addError(
83+
'accessibilityReportUrl',
84+
__('plugins.generic.thoth.publicationFormat.accessibilityReportUrl.invalid')
85+
);
86+
}
87+
88+
return false;
89+
}
90+
91+
public function saveAccessibilityFields($hookName, $args): bool
92+
{
93+
$form = $args[0];
94+
$publicationFormat = $form->getPublicationFormat();
95+
96+
if (!$publicationFormat) {
97+
return false;
98+
}
99+
100+
foreach (self::ACCESSIBILITY_FIELDS as $fieldName) {
101+
$publicationFormat->setData($fieldName, $this->normalizeOptionalValue($form->getData($fieldName)));
102+
}
103+
104+
return false;
105+
}
106+
107+
private function normalizeOptionalValue($value): ?string
108+
{
109+
$value = trim((string) $value);
110+
return $value === '' ? null : $value;
111+
}
112+
113+
private function getAccessibilityStandardOptions(): array
114+
{
115+
return [
116+
'' => 'common.none',
117+
'WCAG21AA' => 'plugins.generic.thoth.publicationFormat.accessibilityStandard.wcag21aa',
118+
'WCAG21AAA' => 'plugins.generic.thoth.publicationFormat.accessibilityStandard.wcag21aaa',
119+
'WCAG22AA' => 'plugins.generic.thoth.publicationFormat.accessibilityStandard.wcag22aa',
120+
'WCAG22AAA' => 'plugins.generic.thoth.publicationFormat.accessibilityStandard.wcag22aaa',
121+
'EPUB_A11Y10AA' => 'plugins.generic.thoth.publicationFormat.accessibilityStandard.epubA11y10aa',
122+
'EPUB_A11Y10AAA' => 'plugins.generic.thoth.publicationFormat.accessibilityStandard.epubA11y10aaa',
123+
'EPUB_A11Y11AA' => 'plugins.generic.thoth.publicationFormat.accessibilityStandard.epubA11y11aa',
124+
'EPUB_A11Y11AAA' => 'plugins.generic.thoth.publicationFormat.accessibilityStandard.epubA11y11aaa',
125+
'PDF_UA1' => 'plugins.generic.thoth.publicationFormat.accessibilityStandard.pdfUa1',
126+
'PDF_UA2' => 'plugins.generic.thoth.publicationFormat.accessibilityStandard.pdfUa2',
127+
];
128+
}
129+
130+
private function getAccessibilityExceptionOptions(): array
131+
{
132+
return [
133+
'' => 'common.none',
134+
'MICRO_ENTERPRISES' => 'plugins.generic.thoth.publicationFormat.accessibilityException.microEnterprises',
135+
'DISPROPORTIONATE_BURDEN' => 'plugins.generic.thoth.publicationFormat.accessibilityException.disproportionateBurden',
136+
'FUNDAMENTAL_ALTERATION' => 'plugins.generic.thoth.publicationFormat.accessibilityException.fundamentalAlteration',
137+
];
138+
}
139+
}

classes/repositories/ThothAccountRepository.php

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,57 @@
1616

1717
namespace APP\plugins\generic\thoth\classes\repositories;
1818

19+
use ThothApi\GraphQL\Client;
20+
use ThothApi\GraphQL\Request;
21+
1922
class ThothAccountRepository
2023
{
24+
private const ME_WITH_PUBLISHERS_QUERY = <<<GQL
25+
query {
26+
me {
27+
publisherContexts {
28+
publisher {
29+
publisherId
30+
publisherName
31+
}
32+
permissions {
33+
publisherAdmin
34+
workLifecycle
35+
cdnWrite
36+
}
37+
}
38+
}
39+
}
40+
GQL;
41+
2142
protected $thothClient;
43+
protected array $httpConfig;
44+
protected string $token;
2245

23-
public function __construct($thothClient)
46+
public function __construct($thothClient, array $httpConfig = [], string $token = '')
2447
{
2548
$this->thothClient = $thothClient;
49+
$this->httpConfig = $httpConfig;
50+
$this->token = $token;
2651
}
2752

2853
public function getLinkedPublishers()
2954
{
30-
$publisherContexts = $this->thothClient->me()->getPublisherContexts() ?? [];
55+
$publisherContexts = $this->token
56+
? $this->getPublisherContextsWithPublishers()
57+
: $this->thothClient->me()->getPublisherContexts() ?? [];
3158

3259
return array_values(array_map(
3360
fn (array $publisherContext) => $publisherContext['publisher'],
3461
array_filter($publisherContexts, fn (array $publisherContext) => !empty($publisherContext['publisher']))
3562
));
3663
}
64+
65+
protected function getPublisherContextsWithPublishers(): array
66+
{
67+
$httpConfig = $this->httpConfig ?: ['base_uri' => Client::THOTH_BASE_URI];
68+
$response = (new Request($httpConfig))->runQuery(self::ME_WITH_PUBLISHERS_QUERY, null, $this->token);
69+
70+
return $response->getData()['me']['publisherContexts'] ?? [];
71+
}
3772
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
/**
4+
* @file plugins/generic/thoth/classes/templateFilters/PublicationFormatTemplateFilter.php
5+
*
6+
* Copyright (c) 2024-2026 Lepidus Tecnologia
7+
* Copyright (c) 2024-2026 Thoth
8+
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
9+
*
10+
* @class PublicationFormatTemplateFilter
11+
*
12+
* @ingroup plugins_generic_thoth
13+
*
14+
* @brief Injects Thoth accessibility fields into OMP publication format forms
15+
*/
16+
17+
namespace APP\plugins\generic\thoth\classes\templateFilters;
18+
19+
use PKP\plugins\GenericPlugin;
20+
21+
class PublicationFormatTemplateFilter
22+
{
23+
private const FORMAT_FORM_ID = 'addPublicationFormatForm';
24+
private const ISBN_SECTION_END = '{/fbvFormSection}';
25+
26+
private GenericPlugin $plugin;
27+
28+
public function __construct(GenericPlugin $plugin)
29+
{
30+
$this->plugin = $plugin;
31+
}
32+
33+
public function register($templateMgr): void
34+
{
35+
$templateMgr->registerFilter('output', $this->injectAccessibilityFields(...));
36+
}
37+
38+
public function injectAccessibilityFields(string $output, $template): string
39+
{
40+
if (
41+
strpos($output, self::FORMAT_FORM_ID) === false
42+
|| strpos($output, 'id="accessibilityStandard"') !== false
43+
) {
44+
return $output;
45+
}
46+
47+
$partial = $template->smarty->fetch(
48+
$this->plugin->getTemplateResource('publicationFormatAccessibilityFields.tpl')
49+
);
50+
51+
$isbnTitle = __('grid.catalogEntry.isbn');
52+
$isbnTitlePosition = strpos($output, $isbnTitle);
53+
if ($isbnTitlePosition === false) {
54+
return $output;
55+
}
56+
57+
$insertionPosition = strpos($output, '</fieldset>', $isbnTitlePosition);
58+
if ($insertionPosition === false) {
59+
return $output;
60+
}
61+
62+
return substr_replace($output, $partial, $insertionPosition + strlen('</fieldset>'), 0);
63+
}
64+
}

docs/images/plugin_settings.png

6.06 KB
Loading

0 commit comments

Comments
 (0)