Open Journal Systems  3.3.0
PKPWorkflowHandler.inc.php
1 <?php
2 
16 import('classes.handler.Handler');
17 import('lib.pkp.classes.workflow.WorkflowStageDAO');
18 
19 
20 // import UI base classes
21 import('lib.pkp.classes.linkAction.LinkAction');
22 import('lib.pkp.classes.linkAction.request.AjaxModal');
23 
24 abstract class PKPWorkflowHandler extends Handler {
25 
27  var $_isBackendPage = true;
28 
29  //
30  // Implement template methods from PKPHandler
31  //
35  function authorize($request, &$args, $roleAssignments) {
36  $router = $request->getRouter();
37  $operation = $router->getRequestedOp($request);
38 
39  if ($operation == 'access') {
40  // Authorize requested submission.
41  import('lib.pkp.classes.security.authorization.internal.SubmissionRequiredPolicy');
42  $this->addPolicy(new SubmissionRequiredPolicy($request, $args, 'submissionId'));
43 
44  // This policy will deny access if user has no accessible workflow stage.
45  // Otherwise it will build an authorized object with all accessible
46  // workflow stages and authorize user operation access.
47  import('lib.pkp.classes.security.authorization.internal.UserAccessibleWorkflowStageRequiredPolicy');
48  $this->addPolicy(new UserAccessibleWorkflowStageRequiredPolicy($request, WORKFLOW_TYPE_EDITORIAL));
49 
51  } else {
52  import('lib.pkp.classes.security.authorization.WorkflowStageAccessPolicy');
53  $this->addPolicy(new WorkflowStageAccessPolicy($request, $args, $roleAssignments, 'submissionId', $this->identifyStageId($request, $args), WORKFLOW_TYPE_EDITORIAL));
54  }
55 
56  return parent::authorize($request, $args, $roleAssignments);
57  }
58 
59 
60  //
61  // Public handler methods
62  //
69  function access($args, $request) {
70  $submission = $this->getAuthorizedContextObject(ASSOC_TYPE_SUBMISSION);
71 
72  $currentStageId = $submission->getStageId();
73  $accessibleWorkflowStages = $this->getAuthorizedContextObject(ASSOC_TYPE_ACCESSIBLE_WORKFLOW_STAGES);
74  $workflowRoles = Application::getWorkflowTypeRoles();
75  $editorialWorkflowRoles = $workflowRoles[WORKFLOW_TYPE_EDITORIAL];
76 
77  // Get the closest workflow stage that user has an assignment.
78  $workingStageId = null;
79  for ($workingStageId = $currentStageId; $workingStageId >= WORKFLOW_STAGE_ID_SUBMISSION; $workingStageId--) {
80  if (isset($accessibleWorkflowStages[$workingStageId]) && array_intersect($editorialWorkflowRoles, $accessibleWorkflowStages[$workingStageId])) {
81  break;
82  }
83  }
84 
85  // If no stage was found, user still have access to future stages of the
86  // submission. Try to get the closest future workflow stage.
87  if ($workingStageId == null) {
88  for ($workingStageId = $currentStageId; $workingStageId <= WORKFLOW_STAGE_ID_PRODUCTION; $workingStageId++) {
89  if (isset($accessibleWorkflowStages[$workingStageId]) && array_intersect($editorialWorkflowRoles, $accessibleWorkflowStages[$workingStageId])) {
90  break;
91  }
92  }
93  }
94 
95  assert(isset($workingStageId));
96 
97  $router = $request->getRouter();
98  $request->redirectUrl($router->url($request, null, 'workflow', 'index', array($submission->getId(), $workingStageId)));
99  }
100 
106  function index($args, $request) {
107  $this->setupTemplate($request);
108  $templateMgr = TemplateManager::getManager($request);
109 
110  $submission = $this->getAuthorizedContextObject(ASSOC_TYPE_SUBMISSION);
111  $requestedStageId = $this->getAuthorizedContextObject(ASSOC_TYPE_WORKFLOW_STAGE);
112 
113  $submissionContext = $request->getContext();
114  if ($submission->getContextId() !== $submissionContext->getId()) {
115  $submissionContext = Services::get('context')->get($submission->getContextId());
116  }
117 
119  $accessibleWorkflowStages = $this->getAuthorizedContextObject(ASSOC_TYPE_ACCESSIBLE_WORKFLOW_STAGES);
120 
121  $workflowRoles = Application::getWorkflowTypeRoles();
122  $editorialWorkflowRoles = $workflowRoles[WORKFLOW_TYPE_EDITORIAL];
123 
124  $userGroupDao = DAORegistry::getDAO('UserGroupDAO'); /* @var $userGroupDao UserGroupDAO */
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;
132  }
133  if (in_array((int) $userGroup->getRoleId(), $editorialWorkflowRoles)) {
134  $workflowUserGroups[] = $userGroup;
135  }
136  }
137 
138  // Publication tab
139  // Users have access to the publication tab if they are assigned to
140  // the active stage id or if they are assigned as an editor or if
141  // they are not assigned in any role and have a manager role in the
142  // context.
143  $currentStageId = $submission->getStageId();
144  $accessibleWorkflowStages = $this->getAuthorizedContextObject(ASSOC_TYPE_ACCESSIBLE_WORKFLOW_STAGES);
145  $canAccessPublication = false; // View title, metadata, etc.
146  $canEditPublication = Services::get('submission')->canEditPublication($submission->getId(), $request->getUser()->getId());
147  $canAccessProduction = false; // Access to galleys and issue entry
148  $canPublish = false; // Ability to publish, unpublish and create versions
149  $canAccessEditorialHistory = false; // Access to activity log
150  // unassigned managers
151  if (!$accessibleWorkflowStages && array_intersect($this->getAuthorizedContextObject(ASSOC_TYPE_USER_ROLES), [ROLE_ID_MANAGER])) {
152  $canAccessProduction = true;
153  $canPublish = true;
154  $canAccessPublication = true;
155  $canAccessEditorialHistory = true;
156 
157  } elseif (!empty($accessibleWorkflowStages[$currentStageId]) && array_intersect($editorialWorkflowRoles, $accessibleWorkflowStages[$currentStageId])) {
158  $canAccessProduction = (bool) array_intersect($editorialWorkflowRoles, $accessibleWorkflowStages[WORKFLOW_STAGE_ID_PRODUCTION]);
159  $canAccessPublication = true;
160 
161  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
162  $result = $stageAssignmentDao->getBySubmissionAndUserIdAndStageId(
163  $submission->getId(),
164  $request->getUser()->getId(),
165  WORKFLOW_STAGE_ID_PRODUCTION
166  );
167 
168  // If they have no stage assignments, check the role they have been granted
169  // for the production workflow stage. An unassigned admin or manager may
170  // have been granted access and should be allowed to publish.
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]);
173 
174  // Otherwise, check stage assignments
175  // "Recommend only" stage assignments can not publish
176  } else {
177  while (!$result->eof()) {
178  $stageAssignment = $result->next();
179  foreach ($workflowUserGroups as $workflowUserGroup) {
180  if ($stageAssignment->getUserGroupId() == $workflowUserGroup->getId() &&
181  !$stageAssignment->getRecommendOnly()) {
182  $canPublish = true;
183  break;
184  }
185  }
186  }
187  }
188  }
189  if (!empty($accessibleWorkflowStages[$currentStageId]) && array_intersect([ROLE_ID_MANAGER, ROLE_ID_SUB_EDITOR], $accessibleWorkflowStages[$currentStageId])) {
190  $canAccessEditorialHistory = true;
191  }
192 
193  $supportedSubmissionLocales = $submissionContext->getSupportedSubmissionLocales();
194  $localeNames = AppLocale::getAllLocales();
195  $locales = array_map(function($localeKey) use ($localeNames) {
196  return ['key' => $localeKey, 'label' => $localeNames[$localeKey]];
197  }, $supportedSubmissionLocales);
198 
199  $latestPublication = $submission->getLatestPublication();
200 
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());
203 
204  $contributorsGridUrl = $request->getDispatcher()->url(
205  $request,
206  ROUTE_COMPONENT,
207  null,
208  'grid.users.author.AuthorGridHandler',
209  'fetchGrid',
210  null,
211  [
212  'submissionId' => $submission->getId(),
213  'publicationId' => '__publicationId__',
214  ]
215  );
216 
217  $editorialHistoryUrl = $request->getDispatcher()->url(
218  $request,
219  ROUTE_COMPONENT,
220  null,
221  'informationCenter.SubmissionInformationCenterHandler',
222  'viewInformationCenter',
223  null,
224  array('submissionId' => $submission->getId())
225  );
226 
227  $submissionLibraryUrl = $request->getDispatcher()->url(
228  $request,
229  ROUTE_COMPONENT,
230  null,
231  'modals.documentLibrary.DocumentLibraryHandler',
232  'documentLibrary',
233  null,
234  array('submissionId' => $submission->getId())
235  );
236 
237  $publishUrl = $request->getDispatcher()->url(
238  $request,
239  ROUTE_COMPONENT,
240  null,
241  'modals.publish.PublishHandler',
242  'publish',
243  null,
244  [
245  'submissionId' => $submission->getId(),
246  'publicationId' => '__publicationId__',
247  ]
248  );
249 
250  $citationsForm = new PKP\components\forms\publication\PKPCitationsForm($latestPublicationApiUrl, $latestPublication);
251  $publicationLicenseForm = new PKP\components\forms\publication\PKPPublicationLicenseForm($latestPublicationApiUrl, $locales, $latestPublication, $submissionContext, $authorUserGroups);
252  $titleAbstractForm = new PKP\components\forms\publication\PKPTitleAbstractForm($latestPublicationApiUrl, $locales, $latestPublication);
253 
254  // Import constants
255  import('classes.submission.Submission');
256  import('classes.components.forms.publication.PublishForm');
257 
258  $templateMgr->setConstants([
259  'STATUS_QUEUED',
260  'STATUS_PUBLISHED',
261  'STATUS_DECLINED',
262  'STATUS_SCHEDULED',
263  'FORM_CITATIONS',
264  'FORM_PUBLICATION_LICENSE',
265  'FORM_PUBLISH',
266  'FORM_TITLE_ABSTRACT',
267  ]);
268 
269  // Get the submission props without the full publication details. We'll
270  // retrieve just the publication information that we need separately to
271  // reduce the amount of data passed to the browser
272  $propNames = Services::get('schema')->getSummaryProps(SCHEMA_SUBMISSION);
273  $propNames = array_filter($propNames, function($propName) { return $propName !== 'publications'; });
274  $submissionProps = Services::get('submission')->getProperties(
275  $submission,
276  $propNames,
277  [
278  'request' => $request,
279  'userGroups' => $authorUserGroups,
280  ]
281  );
282 
283  // Get an array of publication identifiers
284  $publicationList = [];
285  foreach ($submission->getData('publications') as $publication) {
286  $publicationList[] = Services::get('publication')->getProperties(
287  $publication,
288  ['id', 'datePublished', 'status', 'version'],
289  [
290  'context' => $submissionContext,
291  'submission' => $submission,
292  'request' => $request,
293  ]
294  );
295  }
296 
297  // Get full details of the working publication and the currently published publication
298  $workingPublicationProps = Services::get('publication')->getFullProperties(
299  $submission->getLatestPublication(),
300  [
301  'context' => $submissionContext,
302  'submission' => $submission,
303  'request' => $request,
304  'userGroups' => $authorUserGroups,
305  ]
306  );
307  if ($submission->getLatestPublication()->getId() === $submission->getCurrentPublication()->getId()) {
308  $currentPublicationProps = $workingPublicationProps;
309  } else {
310  $currentPublicationProps = Services::get('publication')->getFullProperties(
311  $submission->getCurrentPublication(),
312  [
313  'context' => $submissionContext,
314  'submission' => $submission,
315  'request' => $request,
316  'userGroups' => $authorUserGroups,
317  ]
318  );
319  }
320 
321  $state = [
322  'activityLogLabel' => __('submission.list.infoCenter'),
323  'canAccessPublication' => $canAccessPublication,
324  'canEditPublication' => $canEditPublication,
325  'components' => [
326  FORM_CITATIONS => $citationsForm->getConfig(),
327  FORM_PUBLICATION_LICENSE => $publicationLicenseForm->getConfig(),
328  FORM_TITLE_ABSTRACT => $titleAbstractForm->getConfig(),
329  ],
330  'contributorsGridUrl' => $contributorsGridUrl,
331  'currentPublication' => $currentPublicationProps,
332  'editorialHistoryUrl' => $editorialHistoryUrl,
333  'publicationFormIds' => [
334  FORM_CITATIONS,
335  FORM_PUBLICATION_LICENSE,
336  FORM_PUBLISH,
337  FORM_TITLE_ABSTRACT,
338  ],
339  'publicationList' => $publicationList,
340  'publicationTabsLabel' => __('publication.version.details'),
341  'publishLabel' => __('publication.publish'),
342  'publishUrl' => $publishUrl,
343  'representationsGridUrl' => $this->_getRepresentationsGridUrl($request, $submission),
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,
358  ];
359 
360  // Add the metadata form if one or more metadata fields are enabled
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;
366  break;
367  }
368  }
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__']);
371  $metadataForm = new PKP\components\forms\publication\PKPMetadataForm($latestPublicationApiUrl, $locales, $latestPublication, $submissionContext, $vocabSuggestionUrlBase);
372  $templateMgr->setConstants(['FORM_METADATA']);
373  $state['components'][FORM_METADATA] = $metadataForm->getConfig();
374  $state['publicationFormIds'][] = FORM_METADATA;
375  }
376 
377  // Add the identifieres form if one or more identifier is enabled
378  $identifiersEnabled = false;
379  $pubIdPlugins = PluginRegistry::getPlugins('pubIds');
380  foreach ($pubIdPlugins as $pubIdPlugin) {
381  if ($pubIdPlugin->isObjectTypeEnabled('Publication', $request->getContext()->getId())) {
382  $identifiersEnabled = true;
383  break;
384  }
385  }
386  if ($identifiersEnabled) {
387  $identifiersForm = new PKP\components\forms\publication\PKPPublicationIdentifiersForm($latestPublicationApiUrl, $locales, $latestPublication, $submissionContext);
388  $templateMgr->setConstants(['FORM_PUBLICATION_IDENTIFIERS']);
389  $state['components'][FORM_PUBLICATION_IDENTIFIERS] = $identifiersForm->getConfig();
390  $state['publicationFormIds'][] = FORM_PUBLICATION_IDENTIFIERS;
391  }
392 
393  $templateMgr->setState($state);
394 
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()
407  ]),
408  'pageWidth' => PAGE_WIDTH_WIDE,
409  'requestedStageId' => $requestedStageId,
410  'submission' => $submission,
411  'workflowStages' => $workflowStages,
412  ]);
413 
414  $this->setupIndex($request);
415 
416  $templateMgr->display('workflow/workflow.tpl');
417  }
418 
424  function submission($args, $request) {
425  $this->_redirectToIndex($args, $request);
426  }
427 
433  function externalReview($args, $request) {
434  $this->_redirectToIndex($args, $request);
435  }
436 
442  function editorial($args, $request) {
443  $this->_redirectToIndex($args, $request);
444  }
445 
451  function production($args, $request) {
452  $this->_redirectToIndex($args, $request);
453  }
454 
460  protected function _redirectToIndex($args, $request) {
461  // Translate the operation to a workflow stage identifier.
462  $submission = $this->getAuthorizedContextObject(ASSOC_TYPE_SUBMISSION);
463  $router = $request->getRouter();
464  $workflowPath = $router->getRequestedOp($request);
465  $stageId = WorkflowStageDAO::getIdFromPath($workflowPath);
466  $request->redirectUrl($router->url($request, null, 'workflow', 'index', array($submission->getId(), $stageId)));
467  }
468 
475  function editorDecisionActions($args, $request) {
476  $this->setupTemplate($request);
477  AppLocale::requireComponents(LOCALE_COMPONENT_APP_EDITOR);
478  $reviewRoundId = (int) $request->getUserVar('reviewRoundId');
479 
480  // Prepare the action arguments.
481  $submission = $this->getAuthorizedContextObject(ASSOC_TYPE_SUBMISSION);
482  $stageId = $this->getAuthorizedContextObject(ASSOC_TYPE_WORKFLOW_STAGE);
483 
484  $actionArgs = array(
485  'submissionId' => $submission->getId(),
486  'stageId' => (int) $stageId,
487  );
488 
489  // If a review round was specified, include it in the args;
490  // must also check that this is the last round or decisions
491  // cannot be recorded.
492  if ($reviewRoundId) {
493  $actionArgs['reviewRoundId'] = $reviewRoundId;
494  $reviewRoundDao = DAORegistry::getDAO('ReviewRoundDAO'); /* @var $reviewRoundDao ReviewRoundDAO */
495  $lastReviewRound = $reviewRoundDao->getLastReviewRoundBySubmissionId($submission->getId(), $stageId);
496  $reviewRound = $reviewRoundDao->getById($reviewRoundId);
497  } else {
498  $lastReviewRound = null;
499  }
500 
501  // If there is an editor assigned, retrieve stage decisions.
502  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
503  $editorsStageAssignments = $stageAssignmentDao->getEditorsAssignedToStage($submission->getId(), $stageId);
504  $dispatcher = $request->getDispatcher();
505  $user = $request->getUser();
506 
507  $recommendOnly = $makeDecision = false;
508  // if the user is assigned several times in an editorial role, check his/her assignments permissions i.e.
509  // if the user is assigned with both possibilities: to only recommend as well as make decision
510  foreach ($editorsStageAssignments as $editorsStageAssignment) {
511  if ($editorsStageAssignment->getUserId() == $user->getId()) {
512  if (!$editorsStageAssignment->getRecommendOnly()) {
513  $makeDecision = true;
514  } else {
515  $recommendOnly = true;
516  }
517  }
518  }
519 
520  // If user is not assigned to the submission,
521  // see if the user is manager, and
522  // if the group is recommendOnly
523  if (!$recommendOnly && !$makeDecision) {
524  $userGroupDao = DAORegistry::getDAO('UserGroupDAO'); /* @var $userGroupDao UserGroupDAO */
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;
530  } else {
531  $recommendOnly = true;
532  }
533  }
534  }
535  }
536 
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');
543  $editDecisionDao = DAORegistry::getDAO('EditDecisionDAO'); /* @var $editDecisionDao EditDecisionDAO */
544  $recommendationOptions = (new EditorDecisionActionsManager())->getRecommendationOptions($stageId);
545  // If this is a review stage and the user has "recommend only role"
546  if (($stageId == WORKFLOW_STAGE_ID_EXTERNAL_REVIEW || $stageId == WORKFLOW_STAGE_ID_INTERNAL_REVIEW)) {
547  if ($recommendOnly) {
548  // Get the made editorial decisions from the current user
549  $editorDecisions = $editDecisionDao->getEditorDecisions($submission->getId(), $stageId, $reviewRound->getRound(), $user->getId());
550  // Get the last recommendation
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;
556  }
557  } else {
558  $lastRecommendation = $editorDecision;
559  }
560  }
561  }
562  if ($lastRecommendation) {
563  $lastRecommendation = __($recommendationOptions[$lastRecommendation['decision']]);
564  }
565  // Add the recommend link action.
566  $editorActions[] =
567  new LinkAction(
568  'recommendation',
569  new AjaxModal(
570  $dispatcher->url(
571  $request, ROUTE_COMPONENT, null,
572  'modals.editorDecision.EditorDecisionHandler',
573  'sendRecommendation', null, $actionArgs
574  ),
575  $lastRecommendation ? __('editor.submission.changeRecommendation') : __('editor.submission.makeRecommendation'),
576  'review_recommendation'
577  ),
578  $lastRecommendation ? __('editor.submission.changeRecommendation') : __('editor.submission.makeRecommendation')
579  );
580  } elseif ($makeDecision) {
581  // Get the made editorial decisions from all users
582  $editorDecisions = $editDecisionDao->getEditorDecisions($submission->getId(), $stageId, $reviewRound->getRound());
583  // Get all recommendations
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']);
590  }
591  } else {
592  $recommendations[$editorDecision['editorId']] = array('dateDecided' => $editorDecision['dateDecided'], 'decision' => $editorDecision['decision']);
593  }
594  }
595  }
596  $i = 0;
597  foreach ($recommendations as $recommendation) {
598  $allRecommendations .= $i == 0 ? __($recommendationOptions[$recommendation['decision']]) : __('common.commaListSeparator') . __($recommendationOptions[$recommendation['decision']]);
599  $i++;
600  }
601  }
602  }
603  // Get the possible editor decisions for this stage
604  $decisions = (new EditorDecisionActionsManager())->getStageDecisions($request->getContext(), $stageId, $makeDecision);
605  // Iterate through the editor decisions and create a link action
606  // for each decision which as an operation associated with it.
607  foreach($decisions as $decision => $action) {
608  if (empty($action['operation'])) {
609  continue;
610  }
611  $actionArgs['decision'] = $decision;
612  $editorActions[] = new LinkAction(
613  $action['name'],
614  new AjaxModal(
615  $dispatcher->url(
616  $request, ROUTE_COMPONENT, null,
617  'modals.editorDecision.EditorDecisionHandler',
618  $action['operation'], null, $actionArgs
619  ),
620  __($action['title'])
621  ),
622  __($action['title'])
623  );
624  }
625  }
626 
627  import('lib.pkp.classes.workflow.WorkflowStageDAO');
628  $workflowStageDao = DAORegistry::getDAO('WorkflowStageDAO'); /* @var $workflowStageDao WorkflowStageDAO */
629  $hasSubmissionPassedThisStage = $submission->getStageId() > $stageId;
630  $lastDecision = null;
631  switch( $submission->getStatus() ) {
632  case STATUS_QUEUED:
633  switch( $stageId ) {
634  case WORKFLOW_STAGE_ID_SUBMISSION:
635  if ($hasSubmissionPassedThisStage) {
636  $lastDecision = 'editor.submission.workflowDecision.submission.underReview';
637  }
638  break;
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';
645  }
646  break;
647  case WORKFLOW_STAGE_ID_EDITING:
648  if($hasSubmissionPassedThisStage) {
649  $lastDecision = 'editor.submission.workflowDecision.submission.production';
650  }
651  break;
652  }
653  break;
654  case STATUS_PUBLISHED:
655  $lastDecision = 'editor.submission.workflowDecision.submission.published';
656  break;
657  case STATUS_DECLINED:
658  $lastDecision = 'editor.submission.workflowDecision.submission.declined';
659  break;
660  }
661 
662  // Assign the actions to the template.
663  $templateMgr = TemplateManager::getManager($request);
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,
672  ));
673  return $templateMgr->fetchJson('workflow/editorialLinkActions.tpl');
674  }
675 
682  function submissionProgressBar($args, $request) {
683  $this->setupTemplate($request);
684  $submission = $this->getAuthorizedContextObject(ASSOC_TYPE_SUBMISSION);
686 
687  $templateMgr = TemplateManager::getManager($request);
688  $templateMgr->assign([
689  'submission' => $submission,
690  'currentStageId' => $this->identifyStageId($request, $args),
691  'workflowStages' => $workflowStages,
692  ]);
693 
694  return $templateMgr->fetchJson('workflow/submissionProgressBar.tpl');
695  }
696 
701  function setupTemplate($request) {
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);
704  }
705 
712  public function setupIndex($request) {}
713 
714  //
715  // Protected helper methods
716  //
717 
724  protected function identifyStageId($request, $args) {
725  if ($stageId = $request->getUserVar('stageId')) {
726  return (int) $stageId;
727  }
728 
729  // Maintain the old check for previous path urls
730  $router = $request->getRouter();
731  $workflowPath = $router->getRequestedOp($request);
732  $stageId = WorkflowStageDAO::getIdFromPath($workflowPath);
733  if ($stageId) {
734  return $stageId;
735  }
736 
737  // Finally, retrieve the requested operation, if the stage id is
738  // passed in via an argument in the URL, like index/submissionId/stageId
739  $stageId = $args[1];
740 
741  // Translate the operation to a workflow stage identifier.
742  assert(WorkflowStageDAO::getPathFromId($stageId) !== null);
743  return $stageId;
744  }
745 
754  protected function notificationOptionsByStage($user, $stageId, $contextId) {
755  $submission = $this->getAuthorizedContextObject(ASSOC_TYPE_SUBMISSION);
756  $notificationDao = DAORegistry::getDAO('NotificationDAO'); /* @var $notificationDao NotificationDAO */
757 
758  $editorAssignmentNotificationType = $this->getEditorAssignmentNotificationTypeByStageId($stageId);
759 
760  $editorAssignments = $notificationDao->getByAssoc(ASSOC_TYPE_SUBMISSION, $submission->getId(), null, $editorAssignmentNotificationType, $contextId);
761 
762  // if the User has assigned TASKs in this stage check, return true
763  if (!$editorAssignments->wasEmpty()) {
764  return true;
765  }
766 
767  // check for more specific notifications on those stages that have them.
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()) {
771  return true;
772  }
773  }
774 
775  return false;
776  }
777 
778 
779  //
780  // Abstract protected methods.
781  //
787  abstract protected function getEditorAssignmentNotificationTypeByStageId($stageId);
788 
797  abstract protected function _getRepresentationsGridUrl($request, $submission);
798 }
799 
800 
PKPWorkflowHandler\externalReview
externalReview($args, $request)
Definition: PKPWorkflowHandler.inc.php:433
PKPLocale\getAllLocales
static & getAllLocales()
Definition: PKPLocale.inc.php:537
UserAccessibleWorkflowStageRequiredPolicy
Policy to deny access if an user assigned workflow stage is not found.
Definition: UserAccessibleWorkflowStageRequiredPolicy.inc.php:19
AppLocale\requireComponents
static requireComponents()
Definition: env1/MockAppLocale.inc.php:56
PluginRegistry\getPlugins
static & getPlugins($category=null)
Definition: PluginRegistry.inc.php:30
PKPWorkflowHandler\editorDecisionActions
editorDecisionActions($args, $request)
Definition: PKPWorkflowHandler.inc.php:475
PKPWorkflowHandler\submissionProgressBar
submissionProgressBar($args, $request)
Definition: PKPWorkflowHandler.inc.php:682
DAORegistry\getDAO
static & getDAO($name, $dbconn=null)
Definition: DAORegistry.inc.php:57
PKPWorkflowHandler\access
access($args, $request)
Definition: PKPWorkflowHandler.inc.php:69
PKP\components\forms\publication\PKPPublicationLicenseForm
Definition: PKPPublicationLicenseForm.inc.php:22
PKPWorkflowHandler
Definition: PKPWorkflowHandler.inc.php:24
PKPWorkflowHandler\authorize
authorize($request, &$args, $roleAssignments)
Definition: PKPWorkflowHandler.inc.php:35
PKPHandler\getId
getId()
Definition: PKPHandler.inc.php:107
PKPWorkflowHandler\identifyStageId
identifyStageId($request, $args)
Definition: PKPWorkflowHandler.inc.php:724
PKPWorkflowHandler\production
production($args, $request)
Definition: PKPWorkflowHandler.inc.php:451
EditorDecisionActionsManager
Wrapper class for create and assign editor decisions actions to template manager.
Definition: EditorDecisionActionsManager.inc.php:33
PKPHandler\markRoleAssignmentsChecked
markRoleAssignmentsChecked()
Definition: PKPHandler.inc.php:268
PKPWorkflowHandler\_redirectToIndex
_redirectToIndex($args, $request)
Definition: PKPWorkflowHandler.inc.php:460
PKPWorkflowHandler\_getRepresentationsGridUrl
_getRepresentationsGridUrl($request, $submission)
AjaxModal
A modal that retrieves its content from via AJAX.
Definition: AjaxModal.inc.php:18
LinkAction
Base class defining an action that can be performed by the user in the user interface.
Definition: LinkAction.inc.php:22
PKPWorkflowHandler\getEditorAssignmentNotificationTypeByStageId
getEditorAssignmentNotificationTypeByStageId($stageId)
WorkflowStageDAO\getIdFromPath
static getIdFromPath($stagePath)
Definition: WorkflowStageDAO.inc.php:43
PKPWorkflowHandler\editorial
editorial($args, $request)
Definition: PKPWorkflowHandler.inc.php:442
PKPTemplateManager\getManager
static & getManager($request=null)
Definition: PKPTemplateManager.inc.php:1239
PKPWorkflowHandler\$_isBackendPage
$_isBackendPage
Definition: PKPWorkflowHandler.inc.php:27
PKPApplication\getWorkflowTypeRoles
static getWorkflowTypeRoles()
Definition: PKPApplication.inc.php:756
PKPWorkflowHandler\notificationOptionsByStage
notificationOptionsByStage($user, $stageId, $contextId)
Definition: PKPWorkflowHandler.inc.php:754
PKPHandler\getAuthorizedContextObject
& getAuthorizedContextObject($assocType)
Definition: PKPHandler.inc.php:174
WorkflowStageAccessPolicy
Class to control access to OMP's submission workflow stage components.
Definition: WorkflowStageAccessPolicy.inc.php:19
PKPWorkflowHandler\setupIndex
setupIndex($request)
Definition: PKPWorkflowHandler.inc.php:712
WorkflowStageDAO\getWorkflowStageKeysAndPaths
static getWorkflowStageKeysAndPaths()
Definition: WorkflowStageDAO.inc.php:92
PKPWorkflowHandler\setupTemplate
setupTemplate($request)
Definition: PKPWorkflowHandler.inc.php:701
PKPWorkflowHandler\index
index($args, $request)
Definition: PKPWorkflowHandler.inc.php:106
PKP\components\forms\publication\PKPTitleAbstractForm
Definition: PKPTitleAbstractForm.inc.php:21
PKPWorkflowHandler\submission
submission($args, $request)
Definition: PKPWorkflowHandler.inc.php:424
WorkflowStageDAO\getPathFromId
static getPathFromId($stageId)
Definition: WorkflowStageDAO.inc.php:24
PKP\components\forms\publication\PKPCitationsForm
Definition: PKPCitationsForm.inc.php:20
PKP\components\forms\publication\PKPPublicationIdentifiersForm
Definition: PKPPublicationIdentifiersForm.inc.php:19
SubmissionRequiredPolicy
Policy that ensures that the request contains a valid submission.
Definition: SubmissionRequiredPolicy.inc.php:17
PKP\components\forms\publication\PKPMetadataForm
Definition: PKPMetadataForm.inc.php:21
PKPHandler\addPolicy
addPolicy($authorizationPolicy, $addToTop=false)
Definition: PKPHandler.inc.php:157
Handler
Base request handler application class.
Definition: Handler.inc.php:18
PKPServices\get
static get($service)
Definition: PKPServices.inc.php:49