first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-06-08 17:09:23 -04:00
commit df3a033196
17887 changed files with 8637778 additions and 0 deletions
@@ -0,0 +1,263 @@
<?php
/**
* @file controllers/grid/users/reviewer/form/AdvancedSearchReviewerForm.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class AdvancedSearchReviewerForm
*
* @ingroup controllers_grid_users_reviewer_form
*
* @brief Form for an advanced search and for adding a reviewer to a submission.
*/
namespace PKP\controllers\grid\users\reviewer\form;
use APP\core\Application;
use APP\core\Request;
use APP\core\Services;
use APP\facades\Repo;
use APP\submission\Submission;
use APP\template\TemplateManager;
use Illuminate\Support\Facades\Mail;
use PKP\controllers\grid\users\reviewer\PKPReviewerGridHandler;
use PKP\core\PKPApplication;
use PKP\db\DAORegistry;
use PKP\emailTemplate\EmailTemplate;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxAction;
use PKP\mail\mailables\ReviewRequest;
use PKP\mail\mailables\ReviewRequestSubsequent;
use PKP\security\Role;
use PKP\submission\reviewAssignment\ReviewAssignment;
use PKP\submission\reviewAssignment\ReviewAssignmentDAO;
use PKP\submission\reviewRound\ReviewRound;
use PKP\submission\reviewRound\ReviewRoundDAO;
class AdvancedSearchReviewerForm extends ReviewerForm
{
/**
* Constructor.
*
* @param Submission $submission
* @param ReviewRound $reviewRound
*/
public function __construct($submission, $reviewRound)
{
parent::__construct($submission, $reviewRound);
$this->setTemplate('controllers/grid/users/reviewer/form/advancedSearchReviewerForm.tpl');
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'reviewerId', 'required', 'editor.review.mustSelect'));
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
parent::readInputData();
$this->readUserVars(['reviewerId']);
}
/**
* @copydoc Form::initData()
*/
public function initData()
{
parent::initData();
$request = Application::get()->getRequest();
$context = $request->getContext();
$mailable = $this->getMailable();
$templates = Repo::emailTemplate()->getCollector($context->getId())
->filterByKeys([ReviewRequest::getEmailTemplateKey(), ReviewRequestSubsequent::getEmailTemplateKey()])
->getMany()
->mapWithKeys(function (EmailTemplate $item, int $key) use ($mailable) {
return [$item->getData('key') => Mail::compileParams($item->getLocalizedData('body'), $mailable->viewData)];
});
$this->setData('personalMessage', '');
$this->setData('reviewerMessages', $templates->toArray());
}
/**
* @copydoc Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
// Get submission context
$submissionContext = Services::get('context')->get($this->getSubmission()->getContextId());
// Pass along the request vars
$actionArgs = $request->getUserVars();
$reviewRound = $this->getReviewRound();
$actionArgs['reviewRoundId'] = $reviewRound->getId();
$actionArgs['selectionType'] = PKPReviewerGridHandler::REVIEWER_SELECT_ADVANCED_SEARCH;
// but change the selectionType for each action
$advancedSearchAction = new LinkAction(
'advancedSearch',
new AjaxAction($request->url(null, null, 'reloadReviewerForm', null, $actionArgs)),
__('manager.reviewerSearch.change'),
'user_search'
);
$this->setReviewerFormAction($advancedSearchAction);
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
// get reviewer IDs already assign to this submission and this round
$reviewAssignments = $reviewAssignmentDao->getBySubmissionId($this->getSubmissionId(), $this->getReviewRound()->getId());
$currentlyAssigned = [];
if (!empty($reviewAssignments)) {
foreach ($reviewAssignments as $reviewAssignment) {
$currentlyAssigned[] = (int) $reviewAssignment->getReviewerId();
}
}
// Get user IDs already assigned to this submission, and admins and
// managers who may have access to author identities and can not guarantee
// anonymous reviews
$warnOnAssignment = [];
$stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /** @var StageAssignmentDAO $stageAssignmentDao */
$stageAssignmentResults = $stageAssignmentDao->getBySubmissionAndStageId($this->getSubmissionId());
while ($stageAssignment = $stageAssignmentResults->next()) {
$warnOnAssignment[] = $stageAssignment->getUserId();
}
// Get a list of users in the managerial and admin user groups
// Managers are assigned only to contexts; site admins are assigned only to site.
// Therefore filtering by both context IDs and role IDs will not cause problems.
$userIds = Repo::user()->getCollector()
->filterByRoleIds([Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN])
->filterByContextIds([$submissionContext->getId(), PKPApplication::CONTEXT_SITE])
->getIds()
->toArray();
$warnOnAssignment = array_merge($warnOnAssignment, $userIds);
$warnOnAssignment = array_values(array_unique(array_map('intval', $warnOnAssignment)));
// Get reviewers list
$selectReviewerListPanel = new \PKP\components\listPanels\PKPSelectReviewerListPanel(
'selectReviewer',
__('editor.submission.findAndSelectReviewer'),
[
'apiUrl' => $request->getDispatcher()->url(
$request,
PKPApplication::ROUTE_API,
$submissionContext->getPath(),
'users/reviewers'
),
'currentlyAssigned' => $currentlyAssigned,
'getParams' => [
'contextId' => $submissionContext->getId(),
'reviewStage' => $reviewRound->getStageId(),
],
'selectorName' => 'reviewerId',
'warnOnAssignment' => $warnOnAssignment,
]
);
// Get reviewers who completed a review in the last round
$lastRoundReviewerIds = [];
if ($this->getReviewRound()->getRound() > 1) {
/** @var ReviewRoundDAO */
$reviewRoundDao = DAORegistry::getDAO('ReviewRoundDAO');
$previousRound = $this->getReviewRound()->getRound() - 1;
$lastReviewRound = $reviewRoundDao->getReviewRound($this->getSubmissionId(), $this->getReviewRound()->getStageId(), $previousRound);
if ($lastReviewRound) {
$lastReviewAssignments = $reviewAssignmentDao->getByReviewRoundId($lastReviewRound->getId());
foreach ($lastReviewAssignments as $reviewAssignment) {
if (in_array($reviewAssignment->getStatus(), [ReviewAssignment::REVIEW_ASSIGNMENT_STATUS_THANKED, ReviewAssignment::REVIEW_ASSIGNMENT_STATUS_COMPLETE])) {
$lastRoundReviewerIds[] = (int) $reviewAssignment->getReviewerId();
}
}
$lastRoundReviewers = Repo::user()->getCollector()
->filterByContextIds([$submissionContext->getId()])
->filterByRoleIds([Role::ROLE_ID_REVIEWER])
->filterByUserIds($lastRoundReviewerIds)
->includeReviewerData()
->getMany();
if (count($lastRoundReviewers)) {
$selectReviewerListPanel->set([
'lastRoundReviewers' => $lastRoundReviewers,
]);
}
}
}
$templateMgr = TemplateManager::getManager($request);
// Used to determine the right email template
$templateMgr->assign('lastRoundReviewerIds', $lastRoundReviewerIds);
$selectReviewerListPanel->set([
'items' => $selectReviewerListPanel->getItems($request),
'itemsMax' => $selectReviewerListPanel->getItemsMax(),
]);
$templateMgr->assign('selectReviewerListData', [
'components' => [
'selectReviewer' => $selectReviewerListPanel->getConfig(),
]
]);
// Only add actions to forms where user can operate.
if (array_intersect($this->getUserRoles(), [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SUB_EDITOR])) {
$actionArgs['selectionType'] = PKPReviewerGridHandler::REVIEWER_SELECT_CREATE;
// but change the selectionType for each action
$advancedSearchAction = new LinkAction(
'selectCreate',
new AjaxAction($request->url(null, null, 'reloadReviewerForm', null, $actionArgs)),
__('editor.review.createReviewer'),
'add_user'
);
$this->setReviewerFormAction($advancedSearchAction);
$actionArgs['selectionType'] = PKPReviewerGridHandler::REVIEWER_SELECT_ENROLL_EXISTING;
// but change the selectionType for each action
$advancedSearchAction = new LinkAction(
'enrolExisting',
new AjaxAction($request->url(null, null, 'reloadReviewerForm', null, $actionArgs)),
__('editor.review.enrollReviewer.short'),
'enroll_user'
);
$this->setReviewerFormAction($advancedSearchAction);
}
return parent::fetch($request, $template, $display);
}
protected function getEmailTemplates(): array
{
$subsequentTemplate = Repo::emailTemplate()->getByKey(
Application::get()->getRequest()->getContext()->getId(),
ReviewRequestSubsequent::getEmailTemplateKey()
);
$alternateTemplates = Repo::emailTemplate()->getCollector(Application::get()->getRequest()->getContext()->getId())
->alternateTo([ReviewRequestSubsequent::getEmailTemplateKey()])
->getMany();
$templateKeys = array_merge(
parent::getEmailTemplates(),
[ReviewRequestSubsequent::getEmailTemplateKey() => $subsequentTemplate->getLocalizedData('name')]
);
foreach ($alternateTemplates as $alternateTemplate) {
$templateKeys[$alternateTemplate->getData('key')] = $alternateTemplate->getLocalizedData('name');
}
return $templateKeys;
}
}
@@ -0,0 +1,180 @@
<?php
/**
* @file controllers/grid/users/reviewer/form/CreateReviewerForm.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class CreateReviewerForm
*
* @ingroup controllers_grid_users_reviewer_form
*
* @brief Form for creating and subsequently adding a reviewer to a submission.
*/
namespace PKP\controllers\grid\users\reviewer\form;
use APP\core\Application;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use APP\submission\Submission;
use APP\template\TemplateManager;
use Illuminate\Support\Facades\Mail;
use PKP\core\Core;
use PKP\mail\mailables\ReviewerRegister;
use PKP\notification\PKPNotification;
use PKP\security\Validation;
use PKP\submission\reviewRound\ReviewRound;
use PKP\user\InterestManager;
use Symfony\Component\Mailer\Exception\TransportException;
class CreateReviewerForm extends ReviewerForm
{
/**
* Constructor.
*
* @param Submission $submission
* @param ReviewRound $reviewRound
*/
public function __construct($submission, $reviewRound)
{
parent::__construct($submission, $reviewRound);
$this->setTemplate('controllers/grid/users/reviewer/form/createReviewerForm.tpl');
// the users register for the site, thus
// the site primary locale is the required default locale
$site = Application::get()->getRequest()->getSite();
$this->addSupportedFormLocale($site->getPrimaryLocale());
$form = $this;
$this->addCheck(new \PKP\form\validation\FormValidatorLocale($this, 'givenName', 'required', 'user.profile.form.givenNameRequired', $site->getPrimaryLocale()));
$this->addCheck(new \PKP\form\validation\FormValidatorCustom($this, 'familyName', 'optional', 'user.profile.form.givenNameRequired.locale', function ($familyName) use ($form) {
$givenNames = $form->getData('givenName');
foreach ($familyName as $locale => $value) {
if (!empty($value) && empty($givenNames[$locale])) {
return false;
}
}
return true;
}));
$this->addCheck(new \PKP\form\validation\FormValidatorCustom($this, 'username', 'required', 'user.register.form.usernameExists', [Repo::user(), 'getByUsername'], [true], true));
$this->addCheck(new \PKP\form\validation\FormValidatorUsername($this, 'username', 'required', 'user.register.form.usernameAlphaNumeric'));
$this->addCheck(new \PKP\form\validation\FormValidatorEmail($this, 'email', 'required', 'user.profile.form.emailRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorCustom($this, 'email', 'required', 'user.register.form.emailExists', function ($email) {
return !Repo::user()->getByEmail($email, true);
}));
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'userGroupId', 'required', 'user.profile.form.usergroupRequired'));
}
/**
* @copydoc Form::init()
*/
public function initData()
{
parent::initData();
$mailable = $this->getMailable();
$context = Application::get()->getRequest()->getContext();
$template = Repo::emailTemplate()->getByKey($context->getId(), $mailable::getEmailTemplateKey());
$this->setData('personalMessage', Mail::compileParams($template->getLocalizedData('body'), $mailable->viewData));
}
/**
* @copydoc ReviewerForm::fetch
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$advancedSearchAction = $this->getAdvancedSearchAction($request);
$this->setReviewerFormAction($advancedSearchAction);
$site = $request->getSite();
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('sitePrimaryLocale', $site->getPrimaryLocale());
return parent::fetch($request, $template, $display);
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
parent::readInputData();
$this->readUserVars([
'givenName',
'familyName',
'affiliation',
'interests',
'username',
'email',
'skipEmail',
'userGroupId',
]);
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
$user = Repo::user()->newDataObject();
$user->setGivenName($this->getData('givenName'), null);
$user->setFamilyName($this->getData('familyName'), null);
$user->setEmail($this->getData('email'));
$user->setAffiliation($this->getData('affiliation'), null); // Localized
$user->setInlineHelp(1); // default new reviewers to having inline help visible
$user->setUsername($this->getData('username'));
$password = Validation::generatePassword();
$user->setPassword(Validation::encryptCredentials($this->getData('username'), $password));
$user->setMustChangePassword(true); // Emailed P/W not safe
$user->setDateRegistered(Core::getCurrentDate());
$reviewerId = Repo::user()->add($user);
// Set the reviewerId in the Form for the parent class to use
$this->setData('reviewerId', $reviewerId);
// Insert the user interests
$interestManager = new InterestManager();
$interestManager->setInterestsForUser($user, $this->getData('interests'));
// Assign the selected user group ID to the user
$userGroupId = (int) $this->getData('userGroupId');
Repo::userGroup()->assignUserToGroup($reviewerId, $userGroupId);
if (!$this->getData('skipEmail')) {
// Send welcome email to user
$request = Application::get()->getRequest();
$context = $request->getContext();
$mailable = new ReviewerRegister($context, $password);
$mailable->recipients($user);
$mailable->sender($request->getUser());
$mailable->replyTo($context->getData('contactEmail'), $context->getData('contactName'));
$template = Repo::emailTemplate()->getByKey($context->getId(), ReviewerRegister::getEmailTemplateKey());
$mailable->subject($template->getLocalizedData('subject'));
$mailable->body($template->getLocalizedData('body'));
try {
Mail::send($mailable);
} catch (TransportException $e) {
$notificationMgr = new NotificationManager();
$notificationMgr->createTrivialNotification(
$request->getUser()->getId(),
PKPNotification::NOTIFICATION_TYPE_ERROR,
['contents' => __('email.compose.error')]
);
error_log($e->getMessage());
}
}
return parent::execute(...$functionArgs);
}
}
@@ -0,0 +1,235 @@
<?php
/**
* @file controllers/grid/users/reviewer/form/EditReviewForm.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class EditReviewForm
*
* @ingroup controllers_grid_users_reviewer_form
*
* @brief Allow the editor to limit the available files to an assigned
* reviewer after the assignment has taken place.
*/
namespace PKP\controllers\grid\users\reviewer\form;
use APP\core\Application;
use APP\facades\Repo;
use APP\notification\Notification;
use APP\notification\NotificationManager;
use APP\submission\Submission;
use APP\template\TemplateManager;
use Illuminate\Support\Facades\Mail;
use PKP\core\PKPApplication;
use PKP\db\DAORegistry;
use PKP\form\Form;
use PKP\mail\mailables\EditReviewNotify;
use PKP\notification\NotificationSubscriptionSettingsDAO;
use PKP\notification\PKPNotification;
use PKP\reviewForm\ReviewFormDAO;
use PKP\submission\reviewAssignment\ReviewAssignment;
use PKP\submission\reviewAssignment\ReviewAssignmentDAO;
use PKP\submission\ReviewFilesDAO;
use PKP\submission\reviewRound\ReviewRound;
use PKP\submission\reviewRound\ReviewRoundDAO;
use PKP\submissionFile\SubmissionFile;
class EditReviewForm extends Form
{
/** @var ReviewAssignment */
public $_reviewAssignment;
/** @var ReviewRound */
public $_reviewRound;
protected Submission $submission;
public function __construct(ReviewAssignment $reviewAssignment, Submission $submission)
{
$this->_reviewAssignment = $reviewAssignment;
$this->submission = $submission;
assert($this->_reviewAssignment instanceof ReviewAssignment);
$reviewRoundDao = DAORegistry::getDAO('ReviewRoundDAO'); /** @var ReviewRoundDAO $reviewRoundDao */
$this->_reviewRound = $reviewRoundDao->getById($reviewAssignment->getReviewRoundId());
assert(is_a($this->_reviewRound, 'ReviewRound'));
parent::__construct('controllers/grid/users/reviewer/form/editReviewForm.tpl');
// Validation checks for this form
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'responseDueDate', 'required', 'editor.review.errorAddingReviewer'));
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'reviewDueDate', 'required', 'editor.review.errorAddingReviewer'));
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
//
// Overridden template methods
//
/**
* Initialize form data from the associated author.
*/
public function initData()
{
$this->setData('responseDueDate', $this->_reviewAssignment->getDateResponseDue());
$this->setData('reviewDueDate', $this->_reviewAssignment->getDateDue());
return parent::initData();
}
/**
* Fetch the Edit Review Form form
*
* @see Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$templateMgr = TemplateManager::getManager($request);
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
$context = $request->getContext();
if (!$this->_reviewAssignment->getDateCompleted()) {
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewFormsIterator = $reviewFormDao->getActiveByAssocId(Application::getContextAssocType(), $context->getId());
$reviewForms = [];
while ($reviewForm = $reviewFormsIterator->next()) {
$reviewForms[$reviewForm->getId()] = $reviewForm->getLocalizedTitle();
}
$templateMgr->assign([
'reviewForms' => $reviewForms,
'reviewFormId' => $this->_reviewAssignment->getReviewFormId(),
]);
}
$templateMgr->assign([
'stageId' => $this->_reviewAssignment->getStageId(),
'reviewRoundId' => $this->_reviewRound->getId(),
'submissionId' => $this->_reviewAssignment->getSubmissionId(),
'reviewAssignmentId' => $this->_reviewAssignment->getId(),
'reviewMethod' => $this->_reviewAssignment->getReviewMethod(),
'reviewMethods' => $reviewAssignmentDao->getReviewMethodsTranslationKeys(),
]);
return parent::fetch($request, $template, $display);
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars([
'selectedFiles',
'responseDueDate',
'reviewDueDate',
'reviewMethod',
'reviewFormId',
]);
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
$request = Application::get()->getRequest();
$context = $request->getContext();
// Revoke all, then grant selected.
$reviewFilesDao = DAORegistry::getDAO('ReviewFilesDAO'); /** @var ReviewFilesDAO $reviewFilesDao */
$reviewFilesDao->revokeByReviewId($this->_reviewAssignment->getId());
$fileStages = [$this->_reviewRound->getStageId() == WORKFLOW_STAGE_ID_INTERNAL_REVIEW ? SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_FILE : SubmissionFile::SUBMISSION_FILE_REVIEW_FILE];
$submissionFiles = Repo::submissionFile()
->getCollector()
->filterBySubmissionIds([$this->_reviewAssignment->getSubmissionId()])
->filterByReviewRoundIds([$this->_reviewRound->getId()])
->filterByFileStages($fileStages)
->getMany();
$selectedFiles = array_map(function ($id) {
return (int) $id;
}, (array) $this->getData('selectedFiles'));
foreach ($submissionFiles as $submissionFile) {
if (in_array($submissionFile->getId(), $selectedFiles)) {
$reviewFilesDao->grant($this->_reviewAssignment->getId(), $submissionFile->getId());
}
}
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
$reviewAssignment = $reviewAssignmentDao->getReviewAssignment($this->_reviewRound->getId(), $this->_reviewAssignment->getReviewerId());
// Send notification to reviewer if details have changed.
if (strtotime($reviewAssignment->getDateDue()) != strtotime($this->getData('reviewDueDate')) || strtotime($reviewAssignment->getDateResponseDue()) != strtotime($this->getData('responseDueDate')) || $reviewAssignment->getReviewMethod() != $this->getData('reviewMethod')) {
$notificationManager = new NotificationManager();
$request = Application::get()->getRequest();
$context = $request->getContext();
$notification = $notificationManager->createNotification(
$request,
$reviewAssignment->getReviewerId(),
PKPNotification::NOTIFICATION_TYPE_REVIEW_ASSIGNMENT_UPDATED,
$context->getId(),
PKPApplication::ASSOC_TYPE_REVIEW_ASSIGNMENT,
$reviewAssignment->getId(),
Notification::NOTIFICATION_LEVEL_TASK
);
// Check if user is subscribed to this type of notification emails
$reviewer = Repo::user()->get($reviewAssignment->getReviewerId());
/** @var NotificationSubscriptionSettingsDAO */
$notificationSubscriptionSettingsDao = DAORegistry::getDAO('NotificationSubscriptionSettingsDAO');
if ($notification && !in_array(
PKPNotification::NOTIFICATION_TYPE_REVIEW_ASSIGNMENT_UPDATED,
$notificationSubscriptionSettingsDao->getNotificationSubscriptionSettings(
NotificationSubscriptionSettingsDAO::BLOCKED_EMAIL_NOTIFICATION_KEY,
$reviewer->getId(),
(int) $context->getId()
)
)
) {
$mailable = new EditReviewNotify($context, $this->submission, $reviewAssignment);
$template = Repo::emailTemplate()->getByKey($context->getId(), EditReviewNotify::getEmailTemplateKey());
// The template may not exist, see pkp/pkp-lib#9109
if (!$template) {
$template = Repo::emailTemplate()->getByKey($context->getId(), 'NOTIFICATION');
$mailable->addData([
'notificationContents' => $notificationManager->getNotificationContents($request, $notification),
'notificationUrl' => $notificationManager->getNotificationUrl($request, $notification),
]);
}
$mailable
->sender($request->getUser())
->recipients([$reviewer])
->subject($template->getLocalizedData('subject'))
->body($template->getLocalizedData('body'))
->allowUnsubscribe($notification);
Mail::send($mailable);
}
}
$reviewAssignment->setDateDue($this->getData('reviewDueDate'));
$reviewAssignment->setDateResponseDue($this->getData('responseDueDate'));
$reviewAssignment->setReviewMethod($this->getData('reviewMethod'));
if (!$reviewAssignment->getDateCompleted()) {
// Ensure that the review form ID is valid, if specified
$reviewFormId = (int) $this->getData('reviewFormId');
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewForm = $reviewFormDao->getById($reviewFormId, Application::getContextAssocType(), $context->getId());
$reviewAssignment->setReviewFormId($reviewForm ? $reviewFormId : null);
}
$reviewAssignmentDao->updateObject($reviewAssignment);
parent::execute(...$functionArgs);
}
}
@@ -0,0 +1,130 @@
<?php
/**
* @file controllers/grid/users/reviewer/form/EmailReviewerForm.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class EmailReviewerForm
*
* @ingroup controllers_grid_users_reviewer_form
*
* @brief Form for sending an email to a user
*/
namespace PKP\controllers\grid\users\reviewer\form;
use APP\core\Application;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use APP\submission\Submission;
use APP\template\TemplateManager;
use Illuminate\Support\Facades\Mail;
use PKP\db\DAORegistry;
use PKP\form\Form;
use PKP\log\SubmissionEmailLogDAO;
use PKP\log\SubmissionEmailLogEntry;
use PKP\mail\Mailable;
use PKP\notification\PKPNotification;
use PKP\submission\reviewAssignment\ReviewAssignment;
use Symfony\Component\Mailer\Exception\TransportException;
class EmailReviewerForm extends Form
{
/** @var ReviewAssignment The review assignment to use for this contact */
public $_reviewAssignment;
protected Submission $submission;
/**
* Constructor.
*
* @param ReviewAssignment $reviewAssignment The review assignment to use for this contact.
* @param Submission $submission
*/
public function __construct($reviewAssignment, $submission)
{
parent::__construct('controllers/grid/users/reviewer/form/emailReviewerForm.tpl');
$this->_reviewAssignment = $reviewAssignment;
$this->submission = $submission;
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'subject', 'required', 'email.subjectRequired'));
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'message', 'required', 'email.bodyRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars([
'subject',
'message',
]);
}
/**
* Display the form.
*
* @param array $requestArgs Request parameters to bounce back with the form submission.
* @param null|mixed $template
*
* @see Form::fetch
*/
public function fetch($request, $template = null, $display = false, $requestArgs = [])
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'userFullName' => $this->_reviewAssignment->getReviewerFullName(),
'requestArgs' => $requestArgs,
'reviewAssignmentId' => $this->_reviewAssignment->getId(),
]);
return parent::fetch($request, $template, $display);
}
/**
* Send the email
*/
public function execute(...$functionArgs)
{
$toUser = Repo::user()->get($this->_reviewAssignment->getReviewerId());
$request = Application::get()->getRequest();
$fromUser = $request->getUser();
$mailable = new Mailable([$request->getContext(), $this->submission]);
$mailable->to($toUser->getEmail(), $toUser->getFullName());
$mailable->from($fromUser->getEmail(), $fromUser->getFullName());
$mailable->replyTo($fromUser->getEmail(), $fromUser->getFullName());
$mailable->subject($this->getData('subject'));
$mailable->body($this->getData('message'));
try {
Mail::send($mailable);
$submissionEmailLogDao = DAORegistry::getDAO('SubmissionEmailLogDAO'); /** @var SubmissionEmailLogDAO $submissionEmailLogDao */
$submissionEmailLogDao->logMailable(
SubmissionEmailLogEntry::SUBMISSION_EMAIL_REVIEW_NOTIFY_REVIEWER,
$mailable,
$this->submission,
$fromUser,
);
} catch (TransportException $e) {
$notificationMgr = new NotificationManager();
$notificationMgr->createTrivialNotification(
$fromUser->getId(),
PKPNotification::NOTIFICATION_TYPE_ERROR,
['contents' => __('email.compose.error')]
);
trigger_error($e->getMessage(), E_USER_WARNING);
}
parent::execute(...$functionArgs);
}
}
@@ -0,0 +1,137 @@
<?php
/**
* @file controllers/grid/users/reviewer/form/EnrollExistingReviewerForm.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class EnrollExistingReviewerForm
*
* @ingroup controllers_grid_users_reviewer_form
*
* @brief Form for enrolling an existing reviewer and adding them to a submission.
*/
namespace PKP\controllers\grid\users\reviewer\form;
use APP\core\Application;
use APP\facades\Repo;
use Illuminate\Support\Facades\Mail;
use PKP\db\DAORegistry;
use PKP\security\Role;
use PKP\security\RoleDAO;
class EnrollExistingReviewerForm extends ReviewerForm
{
/**
* Constructor.
*/
public function __construct($submission, $reviewRound)
{
parent::__construct($submission, $reviewRound);
$this->setTemplate('controllers/grid/users/reviewer/form/enrollExistingReviewerForm.tpl');
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'userGroupId', 'required', 'user.profile.form.usergroupRequired'));
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'userId', 'required', 'manager.people.existingUserRequired'));
}
/**
* @copydoc Form::init()
*/
public function initData()
{
parent::initData();
$mailable = $this->getMailable();
$context = Application::get()->getRequest()->getContext();
$template = Repo::emailTemplate()->getByKey($context->getId(), $mailable::getEmailTemplateKey());
$this->setData('personalMessage', Mail::compileParams($template->getLocalizedData('body'), $mailable->viewData));
}
/**
* @copydoc Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$advancedSearchAction = $this->getAdvancedSearchAction($request);
$this->setReviewerFormAction($advancedSearchAction);
return parent::fetch($request, $template, $display);
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
parent::readInputData();
$this->readUserVars(['userId', 'userGroupId']);
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
// Assign a reviewer user group to an existing non-reviewer
$userId = (int) $this->getData('userId');
$userGroupId = (int) $this->getData('userGroupId');
if (!$this->isValidUserAndGroup($userId, $userGroupId)) {
fatalError('invalid user or userGroup ID');
}
Repo::userGroup()->assignUserToGroup($userId, $userGroupId);
// Set the reviewerId in the Form for the parent class to use
$this->setData('reviewerId', $userId);
return parent::execute(...$functionArgs);
}
/**
* Checks if the user group is valid and the user exists and doesn't already have a reviewer role
*/
protected function isValidUserAndGroup(int $userId, int $userGroupId): bool
{
$context = Application::get()->getRequest()->getContext();
// User exists
$user = Repo::user()->get($userId);
if (!$user) {
return false;
}
// Ensure user doesn't have a reviewer role
$roleDao = DAORegistry::getDAO('RoleDAO'); /** @var RoleDAO $roleDao */
if ($roleDao->userHasRole($context->getId(), $user->getId(), Role::ROLE_ID_REVIEWER)) {
return false;
}
// User Group exists
$userGroup = Repo::userGroup()->get($userGroupId);
if (!$userGroup) {
return false;
}
// User Group refers to the reviewer role
if ($userGroup->getData('roleId') != Role::ROLE_ID_REVIEWER) {
return false;
}
// User group refers to the right context
if (intval($userGroup->getData('contextId')) != $context->getId()) {
return false;
}
return true;
}
}
@@ -0,0 +1,112 @@
<?php
/**
* @file controllers/grid/users/reviewer/form/ReinstateReviewerForm.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class ReinstateReviewerForm
*
* @ingroup controllers_grid_users_reviewer_form
*
* @brief Allow the editor to reinstate a cancelled review assignment
*/
namespace PKP\controllers\grid\users\reviewer\form;
use APP\core\Application;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use APP\submission\Submission;
use PKP\context\Context;
use PKP\core\Core;
use PKP\core\PKPApplication;
use PKP\db\DAORegistry;
use PKP\log\event\PKPSubmissionEventLogEntry;
use PKP\mail\Mailable;
use PKP\mail\mailables\ReviewerReinstate;
use PKP\notification\PKPNotification;
use PKP\plugins\Hook;
use PKP\security\Validation;
use PKP\submission\reviewAssignment\ReviewAssignment;
use PKP\submission\reviewAssignment\ReviewAssignmentDAO;
use PKP\submission\reviewRound\ReviewRound;
class ReinstateReviewerForm extends ReviewerNotifyActionForm
{
/**
* Constructor
*
* @param ReviewAssignment $reviewAssignment
* @param ReviewRound $reviewRound
* @param Submission $submission
*/
public function __construct($reviewAssignment, $reviewRound, $submission)
{
parent::__construct($reviewAssignment, $reviewRound, $submission, 'controllers/grid/users/reviewer/form/reinstateReviewerForm.tpl');
}
/**
* @copydoc ReviewerNotifyActionForm::getMailable()
*/
protected function getMailable(Context $context, Submission $submission, ReviewAssignment $reviewAssignment): Mailable
{
return new ReviewerReinstate($context, $submission, $reviewAssignment);
}
/**
* @copydoc Form::execute()
*
* @return bool whether or not the review assignment was deleted successfully
*/
public function execute(...$functionArgs)
{
parent::execute(...$functionArgs);
$request = Application::get()->getRequest();
$submission = $this->getSubmission(); /** @var Submission $submission */
$reviewAssignment = $this->getReviewAssignment();
// Reinstate the review assignment.
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
if (isset($reviewAssignment) && $reviewAssignment->getSubmissionId() == $submission->getId() && !Hook::call('EditorAction::reinstateReview', [&$submission, $reviewAssignment])) {
$reviewer = Repo::user()->get($reviewAssignment->getReviewerId());
if (!isset($reviewer)) {
return false;
}
$reviewAssignment->setCancelled(false);
$reviewAssignmentDao->updateObject($reviewAssignment);
// Stamp the modification date
$submission->stampModified();
Repo::submission()->dao->update($submission);
// Insert a trivial notification to indicate the reviewer was reinstated successfully.
$currentUser = $request->getUser();
$notificationMgr = new NotificationManager();
$notificationMgr->createTrivialNotification($currentUser->getId(), PKPNotification::NOTIFICATION_TYPE_SUCCESS, ['contents' => __('notification.reinstatedReviewer')]);
// Add log
$eventLog = Repo::eventLog()->newDataObject([
'assocType' => PKPApplication::ASSOC_TYPE_SUBMISSION,
'assocId' => $submission->getId(),
'eventType' => PKPSubmissionEventLogEntry::SUBMISSION_LOG_REVIEW_REINSTATED,
'userId' => Validation::loggedInAs() ?? $currentUser->getId(),
'message' => 'log.review.reviewReinstated',
'isTranslated' => false,
'dateLogged' => Core::getCurrentDate(),
'reviewAssignmentId' => $reviewAssignment->getId(),
'reviewerName' => $reviewer->getFullName(),
'submissionId' => $submission->getId(),
'stageId' => $reviewAssignment->getStageId(),
'round' => $reviewAssignment->getRound()
]);
Repo::eventLog()->add($eventLog);
return true;
}
return false;
}
}
@@ -0,0 +1,125 @@
<?php
/**
* @file controllers/grid/users/reviewer/form/ResendRequestReviewerForm.php
*
* Copyright (c) 2014-2022 Simon Fraser University
* Copyright (c) 2003-2022 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class ResendRequestReviewerForm
*
* @ingroup controllers_grid_users_reviewer_form
*
* @brief Allow the editor to resend request to reconsider a declined review assignment invitation
*/
namespace PKP\controllers\grid\users\reviewer\form;
use APP\core\Application;
use APP\core\Request;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use APP\submission\Submission;
use PKP\context\Context;
use PKP\core\Core;
use PKP\core\PKPApplication;
use PKP\db\DAORegistry;
use PKP\log\event\PKPSubmissionEventLogEntry;
use PKP\mail\Mailable;
use PKP\mail\mailables\ReviewerResendRequest;
use PKP\notification\PKPNotification;
use PKP\security\Validation;
use PKP\submission\reviewAssignment\ReviewAssignment;
use PKP\submission\reviewAssignment\ReviewAssignmentDAO;
use PKP\submission\reviewRound\ReviewRound;
class ResendRequestReviewerForm extends ReviewerNotifyActionForm
{
/**
* Constructor
*
*/
public function __construct(ReviewAssignment $reviewAssignment, ReviewRound $reviewRound, Submission $submission)
{
parent::__construct(
$reviewAssignment,
$reviewRound,
$submission,
'controllers/grid/users/reviewer/form/resendRequestReviewerForm.tpl'
);
}
protected function getMailable(Context $context, Submission $submission, ReviewAssignment $reviewAssignment): Mailable
{
return new ReviewerResendRequest($context, $submission, $reviewAssignment);
}
/**
* @copydoc ReviewerNotifyActionForm::getEmailKey()
*/
protected function getEmailKey()
{
return 'REVIEW_RESEND_REQUEST';
}
/**
* @copydoc Form::execute()
*
* @return bool whether or not the review assignment was deleted successfully
*/
public function execute(...$functionArgs)
{
parent::execute(...$functionArgs);
$request = Application::get()->getRequest(); /** @var Request $request */
$submission = $this->getSubmission(); /** @var Submission $submission */
$reviewAssignment = $this->getReviewAssignment(); /** @var ReviewAssignment $reviewAssignment */
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
if (isset($reviewAssignment) && $reviewAssignment->getSubmissionId() == $submission->getId()) {
$reviewer = Repo::user()->get($reviewAssignment->getReviewerId());
if (!isset($reviewer)) {
return false;
}
// $reviewAssignment->setCancelled(false);
$reviewAssignment->setDeclined(false);
$reviewAssignment->setRequestResent(true);
$reviewAssignment->setDateConfirmed(null);
$reviewAssignmentDao->updateObject($reviewAssignment);
// Stamp the modification date
$submission->stampLastActivity();
Repo::submission()->dao->update($submission);
// Insert a trivial notification to indicate the reviewer requested to reconsider successfully.
$currentUser = $request->getUser();
$notificationMgr = new NotificationManager();
$notificationMgr->createTrivialNotification(
$currentUser->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __('notification.reviewerResendRequest')]
);
// Add log
$eventLog = Repo::eventLog()->newDataObject([
'assocType' => PKPApplication::ASSOC_TYPE_SUBMISSION,
'assocId' => $submission->getId(),
'eventType' => PKPSubmissionEventLogEntry::SUBMISSION_LOG_REVIEW_ASSIGN,
'userId' => Validation::loggedInAs() ?? $currentUser->getId(),
'message' => 'log.review.reviewerResendRequest',
'isTranslated' => false,
'dateLogged' => Core::getCurrentDate(),
'reviewAssignmentId' => $reviewAssignment->getId(),
'reviewerName' => $reviewer->getFullName(),
'submissionId' => $submission->getId(),
'stageId' => $reviewAssignment->getStageId(),
'round' => $reviewAssignment->getRound(),
]);
Repo::eventLog()->add($eventLog);
return true;
}
return false;
}
}
@@ -0,0 +1,188 @@
<?php
/**
* @file controllers/grid/users/reviewer/form/ReviewReminderForm.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class ReviewReminderForm
*
* @ingroup controllers_grid_users_reviewer_form
*
* @brief Form for sending a review reminder to a reviewer
*/
namespace PKP\controllers\grid\users\reviewer\form;
use APP\core\Application;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use APP\template\TemplateManager;
use Illuminate\Support\Facades\Mail;
use PKP\core\Core;
use PKP\core\PKPApplication;
use PKP\db\DAORegistry;
use PKP\facades\Locale;
use PKP\form\Form;
use PKP\log\event\PKPSubmissionEventLogEntry;
use PKP\mail\mailables\ReviewRemind;
use PKP\mail\variables\ReviewAssignmentEmailVariable;
use PKP\notification\PKPNotification;
use PKP\security\Validation;
use PKP\submission\reviewAssignment\ReviewAssignment;
use PKP\submission\reviewAssignment\ReviewAssignmentDAO;
use Symfony\Component\Mailer\Exception\TransportException;
class ReviewReminderForm extends Form
{
/** @var ReviewAssignment The review assignment associated with the reviewer */
public $_reviewAssignment;
/**
* Constructor.
*/
public function __construct($reviewAssignment)
{
parent::__construct('controllers/grid/users/reviewer/form/reviewReminderForm.tpl');
$this->_reviewAssignment = $reviewAssignment;
// Validation checks for this form
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
//
// Getters and Setters
//
/**
* Get the review assignment
*
* @return ReviewAssignment
*/
public function getReviewAssignment()
{
return $this->_reviewAssignment;
}
//
// Overridden template methods
//
/**
* @copydoc Form::initData
*/
public function initData()
{
$request = Application::get()->getRequest();
$user = $request->getUser();
$context = $request->getContext();
$reviewAssignment = $this->getReviewAssignment();
$reviewerId = $reviewAssignment->getReviewerId();
$reviewer = Repo::user()->get($reviewerId);
$submission = Repo::submission()->get($reviewAssignment->getSubmissionId());
$mailable = new ReviewRemind($context, $submission, $reviewAssignment);
$mailable->sender($user)->recipients([$reviewer]);
$template = Repo::emailTemplate()->getByKey($context->getId(), $mailable::getEmailTemplateKey());
$data = $mailable->getData(Locale::getLocale());
// Don't expose the reviewer's one-click access URL to editors
$data[ReviewAssignmentEmailVariable::REVIEW_ASSIGNMENT_URL] = '{$' . ReviewAssignmentEmailVariable::REVIEW_ASSIGNMENT_URL . '}';
$body = Mail::compileParams($template->getLocalizedData('body'), $data);
$this->setData('stageId', $reviewAssignment->getStageId());
$this->setData('reviewAssignmentId', $reviewAssignment->getId());
$this->setData('submissionId', $submission->getId());
$this->setData('reviewAssignment', $reviewAssignment);
$this->setData('reviewerName', $reviewer->getFullName() . ' <' . $reviewer->getEmail() . '>');
$this->setData('message', $body);
$this->setData('reviewDueDate', $mailable->viewData[ReviewAssignmentEmailVariable::REVIEW_DUE_DATE]);
}
/**
* @copydoc Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('emailVariables', [
'passwordResetUrl' => __('common.url'),
]);
return parent::fetch($request, $template, $display);
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars([
'message',
'reviewDueDate',
]);
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
$request = Application::get()->getRequest();
$reviewAssignment = $this->getReviewAssignment();
$reviewerId = $reviewAssignment->getReviewerId();
$reviewer = Repo::user()->get($reviewerId);
$submission = Repo::submission()->get($reviewAssignment->getSubmissionId());
$user = $request->getUser();
$context = $request->getContext();
// Create ReviewRemind email and populate with data
$mailable = new ReviewRemind($context, $submission, $reviewAssignment);
$template = Repo::emailTemplate()->getByKey($context->getId(), $mailable::getEmailTemplateKey());
$mailable
->subject($template->getLocalizedData('subject'))
->body($this->getData('message'))
->sender($user)
->recipients([$reviewer]);
// Finally, send email and handle Symfony transport exceptions
try {
Mail::send($mailable);
$eventLog = Repo::eventLog()->newDataObject([
'assocType' => PKPApplication::ASSOC_TYPE_SUBMISSION,
'assocId' => $submission->getId(),
'eventType' => PKPSubmissionEventLogEntry::SUBMISSION_LOG_REVIEW_REMIND,
'userId' => Validation::loggedInAs() ?? $user->getId(),
'message' => 'submission.event.reviewer.reviewerReminded',
'isTranslate' => 0,
'dateLogged' => Core::getCurrentDate(),
'recipientId' => $reviewer->getId(),
'recipientName' => $reviewer->getFullName(),
'senderId' => $user->getId(),
'senderName' => $user->getFullName(),
]);
Repo::eventLog()->add($eventLog);
$reviewAssignment->setDateReminded(Core::getCurrentDate());
$reviewAssignment->stampModified();
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
$reviewAssignmentDao->updateObject($reviewAssignment);
} catch (TransportException $e) {
$notificationMgr = new NotificationManager();
$notificationMgr->createTrivialNotification(
$request->getUser()->getId(),
PKPNotification::NOTIFICATION_TYPE_ERROR,
['contents' => __('email.compose.error')]
);
trigger_error($e->getMessage(), E_USER_WARNING);
}
parent::execute(...$functionArgs);
}
}
@@ -0,0 +1,494 @@
<?php
/**
* @file controllers/grid/users/reviewer/form/ReviewerForm.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class ReviewerForm
*
* @ingroup controllers_grid_users_reviewer_form
*
* @brief Base Form for adding a reviewer to a submission.
* N.B. Requires a subclass to implement the "reviewerId" to be added.
*/
namespace PKP\controllers\grid\users\reviewer\form;
use APP\core\Application;
use APP\core\Request;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use APP\submission\Submission;
use APP\template\TemplateManager;
use PKP\context\Context;
use PKP\controllers\grid\users\reviewer\PKPReviewerGridHandler;
use PKP\core\Core;
use PKP\db\DAORegistry;
use PKP\facades\Locale;
use PKP\form\Form;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxAction;
use PKP\mail\mailables\ReviewRequest;
use PKP\mail\variables\ReviewAssignmentEmailVariable;
use PKP\notification\PKPNotification;
use PKP\reviewForm\ReviewFormDAO;
use PKP\security\Role;
use PKP\security\RoleDAO;
use PKP\submission\action\EditorAction;
use PKP\submission\reviewAssignment\ReviewAssignment;
use PKP\submission\reviewAssignment\ReviewAssignmentDAO;
use PKP\submission\ReviewFilesDAO;
use PKP\submission\reviewRound\ReviewRound;
use PKP\submissionFile\SubmissionFile;
class ReviewerForm extends Form
{
/** @var Submission The submission associated with the review assignment */
public $_submission;
/** @var ReviewRound The review round associated with the review assignment */
public $_reviewRound;
/** @var array An array of actions for the other reviewer forms */
public $_reviewerFormActions;
/** @var array An array with all current user roles */
public $_userRoles;
/**
* Constructor.
*
* @param Submission $submission
* @param ReviewRound $reviewRound
*/
public function __construct($submission, $reviewRound)
{
parent::__construct('controllers/grid/users/reviewer/form/defaultReviewerForm.tpl');
$this->setSubmission($submission);
$this->setReviewRound($reviewRound);
// Validation checks for this form
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'responseDueDate', 'required', 'editor.review.errorAddingReviewer'));
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'reviewDueDate', 'required', 'editor.review.errorAddingReviewer'));
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
//
// Getters and Setters
//
/**
* Get the submission Id
*
* @return int submissionId
*/
public function getSubmissionId()
{
$submission = $this->getSubmission();
return $submission->getId();
}
/**
* Get the submission
*
* @return Submission
*/
public function getSubmission()
{
return $this->_submission;
}
/**
* Get the ReviewRound
*
* @return ReviewRound
*/
public function getReviewRound()
{
return $this->_reviewRound;
}
/**
* Set the submission
*
* @param Submission $submission
*/
public function setSubmission($submission)
{
$this->_submission = $submission;
}
/**
* Set the ReviewRound
*
* @param ReviewRound $reviewRound
*/
public function setReviewRound($reviewRound)
{
$this->_reviewRound = $reviewRound;
}
/**
* Set a reviewer form action
*
* @param LinkAction $action
*/
public function setReviewerFormAction($action)
{
$this->_reviewerFormActions[$action->getId()] = $action;
}
/**
* Set current user roles.
*
* @param array $userRoles
*/
public function setUserRoles($userRoles)
{
$this->_userRoles = $userRoles;
}
/**
* Get current user roles.
*
* @return array $userRoles
*/
public function getUserRoles()
{
return $this->_userRoles;
}
/**
* Get all of the reviewer form actions
*
* @return array
*/
public function getReviewerFormActions()
{
return $this->_reviewerFormActions;
}
//
// Overridden template methods
//
/**
* @copydoc Form::initData
*/
public function initData()
{
$request = Application::get()->getRequest();
$context = $request->getContext();
$reviewRound = $this->getReviewRound();
$submission = $this->getSubmission();
// Set default review method.
$reviewMethod = $context->getData('defaultReviewMode');
if (!$reviewMethod) {
$reviewMethod = ReviewAssignment::SUBMISSION_REVIEW_METHOD_DOUBLEANONYMOUS;
}
// If there is a section/series and it has a default
// review form designated, use it.
$sectionId = $submission->getCurrentPublication()->getData(Application::getSectionIdPropName());
$section = $sectionId ? Repo::section()->get($sectionId, $context->getId()) : null;
if ($section) {
$reviewFormId = $section->getReviewFormId();
} else {
$reviewFormId = null;
}
$numWeeks = (int) $context->getData('numWeeksPerReview');
if ($numWeeks <= 0) {
$numWeeks = 4;
}
$reviewDueDate = strtotime('+' . $numWeeks . ' week');
$numWeeks = (int) $context->getData('numWeeksPerResponse');
if ($numWeeks <= 0) {
$numWeeks = 3;
}
$responseDueDate = strtotime('+' . $numWeeks . ' week');
// Get the currently selected reviewer selection type to show the correct tab if we're re-displaying the form
$selectionType = (int) $request->getUserVar('selectionType');
$stageId = $reviewRound->getStageId();
$this->setData('submissionId', $this->getSubmissionId());
$this->setData('stageId', $stageId);
$this->setData('reviewMethod', $reviewMethod);
$this->setData('reviewFormId', $reviewFormId);
$this->setData('reviewRoundId', $reviewRound->getId());
$this->setData('responseDueDate', $responseDueDate);
$this->setData('reviewDueDate', $reviewDueDate);
$this->setData('selectionType', $selectionType);
$this->setData('considered', ReviewAssignment::REVIEW_ASSIGNMENT_NEW);
}
/**
* @copydoc Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$context = $request->getContext();
// Get the review method options.
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
$reviewMethods = $reviewAssignmentDao->getReviewMethodsTranslationKeys();
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('reviewMethods', $reviewMethods);
$templateMgr->assign('reviewerActions', $this->getReviewerFormActions());
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewFormsIterator = $reviewFormDao->getActiveByAssocId(Application::getContextAssocType(), $context->getId());
$reviewForms = [];
while ($reviewForm = $reviewFormsIterator->next()) {
$reviewForms[$reviewForm->getId()] = $reviewForm->getLocalizedTitle();
}
$templateMgr->assign('reviewForms', $reviewForms);
$templateMgr->assign('emailVariables', [
'recipientName' => __('user.name'),
'responseDueDate' => __('reviewer.submission.responseDueDate'),
'reviewDueDate' => __('reviewer.submission.reviewDueDate'),
'reviewAssignmentUrl' => __('common.url'),
'recipientUsername' => __('user.username'),
]);
$templates = $this->getEmailTemplates();
$templateMgr->assign([
'hasCustomTemplates' => (count($templates) > 1),
'templates' => $templates,
]);
// Get the reviewer user groups for the create new reviewer/enroll existing user tabs
$reviewRound = $this->getReviewRound();
$reviewerUserGroups = Repo::userGroup()->getUserGroupsByStage(
$context->getId(),
$reviewRound->getStageId(),
Role::ROLE_ID_REVIEWER
);
$userGroups = [];
foreach ($reviewerUserGroups as $userGroup) {
$userGroups[$userGroup->getId()] = $userGroup->getLocalizedName();
}
$this->setData('userGroups', $userGroups);
return parent::fetch($request, $template, $display);
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars([
'selectionType',
'submissionId',
'template',
'personalMessage',
'responseDueDate',
'reviewDueDate',
'reviewMethod',
'skipEmail',
'keywords',
'interests',
'reviewRoundId',
'stageId',
'selectedFiles',
'reviewFormId',
]);
}
/**
* Save review assignment
*/
public function execute(...$functionParams)
{
parent::execute(...$functionParams);
$submission = $this->getSubmission();
$request = Application::get()->getRequest();
$context = $request->getContext();
$currentReviewRound = $this->getReviewRound();
$stageId = $currentReviewRound->getStageId();
$reviewDueDate = $this->getData('reviewDueDate');
$responseDueDate = $this->getData('responseDueDate');
// Get reviewer id and validate it.
$reviewerId = (int) $this->getData('reviewerId');
if (!$this->_isValidReviewer($context, $submission, $currentReviewRound, $reviewerId)) {
fatalError('Invalid reviewer id.');
}
$reviewMethod = (int) $this->getData('reviewMethod');
$editorAction = new EditorAction();
$editorAction->addReviewer($request, $submission, $reviewerId, $currentReviewRound, $reviewDueDate, $responseDueDate, $reviewMethod);
// Get the reviewAssignment object now that it has been added.
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
$reviewAssignment = $reviewAssignmentDao->getReviewAssignment($currentReviewRound->getId(), $reviewerId);
$reviewAssignment->setDateNotified(Core::getCurrentDate());
$reviewAssignment->stampModified();
// Ensure that the review form ID is valid, if specified
$reviewFormId = (int) $this->getData('reviewFormId');
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewForm = $reviewFormDao->getById($reviewFormId, Application::getContextAssocType(), $context->getId());
$reviewAssignment->setReviewFormId($reviewForm ? $reviewFormId : null);
$reviewAssignmentDao->updateObject($reviewAssignment);
$fileStages = [$stageId == WORKFLOW_STAGE_ID_INTERNAL_REVIEW ? SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_FILE : SubmissionFile::SUBMISSION_FILE_REVIEW_FILE];
// Grant access for this review to all selected files.
$submissionFiles = Repo::submissionFile()
->getCollector()
->filterBySubmissionIds([$submission->getId()])
->filterByReviewRoundIds([$currentReviewRound->getId()])
->filterByFileStages($fileStages)
->getMany();
$selectedFiles = array_map(function ($id) {
return (int) $id;
}, (array) $this->getData('selectedFiles'));
$reviewFilesDao = DAORegistry::getDAO('ReviewFilesDAO'); /** @var ReviewFilesDAO $reviewFilesDao */
foreach ($submissionFiles as $submissionFile) {
if (in_array($submissionFile->getId(), $selectedFiles)) {
$reviewFilesDao->grant($reviewAssignment->getId(), $submissionFile->getId());
}
}
// Insert a trivial notification to indicate the reviewer was added successfully.
$reviewer = Repo::user()->get($reviewerId);
$currentUser = $request->getUser();
$notificationMgr = new NotificationManager();
$msgKey = $this->getData('skipEmail') ? 'notification.addedReviewerNoEmail' : 'notification.addedReviewer';
$notificationMgr->createTrivialNotification(
$currentUser->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __($msgKey, ['reviewerName' => $reviewer->getFullName()])]
);
return $reviewAssignment;
}
//
// Protected methods.
//
/**
* Get the link action that fetchs the advanced search form content
*
* @param Request $request
*
* @return LinkAction
*/
public function getAdvancedSearchAction($request)
{
$reviewRound = $this->getReviewRound();
return new LinkAction(
'addReviewer',
new AjaxAction($request->url(null, null, 'reloadReviewerForm', null, [
'submissionId' => $this->getSubmissionId(),
'stageId' => $reviewRound->getStageId(),
'reviewRoundId' => $reviewRound->getId(),
'selectionType' => PKPReviewerGridHandler::REVIEWER_SELECT_ADVANCED_SEARCH,
])),
__('editor.submission.backToSearch'),
'return'
);
}
//
// Private helper methods
//
/**
* Check if a given user id is enrolled in reviewer user group.
*
* @param Context $context
* @param Submission $submission
* @param ReviewRound $reviewRound
* @param int $reviewerId
*
* @return bool
*/
public function _isValidReviewer($context, $submission, $reviewRound, $reviewerId)
{
// Ensure the user isn't already assigned to the current submission
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
$reviewAssignments = $reviewAssignmentDao->getBySubmissionId($submission->getId(), $reviewRound->getId());
foreach ($reviewAssignments as $reviewAssignment) {
if ($reviewerId == $reviewAssignment->getReviewerId()) {
return false;
}
}
// Ensure that they are a reviewer
$roleDao = DAORegistry::getDAO('RoleDAO'); /** @var RoleDAO $roleDao */
return $roleDao->userHasRole($context->getId(), $reviewerId, Role::ROLE_ID_REVIEWER);
}
/**
* Get the Mailable and populate with data
*/
protected function getMailable(): ReviewRequest
{
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
$reviewAssignment = $reviewAssignmentDao->newDataObject(); /** @var ReviewAssignment $reviewAssignment */
$reviewAssignment->setSubmissionId($this->getSubmissionId());
$submission = $this->getSubmission();
$request = Application::get()->getRequest();
$mailable = new ReviewRequest($request->getContext(), $submission, $reviewAssignment);
$mailable->sender($request->getUser());
$mailable->addData([
'messageToReviewer' => __('reviewer.step1.requestBoilerplate'),
'abstractTermIfEnabled' => ($submission->getLocalizedAbstract() == '' ? '' : __('common.abstract')), // Deprecated; for OJS 2.x templates
]);
// Remove template variables that haven't been set yet during form initialization
$mailable->setData(Locale::getLocale());
unset($mailable->viewData[ReviewAssignmentEmailVariable::REVIEW_DUE_DATE]);
unset($mailable->viewData[ReviewAssignmentEmailVariable::RESPONSE_DUE_DATE]);
unset($mailable->viewData[ReviewAssignmentEmailVariable::REVIEW_ASSIGNMENT_URL]);
return $mailable;
}
/**
* Get email templates associated with the form
*
* @return array [key => name]
*/
protected function getEmailTemplates(): array
{
$defaultTemplate = Repo::emailTemplate()->getByKey(
Application::get()->getRequest()->getContext()->getId(),
ReviewRequest::getEmailTemplateKey()
);
$templateKeys = [ReviewRequest::getEmailTemplateKey() => $defaultTemplate->getLocalizedData('name')];
$alternateTemplates = Repo::emailTemplate()->getCollector(Application::get()->getRequest()->getContext()->getId())
->alternateTo([ReviewRequest::getEmailTemplateKey()])
->getMany();
foreach ($alternateTemplates as $alternateTemplate) {
$templateKeys[$alternateTemplate->getData('key')] = $alternateTemplate->getLocalizedData('name');
}
return $templateKeys;
}
}
@@ -0,0 +1,83 @@
<?php
/**
* @file controllers/grid/users/reviewer/form/ReviewerGossipForm.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class ReviewerGossipForm
*
* @ingroup controllers_grid_users_reviewer_form
*
* @brief Form for viewing and editing gossip about a reviewer
*/
namespace PKP\controllers\grid\users\reviewer\form;
use APP\facades\Repo;
use APP\template\TemplateManager;
use PKP\form\Form;
use PKP\user\User;
class ReviewerGossipForm extends Form
{
/** @var User The user to gossip about */
public $_user;
/** @var array Arguments used to route the form op */
public $_requestArgs;
/**
* Constructor.
*
* @param User $user The user to gossip about
* @param array $requestArgs Arguments used to route the form op to the
* correct submission, stage and review round
*/
public function __construct($user, $requestArgs)
{
parent::__construct('controllers/grid/users/reviewer/form/reviewerGossipForm.tpl');
$this->_user = $user;
$this->_requestArgs = $requestArgs;
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
/**
* @copydoc Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars([
'gossip',
]);
}
/**
* @copydoc Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'requestArgs' => $this->_requestArgs,
'gossip' => $this->_user->getGossip(),
]);
return parent::fetch($request, $template, $display);
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
$this->_user->setGossip($this->getData('gossip'));
Repo::user()->edit($this->_user);
parent::execute(...$functionArgs);
}
}
@@ -0,0 +1,170 @@
<?php
/**
* @file controllers/grid/users/reviewer/form/ReviewerNotifyActionForm.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class ReviewerNotifyActionForm
*
* @ingroup controllers_grid_users_reviewer_form
*
* @brief Perform an action on a review including a reviewer notification email.
*/
namespace PKP\controllers\grid\users\reviewer\form;
use APP\core\Application;
use APP\facades\Repo;
use APP\submission\Submission;
use Illuminate\Support\Facades\Mail;
use PKP\context\Context;
use PKP\form\Form;
use PKP\mail\Mailable;
use PKP\submission\reviewAssignment\ReviewAssignment;
use PKP\submission\reviewRound\ReviewRound;
abstract class ReviewerNotifyActionForm extends Form
{
/** @var ReviewAssignment The review assignment to alter */
public $_reviewAssignment;
/** @var Submission The submission associated with the review assignment */
public $_submission;
/** @var ReviewRound The review round associated with the review assignment */
public $_reviewRound;
/**
* Constructor
*
* @param ReviewAssignment $reviewAssignment
* @param ReviewRound $reviewRound
* @param Submission $submission
* @param string $template
*/
public function __construct($reviewAssignment, $reviewRound, $submission, $template)
{
$this->setReviewAssignment($reviewAssignment);
$this->setReviewRound($reviewRound);
$this->setSubmission($submission);
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
parent::__construct($template);
}
abstract protected function getMailable(Context $context, Submission $submission, ReviewAssignment $reviewAssignment): Mailable;
//
// Overridden template methods
//
/**
* @copydoc Form::initData
*/
public function initData()
{
$request = Application::get()->getRequest();
$submission = $this->getSubmission();
$reviewAssignment = $this->getReviewAssignment();
$reviewRound = $this->getReviewRound();
$reviewerId = $reviewAssignment->getReviewerId();
$this->setData([
'submissionId' => $submission->getId(),
'stageId' => $reviewRound->getStageId(),
'reviewRoundId' => $reviewRound->getId(),
'reviewAssignmentId' => $reviewAssignment->getId(),
'dateConfirmed' => $reviewAssignment->getDateConfirmed(),
'reviewerId' => $reviewerId,
]);
$context = $request->getContext();
$mailable = $this->getMailable($context, $submission, $reviewAssignment);
$mailable->sender($request->getUser());
$mailable->recipients([Repo::user()->get($reviewerId)]);
$template = Repo::emailTemplate()->getByKey($context->getId(), $mailable::getEmailTemplateKey());
$this->setData('personalMessage', Mail::compileParams($template->getLocalizedData('body'), $mailable->getData()));
}
/**
* @copydoc Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars([
'personalMessage',
'reviewAssignmentId',
'reviewRoundId',
'reviewerId',
'skipEmail',
'stageId',
'submissionId',
]);
}
//
// Getters and Setters
//
/**
* Set the ReviewAssignment
*
* @param mixed $reviewAssignment ReviewAssignment
*/
public function setReviewAssignment($reviewAssignment)
{
$this->_reviewAssignment = $reviewAssignment;
}
/**
* Get the ReviewAssignment
*
* @return ReviewAssignment
*/
public function getReviewAssignment()
{
return $this->_reviewAssignment;
}
/**
* Set the ReviewRound
*
* @param mixed $reviewRound ReviewRound
*/
public function setReviewRound($reviewRound)
{
$this->_reviewRound = $reviewRound;
}
/**
* Get the ReviewRound
*
* @return ReviewRound
*/
public function getReviewRound()
{
return $this->_reviewRound;
}
/**
* Set the submission
*
* @param Submission $submission
*/
public function setSubmission($submission)
{
$this->_submission = $submission;
}
/**
* Get the submission
*
* @return Submission
*/
public function getSubmission()
{
return $this->_submission;
}
}
@@ -0,0 +1,164 @@
<?php
/**
* @file controllers/grid/users/reviewer/form/ThankReviewerForm.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class ThankReviewerForm
*
* @ingroup controllers_grid_users_reviewer_form
*
* @brief Form for sending a thank you to a reviewer
*/
namespace PKP\controllers\grid\users\reviewer\form;
use APP\core\Application;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use Illuminate\Support\Facades\Mail;
use PKP\core\Core;
use PKP\db\DAORegistry;
use PKP\facades\Locale;
use PKP\form\Form;
use PKP\log\SubmissionEmailLogDAO;
use PKP\log\SubmissionEmailLogEntry;
use PKP\mail\mailables\ReviewAcknowledgement;
use PKP\notification\PKPNotification;
use PKP\plugins\Hook;
use PKP\submission\reviewAssignment\ReviewAssignment;
use PKP\submission\reviewAssignment\ReviewAssignmentDAO;
use Symfony\Component\Mailer\Exception\TransportException;
class ThankReviewerForm extends Form
{
/** @var ReviewAssignment The review assignment associated with the reviewer */
public $_reviewAssignment;
/**
* Constructor.
*/
public function __construct($reviewAssignment)
{
parent::__construct('controllers/grid/users/reviewer/form/thankReviewerForm.tpl');
$this->_reviewAssignment = $reviewAssignment;
// Validation checks for this form
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
//
// Getters and Setters
//
/**
* Get the review assignment
*
* @return ReviewAssignment
*/
public function getReviewAssignment()
{
return $this->_reviewAssignment;
}
//
// Overridden template methods
//
/**
* @copydoc Form::initData
*/
public function initData()
{
$request = Application::get()->getRequest();
$user = $request->getUser();
$reviewAssignment = $this->getReviewAssignment();
$reviewerId = $reviewAssignment->getReviewerId();
$reviewer = Repo::user()->get($reviewerId);
$submission = Repo::submission()->get($reviewAssignment->getSubmissionId());
$contextDao = Application::getContextDAO();
$context = $contextDao->getById($submission->getData('contextId'));
$mailable = new ReviewAcknowledgement($context, $submission, $reviewAssignment);
$mailable->sender($user)->recipients([$reviewer]);
$template = Repo::emailTemplate()->getByKey($context->getId(), $mailable->getEmailTemplateKey());
$this->setData('submissionId', $submission->getId());
$this->setData('stageId', $reviewAssignment->getStageId());
$this->setData('reviewAssignmentId', $reviewAssignment->getId());
$this->setData('reviewAssignment', $reviewAssignment);
$this->setData('reviewerName', $reviewer->getFullName() . ' <' . $reviewer->getEmail() . '>');
$this->setData('message', Mail::compileParams($template->getLocalizedData('body'), $mailable->getData(Locale::getLocale())));
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars(['message', 'skipEmail']);
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
$request = Application::get()->getRequest();
$reviewAssignment = $this->getReviewAssignment();
$reviewerId = $reviewAssignment->getReviewerId();
$reviewer = Repo::user()->get($reviewerId);
$submission = Repo::submission()->get($reviewAssignment->getSubmissionId());
$contextDao = Application::getContextDAO();
$context = $contextDao->getById($submission->getData('contextId'));
$user = $request->getUser();
// Create mailable and populate with data
$mailable = new ReviewAcknowledgement($context, $submission, $reviewAssignment);
$mailable->sender($user)->recipients([$reviewer]);
$template = Repo::emailTemplate()->getByKey($context->getId(), $mailable->getEmailTemplateKey());
$mailable->body($this->getData('message'))->subject($template->getLocalizedData('subject'));
Hook::call('ThankReviewerForm::thankReviewer', [$submission, $reviewAssignment, $mailable]);
if (!$this->getData('skipEmail')) {
$mailable->setData(Locale::getLocale());
try {
Mail::send($mailable);
$submissionEmailLogDao = DAORegistry::getDAO('SubmissionEmailLogDAO'); /** @var SubmissionEmailLogDAO $submissionEmailLogDao */
$submissionEmailLogDao->logMailable(
SubmissionEmailLogEntry::SUBMISSION_EMAIL_REVIEW_THANK_REVIEWER,
$mailable,
$submission,
$user,
);
} catch (TransportException $e) {
$notificationMgr = new NotificationManager();
$notificationMgr->createTrivialNotification(
$request->getUser()->getId(),
PKPNotification::NOTIFICATION_TYPE_ERROR,
['contents' => __('email.compose.error')]
);
trigger_error($e->getMessage(), E_USER_WARNING);
}
}
// update the ReviewAssignment with the acknowledged date
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
$reviewAssignment->setDateAcknowledged(Core::getCurrentDate());
$reviewAssignment->stampModified();
if (!in_array($reviewAssignment->getConsidered(), [ReviewAssignment::REVIEW_ASSIGNMENT_CONSIDERED, ReviewAssignment::REVIEW_ASSIGNMENT_RECONSIDERED])) {
$reviewAssignment->setConsidered(
$reviewAssignment->getConsidered() === ReviewAssignment::REVIEW_ASSIGNMENT_NEW
? ReviewAssignment::REVIEW_ASSIGNMENT_CONSIDERED
: ReviewAssignment::REVIEW_ASSIGNMENT_RECONSIDERED
);
}
$reviewAssignmentDao->updateObject($reviewAssignment);
parent::execute(...$functionArgs);
}
}
@@ -0,0 +1,126 @@
<?php
/**
* @file controllers/grid/users/reviewer/form/UnassignReviewerForm.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class UnassignReviewerForm
*
* @ingroup controllers_grid_users_reviewer_form
*
* @brief Allow the editor to remove a review assignment
*/
namespace PKP\controllers\grid\users\reviewer\form;
use APP\core\Application;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use APP\submission\Submission;
use PKP\context\Context;
use PKP\core\Core;
use PKP\core\PKPApplication;
use PKP\db\DAORegistry;
use PKP\log\event\PKPSubmissionEventLogEntry;
use PKP\mail\Mailable;
use PKP\mail\mailables\ReviewerUnassign;
use PKP\notification\NotificationDAO;
use PKP\notification\PKPNotification;
use PKP\plugins\Hook;
use PKP\security\Validation;
use PKP\submission\reviewAssignment\ReviewAssignment;
use PKP\submission\reviewAssignment\ReviewAssignmentDAO;
class UnassignReviewerForm extends ReviewerNotifyActionForm
{
/**
* Constructor
*
* @param mixed $reviewAssignment ReviewAssignment
* @param mixed $reviewRound ReviewRound
* @param mixed $submission Submission
*/
public function __construct($reviewAssignment, $reviewRound, $submission)
{
parent::__construct($reviewAssignment, $reviewRound, $submission, 'controllers/grid/users/reviewer/form/unassignReviewerForm.tpl');
}
/**
* @copydoc ReviewerNotifyActionForm::getMailable()
*/
protected function getMailable(Context $context, Submission $submission, ReviewAssignment $reviewAssignment): Mailable
{
return new ReviewerUnassign($context, $submission, $reviewAssignment);
}
/**
* @copydoc Form::execute()
*
* @return bool whether or not the review assignment was deleted successfully
*/
public function execute(...$functionArgs)
{
parent::execute(...$functionArgs);
$request = Application::get()->getRequest();
$submission = $this->getSubmission();
$reviewAssignment = $this->getReviewAssignment();
// Delete or cancel the review assignment.
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
if (isset($reviewAssignment) && $reviewAssignment->getSubmissionId() == $submission->getId() && !Hook::call('EditorAction::clearReview', [&$submission, $reviewAssignment])) {
$reviewer = Repo::user()->get($reviewAssignment->getReviewerId(), true);
if (!isset($reviewer)) {
return false;
}
if ($reviewAssignment->getDateConfirmed()) {
// The review has been confirmed but not completed. Flag it as cancelled.
$reviewAssignment->setCancelled(true);
$reviewAssignmentDao->updateObject($reviewAssignment);
} else {
// The review had not been confirmed yet. Delete the assignment.
$reviewAssignmentDao->deleteById($reviewAssignment->getId());
}
// Stamp the modification date
$submission->stampModified();
Repo::submission()->dao->update($submission);
$notificationDao = DAORegistry::getDAO('NotificationDAO'); /** @var NotificationDAO $notificationDao */
$notificationDao->deleteByAssoc(
Application::ASSOC_TYPE_REVIEW_ASSIGNMENT,
$reviewAssignment->getId(),
$reviewAssignment->getReviewerId(),
PKPNotification::NOTIFICATION_TYPE_REVIEW_ASSIGNMENT
);
// Insert a trivial notification to indicate the reviewer was removed successfully.
$currentUser = $request->getUser();
$notificationMgr = new NotificationManager();
$notificationMgr->createTrivialNotification($currentUser->getId(), PKPNotification::NOTIFICATION_TYPE_SUCCESS, ['contents' => $reviewAssignment->getDateConfirmed() ? __('notification.cancelledReviewer') : __('notification.removedReviewer')]);
// Add log
$eventLog = Repo::eventLog()->newDataObject([
'assocType' => PKPApplication::ASSOC_TYPE_SUBMISSION,
'assocId' => $submission->getId(),
'eventType' => PKPSubmissionEventLogEntry::SUBMISSION_LOG_REVIEW_CLEAR,
'userId' => Validation::loggedInAs() ?? $currentUser->getId(),
'message' => 'log.review.reviewCleared',
'isTranslated' => false,
'dateLogged' => Core::getCurrentDate(),
'reviewAssignmentId' => $reviewAssignment->getId(),
'reviewerName' => $reviewer->getFullName(),
'submissionId' => $submission->getId(),
'stageId' => $reviewAssignment->getStageId(),
'round' => $reviewAssignment->getRound()
]);
Repo::eventLog()->add($eventLog);
return true;
}
return false;
}
}