267 lines
9.8 KiB
PHP
267 lines
9.8 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @file pages/decision/DecisionHandler.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 DecisionHandler
|
|
*
|
|
* @ingroup pages_decision
|
|
*
|
|
* @brief Handle requests to take an editorial decision.
|
|
*/
|
|
|
|
namespace PKP\pages\decision;
|
|
|
|
use APP\core\Application;
|
|
use APP\core\PageRouter;
|
|
use APP\core\Request;
|
|
use APP\facades\Repo;
|
|
use APP\handler\Handler;
|
|
use APP\submission\Submission;
|
|
use APP\template\TemplateManager;
|
|
use PKP\context\Context;
|
|
use PKP\core\Dispatcher;
|
|
use PKP\db\DAORegistry;
|
|
use PKP\decision\DecisionType;
|
|
use PKP\decision\types\interfaces\DecisionRetractable;
|
|
use PKP\security\authorization\ContextAccessPolicy;
|
|
use PKP\security\authorization\DecisionWritePolicy;
|
|
use PKP\security\authorization\internal\SubmissionRequiredPolicy;
|
|
use PKP\security\authorization\UserRequiredPolicy;
|
|
use PKP\security\Role;
|
|
use PKP\stageAssignment\StageAssignmentDAO;
|
|
use PKP\submission\Genre;
|
|
use PKP\submission\GenreDAO;
|
|
use PKP\submission\reviewRound\ReviewRound;
|
|
use PKP\submission\reviewRound\ReviewRoundDAO;
|
|
use Stringy\Stringy;
|
|
|
|
class DecisionHandler extends Handler
|
|
{
|
|
/** @copydoc PKPHandler::_isBackendPage */
|
|
public $_isBackendPage = true;
|
|
|
|
protected DecisionType $decisionType;
|
|
protected Submission $submission;
|
|
protected ?ReviewRound $reviewRound = null;
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
|
|
$this->addRoleAssignment(
|
|
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR],
|
|
['record']
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @copydoc PKPHandler::authorize()
|
|
*/
|
|
public function authorize($request, &$args, $roleAssignments): bool
|
|
{
|
|
/** @var PageRouter */
|
|
$router = $request->getRouter();
|
|
$op = $router->getRequestedOp($request);
|
|
|
|
if (!$op || $op !== 'record') {
|
|
return false;
|
|
}
|
|
|
|
$this->addPolicy(new UserRequiredPolicy($request));
|
|
$this->addPolicy(new ContextAccessPolicy($request, $roleAssignments));
|
|
$this->addPolicy(new SubmissionRequiredPolicy($request, $args, 'submissionId'));
|
|
$this->addPolicy(new DecisionWritePolicy($request, $args, (int) $request->getUserVar('decision'), $request->getUser()));
|
|
|
|
return parent::authorize($request, $args, $roleAssignments);
|
|
}
|
|
|
|
public function record($args, $request)
|
|
{
|
|
$this->setupTemplate($request);
|
|
$dispatcher = $request->getDispatcher();
|
|
$context = $request->getContext();
|
|
$reviewRoundId = (int) $request->getUserVar('reviewRoundId');
|
|
|
|
$this->decisionType = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_DECISION_TYPE);
|
|
$this->submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
|
|
|
|
// Don't allow a decision unless the submission is at the correct stage
|
|
if ($this->submission->getData('stageId') !== $this->decisionType->getStageId()) {
|
|
$request->getDispatcher()->handle404();
|
|
}
|
|
|
|
// Don't allow a decision in a review stage unless there is a valid review round
|
|
if (in_array($this->decisionType->getStageId(), [WORKFLOW_STAGE_ID_INTERNAL_REVIEW, WORKFLOW_STAGE_ID_EXTERNAL_REVIEW])) {
|
|
if (!$reviewRoundId) {
|
|
$request->getDispatcher()->handle404();
|
|
}
|
|
$reviewRoundDao = DAORegistry::getDAO('ReviewRoundDAO'); /** @var ReviewRoundDAO $reviewRoundDao */
|
|
$this->reviewRound = $reviewRoundDao->getById($reviewRoundId);
|
|
if (!$this->reviewRound || $this->reviewRound->getSubmissionId() !== $this->submission->getId()) {
|
|
$request->getDispatcher()->handle404();
|
|
}
|
|
}
|
|
|
|
// For a retractable decision, don't allow if it can not be retracted
|
|
if ($this->decisionType instanceof DecisionRetractable && !$this->decisionType->canRetract($this->submission, $reviewRoundId)) {
|
|
$request->getDispatcher()->handle404();
|
|
}
|
|
|
|
// Don't allow a recommendation unless at least one deciding editor exists
|
|
if (Repo::decision()->isRecommendation($this->decisionType->getDecision())) {
|
|
/** @var StageAssignmentDAO $stageAssignmentDao */
|
|
$stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO');
|
|
$assignedEditorIds = $stageAssignmentDao->getDecidingEditorIds($this->submission->getId(), $this->decisionType->getStageId());
|
|
if (!$assignedEditorIds) {
|
|
$request->getDispatcher()->handle404();
|
|
}
|
|
}
|
|
|
|
$steps = $this->decisionType->getSteps(
|
|
$this->submission,
|
|
$context,
|
|
$request->getUser(),
|
|
$this->reviewRound
|
|
);
|
|
|
|
$templateMgr = TemplateManager::getManager($request);
|
|
|
|
$templateMgr->setState([
|
|
'abandonDecisionLabel' => __('editor.decision.cancelDecision'),
|
|
'cancelConfirmationPrompt' => __('editor.decision.cancelDecision.confirmation'),
|
|
'decision' => $this->decisionType->getDecision(),
|
|
'decisionCompleteLabel' => $this->decisionType->getCompletedLabel(),
|
|
'decisionCompleteDescription' => $this->decisionType->getCompletedMessage($this->submission),
|
|
'emailTemplatesApiUrl' => $dispatcher->url(
|
|
$request,
|
|
Application::ROUTE_API,
|
|
$context->getData('urlPath'),
|
|
'emailTemplates'
|
|
),
|
|
'fileGenres' => $this->getFileGenres($context),
|
|
'keepWorkingLabel' => __('common.keepWorking'),
|
|
'reviewRoundId' => $this->reviewRound ? $this->reviewRound->getId() : null,
|
|
'stageId' => $this->submission->getStageId(),
|
|
'stepErrorMessage' => __('editor.decision.stepError'),
|
|
'steps' => $steps->getState(),
|
|
'submissionUrl' => $dispatcher->url(
|
|
$request,
|
|
Application::ROUTE_PAGE,
|
|
$context->getData('urlPath'),
|
|
'workflow',
|
|
'access',
|
|
[$this->submission->getId()]
|
|
),
|
|
'submissionApiUrl' => $dispatcher->url(
|
|
$request,
|
|
Application::ROUTE_API,
|
|
$context->getData('urlPath'),
|
|
'submissions/' . $this->submission->getId()
|
|
),
|
|
'submissionListUrl' => $dispatcher->url(
|
|
$request,
|
|
Application::ROUTE_PAGE,
|
|
$context->getData('urlPath'),
|
|
'submissions',
|
|
),
|
|
'viewAllSubmissionsLabel' => __('submission.list.viewAllSubmissions'),
|
|
'viewSubmissionLabel' => __('submission.list.viewSubmission'),
|
|
]);
|
|
|
|
$templateMgr->assign([
|
|
'breadcrumbs' => $this->getBreadcrumb($this->submission, $context, $request, $dispatcher),
|
|
'decisionType' => $this->decisionType,
|
|
'pageComponent' => 'DecisionPage',
|
|
'pageWidth' => TemplateManager::PAGE_WIDTH_WIDE,
|
|
'pageTitle' => join(
|
|
__('common.titleSeparator'),
|
|
[
|
|
$this->decisionType->getLabel(),
|
|
$this->submission->getCurrentPublication()->getShortAuthorString()
|
|
? $this->submission->getCurrentPublication()->getShortAuthorString()
|
|
: $this->submission->getCurrentPublication()->getLocalizedFullTitle(),
|
|
]
|
|
),
|
|
'reviewRound' => $this->reviewRound,
|
|
'submission' => $this->submission,
|
|
]);
|
|
|
|
$templateMgr->display('decision/record.tpl');
|
|
}
|
|
|
|
protected function getBreadcrumb(Submission $submission, Context $context, Request $request, Dispatcher $dispatcher)
|
|
{
|
|
$currentPublication = $submission->getCurrentPublication();
|
|
$submissionTitle = Stringy::create(
|
|
join(
|
|
__('common.commaListSeparator'),
|
|
[
|
|
$currentPublication->getShortAuthorString(),
|
|
$currentPublication->getLocalizedFullTitle(null, 'html'),
|
|
]
|
|
)
|
|
);
|
|
if ($submissionTitle->length() > 50) {
|
|
$submissionTitle = $submissionTitle->safeTruncate(50)
|
|
->append('...');
|
|
}
|
|
|
|
return [
|
|
[
|
|
'id' => 'submissions',
|
|
'name' => __('navigation.submissions'),
|
|
'url' => $dispatcher->url(
|
|
$request,
|
|
Application::ROUTE_PAGE,
|
|
$context->getData('urlPath'),
|
|
'submissions'
|
|
),
|
|
],
|
|
[
|
|
'id' => 'submission',
|
|
'name' => $submissionTitle,
|
|
'format' => 'html',
|
|
'url' => $dispatcher->url(
|
|
$request,
|
|
Application::ROUTE_PAGE,
|
|
$context->getData('urlPath'),
|
|
'workflow',
|
|
'access',
|
|
[$submission->getId()]
|
|
),
|
|
],
|
|
[
|
|
'id' => 'decision',
|
|
'name' => $this->decisionType->getLabel(),
|
|
]
|
|
];
|
|
}
|
|
|
|
protected function getFileGenres(Context $context): array
|
|
{
|
|
$fileGenres = [];
|
|
|
|
/** @var GenreDAO $genreDao */
|
|
$genreDao = DAORegistry::getDAO('GenreDAO');
|
|
$genreResults = $genreDao->getEnabledByContextId($context->getId());
|
|
/** @var Genre $genre */
|
|
while ($genre = $genreResults->next()) {
|
|
$fileGenres[] = [
|
|
'id' => $genre->getId(),
|
|
'name' => $genre->getLocalizedName(),
|
|
'isPrimary' => !$genre->getSupplementary() && !$genre->getDependent(),
|
|
];
|
|
}
|
|
|
|
return $fileGenres;
|
|
}
|
|
}
|