getRequiredReviewFormElementIds($reviewAssignment->getReviewFormId()); $this->addCheck(new \PKP\form\validation\FormValidatorCustom($this, 'reviewFormResponses', 'required', 'reviewer.submission.reviewFormResponse.form.responseRequired', function ($reviewFormResponses) use ($requiredReviewFormElementIds) { foreach ($requiredReviewFormElementIds as $requiredReviewFormElementId) { if (!isset($reviewFormResponses[$requiredReviewFormElementId]) || $reviewFormResponses[$requiredReviewFormElementId] == '') { return false; } } return true; })); $this->addCheck(new \PKP\form\validation\FormValidatorPost($this)); $this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this)); } /** * @copydoc ReviewerReviewForm::initData */ public function initData() { $reviewAssignment = $this->getReviewAssignment(); // Retrieve most recent reviewer comments, one private, one public. $submissionCommentDao = DAORegistry::getDAO('SubmissionCommentDAO'); /** @var SubmissionCommentDAO $submissionCommentDao */ $submissionComments = $submissionCommentDao->getReviewerCommentsByReviewerId($reviewAssignment->getSubmissionId(), $reviewAssignment->getReviewerId(), $reviewAssignment->getId(), true); $submissionComment = $submissionComments->next(); $this->setData('comments', $submissionComment ? $submissionComment->getComments() : ''); $submissionCommentsPrivate = $submissionCommentDao->getReviewerCommentsByReviewerId($reviewAssignment->getSubmissionId(), $reviewAssignment->getReviewerId(), $reviewAssignment->getId(), false); $submissionCommentPrivate = $submissionCommentsPrivate->next(); $this->setData('commentsPrivate', $submissionCommentPrivate ? $submissionCommentPrivate->getComments() : ''); parent::initData(); } // // Implement protected template methods from Form // /** * @see Form::readInputData() */ public function readInputData() { $this->readUserVars( ['reviewFormResponses', 'comments', 'recommendation', 'commentsPrivate'] ); } /** * @copydoc ReviewerReviewForm::fetch() * * @param null|mixed $template */ public function fetch($request, $template = null, $display = false) { $templateMgr = TemplateManager::getManager($request); $reviewAssignment = $this->getReviewAssignment(); // Assign the objects and data to the template. $context = $this->request->getContext(); $templateMgr->assign([ 'reviewAssignment' => $reviewAssignment, 'reviewRoundId' => $reviewAssignment->getReviewRoundId(), 'reviewerRecommendationOptions' => ReviewAssignment::getReviewerRecommendationOptions(), ]); if ($reviewAssignment->getReviewFormId()) { // Get the review form components $reviewFormElementDao = DAORegistry::getDAO('ReviewFormElementDAO'); /** @var ReviewFormElementDAO $reviewFormElementDao */ $reviewFormResponseDao = DAORegistry::getDAO('ReviewFormResponseDAO'); /** @var ReviewFormResponseDAO $reviewFormResponseDao */ $reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */ $templateMgr->assign([ 'reviewForm' => $reviewFormDao->getById($reviewAssignment->getReviewFormId(), Application::getContextAssocType(), $context->getId()), 'reviewFormElements' => $reviewFormElementDao->getByReviewFormId($reviewAssignment->getReviewFormId()), 'reviewFormResponses' => $reviewFormResponseDao->getReviewReviewFormResponseValues($reviewAssignment->getId()), 'disabled' => isset($reviewAssignment) && $reviewAssignment->getDateCompleted() != null, ]); } // // Assign the link actions // $viewReviewGuidelinesAction = new ViewReviewGuidelinesLinkAction($request, $reviewAssignment->getStageId()); if ($viewReviewGuidelinesAction->getGuidelines()) { $templateMgr->assign('viewGuidelinesAction', $viewReviewGuidelinesAction); } return parent::fetch($request, $template, $display); } /** * @see Form::execute() */ public function execute(...$functionParams) { $reviewAssignment = $this->getReviewAssignment(); $notificationMgr = new NotificationManager(); // Save the answers to the review form $this->saveReviewForm($reviewAssignment); // Send notification $submission = Repo::submission()->get($reviewAssignment->getSubmissionId()); $context = Application::getContextDAO()->getById($submission->getData('contextId')); // Set review to next step. $this->updateReviewStepAndSaveSubmission($this->getReviewAssignment()); // Mark the review assignment as completed. $reviewAssignment->setDateCompleted(Core::getCurrentDate()); $reviewAssignment->stampModified(); // assign the recommendation to the review assignment, if there was one. $reviewAssignment->setRecommendation((int) $this->getData('recommendation')); // Persist the updated review assignment. $reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */ $reviewAssignmentDao->updateObject($reviewAssignment); $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /** @var StageAssignmentDAO $stageAssignmentDao */ $stageAssignments = $stageAssignmentDao->getBySubmissionAndStageId($submission->getId(), $submission->getStageId()); $receivedList = []; // Avoid sending twice to the same user. /** @var NotificationSubscriptionSettingsDAO $notificationSubscriptionSettingsDao */ $notificationSubscriptionSettingsDao = DAORegistry::getDAO('NotificationSubscriptionSettingsDAO'); while ($stageAssignment = $stageAssignments->next()) { $userId = $stageAssignment->getUserId(); $userGroup = Repo::userGroup()->get($stageAssignment->getUserGroupId()); // Never send reviewer comment notification to users other than managers and editors. if (!in_array($userGroup->getRoleId(), [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SUB_EDITOR]) || in_array($userId, $receivedList)) { continue; } // Notify editors $notification = $notificationMgr->createNotification( Application::get()->getRequest(), $userId, PKPNotification::NOTIFICATION_TYPE_REVIEWER_COMMENT, $submission->getContextId(), PKPApplication::ASSOC_TYPE_REVIEW_ASSIGNMENT, $reviewAssignment->getId() ); // Check if user is subscribed to this type of notification emails if (!$notification || in_array( PKPNotification::NOTIFICATION_TYPE_REVIEWER_COMMENT, $notificationSubscriptionSettingsDao->getNotificationSubscriptionSettings( NotificationSubscriptionSettingsDAO::BLOCKED_EMAIL_NOTIFICATION_KEY, $userId, (int) $context->getId() ) ) ) { continue; } $mailable = new ReviewCompleteNotifyEditors($context, $submission, $reviewAssignment); $template = Repo::emailTemplate()->getByKey($context->getId(), ReviewCompleteNotifyEditors::getEmailTemplateKey()); // The template may not exist, see pkp/pkp-lib#9109 if (!$template) { $template = Repo::emailTemplate()->getByKey($context->getId(), 'NOTIFICATION'); $request = Application::get()->getRequest(); $mailable->addData([ 'notificationContents' => $notificationMgr->getNotificationContents($request, $notification), 'notificationUrl' => $notificationMgr->getNotificationUrl($request, $notification), ]); } $user = Repo::user()->get($userId); $mailable ->from($context->getData('contactEmail'), $context->getData('contactName')) ->recipients([$user]) ->subject($template->getLocalizedData('subject')) ->body($template->getLocalizedData('body')) ->allowUnsubscribe($notification); Mail::send($mailable); $receivedList[] = $userId; } // Remove the task $notificationDao = DAORegistry::getDAO('NotificationDAO'); /** @var NotificationDAO $notificationDao */ $notificationDao->deleteByAssoc( PKPApplication::ASSOC_TYPE_REVIEW_ASSIGNMENT, $reviewAssignment->getId(), $reviewAssignment->getReviewerId(), PKPNotification::NOTIFICATION_TYPE_REVIEW_ASSIGNMENT ); // Add log $reviewer = Repo::user()->get($reviewAssignment->getReviewerId(), true); $eventLog = Repo::eventLog()->newDataObject([ 'assocType' => PKPApplication::ASSOC_TYPE_SUBMISSION, 'assocId' => $submission->getId(), 'eventType' => PKPSubmissionEventLogEntry::SUBMISSION_LOG_REVIEW_READY, 'userId' => Validation::loggedInAs() ?? Application::get()->getRequest()->getUser()->getId(), 'message' => 'log.review.reviewReady', 'isTranslated' => false, 'dateLogged' => Core::getCurrentDate(), 'reviewAssignmentId' => $reviewAssignment->getId(), 'reviewerName' => $reviewer->getFullName(), 'submissionId' => $reviewAssignment->getSubmissionId(), 'round' => $reviewAssignment->getRound() ]); Repo::eventLog()->add($eventLog); parent::execute(...$functionParams); } /** * Save the given answers for later */ public function saveForLater() { $reviewAssignment = $this->getReviewAssignment(); $notificationMgr = new NotificationManager(); // Save the answers to the review form $this->saveReviewForm($reviewAssignment); // Mark the review assignment as modified. $reviewAssignment->stampModified(); // save the recommendation to the review assignment $reviewAssignment->setRecommendation((int) $this->getData('recommendation')); // Persist the updated review assignment. $reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */ $reviewAssignmentDao->updateObject($reviewAssignment); return true; } /** * Save the given answers to the review form * * @param ReviewAssignment $reviewAssignment */ public function saveReviewForm($reviewAssignment) { if ($reviewAssignment->getReviewFormId()) { $reviewFormResponseDao = DAORegistry::getDAO('ReviewFormResponseDAO'); /** @var ReviewFormResponseDAO $reviewFormResponseDao */ $reviewFormResponses = $this->getData('reviewFormResponses'); if (is_array($reviewFormResponses)) { foreach ($reviewFormResponses as $reviewFormElementId => $reviewFormResponseValue) { $reviewFormResponse = $reviewFormResponseDao->getReviewFormResponse($reviewAssignment->getId(), $reviewFormElementId); if (!isset($reviewFormResponse)) { $reviewFormResponse = new ReviewFormResponse(); } $reviewFormElementDao = DAORegistry::getDAO('ReviewFormElementDAO'); /** @var ReviewFormElementDAO $reviewFormElementDao */ $reviewFormElement = $reviewFormElementDao->getById($reviewFormElementId); $elementType = $reviewFormElement->getElementType(); switch ($elementType) { case ReviewFormElement::REVIEW_FORM_ELEMENT_TYPE_SMALL_TEXT_FIELD: case ReviewFormElement::REVIEW_FORM_ELEMENT_TYPE_TEXT_FIELD: case ReviewFormElement::REVIEW_FORM_ELEMENT_TYPE_TEXTAREA: $reviewFormResponse->setResponseType('string'); $reviewFormResponse->setValue($reviewFormResponseValue); break; case ReviewFormElement::REVIEW_FORM_ELEMENT_TYPE_RADIO_BUTTONS: case ReviewFormElement::REVIEW_FORM_ELEMENT_TYPE_DROP_DOWN_BOX: $reviewFormResponse->setResponseType('int'); $reviewFormResponse->setValue($reviewFormResponseValue); break; case ReviewFormElement::REVIEW_FORM_ELEMENT_TYPE_CHECKBOXES: $reviewFormResponse->setResponseType('object'); $reviewFormResponse->setValue($reviewFormResponseValue); break; } if ($reviewFormResponse->getReviewFormElementId() != null && $reviewFormResponse->getReviewId() != null) { $reviewFormResponseDao->updateObject($reviewFormResponse); } else { $reviewFormResponse->setReviewFormElementId($reviewFormElementId); $reviewFormResponse->setReviewId($reviewAssignment->getId()); $reviewFormResponseDao->insertObject($reviewFormResponse); } } } } else { // No review form configured. Use the default form. if (strlen($comments = $this->getData('comments')) > 0) { // Create a comment with the review. $submissionCommentDao = DAORegistry::getDAO('SubmissionCommentDAO'); /** @var SubmissionCommentDAO $submissionCommentDao */ $submissionComments = $submissionCommentDao->getReviewerCommentsByReviewerId($reviewAssignment->getSubmissionId(), $reviewAssignment->getReviewerId(), $reviewAssignment->getId(), true); $comment = $submissionComments->next(); if (!isset($comment)) { $comment = $submissionCommentDao->newDataObject(); } $comment->setCommentType(SubmissionComment::COMMENT_TYPE_PEER_REVIEW); $comment->setRoleId(Role::ROLE_ID_REVIEWER); $comment->setAssocId($reviewAssignment->getId()); $comment->setSubmissionId($reviewAssignment->getSubmissionId()); $comment->setAuthorId($reviewAssignment->getReviewerId()); $comment->setComments($comments); $comment->setCommentTitle(''); $comment->setViewable(true); $comment->setDatePosted(Core::getCurrentDate()); // Save or update if ($comment->getId() != null) { $submissionCommentDao->updateObject($comment); } else { $submissionCommentDao->insertObject($comment); } } unset($comment); if (strlen($commentsPrivate = $this->getData('commentsPrivate')) > 0) { // Create a comment with the review. $submissionCommentDao = DAORegistry::getDAO('SubmissionCommentDAO'); /** @var SubmissionCommentDAO $submissionCommentDao */ $submissionCommentsPrivate = $submissionCommentDao->getReviewerCommentsByReviewerId($reviewAssignment->getSubmissionId(), $reviewAssignment->getReviewerId(), $reviewAssignment->getId(), false); $comment = $submissionCommentsPrivate->next(); if (!isset($comment)) { $comment = $submissionCommentDao->newDataObject(); } $comment->setCommentType(SubmissionComment::COMMENT_TYPE_PEER_REVIEW); $comment->setRoleId(Role::ROLE_ID_REVIEWER); $comment->setAssocId($reviewAssignment->getId()); $comment->setSubmissionId($reviewAssignment->getSubmissionId()); $comment->setAuthorId($reviewAssignment->getReviewerId()); $comment->setComments($commentsPrivate); $comment->setCommentTitle(''); $comment->setViewable(false); $comment->setDatePosted(Core::getCurrentDate()); // Save or update if ($comment->getId() != null) { $submissionCommentDao->updateObject($comment); } else { $submissionCommentDao->insertObject($comment); } } unset($comment); } } } if (!PKP_STRICT_MODE) { class_alias('\PKP\submission\reviewer\form\PKPReviewerReviewStep3Form', '\PKPReviewerReviewStep3Form'); }