Open Monograph Press  3.3.0
PKPEditorDecisionHandler.inc.php
1 <?php
2 
16 import('classes.handler.Handler');
17 
18 // import JSON class for use with all AJAX requests
19 import('lib.pkp.classes.core.JSONMessage');
20 
22 
23  //
24  // Implement template methods from PKPHandler
25  //
29  function authorize($request, &$args, $roleAssignments) {
30  // Some operations need a review round id in request.
31  $reviewRoundOps = $this->_getReviewRoundOps();
32  import('lib.pkp.classes.security.authorization.internal.ReviewRoundRequiredPolicy');
33  $this->addPolicy(new ReviewRoundRequiredPolicy($request, $args, 'reviewRoundId', $reviewRoundOps));
34 
35  if (!parent::authorize($request, $args, $roleAssignments)) return false;
36 
37  // Prevent editors who are also assigned as authors from accessing the
38  // review stage operations
39  $operation = $request->getRouter()->getRequestedOp($request);
40  if (in_array($operation, $reviewRoundOps)) {
41  $userAccessibleStages = $this->getAuthorizedContextObject(ASSOC_TYPE_ACCESSIBLE_WORKFLOW_STAGES);
42  foreach ($userAccessibleStages as $stageId => $roles) {
43  if (in_array(ROLE_ID_AUTHOR, $roles)) {
44  return false;
45  }
46  }
47  }
48 
49  return true;
50  }
51 
55  function initialize($request) {
57  LOCALE_COMPONENT_APP_COMMON,
58  LOCALE_COMPONENT_APP_EDITOR,
59  LOCALE_COMPONENT_APP_SUBMISSION,
60  LOCALE_COMPONENT_PKP_EDITOR,
61  LOCALE_COMPONENT_PKP_SUBMISSION
62  );
63  }
64 
65 
66  //
67  // Public handler actions
68  //
75  function newReviewRound($args, $request) {
76  return $this->_initiateEditorDecision($args, $request, 'NewReviewRoundForm');
77  }
78 
85  function externalReview($args, $request) {
86  return $this->_initiateEditorDecision($args, $request, 'InitiateExternalReviewForm');
87  }
88 
95  function saveExternalReview($args, $request) {
96  assert($this->getAuthorizedContextObject(ASSOC_TYPE_WORKFLOW_STAGE) == WORKFLOW_STAGE_ID_SUBMISSION);
97  return $this->_saveEditorDecision(
98  $args, $request, 'InitiateExternalReviewForm',
99  WORKFLOW_STAGE_PATH_EXTERNAL_REVIEW,
100  SUBMISSION_EDITOR_DECISION_EXTERNAL_REVIEW
101  );
102  }
103 
110  function sendReviews($args, $request) {
111  return $this->_initiateEditorDecision($args, $request, 'SendReviewsForm');
112  }
113 
123  function sendReviewsInReview($args, $request) {
124  return $this->_initiateEditorDecision($args, $request, 'SendReviewsForm');
125  }
126 
133  function saveSendReviews($args, $request) {
134  return $this->_saveEditorDecision($args, $request, 'SendReviewsForm');
135  }
136 
143  function saveSendReviewsInReview($args, $request) {
144  return $this->_saveEditorDecision($args, $request, 'SendReviewsForm');
145  }
146 
153  function promote($args, $request) {
154  return $this->_initiateEditorDecision($args, $request, 'PromoteForm');
155  }
156 
165  function promoteInReview($args, $request) {
166  return $this->_initiateEditorDecision($args, $request, 'PromoteForm');
167  }
168 
175  function savePromote($args, $request) {
176  return $this->_saveGeneralPromote($args, $request);
177  }
178 
186  function savePromoteInReview($args, $request) {
187  return $this->_saveGeneralPromote($args, $request);
188  }
189 
196  function importPeerReviews($args, $request) {
197  // Retrieve the authorized submission.
198  $submission = $this->getAuthorizedContextObject(ASSOC_TYPE_SUBMISSION);
199 
200  // Retrieve the current review round.
201  $reviewRound = $this->getAuthorizedContextObject(ASSOC_TYPE_REVIEW_ROUND);
202 
203  // Retrieve peer reviews.
204  $reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /* @var $reviewAssignmentDao ReviewAssignmentDAO */
205  $submissionCommentDao = DAORegistry::getDAO('SubmissionCommentDAO'); /* @var $submissionCommentDao SubmissionCommentDAO */
206  $reviewFormResponseDao = DAORegistry::getDAO('ReviewFormResponseDAO'); /* @var $reviewFormResponseDao ReviewFormResponseDAO */
207  $reviewFormElementDao = DAORegistry::getDAO('ReviewFormElementDAO'); /* @var $reviewFormElementDao ReviewFormElementDAO */
208 
209  $reviewAssignments = $reviewAssignmentDao->getBySubmissionId($submission->getId(), $reviewRound->getId());
210  $reviewIndexes = $reviewAssignmentDao->getReviewIndexesForRound($submission->getId(), $reviewRound->getId());
211  AppLocale::requireComponents(LOCALE_COMPONENT_PKP_SUBMISSION);
212 
213  $body = '';
214  $textSeparator = '------------------------------------------------------';
215  foreach ($reviewAssignments as $reviewAssignment) {
216  // If the reviewer has completed the assignment, then import the review.
217  if ($reviewAssignment->getDateCompleted() != null) {
218  // Get the comments associated with this review assignment
219  $submissionComments = $submissionCommentDao->getSubmissionComments($submission->getId(), COMMENT_TYPE_PEER_REVIEW, $reviewAssignment->getId());
220 
221  $body .= "<br><br>$textSeparator<br>";
222  // If it is an open review, show reviewer's name.
223  if ($reviewAssignment->getReviewMethod() == SUBMISSION_REVIEW_METHOD_OPEN) {
224  $body .= $reviewAssignment->getReviewerFullName() . "<br>\n";
225  } else {
226  $body .= __('submission.comments.importPeerReviews.reviewerLetter', array('reviewerLetter' => PKPString::enumerateAlphabetically($reviewIndexes[$reviewAssignment->getId()]))) . "<br>\n";
227  }
228 
229  while ($comment = $submissionComments->next()) {
230  // If the comment is viewable by the author, then add the comment.
231  if ($comment->getViewable()) {
232  $body .= PKPString::stripUnsafeHtml($comment->getComments());
233  }
234  }
235 
236  // Add reviewer recommendation
237  $recommendation = $reviewAssignment->getLocalizedRecommendation();
238  $body .= __('submission.recommendation', array('recommendation' => $recommendation)) . "<br>\n";
239 
240  $body .= "<br>$textSeparator<br><br>";
241 
242  if ($reviewFormId = $reviewAssignment->getReviewFormId()) {
243  $reviewId = $reviewAssignment->getId();
244 
245 
246  $reviewFormElements = $reviewFormElementDao->getByReviewFormId($reviewFormId);
247  if(!$submissionComments) {
248  $body .= "$textSeparator<br>";
249 
250  $body .= __('submission.comments.importPeerReviews.reviewerLetter', array('reviewerLetter' => PKPString::enumerateAlphabetically($reviewIndexes[$reviewAssignment->getId()]))) . '<br><br>';
251  }
252  while ($reviewFormElement = $reviewFormElements->next()) {
253  if (!$reviewFormElement->getIncluded()) continue;
254 
255  $body .= PKPString::stripUnsafeHtml($reviewFormElement->getLocalizedQuestion());
256  $reviewFormResponse = $reviewFormResponseDao->getReviewFormResponse($reviewId, $reviewFormElement->getId());
257 
258  if ($reviewFormResponse) {
259  $possibleResponses = $reviewFormElement->getLocalizedPossibleResponses();
260  // See issue #2437.
261  if (in_array($reviewFormElement->getElementType(), array(REVIEW_FORM_ELEMENT_TYPE_CHECKBOXES, REVIEW_FORM_ELEMENT_TYPE_RADIO_BUTTONS))) {
262  ksort($possibleResponses);
263  $possibleResponses = array_values($possibleResponses);
264  }
265  if (in_array($reviewFormElement->getElementType(), $reviewFormElement->getMultipleResponsesElementTypes())) {
266  if ($reviewFormElement->getElementType() == REVIEW_FORM_ELEMENT_TYPE_CHECKBOXES) {
267  $body .= '<ul>';
268  foreach ($reviewFormResponse->getValue() as $value) {
269  $body .= '<li>' . PKPString::stripUnsafeHtml($possibleResponses[$value]) . '</li>';
270  }
271  $body .= '</ul>';
272  } else {
273  $body .= '<blockquote>' . PKPString::stripUnsafeHtml($possibleResponses[$reviewFormResponse->getValue()]) . '</blockquote>';
274  }
275  $body .= '<br>';
276  } else {
277  $body .= '<blockquote>' . nl2br(htmlspecialchars($reviewFormResponse->getValue())) . '</blockquote>';
278  }
279  }
280 
281  }
282  $body .= "$textSeparator<br><br>";
283 
284  }
285  }
286  }
287 
288  // Notify the user.
289  $notificationMgr = new NotificationManager();
290  $user = $request->getUser();
291  $notificationMgr->createTrivialNotification($user->getId(), NOTIFICATION_TYPE_SUCCESS, array('contents' => __('editor.review.reviewsAdded')));
292 
293  return new JSONMessage(true, empty($body)?__('editor.review.noReviews'):$body);
294  }
295 
302  function sendRecommendation($args, $request) {
303  // Retrieve the authorized submission, stage id and review round.
304  $submission = $this->getAuthorizedContextObject(ASSOC_TYPE_SUBMISSION);
305  $stageId = $this->getAuthorizedContextObject(ASSOC_TYPE_WORKFLOW_STAGE);
306  assert(in_array($stageId, $this->_getReviewStages()));
307  $reviewRound = $this->getAuthorizedContextObject(ASSOC_TYPE_REVIEW_ROUND);
308  assert(is_a($reviewRound, 'ReviewRound'));
309 
310  // Form handling
311  import('lib.pkp.controllers.modals.editorDecision.form.RecommendationForm');
312  $editorRecommendationForm = new RecommendationForm($submission, $stageId, $reviewRound);
313  $editorRecommendationForm->initData();
314  return new JSONMessage(true, $editorRecommendationForm->fetch($request));
315  }
316 
323  function saveRecommendation($args, $request) {
324  // Retrieve the authorized submission, stage id and review round.
325  $submission = $this->getAuthorizedContextObject(ASSOC_TYPE_SUBMISSION);
326  $stageId = $this->getAuthorizedContextObject(ASSOC_TYPE_WORKFLOW_STAGE);
327  assert(in_array($stageId, $this->_getReviewStages()));
328  $reviewRound = $this->getAuthorizedContextObject(ASSOC_TYPE_REVIEW_ROUND);
329  assert(is_a($reviewRound, 'ReviewRound'));
330 
331  // Form handling
332  import('lib.pkp.controllers.modals.editorDecision.form.RecommendationForm');
333  $editorRecommendationForm = new RecommendationForm($submission, $stageId, $reviewRound);
334  $editorRecommendationForm->readInputData();
335  if ($editorRecommendationForm->validate()) {
336  $editorRecommendationForm->execute();
337  $json = new JSONMessage(true);
338  $json->setGlobalEvent('decisionActionUpdated');
339  return $json;
340  }
341  return new JSONMessage(false);
342  }
343 
344 
345  //
346  // Protected helper methods
347  //
352  protected function _getReviewRoundOps() {
353  return array('promoteInReview', 'savePromoteInReview', 'newReviewRound', 'saveNewReviewRound', 'sendReviewsInReview', 'saveSendReviewsInReview', 'importPeerReviews', 'sendRecommendation', 'saveRecommendation');
354  }
355 
361  protected function _resolveEditorDecisionForm($formName) {
362  switch($formName) {
363  case 'EditorDecisionWithEmailForm':
364  case 'NewReviewRoundForm':
365  case 'PromoteForm':
366  case 'SendReviewsForm':
367  return "lib.pkp.controllers.modals.editorDecision.form.$formName";
368  default:
369  assert(false);
370  }
371  }
372 
379  protected function _getEditorDecisionForm($formName, $decision) {
380  // Retrieve the authorized submission.
381  $submission = $this->getAuthorizedContextObject(ASSOC_TYPE_SUBMISSION);
382  // Retrieve the stage id
383  $stageId = $this->getAuthorizedContextObject(ASSOC_TYPE_WORKFLOW_STAGE);
384 
385  import($this->_resolveEditorDecisionForm($formName));
386  if (in_array($stageId, $this->_getReviewStages())) {
387  $reviewRound = $this->getAuthorizedContextObject(ASSOC_TYPE_REVIEW_ROUND);
388  $editorDecisionForm = new $formName($submission, $decision, $stageId, $reviewRound);
389  // We need a different save operation in review stages to authorize
390  // the review round object.
391  if (is_a($editorDecisionForm, 'PromoteForm')) {
392  $editorDecisionForm->setSaveFormOperation('savePromoteInReview');
393  } else if (is_a($editorDecisionForm, 'SendReviewsForm')) {
394  $editorDecisionForm->setSaveFormOperation('saveSendReviewsInReview');
395  }
396  } else {
397  $editorDecisionForm = new $formName($submission, $decision, $stageId);
398  }
399 
400  if (is_a($editorDecisionForm, $formName)) {
401  return $editorDecisionForm;
402  } else {
403  assert(false);
404  return null;
405  }
406  }
407 
415  protected function _initiateEditorDecision($args, $request, $formName) {
416  // Retrieve the decision
417  $decision = (int)$request->getUserVar('decision');
418 
419  // Form handling
420  $editorDecisionForm = $this->_getEditorDecisionForm($formName, $decision);
421  $editorDecisionForm->initData();
422 
423  return new JSONMessage(true, $editorDecisionForm->fetch($request));
424  }
425 
435  protected function _saveEditorDecision($args, $request, $formName, $redirectOp = null, $decision = null) {
436  // Retrieve the authorized submission.
437  $submission = $this->getAuthorizedContextObject(ASSOC_TYPE_SUBMISSION);
438  // Retrieve the decision
439  if (is_null($decision)) {
440  $decision = (int)$request->getUserVar('decision');
441  }
442 
443  $editorDecisionForm = $this->_getEditorDecisionForm($formName, $decision);
444  $editorDecisionForm->readInputData();
445  if ($editorDecisionForm->validate()) {
446  $editorDecisionForm->execute();
447 
448  // Get a list of author user IDs
449  $authorUserIds = array();
450  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
451  $submitterAssignments = $stageAssignmentDao->getBySubmissionAndRoleId($submission->getId(), ROLE_ID_AUTHOR);
452  while ($assignment = $submitterAssignments->next()) {
453  $authorUserIds[] = $assignment->getUserId();
454  }
455  // De-duplicate assignments
456  $authorUserIds = array_unique($authorUserIds);
457 
458  // Update editor decision and pending revisions notifications.
459  $notificationMgr = new NotificationManager();
460  $editorDecisionNotificationType = $this->_getNotificationTypeByEditorDecision($decision);
461  $notificationTypes = array_merge(array($editorDecisionNotificationType), $this->_getReviewNotificationTypes());
462  $notificationMgr->updateNotification(
463  $request,
464  $notificationTypes,
465  $authorUserIds,
466  ASSOC_TYPE_SUBMISSION,
467  $submission->getId()
468  );
469 
470  // Update submission notifications
471  $submissionNotificationsToUpdate = array(
472  SUBMISSION_EDITOR_DECISION_ACCEPT => array(NOTIFICATION_TYPE_ASSIGN_COPYEDITOR, NOTIFICATION_TYPE_AWAITING_COPYEDITS),
473  SUBMISSION_EDITOR_DECISION_SEND_TO_PRODUCTION => array(
474  NOTIFICATION_TYPE_ASSIGN_COPYEDITOR,
475  NOTIFICATION_TYPE_AWAITING_COPYEDITS,
476  NOTIFICATION_TYPE_ASSIGN_PRODUCTIONUSER,
477  NOTIFICATION_TYPE_AWAITING_REPRESENTATIONS,
478  ),
479  );
480  $notificationMgr = new NotificationManager();
481  if (array_key_exists($decision, $submissionNotificationsToUpdate)) {
482  $notificationMgr->updateNotification(
483  $request,
484  $submissionNotificationsToUpdate[$decision],
485  null,
486  ASSOC_TYPE_SUBMISSION,
487  $submission->getId()
488  );
489  }
490 
491  if ($redirectOp) {
492  $dispatcher = $this->getDispatcher();
493  $redirectUrl = $dispatcher->url($request, ROUTE_PAGE, null, 'workflow', $redirectOp, array($submission->getId()));
494  return $request->redirectUrlJson($redirectUrl);
495  } else {
496  if (in_array($decision, [SUBMISSION_EDITOR_DECISION_DECLINE, SUBMISSION_EDITOR_DECISION_INITIAL_DECLINE])) {
497  $dispatcher = $this->getDispatcher();
498  $redirectUrl = $dispatcher->url($request, ROUTE_PAGE, null, 'workflow', 'access', array($submission->getId()));
499  return $request->redirectUrlJson($redirectUrl);
500 
501  } else {
502  // Needed to update review round status notifications.
503  return DAO::getDataChangedEvent();
504  }
505  }
506  } else {
507  return new JSONMessage(false);
508  }
509  }
510 
515  protected function _getReviewStages() {
516  assert(false);
517  }
518 
523  protected function _getReviewNotificationTypes() {
524  assert(false); // Subclasses to override
525  }
526 }
527 
528 
RecommendationForm
Editor recommendation form.
Definition: RecommendationForm.inc.php:21
PKPEditorDecisionHandler\_getReviewRoundOps
_getReviewRoundOps()
Definition: PKPEditorDecisionHandler.inc.php:352
AppLocale\requireComponents
static requireComponents()
Definition: env1/MockAppLocale.inc.php:56
PKPEditorDecisionHandler\_getReviewNotificationTypes
_getReviewNotificationTypes()
Definition: PKPEditorDecisionHandler.inc.php:523
PKPEditorDecisionHandler\_resolveEditorDecisionForm
_resolveEditorDecisionForm($formName)
Definition: PKPEditorDecisionHandler.inc.php:361
PKPString\stripUnsafeHtml
static stripUnsafeHtml($input)
Definition: PKPString.inc.php:377
PKPEditorDecisionHandler\authorize
authorize($request, &$args, $roleAssignments)
Definition: PKPEditorDecisionHandler.inc.php:29
PKPEditorDecisionHandler\initialize
initialize($request)
Definition: PKPEditorDecisionHandler.inc.php:55
PKPEditorDecisionHandler\sendReviews
sendReviews($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:110
DAORegistry\getDAO
static & getDAO($name, $dbconn=null)
Definition: DAORegistry.inc.php:57
PKPEditorDecisionHandler\saveSendReviews
saveSendReviews($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:133
PKPEditorDecisionHandler\newReviewRound
newReviewRound($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:75
ReviewRoundRequiredPolicy
Policy that ensures that the request contains a valid review round.
Definition: ReviewRoundRequiredPolicy.inc.php:17
PKPEditorDecisionHandler\_getReviewStages
_getReviewStages()
Definition: PKPEditorDecisionHandler.inc.php:515
PKPEditorDecisionHandler\sendRecommendation
sendRecommendation($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:302
PKPEditorDecisionHandler\importPeerReviews
importPeerReviews($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:196
PKPEditorDecisionHandler\saveExternalReview
saveExternalReview($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:95
PKPEditorDecisionHandler\_getEditorDecisionForm
_getEditorDecisionForm($formName, $decision)
Definition: PKPEditorDecisionHandler.inc.php:379
PKPEditorDecisionHandler\_saveEditorDecision
_saveEditorDecision($args, $request, $formName, $redirectOp=null, $decision=null)
Definition: PKPEditorDecisionHandler.inc.php:435
PKPEditorDecisionHandler\promote
promote($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:153
PKPEditorDecisionHandler\saveSendReviewsInReview
saveSendReviewsInReview($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:143
DAO\getDataChangedEvent
static getDataChangedEvent($elementId=null, $parentElementId=null, $content='')
Definition: DAO.inc.php:647
PKPEditorDecisionHandler\_initiateEditorDecision
_initiateEditorDecision($args, $request, $formName)
Definition: PKPEditorDecisionHandler.inc.php:415
PKPEditorDecisionHandler\promoteInReview
promoteInReview($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:165
JSONMessage
Class to represent a JSON (Javascript Object Notation) message.
Definition: JSONMessage.inc.php:18
PKPEditorDecisionHandler\savePromoteInReview
savePromoteInReview($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:186
PKPEditorDecisionHandler\savePromote
savePromote($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:175
PKPEditorDecisionHandler\saveRecommendation
saveRecommendation($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:323
PKPEditorDecisionHandler\externalReview
externalReview($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:85
PKPHandler\getDispatcher
& getDispatcher()
Definition: PKPHandler.inc.php:120
PKPHandler\getAuthorizedContextObject
& getAuthorizedContextObject($assocType)
Definition: PKPHandler.inc.php:174
PKPEditorDecisionHandler
Definition: PKPEditorDecisionHandler.inc.php:21
NotificationManager
Definition: NotificationManager.inc.php:19
PKPHandler\addPolicy
addPolicy($authorizationPolicy, $addToTop=false)
Definition: PKPHandler.inc.php:157
Handler
Base request handler application class.
Definition: Handler.inc.php:18
PKPEditorDecisionHandler\sendReviewsInReview
sendReviewsInReview($args, $request)
Definition: PKPEditorDecisionHandler.inc.php:123
PKPString\enumerateAlphabetically
static enumerateAlphabetically($steps)
Definition: PKPString.inc.php:473