Skip to content

Commit 552d782

Browse files
Merge branch 'modifyCrossrefDeposit-330-902' into 'stable-3_3_0'
Adicionar relação de conjunto de dados na exportação Crossref - 3.3.0 See merge request softwares-pkp/plugins_ojs/dataverse!219
2 parents 650a48c + e6dca67 commit 552d782

19 files changed

Lines changed: 609 additions & 11 deletions

.gitlab-ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ include:
1313
.integration_tests_template:
1414
before_script:
1515
- sed -i "s/api_key_secret = \"\"/api_key_secret = \"$API_KEY_SECRET\"/" /var/www/$CY_APPLICATION/config.inc.php
16+
17+
ojs_integration_tests:
18+
rules:
19+
- when: never

DataversePlugin.inc.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ private function loadDispatcherClasses(): void
4545
'DatasetTabDispatcher',
4646
'DatasetReviewDispatcher',
4747
'DataverseEventsDispatcher',
48-
'DraftDatasetFilesDispatcher'
48+
'DraftDatasetFilesDispatcher',
49+
'CrossrefDispatcher'
4950
];
5051

5152
foreach ($dispatcherClasses as $dispatcherClass) {

classes/CrossrefXmlEditor.inc.php

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
import('plugins.generic.dataverse.classes.dataverseStudy.DataverseStudyDAO');
4+
import('plugins.generic.dataverse.dataverseAPI.actions.DatasetActions');
5+
import('plugins.generic.dataverse.classes.exception.DataverseException');
6+
7+
use Illuminate\Database\Capsule\Manager as Capsule;
8+
9+
class CrossrefXmlEditor
10+
{
11+
private const RELATIONS_NAMESPACE = 'http://www.crossref.org/relations.xsd';
12+
13+
private $datasetActions;
14+
15+
public function __construct(?DatasetActions $actions = null)
16+
{
17+
$this->datasetActions = $actions ?? (new DatasetActions());
18+
}
19+
20+
public function addDatasetRelationToDepositXml(DOMDocument $depositXml): DOMDocument
21+
{
22+
$submissionNodes = $depositXml->getElementsByTagName('journal_article');
23+
if ($submissionNodes->count() == 0) {
24+
$submissionNodes = $depositXml->getElementsByTagName('posted_content');
25+
}
26+
27+
foreach ($submissionNodes as $submissionNode) {
28+
$doiDataNode = $submissionNode->getElementsByTagName('doi_data')->item(0);
29+
$doiNode = $doiDataNode->getElementsByTagName('doi')->item(0);
30+
$doi = $doiNode->nodeValue;
31+
32+
$submissionId = Capsule::table('publications as p')
33+
->leftJoin('publication_settings as ps', 'p.publication_id', '=', 'ps.publication_id')
34+
->where('ps.setting_name', '=', 'pub-id::doi')
35+
->where('ps.setting_value', '=', $doi)
36+
->value('p.submission_id');
37+
38+
if (!$submissionId) {
39+
continue;
40+
}
41+
42+
$dataverseStudyDao = new DataverseStudyDAO();
43+
$study = $dataverseStudyDao->getStudyBySubmissionId($submissionId);
44+
if (!$study) {
45+
continue;
46+
}
47+
48+
try {
49+
$dataset = $this->datasetActions->get($study->getPersistentId());
50+
} catch (DataverseException $e) {
51+
$error = $e->getMessage();
52+
error_log('Dataverse API error on Crossref export: ' . $error);
53+
54+
return $depositXml;
55+
}
56+
57+
if ($dataset->isPublished()) {
58+
$this->addDatasetRelationToWorkNode($submissionNode, $study->getPersistentId());
59+
}
60+
}
61+
62+
return $depositXml;
63+
}
64+
65+
public function addDatasetRelationToWorkNode(DOMElement $workNode, string $persistentId): DOMElement
66+
{
67+
$doc = $workNode->ownerDocument;
68+
69+
$relatedItemNode = $doc->createElementNS(self::RELATIONS_NAMESPACE, 'related_item');
70+
71+
$descriptionNode = $doc->createElementNS(self::RELATIONS_NAMESPACE, 'description');
72+
$descriptionNode->appendChild($doc->createTextNode('Dataset deposited in Dataverse repository.'));
73+
74+
$doi = preg_replace('/^doi:/i', '', $persistentId);
75+
76+
$interWorkRelationNode = $doc->createElementNS(self::RELATIONS_NAMESPACE, 'inter_work_relation');
77+
$interWorkRelationNode->setAttribute('relationship-type', 'isSupplementedBy');
78+
$interWorkRelationNode->setAttribute('identifier-type', 'doi');
79+
$interWorkRelationNode->appendChild($doc->createTextNode($doi));
80+
81+
$relatedItemNode->appendChild($descriptionNode);
82+
$relatedItemNode->appendChild($interWorkRelationNode);
83+
84+
$existingProgramNodes = $workNode->getElementsByTagNameNS(self::RELATIONS_NAMESPACE, 'program');
85+
if ($existingProgramNodes->count() > 0) {
86+
$existingProgramNodes->item(0)->appendChild($relatedItemNode);
87+
} else {
88+
$programNode = $doc->createElementNS(self::RELATIONS_NAMESPACE, 'program');
89+
$programNode->appendChild($relatedItemNode);
90+
$doiDataNode = $workNode->getElementsByTagName('doi_data')->item(0);
91+
$workNode->insertBefore($programNode, $doiDataNode);
92+
}
93+
94+
return $workNode;
95+
}
96+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
import('plugins.generic.dataverse.classes.dispatchers.DataverseDispatcher');
4+
import('plugins.generic.dataverse.classes.CrossrefXmlEditor');
5+
6+
class CrossrefDispatcher extends DataverseDispatcher
7+
{
8+
protected function registerHooks(): void
9+
{
10+
HookRegistry::register('articlecrossrefxmlfilter::execute', [$this, 'addDatasetRelationToCrossrefExport']);
11+
HookRegistry::register('preprintcrossrefxmlfilter::execute', [$this, 'addDatasetRelationToCrossrefExport']);
12+
}
13+
14+
public function addDatasetRelationToCrossrefExport(string $hookName, array $params)
15+
{
16+
$preliminaryOutput = &$params[0];
17+
18+
$crossrefXmlEditor = new CrossrefXmlEditor();
19+
$preliminaryOutput = $crossrefXmlEditor->addDatasetRelationToDepositXml($preliminaryOutput);
20+
21+
return false;
22+
}
23+
}

cypress/tests/Test02_ResearchDataState.spec.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ describe('Research data state', function () {
2525
cy.get('select[id="sectionId"],select[id="seriesId"]').select(submission.section);
2626
}
2727
cy.get('input[id^="checklist-"]').click({ multiple: true });
28-
cy.get('input[id=privacyConsent]').click();
28+
cy.contains('label', 'Yes, I agree to have my data collected').within(() => {
29+
cy.get('input').check();
30+
});
2931

3032
cy.get('input[id^="dataStatementReason-en_US-"]').should('not.be.visible');
3133
cy.get('ul[id^="dataStatementUrls"]').should('not.be.visible');

cypress/tests/Test03_ResearchDataDeposit.spec.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ describe('Research data deposit', function () {
2929
cy.get('select[id="sectionId"],select[id="seriesId"]').select(submission.section);
3030
cy.get('input[id^="dataStatementTypes"][value=1]').click();
3131
cy.get('input[id^="checklist-"]').click({ multiple: true });
32-
cy.get('input[id=privacyConsent]').click();
32+
cy.contains('label', 'Yes, I agree to have my data collected').within(() => {
33+
cy.get('input').check();
34+
});
3335
cy.get('#submitStep1Form button.submitFormButton').click();
3436

3537
cy.wait(1000);
@@ -54,7 +56,9 @@ describe('Research data deposit', function () {
5456
cy.contains('a', 'Dataverse de Exemplo Lepidus');
5557
cy.get('input[id^="dataStatementTypes"][value=3]').click();
5658
cy.get('input[id^="checklist-"]').click({ multiple: true });
57-
cy.get('input[id=privacyConsent]').click();
59+
cy.contains('label', 'Yes, I agree to have my data collected').within(() => {
60+
cy.get('input').check();
61+
});
5862
cy.get('#submitStep1Form button.submitFormButton').click();
5963

6064
cy.wait(1000);
@@ -150,6 +154,7 @@ describe('Research data deposit', function () {
150154
});
151155

152156
cy.get('input[name="datasetTitle"]').should('have.value', 'Replication data for: ' + submission.title);
157+
cy.logout();
153158
});
154159
it('Check if options are disabled for authors without edit permission', function () {
155160
cy.login('ckwantes', null, 'publicknowledge');
@@ -511,7 +516,9 @@ describe('Research data deposit', function () {
511516
}
512517
cy.get('input[id^="dataStatementTypes"][value=3]').click();
513518
cy.get('input[id^="checklist-"]').click({ multiple: true });
514-
cy.get('input[id=privacyConsent]').click();
519+
cy.contains('label', 'Yes, I agree to have my data collected').within(() => {
520+
cy.get('input').check();
521+
});
515522
cy.get('button.submitFormButton').click();
516523

517524
cy.contains('Add research data').click();

cypress/tests/Test04_Review.spec.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ describe('Research data on review', function () {
4444
}
4545
cy.get('input[id^="dataStatementTypes"][value=3]').click();
4646
cy.get('input[id^="checklist-"]').click({ multiple: true });
47-
cy.get('input[id=privacyConsent]').click();
47+
cy.contains('label', 'Yes, I agree to have my data collected').within(() => {
48+
cy.get('input').check();
49+
});
4850
cy.get('#submitStep1Form button.submitFormButton').click();
4951

5052
addResearchDataFile('dummy.pdf', submission.researchDataFileNames[0]);
@@ -72,6 +74,7 @@ describe('Research data on review', function () {
7274
cy.waitJQuery();
7375
cy.get('#submitStep4Form button.submitFormButton').click();
7476
cy.get('button.pkpModalConfirmButton').click();
77+
cy.wait(7000);
7578

7679
cy.waitJQuery();
7780
cy.get('h2:contains("Submission complete")');

cypress/tests/Test05_EditorDecision.spec.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ describe('Research data publishing in editor decision', function () {
4545
}
4646
cy.get('input[id^="dataStatementTypes"][value=3]').click();
4747
cy.get('input[id^="checklist-"]').click({ multiple: true });
48-
cy.get('input[id=privacyConsent]').click();
48+
cy.contains('label', 'Yes, I agree to have my data collected').within(() => {
49+
cy.get('input').check();
50+
});
4951
cy.get('button.submitFormButton').click();
5052

5153
cy.contains('Add research data').click();

cypress/tests/Test06_legacySubmissions.spec.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ describe('Legacy submissions', function () {
3636
cy.get('select[id="sectionId"],select[id="seriesId"]').select(submission.section);
3737
}
3838
cy.get('input[id^="checklist-"]').click({ multiple: true });
39-
cy.get('input[id=privacyConsent]').click();
39+
cy.contains('label', 'Yes, I agree to have my data collected').within(() => {
40+
cy.get('input').check();
41+
});
4042
cy.get('#submitStep1Form button.submitFormButton').click();
4143

4244
cy.get('#submitStep2Form button.submitFormButton').click();

tests/CrossrefXmlEditorTest.php

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
<?php
2+
3+
import('lib.pkp.tests.DatabaseTestCase');
4+
import('plugins.generic.dataverse.classes.CrossrefXmlEditor');
5+
import('plugins.generic.dataverse.classes.dataverseStudy.DataverseStudy');
6+
import('plugins.generic.dataverse.classes.dataverseStudy.DataverseStudyDAO');
7+
import('plugins.generic.dataverse.classes.entities.Dataset');
8+
import('plugins.generic.dataverse.dataverseAPI.actions.DatasetActions');
9+
import('plugins.generic.dataverse.classes.dispatchers.DataStatementDispatcher');
10+
import('plugins.generic.dataverse.DataversePlugin');
11+
12+
use Illuminate\Database\Capsule\Manager as Capsule;
13+
14+
class CrossrefXmlEditorTest extends DatabaseTestCase
15+
{
16+
private $xmlEditor;
17+
private $doc;
18+
private $contextId = 1;
19+
private $submissionId = null;
20+
private $doiId = null;
21+
private $doi = '10.1234/PublicKnowledge.17';
22+
private $study = null;
23+
private $dataset = null;
24+
private $persistentId = 'doi:10.5072/FK2/ABCDEF';
25+
26+
public function setUp(): void
27+
{
28+
parent::setUp();
29+
$plugin = new DataversePlugin();
30+
$dispatcher = new DataStatementDispatcher($plugin);
31+
32+
$this->doc = $this->createTestXml();
33+
$this->submissionId = $this->createTestSubmission();
34+
$this->study = $this->createDataverseStudy();
35+
$this->dataset = $this->createTestDataset();
36+
$this->xmlEditor = $this->createXmlEditor();
37+
}
38+
39+
protected function getAffectedTables(): array
40+
{
41+
return ['submissions', 'submission_settings', 'publications', 'publication_settings', 'dataverse_studies'];
42+
}
43+
44+
private function createTestSubmission(): int
45+
{
46+
$submissionDao = DAORegistry::getDAO('SubmissionDAO');
47+
$submission = $submissionDao->newDataObject();
48+
$submission->setData('contextId', $this->contextId);
49+
$submissionId = $submissionDao->insertObject($submission);
50+
51+
$publicationDao = DAORegistry::getDAO('PublicationDAO');
52+
$publication = $publicationDao->newDataObject();
53+
$publication->setData('pub-id::doi', $this->doi);
54+
$publication->setData('submissionId', $submissionId);
55+
$pubId = $publicationDao->insertObject($publication);
56+
57+
Capsule::table('publication_settings')->insert([
58+
'publication_id' => $pubId,
59+
'locale' => '',
60+
'setting_name' => 'pub-id::doi',
61+
'setting_value' => $this->doi,
62+
]);
63+
64+
return $submissionId;
65+
}
66+
67+
private function createDataverseStudy(): DataverseStudy
68+
{
69+
$study = new DataverseStudy();
70+
$study->setSubmissionId($this->submissionId);
71+
$study->setEditUri('https://demo.dataverse.org/dvn/api/data-deposit/v1.1/swordv2/edit/study/' . $this->persistentId);
72+
$study->setEditMediaUri('https://demo.dataverse.org/dvn/api/data-deposit/v1.1/swordv2/edit-media/study/' . $this->persistentId);
73+
$study->setStatementUri('https://demo.dataverse.org/dvn/api/data-deposit/v1.1/swordv2/statement/study/' . $this->persistentId);
74+
$study->setPersistentUri('https://doi.org/10.5072/FK2/ABCDEF');
75+
$study->setPersistentId($this->persistentId);
76+
77+
$dataverseStudyDao = new DataverseStudyDAO();
78+
$studyId = $dataverseStudyDao->insertStudy($study);
79+
$study->setId($studyId);
80+
81+
return $study;
82+
}
83+
84+
private function createTestXml()
85+
{
86+
$xml = new DOMDocument('1.0', 'UTF-8');
87+
$xml->appendChild($xml->createElement('work'));
88+
89+
return $xml;
90+
}
91+
92+
private function createTestDataset(): Dataset
93+
{
94+
$dataset = new Dataset();
95+
$dataset->setPersistentId($this->persistentId);
96+
$dataset->setVersionState(Dataset::VERSION_STATE_RELEASED);
97+
98+
return $dataset;
99+
}
100+
101+
private function createXmlEditor(): CrossrefXmlEditor
102+
{
103+
$mockDatasetActions = $this->createMock(DatasetActions::class);
104+
$mockDatasetActions->method('get')->willReturn($this->dataset);
105+
106+
return new CrossrefXmlEditor($mockDatasetActions);
107+
}
108+
109+
public function testAddsDatasetRelationToWorkNode(): void
110+
{
111+
$workNode = $this->doc->documentElement;
112+
113+
$result = $this->xmlEditor->addDatasetRelationToWorkNode($workNode, $this->persistentId);
114+
115+
$programNode = $result->getElementsByTagNameNS('http://www.crossref.org/relations.xsd', 'program')->item(0);
116+
$resultXml = $result->ownerDocument->saveXML($programNode);
117+
118+
$expectedXml = file_get_contents(__DIR__ . '/fixtures/crossref/expected/dataset_relation.xml');
119+
120+
$this->assertXmlStringEqualsXmlString($expectedXml, $resultXml);
121+
}
122+
123+
public function testAddsDatasetRelationToDepositXml(): void
124+
{
125+
$this->assertAddingOfRelationToXmlMatchesExpected('preprint_deposit.xml');
126+
$this->assertAddingOfRelationToXmlMatchesExpected('article_deposit.xml');
127+
}
128+
129+
public function testAddsRelationToXmlAlreadyWithRelation(): void
130+
{
131+
$this->assertAddingOfRelationToXmlMatchesExpected('preprint_deposit_with_relation.xml');
132+
}
133+
134+
private function assertAddingOfRelationToXmlMatchesExpected(string $fixture): void
135+
{
136+
$depositXml = new DOMDocument();
137+
$depositXml->load(__DIR__ . '/fixtures/crossref/' . $fixture);
138+
139+
$result = $this->xmlEditor->addDatasetRelationToDepositXml($depositXml);
140+
141+
$expectedXml = file_get_contents(__DIR__ . '/fixtures/crossref/expected/' . $fixture);
142+
143+
$this->assertXmlStringEqualsXmlString($expectedXml, $result->saveXML());
144+
}
145+
}

0 commit comments

Comments
 (0)