• Main Page
  • Modules
  • Classes
  • Files
  • File List

pages/workflow/WorkflowHandler.inc.php

00001 <?php
00002 
00015 import('classes.handler.Handler');
00016 
00017 // import UI base classes
00018 import('lib.pkp.classes.linkAction.LinkAction');
00019 import('lib.pkp.classes.linkAction.request.AjaxModal');
00020 
00021 // Access decision actions constants.
00022 import('classes.workflow.EditorDecisionActionsManager');
00023 
00024 
00025 class WorkflowHandler extends Handler {
00029    function WorkflowHandler() {
00030       parent::Handler();
00031 
00032       $this->addRoleAssignment(
00033          array(ROLE_ID_SERIES_EDITOR, ROLE_ID_PRESS_MANAGER, ROLE_ID_PRESS_ASSISTANT),
00034          array(
00035             'access', 'submission',
00036             'editorDecisionActions', // Submission & review
00037             'internalReview', // Internal review
00038             'externalReview', // External review
00039             'editorial',
00040             'production', 'productionFormatsTab', // Production
00041             'submissionProgressBar'
00042          )
00043       );
00044    }
00045 
00046 
00047    //
00048    // Implement template methods from PKPHandler
00049    //
00053    function authorize(&$request, $args, $roleAssignments) {
00054       $router =& $request->getRouter();
00055       $operation = $router->getRequestedOp($request);
00056 
00057       if ($operation == 'access') {
00058          // Authorize requested monograph.
00059          import('classes.security.authorization.internal.MonographRequiredPolicy');
00060          $this->addPolicy(new MonographRequiredPolicy($request, $args, 'monographId'));
00061 
00062          // This policy will deny access if user has no accessible workflow stage.
00063          // Otherwise it will build an authorized object with all accessible
00064          // workflow stages and authorize user operation access.
00065          import('classes.security.authorization.internal.UserAccessibleWorkflowStageRequiredPolicy');
00066          $this->addPolicy(new UserAccessibleWorkflowStageRequiredPolicy($request));
00067       } else {
00068          import('classes.security.authorization.OmpWorkflowStageAccessPolicy');
00069          $this->addPolicy(new OmpWorkflowStageAccessPolicy($request, $args, $roleAssignments, 'monographId', $this->_identifyStageId($request)));
00070       }
00071 
00072       return parent::authorize($request, $args, $roleAssignments);
00073    }
00074 
00078    function initialize(&$request, $args) {
00079       $router =& $request->getRouter();
00080       $operation = $router->getRequestedOp($request);
00081 
00082       if ($operation != 'access') {
00083          $this->setupTemplate($request);
00084       }
00085 
00086       // Call parent method.
00087       parent::initialize($request, $args);
00088    }
00089 
00094    function setupTemplate(&$request) {
00095       parent::setupTemplate();
00096       AppLocale::requireComponents(LOCALE_COMPONENT_PKP_SUBMISSION, LOCALE_COMPONENT_OMP_SUBMISSION, LOCALE_COMPONENT_OMP_EDITOR, LOCALE_COMPONENT_PKP_GRID);
00097 
00098       $router =& $request->getRouter();
00099 
00100       $monograph =& $this->getAuthorizedContextObject(ASSOC_TYPE_MONOGRAPH);
00101       $stageId = $this->getAuthorizedContextObject(ASSOC_TYPE_WORKFLOW_STAGE);
00102 
00103       // Construct array with workflow stages data.
00104       $userGroupDao =& DAORegistry::getDAO('UserGroupDAO');
00105       $workflowStages = $userGroupDao->getWorkflowStageKeysAndPaths();
00106 
00107       $templateMgr =& TemplateManager::getManager();
00108 
00109       // Assign the authorized monograph.
00110       $templateMgr->assign_by_ref('monograph', $monograph);
00111 
00112       // Assign workflow stages related data.
00113       $templateMgr->assign('stageId', $stageId);
00114       $templateMgr->assign('monographStageId', $monograph->getStageId());
00115       $templateMgr->assign('workflowStages', $workflowStages);
00116 
00117       // Get the right notifications type based on current stage id.
00118       $notificationMgr = new NotificationManager();
00119       $editorAssignmentNotificationType = $notificationMgr->getEditorAssignmentNotificationTypeByStageId($stageId);
00120 
00121       // Define the workflow notification options.
00122       $notificationRequestOptions = array(
00123          NOTIFICATION_LEVEL_TASK => array(
00124             $editorAssignmentNotificationType => array(ASSOC_TYPE_MONOGRAPH, $monograph->getId())
00125          ),
00126          NOTIFICATION_LEVEL_TRIVIAL => array()
00127       );
00128 
00129       $signoffNotificationType = $notificationMgr->getSignoffNotificationTypeByStageId($stageId);
00130       if (!is_null($signoffNotificationType)) {
00131          $notificationRequestOptions[NOTIFICATION_LEVEL_TASK][$signoffNotificationType] = array(ASSOC_TYPE_MONOGRAPH, $monograph->getId());
00132       }
00133 
00134       $templateMgr->assign('workflowNotificationRequestOptions', $notificationRequestOptions);
00135 
00136       import('controllers.modals.submissionMetadata.linkAction.CatalogEntryLinkAction');
00137        $templateMgr->assign(
00138          'catalogEntryAction',
00139          new CatalogEntryLinkAction($request, $monograph->getId(), $stageId)
00140       );
00141 
00142       import('controllers.informationCenter.linkAction.SubmissionInfoCenterLinkAction');
00143       $templateMgr->assign(
00144          'submissionInformationCenterAction',
00145          new SubmissionInfoCenterLinkAction($request, $monograph->getId())
00146       );
00147    }
00148 
00149 
00150    //
00151    // Public handler methods
00152    //
00157    function access($args, &$request) {
00158       $monograph =& $this->getAuthorizedContextObject(ASSOC_TYPE_MONOGRAPH);
00159       $userGroupDao =& DAORegistry::getDAO('UserGroupDAO');
00160       $reviewRoundDao =& DAORegistry::getDAO('ReviewRoundDAO');
00161 
00162       $stageId = $monograph->getStageId();
00163       $accessibleWorkflowStages = $this->getAuthorizedContextObject(ASSOC_TYPE_ACCESSIBLE_WORKFLOW_STAGES);
00164 
00165       // Get the closest workflow stage that user has an assignment.
00166       $stagePath = null;
00167       for ($workingStageId = $stageId; $workingStageId >= WORKFLOW_STAGE_ID_SUBMISSION; $workingStageId--) {
00168          if (array_key_exists($workingStageId, $accessibleWorkflowStages)) {
00169             $stagePath = $userGroupDao->getPathFromId($workingStageId);
00170             break;
00171          }
00172       }
00173 
00174       // If no stage was found, user still have access to future stages of the
00175       // monograph. Try to get the closest future workflow stage.
00176       if (!$stagePath) {
00177          for ($workingStageId = $stageId; $workingStageId <= WORKFLOW_STAGE_ID_PRODUCTION; $workingStageId++) {
00178             if (array_key_exists($workingStageId, $accessibleWorkflowStages)) {
00179                $stagePath = $userGroupDao->getPathFromId($workingStageId);
00180                break;
00181             }
00182          }
00183       }
00184 
00185       assert(!is_null($stagePath));
00186 
00187       $router =& $request->getRouter();
00188       $request->redirectUrl($router->url($request, null, 'workflow', $stagePath, $monograph->getId()));
00189    }
00195    function submission($args, &$request) {
00196       // Render the view.
00197       $templateMgr =& TemplateManager::getManager();
00198       $templateMgr->display('workflow/submission.tpl');
00199    }
00200 
00206    function internalReview($args, &$request) {
00207       // Use different ops so we can identify stage by op.
00208       $templateMgr =& TemplateManager::getManager();
00209       $templateMgr->assign('reviewRoundOp', 'internalReviewRound');
00210       return $this->_review($args, $request);
00211    }
00212 
00218    function externalReview($args, &$request) {
00219       // Use different ops so we can identify stage by op.
00220       $templateMgr =& TemplateManager::getManager();
00221       $templateMgr->assign('reviewRoundOp', 'externalReviewRound');
00222       return $this->_review($args, $request);
00223    }
00224 
00230    function editorial(&$args, &$request) {
00231       // Render the view.
00232       $templateMgr =& TemplateManager::getManager();
00233       $templateMgr->display('workflow/editorial.tpl');
00234    }
00235 
00241    function production(&$args, &$request) {
00242       $templateMgr =& TemplateManager::getManager();
00243       $monograph =& $this->getAuthorizedContextObject(ASSOC_TYPE_MONOGRAPH);
00244       $notificationRequestOptions = array(
00245          NOTIFICATION_LEVEL_NORMAL => array(
00246             NOTIFICATION_TYPE_VISIT_CATALOG => array(ASSOC_TYPE_MONOGRAPH, $monograph->getId()),
00247             NOTIFICATION_TYPE_APPROVE_SUBMISSION => array(ASSOC_TYPE_MONOGRAPH, $monograph->getId()),
00248          ),
00249          NOTIFICATION_LEVEL_TRIVIAL => array()
00250       );
00251 
00252       $publicationFormatDao =& DAORegistry::getDAO('PublicationFormatDAO');
00253       $monograph =& $this->getAuthorizedContextObject(ASSOC_TYPE_MONOGRAPH);
00254       $publicationFormats =& $publicationFormatDao->getByMonographId($monograph->getId());
00255       $templateMgr->assign_by_ref('publicationFormats', $publicationFormats->toAssociativeArray());
00256 
00257       $templateMgr->assign('productionNotificationRequestOptions', $notificationRequestOptions);
00258       $templateMgr->display('workflow/production.tpl');
00259    }
00260 
00266    function productionFormatsTab(&$args, &$request) {
00267       $templateMgr =& TemplateManager::getManager();
00268       $publicationFormatDao =& DAORegistry::getDAO('PublicationFormatDAO');
00269       $monograph =& $this->getAuthorizedContextObject(ASSOC_TYPE_MONOGRAPH);
00270       $publicationFormats =& $publicationFormatDao->getByMonographId($monograph->getId());
00271       $templateMgr->assign_by_ref('$monograph', $monograph);
00272       $templateMgr->assign_by_ref('publicationFormats', $publicationFormats->toAssociativeArray());
00273       $templateMgr->assign('currentFormatTabId', (int) $request->getUserVar('currentFormatTabId'));
00274 
00275       return $templateMgr->fetchJson('workflow/productionFormatsTab.tpl');
00276    }
00277 
00283    function editorDecisionActions($args, &$request) {
00284       AppLocale::requireComponents(LOCALE_COMPONENT_OMP_EDITOR);
00285       $reviewRoundId = (int) $request->getUserVar('reviewRoundId');
00286 
00287       // Prepare the action arguments.
00288       $monograph =& $this->getAuthorizedContextObject(ASSOC_TYPE_MONOGRAPH);
00289       $stageId = $this->getAuthorizedContextObject(ASSOC_TYPE_WORKFLOW_STAGE);
00290 
00291       $actionArgs = array(
00292          'monographId' => $monograph->getId(),
00293          'stageId' => (int) $stageId,
00294       );
00295       // If a review round was specified, include it in the args;
00296       // must also check that this is the last round or decisions
00297       // cannot be recorded.
00298       if ($reviewRoundId) {
00299          $actionArgs['reviewRoundId'] = $reviewRoundId;
00300          $reviewRoundDao =& DAORegistry::getDAO('ReviewRoundDAO');
00301          $lastReviewRound =& $reviewRoundDao->getLastReviewRoundByMonographId($monograph->getId(), $stageId);
00302       }
00303 
00304       // If a review round was specified,
00305 
00306       // If there is an editor assigned, retrieve stage decisions.
00307       $stageAssignmentDao =& DAORegistry::getDAO('StageAssignmentDAO');
00308       if ($stageAssignmentDao->editorAssignedToStage($monograph->getId(), $stageId) && (!$reviewRoundId || $reviewRoundId == $lastReviewRound->getId())) {
00309          import('classes.workflow.EditorDecisionActionsManager');
00310          $decisions = EditorDecisionActionsManager::getStageDecisions($stageId);
00311       } else {
00312          $decisions = array(); // None available
00313       }
00314 
00315       // Iterate through the editor decisions and create a link action for each decision.
00316       $editorActions = array();
00317       $dispatcher =& $request->getDispatcher();
00318       import('classes.linkAction.request.AjaxModal');
00319       foreach($decisions as $decision => $action) {
00320          $actionArgs['decision'] = $decision;
00321          $editorActions[] = new LinkAction(
00322             $action['name'],
00323             new AjaxModal(
00324                $dispatcher->url(
00325                   $request, ROUTE_COMPONENT, null,
00326                   'modals.editorDecision.EditorDecisionHandler',
00327                   $action['operation'], null, $actionArgs
00328                ),
00329                __($action['title']),
00330                $action['titleIcon']
00331             ),
00332             __($action['title'])
00333          );
00334       }
00335 
00336       // Assign the actions to the template.
00337       $templateMgr =& TemplateManager::getManager();
00338       $templateMgr->assign('editorActions', $editorActions);
00339       $templateMgr->assign('stageId', $stageId);
00340       return $templateMgr->fetchJson('workflow/editorialLinkActions.tpl');
00341    }
00342 
00348    function submissionProgressBar($args, &$request) {
00349       // Assign the actions to the template.
00350       $templateMgr =& TemplateManager::getManager();
00351       $press =& $request->getPress();
00352 
00353       $userGroupDao =& DAORegistry::getDAO('UserGroupDAO');
00354       $workflowStages = $userGroupDao->getWorkflowStageKeysAndPaths();
00355       $stageNotifications = array();
00356       foreach (array_keys($workflowStages) as $stageId) {
00357          $stageNotifications[$stageId] = $this->_notificationOptionsByStage($request->getUser(), $stageId, $press->getId());
00358       }
00359 
00360       $templateMgr->assign('stageNotifications', $stageNotifications);
00361 
00362       $monograph =& $this->getAuthorizedContextObject(ASSOC_TYPE_MONOGRAPH);
00363       $publishedMonographDao =& DAORegistry::getDAO('PublishedMonographDAO');
00364       $publishedMonograph =& $publishedMonographDao->getById($monograph->getId());
00365       if ($publishedMonograph) { // first check, there's a published monograph
00366          $publicationFormats =& $publishedMonograph->getPublicationFormats(true);
00367          $submissionFileDao =& DAORegistry::getDAO('SubmissionFileDAO');
00368          import('classes.monograph.MonographFile'); // constants
00369 
00370          foreach ($publicationFormats as $format) { // there is at least one publication format.
00371             if ($format->getIsApproved()) { // it's ready to be included in the catalog
00372 
00373                $monographFiles =& $submissionFileDao->getLatestRevisionsByAssocId(
00374                      ASSOC_TYPE_PUBLICATION_FORMAT, $format->getId(),
00375                      $publishedMonograph->getId()
00376                );
00377 
00378                foreach ($monographFiles as $file) {
00379                   if ($file->getViewable() && !is_null($file->getDirectSalesPrice())) { // at least one file has a price set.
00380                      $templateMgr->assign('submissionIsReady', true);
00381                   }
00382                }
00383             }
00384          }
00385       }
00386       return $templateMgr->fetchJson('workflow/submissionProgressBar.tpl');
00387    }
00388 
00395    function _notificationOptionsByStage(&$user, $stageId, $contextId) {
00396 
00397       $monograph =& $this->getAuthorizedContextObject(ASSOC_TYPE_MONOGRAPH);
00398       $notificationDao =& DAORegistry::getDAO('NotificationDAO');
00399       $notificationMgr = new NotificationManager();
00400 
00401       $signOffNotificationType = $notificationMgr->getSignoffNotificationTypeByStageId($stageId);
00402       $editorAssignmentNotificationType = $notificationMgr->getEditorAssignmentNotificationTypeByStageId($stageId);
00403 
00404       $editorAssignments =& $notificationDao->getByAssoc(ASSOC_TYPE_MONOGRAPH, $monograph->getId(), null, $editorAssignmentNotificationType, $contextId);
00405       if (isset($signOffNotificationType)) {
00406          $signoffAssignments =& $notificationDao->getByAssoc(ASSOC_TYPE_MONOGRAPH, $monograph->getId(), $user->getUserId(), $signOffNotificationType, $contextId);
00407       }
00408 
00409       // if the User has assigned TASKs in this stage check, return true
00410       if (!$editorAssignments->wasEmpty() || (isset($signoffAssignments) && !$signoffAssignments->wasEmpty())) {
00411          return true;
00412       }
00413 
00414       // check for more specific notifications on those stages that have them.
00415       if ($stageId == WORKFLOW_STAGE_ID_PRODUCTION) {
00416          $submissionApprovalNotification =& $notificationDao->getByAssoc(ASSOC_TYPE_MONOGRAPH, $monograph->getId(), null, NOTIFICATION_TYPE_APPROVE_SUBMISSION, $contextId);
00417          if (!$submissionApprovalNotification->wasEmpty()) {
00418             return true;
00419          }
00420       }
00421 
00422       if ($stageId == WORKFLOW_STAGE_ID_INTERNAL_REVIEW || $stageId == WORKFLOW_STAGE_ID_EXTERNAL_REVIEW) {
00423          $reviewRoundDao =& DAORegistry::getDAO('ReviewRoundDAO');
00424          $reviewRounds =& $reviewRoundDao->getByMonographId($monograph->getId(), $stageId);
00425          $notificationTypes = array(NOTIFICATION_TYPE_REVIEW_ROUND_STATUS, NOTIFICATION_TYPE_ALL_REVIEWS_IN);
00426          while ($reviewRound =& $reviewRounds->next()) {
00427             foreach ($notificationTypes as $type) {
00428                $notifications =& $notificationDao->getByAssoc(ASSOC_TYPE_REVIEW_ROUND, $reviewRound->getId(), null, $type, $contextId);
00429                if (!$notifications->wasEmpty()) {
00430                   return true;
00431                }
00432             }
00433             unset($reviewRound);
00434          }
00435       }
00436 
00437       return false;
00438    }
00439 
00440    //
00441    // Private helper methods
00442    //
00448    function _review($args, &$request) {
00449       // Retrieve the authorized submission and stage id.
00450       $monograph =& $this->getAuthorizedContextObject(ASSOC_TYPE_MONOGRAPH);
00451       $selectedStageId = $this->getAuthorizedContextObject(ASSOC_TYPE_WORKFLOW_STAGE);
00452 
00453       $templateMgr =& TemplateManager::getManager();
00454 
00455       // Get all review rounds for this submission, on the current stage.
00456       $reviewRoundDao =& DAORegistry::getDAO('ReviewRoundDAO');
00457       $reviewRoundsFactory =& $reviewRoundDao->getByMonographId($monograph->getId(), $selectedStageId);
00458       if (!$reviewRoundsFactory->wasEmpty()) {
00459          $reviewRoundsArray =& $reviewRoundsFactory->toAssociativeArray();
00460 
00461          // Get the review round number of the last review round to be used
00462          // as the current review round tab index.
00463          $lastReviewRoundNumber = end($reviewRoundsArray)->getRound();
00464          $lastReviewRoundId = end($reviewRoundsArray)->getId();
00465          reset($reviewRoundsArray);
00466 
00467          // Add the round information to the template.
00468          $templateMgr->assign_by_ref('reviewRounds', $reviewRoundsArray);
00469          $templateMgr->assign('lastReviewRoundNumber', $lastReviewRoundNumber);
00470 
00471          if ($monograph->getStageId() == $selectedStageId) {
00472             $dispatcher =& $request->getDispatcher();
00473             $newRoundAction = new LinkAction(
00474                'newRound',
00475                new AjaxModal(
00476                   $dispatcher->url(
00477                      $request, ROUTE_COMPONENT, null,
00478                      'modals.editorDecision.EditorDecisionHandler',
00479                      'newReviewRound', null, array(
00480                         'monographId' => $monograph->getId(),
00481                         'decision' => SUBMISSION_EDITOR_DECISION_RESUBMIT,
00482                         'stageId' => $selectedStageId,
00483                         'reviewRoundId' => $lastReviewRoundId
00484                      )
00485                   ),
00486                   __('editor.monograph.newRound'),
00487                   'modal_add_item'
00488                ),
00489                __('editor.monograph.newRound'),
00490                'add_item_small'
00491             );
00492             $templateMgr->assign_by_ref('newRoundAction', $newRoundAction);
00493          }
00494       }
00495 
00496       // Render the view.
00497       $templateMgr->display('workflow/review.tpl');
00498    }
00499 
00505    function _identifyStageId(&$request) {
00506       if ($stageId = $request->getUserVar('stageId')) {
00507          return (int) $stageId;
00508       }
00509 
00510       // Retrieve the requested operation.
00511       $router =& $request->getRouter();
00512       $operation = $router->getRequestedOp($request);
00513 
00514       // Translate the operation to a workflow stage identifier.
00515       $userGroupDao =& DAORegistry::getDAO('UserGroupDAO');
00516       return $userGroupDao->getIdFromPath($operation);
00517    }
00518 }
00519 
00520 ?>

Generated on Mon Sep 17 2012 13:58:56 for Open Monograph Press by  doxygen 1.7.1