16 import(
'classes.handler.Handler');
17 import(
'lib.pkp.classes.workflow.WorkflowStageDAO');
21 import(
'lib.pkp.classes.linkAction.LinkAction');
22 import(
'lib.pkp.classes.linkAction.request.AjaxModal');
35 function authorize($request, &$args, $roleAssignments) {
36 $router = $request->getRouter();
37 $operation = $router->getRequestedOp($request);
39 if ($operation ==
'access') {
41 import(
'lib.pkp.classes.security.authorization.internal.SubmissionRequiredPolicy');
47 import(
'lib.pkp.classes.security.authorization.internal.UserAccessibleWorkflowStageRequiredPolicy');
52 import(
'lib.pkp.classes.security.authorization.WorkflowStageAccessPolicy');
56 return parent::authorize($request, $args, $roleAssignments);
72 $currentStageId = $submission->getStageId();
75 $editorialWorkflowRoles = $workflowRoles[WORKFLOW_TYPE_EDITORIAL];
78 $workingStageId =
null;
79 for ($workingStageId = $currentStageId; $workingStageId >= WORKFLOW_STAGE_ID_SUBMISSION; $workingStageId--) {
80 if (isset($accessibleWorkflowStages[$workingStageId]) && array_intersect($editorialWorkflowRoles, $accessibleWorkflowStages[$workingStageId])) {
87 if ($workingStageId ==
null) {
88 for ($workingStageId = $currentStageId; $workingStageId <= WORKFLOW_STAGE_ID_PRODUCTION; $workingStageId++) {
89 if (isset($accessibleWorkflowStages[$workingStageId]) && array_intersect($editorialWorkflowRoles, $accessibleWorkflowStages[$workingStageId])) {
95 assert(isset($workingStageId));
97 $router = $request->getRouter();
98 $request->redirectUrl($router->url($request,
null,
'workflow',
'index', array($submission->getId(), $workingStageId)));
113 $submissionContext = $request->getContext();
114 if ($submission->getContextId() !== $submissionContext->getId()) {
115 $submissionContext =
Services::get(
'context')->get($submission->getContextId());
122 $editorialWorkflowRoles = $workflowRoles[WORKFLOW_TYPE_EDITORIAL];
125 $result = $userGroupDao->getByContextId($submission->getData(
'contextId'));
126 $authorUserGroups = [];
127 $workflowUserGroups = [];
128 while (!$result->eof()) {
129 $userGroup = $result->next();
130 if ($userGroup->getRoleId() == ROLE_ID_AUTHOR) {
131 $authorUserGroups[] = $userGroup;
133 if (in_array((
int) $userGroup->getRoleId(), $editorialWorkflowRoles)) {
134 $workflowUserGroups[] = $userGroup;
143 $currentStageId = $submission->getStageId();
145 $canAccessPublication =
false;
146 $canEditPublication =
Services::get(
'submission')->canEditPublication($submission->getId(), $request->getUser()->getId());
147 $canAccessProduction =
false;
149 $canAccessEditorialHistory =
false;
151 if (!$accessibleWorkflowStages && array_intersect($this->
getAuthorizedContextObject(ASSOC_TYPE_USER_ROLES), [ROLE_ID_MANAGER])) {
152 $canAccessProduction =
true;
154 $canAccessPublication =
true;
155 $canAccessEditorialHistory =
true;
157 } elseif (!empty($accessibleWorkflowStages[$currentStageId]) && array_intersect($editorialWorkflowRoles, $accessibleWorkflowStages[$currentStageId])) {
158 $canAccessProduction = (bool) array_intersect($editorialWorkflowRoles, $accessibleWorkflowStages[WORKFLOW_STAGE_ID_PRODUCTION]);
159 $canAccessPublication =
true;
162 $result = $stageAssignmentDao->getBySubmissionAndUserIdAndStageId(
163 $submission->getId(),
164 $request->getUser()->getId(),
165 WORKFLOW_STAGE_ID_PRODUCTION
171 if ($result->wasEmpty() && is_array($accessibleWorkflowStages[WORKFLOW_STAGE_ID_PRODUCTION])) {
172 $canPublish = (bool) array_intersect([ROLE_ID_SITE_ADMIN, ROLE_ID_MANAGER], $accessibleWorkflowStages[WORKFLOW_STAGE_ID_PRODUCTION]);
177 while (!$result->eof()) {
178 $stageAssignment = $result->next();
179 foreach ($workflowUserGroups as $workflowUserGroup) {
180 if ($stageAssignment->getUserGroupId() == $workflowUserGroup->getId() &&
181 !$stageAssignment->getRecommendOnly()) {
189 if (!empty($accessibleWorkflowStages[$currentStageId]) && array_intersect([ROLE_ID_MANAGER, ROLE_ID_SUB_EDITOR], $accessibleWorkflowStages[$currentStageId])) {
190 $canAccessEditorialHistory =
true;
193 $supportedSubmissionLocales = $submissionContext->getSupportedSubmissionLocales();
195 $locales = array_map(
function($localeKey) use ($localeNames) {
196 return [
'key' => $localeKey,
'label' => $localeNames[$localeKey]];
197 }, $supportedSubmissionLocales);
199 $latestPublication = $submission->getLatestPublication();
201 $submissionApiUrl = $request->getDispatcher()->url($request, ROUTE_API, $submissionContext->getData(
'urlPath'),
'submissions/' . $submission->getId());
202 $latestPublicationApiUrl = $request->getDispatcher()->url($request, ROUTE_API, $submissionContext->getData(
'urlPath'),
'submissions/' . $submission->getId() .
'/publications/' . $latestPublication->getId());
204 $contributorsGridUrl = $request->getDispatcher()->url(
208 'grid.users.author.AuthorGridHandler',
212 'submissionId' => $submission->getId(),
213 'publicationId' =>
'__publicationId__',
217 $editorialHistoryUrl = $request->getDispatcher()->url(
221 'informationCenter.SubmissionInformationCenterHandler',
222 'viewInformationCenter',
224 array(
'submissionId' => $submission->getId())
227 $submissionLibraryUrl = $request->getDispatcher()->url(
231 'modals.documentLibrary.DocumentLibraryHandler',
234 array(
'submissionId' => $submission->getId())
237 $publishUrl = $request->getDispatcher()->url(
241 'modals.publish.PublishHandler',
245 'submissionId' => $submission->getId(),
246 'publicationId' =>
'__publicationId__',
255 import(
'classes.submission.Submission');
256 import(
'classes.components.forms.publication.PublishForm');
258 $templateMgr->setConstants([
264 'FORM_PUBLICATION_LICENSE',
266 'FORM_TITLE_ABSTRACT',
272 $propNames =
Services::get(
'schema')->getSummaryProps(SCHEMA_SUBMISSION);
273 $propNames = array_filter($propNames,
function($propName) {
return $propName !==
'publications'; });
274 $submissionProps =
Services::get(
'submission')->getProperties(
278 'request' => $request,
279 'userGroups' => $authorUserGroups,
284 $publicationList = [];
285 foreach ($submission->getData(
'publications') as $publication) {
286 $publicationList[] =
Services::get(
'publication')->getProperties(
288 [
'id',
'datePublished',
'status',
'version'],
290 'context' => $submissionContext,
291 'submission' => $submission,
292 'request' => $request,
298 $workingPublicationProps =
Services::get(
'publication')->getFullProperties(
299 $submission->getLatestPublication(),
301 'context' => $submissionContext,
302 'submission' => $submission,
303 'request' => $request,
304 'userGroups' => $authorUserGroups,
307 if ($submission->getLatestPublication()->getId() === $submission->getCurrentPublication()->getId()) {
308 $currentPublicationProps = $workingPublicationProps;
310 $currentPublicationProps =
Services::get(
'publication')->getFullProperties(
311 $submission->getCurrentPublication(),
313 'context' => $submissionContext,
314 'submission' => $submission,
315 'request' => $request,
316 'userGroups' => $authorUserGroups,
322 'activityLogLabel' => __(
'submission.list.infoCenter'),
323 'canAccessPublication' => $canAccessPublication,
324 'canEditPublication' => $canEditPublication,
326 FORM_CITATIONS => $citationsForm->getConfig(),
327 FORM_PUBLICATION_LICENSE => $publicationLicenseForm->getConfig(),
328 FORM_TITLE_ABSTRACT => $titleAbstractForm->getConfig(),
330 'contributorsGridUrl' => $contributorsGridUrl,
331 'currentPublication' => $currentPublicationProps,
332 'editorialHistoryUrl' => $editorialHistoryUrl,
333 'publicationFormIds' => [
335 FORM_PUBLICATION_LICENSE,
339 'publicationList' => $publicationList,
340 'publicationTabsLabel' => __(
'publication.version.details'),
341 'publishLabel' => __(
'publication.publish'),
342 'publishUrl' => $publishUrl,
344 'schedulePublicationLabel' => __(
'editor.submission.schedulePublication'),
345 'statusLabel' => __(
'semicolon', [
'label' => __(
'common.status')]),
346 'submission' => $submissionProps,
347 'submissionApiUrl' => $submissionApiUrl,
348 'submissionLibraryLabel' => __(
'grid.libraryFiles.submission.title'),
349 'submissionLibraryUrl' => $submissionLibraryUrl,
350 'supportsReferences' => !!$submissionContext->getData(
'citations'),
351 'unpublishConfirmLabel' => __(
'publication.unpublish.confirm'),
352 'unpublishLabel' => __(
'publication.unpublish'),
353 'unscheduleConfirmLabel' => __(
'publication.unschedule.confirm'),
354 'unscheduleLabel' => __(
'publication.unschedule'),
355 'versionLabel' => __(
'semicolon', [
'label' => __(
'admin.version')]),
356 'versionConfirmLabel' => __(
'publication.version.confirm'),
357 'workingPublication' => $workingPublicationProps,
361 $metadataFields = [
'coverage',
'disciplines',
'keywords',
'languages',
'rights',
'source',
'subjects',
'agencies',
'type'];
362 $metadataEnabled =
false;
363 foreach ($metadataFields as $metadataField) {
364 if ($submissionContext->getData($metadataField)) {
365 $metadataEnabled =
true;
369 if ($metadataEnabled || in_array(
'publication', $submissionContext->getData(
'enablePublisherId'))) {
370 $vocabSuggestionUrlBase =$request->getDispatcher()->url($request, ROUTE_API, $submissionContext->getData(
'urlPath'),
'vocabs',
null,
null, [
'vocab' =>
'__vocab__']);
372 $templateMgr->setConstants([
'FORM_METADATA']);
373 $state[
'components'][FORM_METADATA] = $metadataForm->getConfig();
374 $state[
'publicationFormIds'][] = FORM_METADATA;
378 $identifiersEnabled =
false;
380 foreach ($pubIdPlugins as $pubIdPlugin) {
381 if ($pubIdPlugin->isObjectTypeEnabled(
'Publication', $request->getContext()->getId())) {
382 $identifiersEnabled =
true;
386 if ($identifiersEnabled) {
388 $templateMgr->setConstants([
'FORM_PUBLICATION_IDENTIFIERS']);
389 $state[
'components'][FORM_PUBLICATION_IDENTIFIERS] = $identifiersForm->getConfig();
390 $state[
'publicationFormIds'][] = FORM_PUBLICATION_IDENTIFIERS;
393 $templateMgr->setState($state);
395 $templateMgr->assign([
396 'canAccessEditorialHistory' => $canAccessEditorialHistory,
397 'canAccessPublication' => $canAccessPublication,
398 'canEditPublication' => $canEditPublication,
399 'canAccessProduction' => $canAccessProduction,
400 'canPublish' => $canPublish,
401 'identifiersEnabled' => $identifiersEnabled,
402 'metadataEnabled' => $metadataEnabled,
403 'pageComponent' =>
'WorkflowPage',
404 'pageTitle' => join(__(
'common.titleSeparator'), [
405 $submission->getShortAuthorString(),
406 $submission->getLocalizedTitle()
408 'pageWidth' => PAGE_WIDTH_WIDE,
409 'requestedStageId' => $requestedStageId,
410 'submission' => $submission,
411 'workflowStages' => $workflowStages,
416 $templateMgr->display(
'workflow/workflow.tpl');
463 $router = $request->getRouter();
464 $workflowPath = $router->getRequestedOp($request);
466 $request->redirectUrl($router->url($request,
null,
'workflow',
'index', array($submission->getId(), $stageId)));
478 $reviewRoundId = (int) $request->getUserVar(
'reviewRoundId');
485 'submissionId' => $submission->getId(),
486 'stageId' => (
int) $stageId,
492 if ($reviewRoundId) {
493 $actionArgs[
'reviewRoundId'] = $reviewRoundId;
495 $lastReviewRound = $reviewRoundDao->getLastReviewRoundBySubmissionId($submission->getId(), $stageId);
496 $reviewRound = $reviewRoundDao->getById($reviewRoundId);
498 $lastReviewRound =
null;
503 $editorsStageAssignments = $stageAssignmentDao->getEditorsAssignedToStage($submission->getId(), $stageId);
504 $dispatcher = $request->getDispatcher();
505 $user = $request->getUser();
507 $recommendOnly = $makeDecision =
false;
510 foreach ($editorsStageAssignments as $editorsStageAssignment) {
511 if ($editorsStageAssignment->getUserId() == $user->getId()) {
512 if (!$editorsStageAssignment->getRecommendOnly()) {
513 $makeDecision =
true;
515 $recommendOnly =
true;
523 if (!$recommendOnly && !$makeDecision) {
525 $userGroups = $userGroupDao->getByUserId($user->getId(), $request->getContext()->getId());
526 while ($userGroup = $userGroups->next()) {
527 if (in_array($userGroup->getRoleId(), array(ROLE_ID_MANAGER))) {
528 if (!$userGroup->getRecommendOnly()) {
529 $makeDecision =
true;
531 $recommendOnly =
true;
537 import(
'lib.pkp.classes.linkAction.request.AjaxModal');
538 $editorActions = array();
539 $editorDecisions = array();
540 $lastRecommendation = $allRecommendations =
null;
541 if (!empty($editorsStageAssignments) && (!$reviewRoundId || ($lastReviewRound && $reviewRoundId == $lastReviewRound->getId()))) {
542 import(
'classes.workflow.EditorDecisionActionsManager');
546 if (($stageId == WORKFLOW_STAGE_ID_EXTERNAL_REVIEW || $stageId == WORKFLOW_STAGE_ID_INTERNAL_REVIEW)) {
547 if ($recommendOnly) {
549 $editorDecisions = $editDecisionDao->getEditorDecisions($submission->getId(), $stageId, $reviewRound->getRound(), $user->getId());
551 foreach ($editorDecisions as $editorDecision) {
552 if (array_key_exists($editorDecision[
'decision'], $recommendationOptions)) {
553 if ($lastRecommendation) {
554 if ($editorDecision[
'dateDecided'] >= $lastRecommendation[
'dateDecided']) {
555 $lastRecommendation = $editorDecision;
558 $lastRecommendation = $editorDecision;
562 if ($lastRecommendation) {
563 $lastRecommendation = __($recommendationOptions[$lastRecommendation[
'decision']]);
571 $request, ROUTE_COMPONENT,
null,
572 'modals.editorDecision.EditorDecisionHandler',
573 'sendRecommendation',
null, $actionArgs
575 $lastRecommendation ? __(
'editor.submission.changeRecommendation') : __(
'editor.submission.makeRecommendation'),
576 'review_recommendation'
578 $lastRecommendation ? __(
'editor.submission.changeRecommendation') : __(
'editor.submission.makeRecommendation')
580 } elseif ($makeDecision) {
582 $editorDecisions = $editDecisionDao->getEditorDecisions($submission->getId(), $stageId, $reviewRound->getRound());
584 $recommendations = array();
585 foreach ($editorDecisions as $editorDecision) {
586 if (array_key_exists($editorDecision[
'decision'], $recommendationOptions)) {
587 if (array_key_exists($editorDecision[
'editorId'], $recommendations)) {
588 if ($editorDecision[
'dateDecided'] >= $recommendations[$editorDecision[
'editorId']][
'dateDecided']) {
589 $recommendations[$editorDecision[
'editorId']] = array(
'dateDecided' => $editorDecision[
'dateDecided'],
'decision' => $editorDecision[
'decision']);
592 $recommendations[$editorDecision[
'editorId']] = array(
'dateDecided' => $editorDecision[
'dateDecided'],
'decision' => $editorDecision[
'decision']);
597 foreach ($recommendations as $recommendation) {
598 $allRecommendations .= $i == 0 ? __($recommendationOptions[$recommendation[
'decision']]) : __(
'common.commaListSeparator') . __($recommendationOptions[$recommendation[
'decision']]);
607 foreach($decisions as $decision => $action) {
608 if (empty($action[
'operation'])) {
611 $actionArgs[
'decision'] = $decision;
616 $request, ROUTE_COMPONENT,
null,
617 'modals.editorDecision.EditorDecisionHandler',
618 $action[
'operation'],
null, $actionArgs
627 import(
'lib.pkp.classes.workflow.WorkflowStageDAO');
629 $hasSubmissionPassedThisStage = $submission->getStageId() > $stageId;
630 $lastDecision =
null;
631 switch( $submission->getStatus() ) {
634 case WORKFLOW_STAGE_ID_SUBMISSION:
635 if ($hasSubmissionPassedThisStage) {
636 $lastDecision =
'editor.submission.workflowDecision.submission.underReview';
639 case WORKFLOW_STAGE_ID_INTERNAL_REVIEW:
640 case WORKFLOW_STAGE_ID_EXTERNAL_REVIEW:
641 if ($reviewRoundId < $lastReviewRound->
getId()) {
642 $lastDecision =
'editor.submission.workflowDecision.submission.reviewRound';
643 } elseif ($hasSubmissionPassedThisStage) {
644 $lastDecision =
'editor.submission.workflowDecision.submission.accepted';
647 case WORKFLOW_STAGE_ID_EDITING:
648 if($hasSubmissionPassedThisStage) {
649 $lastDecision =
'editor.submission.workflowDecision.submission.production';
654 case STATUS_PUBLISHED:
655 $lastDecision =
'editor.submission.workflowDecision.submission.published';
657 case STATUS_DECLINED:
658 $lastDecision =
'editor.submission.workflowDecision.submission.declined';
664 $templateMgr->assign(array(
665 'editorActions' => $editorActions,
666 'editorsAssigned' => count($editorsStageAssignments) > 0,
667 'stageId' => $stageId,
668 'lastDecision' => $lastDecision,
669 'submissionStatus' => $submission->getStatus(),
670 'lastRecommendation' => $lastRecommendation,
671 'allRecommendations' => $allRecommendations,
673 return $templateMgr->fetchJson(
'workflow/editorialLinkActions.tpl');
688 $templateMgr->assign([
689 'submission' => $submission,
691 'workflowStages' => $workflowStages,
694 return $templateMgr->fetchJson(
'workflow/submissionProgressBar.tpl');
702 parent::setupTemplate($request);
703 AppLocale::requireComponents(LOCALE_COMPONENT_PKP_ADMIN, LOCALE_COMPONENT_APP_ADMIN, LOCALE_COMPONENT_PKP_MANAGER, LOCALE_COMPONENT_APP_MANAGER, LOCALE_COMPONENT_PKP_SUBMISSION, LOCALE_COMPONENT_APP_SUBMISSION, LOCALE_COMPONENT_APP_EDITOR, LOCALE_COMPONENT_PKP_GRID, LOCALE_COMPONENT_PKP_EDITOR);
725 if ($stageId = $request->getUserVar(
'stageId')) {
726 return (
int) $stageId;
730 $router = $request->getRouter();
731 $workflowPath = $router->getRequestedOp($request);
760 $editorAssignments = $notificationDao->getByAssoc(ASSOC_TYPE_SUBMISSION, $submission->getId(),
null, $editorAssignmentNotificationType, $contextId);
763 if (!$editorAssignments->wasEmpty()) {
768 if ($stageId == WORKFLOW_STAGE_ID_PRODUCTION) {
769 $submissionApprovalNotification = $notificationDao->getByAssoc(ASSOC_TYPE_SUBMISSION, $submission->getId(),
null, NOTIFICATION_TYPE_APPROVE_SUBMISSION, $contextId);
770 if (!$submissionApprovalNotification->wasEmpty()) {