Skip to content

Commit 2183da9

Browse files
committed
Merge branch 'adaptsTo35-879' into 'main'
Adapts plugin to 3.5.0.x See merge request softwares-pkp/plugins_ojs/doiscielo!36
2 parents 3d71a22 + 3c74d84 commit 2183da9

22 files changed

Lines changed: 2214 additions & 603 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
.phpunit.result.cache
1+
.phpunit.result.cache
2+
node_modules

.gitlab-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ variables:
33

44
include:
55
- project: 'documentacao-e-tarefas/modelosparaintegracaocontinua'
6-
ref: main
6+
ref: stable-3_5_0
77
file:
88
- 'templates/groups/pkp_plugin.yml'
99
- 'templates/groups/ops/unit_tests.yml'

ScieloScreeningPlugin.php

Lines changed: 108 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,34 @@
11
<?php
22

33
/**
4-
* @file plugins/generic/scieloScreening/ScieloScreeningPlugin.inc.php
4+
* @file plugins/generic/scieloScreening/ScieloScreeningPlugin.php
55
*
66
* @class ScieloScreeningPlugin
77
* @ingroup plugins_generic_scieloScreening
88
*
9-
* @brief Plugin class for the DefaultScreening plugin.
9+
* @brief Plugin class for the SciELO Screening plugin.
1010
*/
1111

1212
namespace APP\plugins\generic\scieloScreening;
1313

1414
use PKP\plugins\GenericPlugin;
1515
use APP\core\Application;
1616
use PKP\plugins\Hook;
17-
use PKP\db\DAORegistry;
1817
use APP\facades\Repo;
18+
use PKP\stageAssignment\StageAssignment;
19+
use PKP\userGroup\UserGroup;
1920
use PKP\security\Role;
2021
use PKP\linkAction\LinkAction;
2122
use PKP\linkAction\request\AjaxModal;
2223
use APP\template\TemplateManager;
2324
use PKP\core\JSONMessage;
2425
use APP\pages\submission\SubmissionHandler;
2526
use Illuminate\Database\Migrations\Migration;
27+
use Illuminate\Http\Request as IlluminateRequest;
28+
use Illuminate\Http\Response;
29+
use Illuminate\Http\JsonResponse;
30+
use PKP\core\PKPBaseController;
31+
use PKP\handler\APIHandler;
2632
use APP\plugins\generic\scieloScreening\classes\components\forms\NumberContributorsForm;
2733
use APP\plugins\generic\scieloScreening\classes\ScreeningExecutor;
2834
use APP\plugins\generic\scieloScreening\classes\ScreeningChecker;
@@ -46,17 +52,96 @@ public function register($category, $path, $mainContextId = null)
4652
Hook::add('Submission::validateSubmit', [$this, 'validateSubmissionFields']);
4753
Hook::add('Template::SubmissionWizard::Section::Review', [$this, 'modifyReviewSections']);
4854
Hook::add('Schema::get::publication', [$this, 'addOurFieldsToPublicationSchema']);
49-
Hook::add('Template::Workflow::Publication', [$this, 'addToWorkFlow']);
50-
Hook::add('Template::Workflow::Publication', [$this, 'addPdfsWarningToGalleysTab']);
5155

5256
Hook::add('Publication::validatePublish', [$this, 'validateOnPosting']);
5357
Hook::add('Settings::Workflow::listScreeningPlugins', [$this, 'listPluginScreeningRules']);
5458

5559
$this->loadDispatcherClasses();
60+
61+
$request = Application::get()->getRequest();
62+
$templateMgr = TemplateManager::getManager($request);
63+
$this->registerWorkflowAssets($request, $templateMgr);
64+
$this->addScreeningApiRoute();
5665
}
5766
return $success;
5867
}
5968

69+
private function registerWorkflowAssets($request, $templateMgr): void
70+
{
71+
$baseUrl = $request->getBaseUrl();
72+
$pluginPath = $this->getPluginPath();
73+
74+
$templateMgr->addJavaScript(
75+
'scieloScreening',
76+
"{$baseUrl}/{$pluginPath}/public/build/build.iife.js",
77+
[
78+
'inline' => false,
79+
'contexts' => ['backend'],
80+
'priority' => TemplateManager::STYLE_SEQUENCE_LAST
81+
]
82+
);
83+
84+
$templateMgr->addStyleSheet(
85+
'scieloScreeningStyles',
86+
"{$baseUrl}/{$pluginPath}/public/build/build.css",
87+
[
88+
'contexts' => ['backend']
89+
]
90+
);
91+
}
92+
93+
private function addScreeningApiRoute(): void
94+
{
95+
Hook::add(
96+
'APIHandler::endpoints::submissions',
97+
function (
98+
string $hookName,
99+
PKPBaseController $apiController,
100+
APIHandler $apiHandler
101+
): bool {
102+
$apiHandler->addRoute(
103+
'GET',
104+
'{submissionId}/screening',
105+
$this->getScreeningDataHandler(),
106+
'screening.get',
107+
[
108+
Role::ROLE_ID_SITE_ADMIN,
109+
Role::ROLE_ID_MANAGER,
110+
Role::ROLE_ID_SUB_EDITOR,
111+
]
112+
);
113+
114+
return false;
115+
}
116+
);
117+
}
118+
119+
private function getScreeningDataHandler(): callable
120+
{
121+
return function (IlluminateRequest $request): JsonResponse {
122+
$submissionId = $request->route('submissionId');
123+
$submission = Repo::submission()->get((int) $submissionId);
124+
125+
if (!$submission) {
126+
return response()->json(
127+
['error' => 'Submission not found'],
128+
Response::HTTP_NOT_FOUND
129+
);
130+
}
131+
132+
$context = Application::get()->getRequest()->getContext();
133+
$documentChecker = $this->getDocumentChecker($submission);
134+
$orcidClient = new OrcidClient($this, $context->getId());
135+
$screeningExecutor = new ScreeningExecutor(
136+
$documentChecker,
137+
$orcidClient
138+
);
139+
$screeningData = $screeningExecutor->getScreeningData($submission);
140+
141+
return response()->json($screeningData, Response::HTTP_OK);
142+
};
143+
}
144+
60145
private function loadDispatcherClasses(): void
61146
{
62147
$dispatcherClasses = [
@@ -295,34 +380,6 @@ public function modifyReviewSections($hookName, $params)
295380
}
296381
}
297382

298-
public function addToWorkFlow($hookName, $params)
299-
{
300-
$smarty = &$params[1];
301-
$output = &$params[2];
302-
$context = Application::get()->getRequest()->getContext();
303-
$submission = $smarty->getTemplateVars('submission');
304-
305-
$documentChecker = $this->getDocumentChecker($submission);
306-
$orcidClient = new OrcidClient($this, $context->getId());
307-
$screeningExecutor = new ScreeningExecutor($documentChecker, $orcidClient);
308-
$dataScreening = $screeningExecutor->getScreeningData($submission);
309-
310-
$smarty->assign($dataScreening);
311-
$output .= sprintf(
312-
'<tab id="screeningInfo" label="%s">%s</tab>',
313-
__('plugins.generic.scieloScreening.info.name'),
314-
$smarty->fetch($this->getTemplateResource('screeningInfo.tpl'))
315-
);
316-
}
317-
318-
public function addPdfsWarningToGalleysTab($hookName, $params)
319-
{
320-
$smarty = & $params[1];
321-
$output = & $params[2];
322-
323-
$output .= sprintf('%s', $smarty->fetch($this->getTemplateResource('addGalleysWarning.tpl')));
324-
}
325-
326383
public function listPluginScreeningRules($hookName, $args)
327384
{
328385
$rules = & $args[0];
@@ -368,11 +425,16 @@ public function validateOnPosting($hookName, $args)
368425

369426
private function getDocumentChecker($submission)
370427
{
371-
$galleys = $submission->getGalleys();
428+
$publication = $submission->getCurrentPublication();
429+
$galleys = Repo::galley()->getCollector()
430+
->filterByPublicationIds([$publication->getId()])
431+
->getMany()
432+
->toArray();
372433

373434
if (count($galleys) > 0 && $galleys[0]->getFile()) {
374435
$galley = $galleys[0];
375-
$path = \Config::getVar('files', 'files_dir') . DIRECTORY_SEPARATOR . $galley->getFile()->getData('path');
436+
$filesDir = \Config::getVar('files', 'files_dir');
437+
$path = $filesDir . DIRECTORY_SEPARATOR . $galley->getFile()->getData('path');
376438

377439
return new DocumentChecker($path);
378440
}
@@ -385,15 +447,19 @@ public function userIsAuthor($submission)
385447
$currentUser = Application::get()->getRequest()->getUser();
386448
$currentUserAssignedRoles = [];
387449
if ($currentUser) {
388-
$stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO');
389-
$stageAssignmentsResult = $stageAssignmentDao->getBySubmissionAndUserIdAndStageId($submission->getId(), $currentUser->getId(), $submission->getData('stageId'));
390-
391-
while ($stageAssignment = $stageAssignmentsResult->next()) {
392-
$userGroup = Repo::userGroup()->get($stageAssignment->getUserGroupId(), $submission->getData('contextId'));
393-
$currentUserAssignedRoles[] = (int) $userGroup->getRoleId();
450+
$stageAssignments = StageAssignment::withSubmissionIds([$submission->getId()])
451+
->withStageIds([$submission->getData('stageId')])
452+
->withUserId($currentUser->getId())
453+
->get();
454+
455+
foreach ($stageAssignments as $stageAssignment) {
456+
$userGroup = UserGroup::find($stageAssignment->userGroupId);
457+
if ($userGroup) {
458+
$currentUserAssignedRoles[] = (int) $userGroup->roleId;
459+
}
394460
}
395461
}
396462

397-
return !empty($currentUserAssignedRoles) and $currentUserAssignedRoles[0] == Role::ROLE_ID_AUTHOR;
463+
return !empty($currentUserAssignedRoles) && $currentUserAssignedRoles[0] == Role::ROLE_ID_AUTHOR;
398464
}
399465
}

classes/DocumentChecker.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,22 @@ class DocumentChecker
88

99
public function __construct(string $pathFile)
1010
{
11-
$pathTxt = substr($pathFile, 0, -3) . 'txt';
12-
shell_exec("pdftotext " . $pathFile . " " . $pathTxt . " -layout 2>/dev/null");
11+
$this->fileText = '';
1312

14-
$this->fileText = file_get_contents($pathTxt);
15-
$this->fileText = str_replace(["\r", "\n"], '', $this->fileText);
13+
if (!file_exists($pathFile)) {
14+
return;
15+
}
1616

17-
unlink($pathTxt);
17+
$pathTxt = substr($pathFile, 0, -3) . 'txt';
18+
$command = "pdftotext " . escapeshellarg($pathFile) .
19+
" " . escapeshellarg($pathTxt) . " -layout 2>/dev/null";
20+
shell_exec($command);
21+
22+
if (file_exists($pathTxt)) {
23+
$this->fileText = file_get_contents($pathTxt);
24+
$this->fileText = str_replace(["\r", "\n"], '', $this->fileText);
25+
unlink($pathTxt);
26+
}
1827
}
1928

2029
public function checkTextOrcids(): array

classes/ScreeningExecutor.php

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace APP\plugins\generic\scieloScreening\classes;
44

55
use APP\plugins\generic\scieloScreening\classes\ScreeningChecker;
6+
use APP\facades\Repo;
67

78
class ScreeningExecutor
89
{
@@ -23,7 +24,7 @@ public function getStatusAuthors($submission)
2324
$affiliationAuthors = $nameAuthors = $orcidAuthors = $creditAuthors = [];
2425

2526
foreach ($authors as $author) {
26-
$affiliationAuthors[] = $author->getLocalizedAffiliation();
27+
$affiliationAuthors[] = $this->getAuthorAffiliationString($author);
2728
$nameAuthors[] = $author->getLocalizedGivenName() . " " . $author->getLocalizedFamilyName();
2829
$orcidAuthors[] = $author->getOrcid();
2930
$creditAuthors[] = $author->getData('creditRoles');
@@ -39,6 +40,28 @@ public function getStatusAuthors($submission)
3940
];
4041
}
4142

43+
private function getAuthorAffiliationString($author)
44+
{
45+
$affiliations = Repo::affiliation()->getCollector()
46+
->filterByAuthorId($author->getId())
47+
->getMany()
48+
->toArray();
49+
50+
if (empty($affiliations)) {
51+
return '';
52+
}
53+
54+
$affiliationNames = [];
55+
foreach ($affiliations as $affiliation) {
56+
$name = $affiliation->getLocalizedName();
57+
if ($name) {
58+
$affiliationNames[] = $name;
59+
}
60+
}
61+
62+
return implode('; ', $affiliationNames);
63+
}
64+
4265
private function getStatusMetadataEnglish($submission)
4366
{
4467
$publication = $submission->getCurrentPublication();
@@ -62,7 +85,11 @@ private function getStatusMetadataEnglish($submission)
6285
private function getStatusPDFs($submission)
6386
{
6487
$checker = new ScreeningChecker();
65-
$galleys = $submission->getGalleys();
88+
$publication = $submission->getCurrentPublication();
89+
$galleys = Repo::galley()->getCollector()
90+
->filterByPublicationIds([$publication->getId()])
91+
->getMany()
92+
->toArray();
6693

6794
$fileTypeGalleys = array_map(function ($galley) {
6895
return ($galley->getFileType());

cypress/support/commands.js

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,44 @@
1-
Cypress.Commands.add('findSubmission', function(tab, title) {
2-
cy.get('#' + tab + '-button').click();
3-
cy.get('.listPanel__itemSubtitle:visible:contains("' + title + '")').first()
4-
.parent().parent().within(() => {
5-
cy.get('.pkpButton:contains("View")').click();
6-
});
1+
Cypress.Commands.add('beginSubmission', function(submissionData) {
2+
cy.get('label:contains("English")').click();
3+
cy.setTinyMceContent('startSubmission-title-control', submissionData.title);
4+
5+
cy.get('input[name="submissionRequirements"]').check();
6+
cy.get('input[name="privacyConsent"]').check();
7+
cy.contains('button', 'Begin Submission').click();
8+
});
9+
10+
Cypress.Commands.add('detailsStep', function(submissionData) {
11+
cy.setTinyMceContent('titleAbstract-abstract-control-en', submissionData.abstract);
12+
cy.get('.submissionWizard__footer button').contains('Continue').click();
713
});
814

9-
Cypress.Commands.add('addSubmissionGalleys', (files) => {
10-
files.forEach(file => {
11-
cy.get('a[id^=component-grid-preprintgalleys-preprintgalleygrid-addGalley-button-]').contains("Add File").click();
12-
cy.wait(2000); // Avoid occasional failure due to form init taking time
13-
cy.get('div.pkp_modal_panel').then($modalDiv => {
14-
cy.wait(3000);
15-
$modalDiv.find('div.header:contains("Add File")');
16-
cy.get('div.pkp_modal_panel input[id^="label-"]').type('PDF', {delay: 0});
17-
cy.get('div.pkp_modal_panel button:contains("Save")').click();
18-
cy.wait(2000); // Avoid occasional failure due to form init taking time
19-
});
20-
cy.get('select[id=genreId]').select(file.genre);
21-
cy.fixture(file.file, 'base64').then(fileContent => {
22-
cy.get('input[type=file]').attachFile(
23-
{fileContent, 'filePath': file.fileName, 'mimeType': 'application/pdf', 'encoding': 'base64'}
24-
);
25-
});
26-
cy.get('#continueButton').click();
27-
cy.wait(2000);
28-
for (const field in file.metadata) {
29-
cy.get('input[id^="' + Cypress.$.escapeSelector(field) + '"]:visible,textarea[id^="' + Cypress.$.escapeSelector(field) + '"]').type(file.metadata[field], {delay: 0});
30-
cy.get('input[id^="language"').click({force: true}); // Close multilingual and datepicker pop-overs
31-
}
32-
cy.get('#continueButton').click();
33-
cy.get('#continueButton').click();
34-
});
35-
});
15+
Cypress.Commands.add('addContributor', function(contributorData, toUpperCase = false) {
16+
let given = (toUpperCase) ? contributorData.given.toUpperCase() : contributorData.given;
17+
let family = (toUpperCase) ? contributorData.family.toUpperCase() : contributorData.family;
18+
19+
cy.get('button').contains('Add Contributor').click();
20+
cy.wait(1000);
21+
cy.get('.pkpFormField:contains("Given Name")').find('input[name*="givenName-en"]').type(given, {delay: 0});
22+
cy.get('.pkpFormField:contains("Family Name")').find('input[name*="familyName-en"]').type(family, {delay: 0});
23+
cy.get('.pkpFormField:contains("Email")').find('input').type(contributorData.email, {delay: 0});
24+
cy.get('.pkpFormField:contains("Country")').find('select').select(contributorData.country);
25+
26+
if ('affiliation' in contributorData) {
27+
cy.get('.pkpFormField--affiliations .pkpAutosuggest__input')
28+
.type(contributorData.affiliation, {delay: 0})
29+
.type('{enter}');
30+
cy.wait(1000);
31+
cy.get('.pkpFormField--affiliations .pkpButton').contains('Add').click();
32+
cy.wait(500);
33+
}
34+
35+
cy.get('div[role=dialog]:contains("Add Contributor")').find('button').contains('Save').click();
36+
cy.wait(2000);
37+
});
38+
39+
Cypress.Commands.add('openIncompleteSubmission', function(authorName) {
40+
cy.get('nav').contains('Submissions').click();
41+
cy.contains('table tr', authorName).within(() => {
42+
cy.get('button').contains('Complete submission').click({force: true});
43+
});
44+
});

0 commit comments

Comments
 (0)