first commit
This commit is contained in:
@@ -0,0 +1,890 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file pages/submission/PKPSubmissionHandler.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 PKPSubmissionHandler
|
||||
*
|
||||
* @ingroup pages_submission
|
||||
*
|
||||
* @brief Handles page requests to the submission wizard
|
||||
*/
|
||||
|
||||
namespace PKP\pages\submission;
|
||||
|
||||
use APP\components\forms\submission\ReconfigureSubmission;
|
||||
use APP\core\Application;
|
||||
use APP\core\Request;
|
||||
use APP\facades\Repo;
|
||||
use APP\handler\Handler;
|
||||
use APP\publication\Publication;
|
||||
use APP\section\Section;
|
||||
use APP\submission\Submission;
|
||||
use APP\template\TemplateManager;
|
||||
use Illuminate\Support\LazyCollection;
|
||||
use PKP\components\forms\FormComponent;
|
||||
use PKP\components\forms\publication\PKPCitationsForm;
|
||||
use PKP\components\forms\publication\TitleAbstractForm;
|
||||
use PKP\components\forms\submission\CommentsForTheEditors;
|
||||
use PKP\components\forms\submission\ConfirmSubmission;
|
||||
use PKP\components\forms\submission\ForTheEditors;
|
||||
use PKP\components\forms\submission\PKPSubmissionFileForm;
|
||||
use PKP\components\listPanels\ContributorsListPanel;
|
||||
use PKP\context\Context;
|
||||
use PKP\db\DAORegistry;
|
||||
use PKP\security\authorization\SubmissionAccessPolicy;
|
||||
use PKP\security\authorization\UserRequiredPolicy;
|
||||
use PKP\security\Role;
|
||||
use PKP\stageAssignment\StageAssignmentDAO;
|
||||
use PKP\submission\GenreDAO;
|
||||
use PKP\submissionFile\SubmissionFile;
|
||||
use PKP\user\User;
|
||||
|
||||
abstract class PKPSubmissionHandler extends Handler
|
||||
{
|
||||
public const SECTION_TYPE_CONFIRM = 'confirm';
|
||||
public const SECTION_TYPE_CONTRIBUTORS = 'contributors';
|
||||
public const SECTION_TYPE_FILES = 'files';
|
||||
public const SECTION_TYPE_FORM = 'form';
|
||||
public const SECTION_TYPE_TEMPLATE = 'template';
|
||||
public const SECTION_TYPE_REVIEW = 'review';
|
||||
|
||||
public $_isBackendPage = true;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->addRoleAssignment(
|
||||
[
|
||||
Role::ROLE_ID_AUTHOR,
|
||||
Role::ROLE_ID_SUB_EDITOR,
|
||||
Role::ROLE_ID_MANAGER,
|
||||
Role::ROLE_ID_SITE_ADMIN,
|
||||
],
|
||||
[
|
||||
'index',
|
||||
'saved',
|
||||
'wizard', // @deprecated 3.4
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*/
|
||||
public function authorize($request, &$args, $roleAssignments): bool
|
||||
{
|
||||
$submissionId = (int) $request->getUserVar('id');
|
||||
|
||||
// Creating a new submission
|
||||
if ($submissionId === 0) {
|
||||
$this->addPolicy(new UserRequiredPolicy($request));
|
||||
$this->markRoleAssignmentsChecked();
|
||||
} else {
|
||||
$this->addPolicy(new SubmissionAccessPolicy($request, $args, $roleAssignments, 'id'));
|
||||
}
|
||||
|
||||
return parent::authorize($request, $args, $roleAssignments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Route the request to the correct page based
|
||||
* on whether they are starting a new submission,
|
||||
* working on a submission in progress, or viewing
|
||||
* a submission that has been submitted.
|
||||
*
|
||||
* @param array $args
|
||||
* @param Request $request
|
||||
*/
|
||||
public function index($args, $request): void
|
||||
{
|
||||
$this->setupTemplate($request);
|
||||
|
||||
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
|
||||
if (!$submission) {
|
||||
$this->start($args, $request);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($submission->getData('submissionProgress')) {
|
||||
$this->showWizard($args, $request, $submission);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->complete($args, $request, $submission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the screen to start a new submission
|
||||
*/
|
||||
protected function start(array $args, Request $request): void
|
||||
{
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
|
||||
$templateMgr->assign([
|
||||
'pageComponent' => 'StartSubmissionPage',
|
||||
'pageTitle' => __('submission.wizard.title'),
|
||||
'pageWidth' => TemplateManager::PAGE_WIDTH_NARROW,
|
||||
]);
|
||||
|
||||
$templateMgr->display('submission/start.tpl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Backwards compatibility for old links to the submission wizard
|
||||
*
|
||||
* @deprecated 3.4
|
||||
*/
|
||||
public function wizard(array $args, Request $request): void
|
||||
{
|
||||
$submissionId = $request->getUserVar('submissionId')
|
||||
? (int) $request->getUserVar('submissionId')
|
||||
: null;
|
||||
|
||||
$request->redirectUrl(
|
||||
Repo::submission()->getUrlSubmissionWizard($request->getContext(), $submissionId)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the submission wizard
|
||||
*/
|
||||
protected function showWizard(array $args, Request $request, Submission $submission): void
|
||||
{
|
||||
$context = $request->getContext();
|
||||
|
||||
/** @var Publication $publication */
|
||||
$publication = $submission->getCurrentPublication();
|
||||
|
||||
/** @var int $sectionId */
|
||||
$sectionId = $publication->getData(Application::getSectionIdPropName());
|
||||
|
||||
if ($sectionId) {
|
||||
$section = Repo::section()->get($sectionId, $context->getId());
|
||||
}
|
||||
|
||||
if (isset($section) &&
|
||||
(
|
||||
$section->getIsInactive() ||
|
||||
($section->getEditorRestricted() && !$this->isEditor())
|
||||
)
|
||||
) {
|
||||
$this->showErrorPage(
|
||||
'submission.wizard.sectionClosed',
|
||||
__('submission.wizard.sectionClosed.message', [
|
||||
'contextName' => $context->getLocalizedData('name'),
|
||||
'section' => $section->getLocalizedTitle(),
|
||||
'email' => $context->getData('contactEmail'),
|
||||
'name' => $context->getData('contactName'),
|
||||
])
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$supportedSubmissionLocales = $context->getSupportedSubmissionLocaleNames();
|
||||
$formLocales = array_map(fn (string $locale, string $name) => ['key' => $locale, 'label' => $name], array_keys($supportedSubmissionLocales), $supportedSubmissionLocales);
|
||||
|
||||
// Order locales with submission locale first
|
||||
$orderedLocales = $supportedSubmissionLocales;
|
||||
uksort($orderedLocales, fn ($a, $b) => $a === $submission->getData('locale') ? $a : $b);
|
||||
|
||||
$userGroups = Repo::userGroup()
|
||||
->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->getMany();
|
||||
|
||||
/** @var GenreDAO $genreDao */
|
||||
$genreDao = DAORegistry::getDAO('GenreDAO');
|
||||
$genres = $genreDao->getEnabledByContextId($context->getId())->toArray();
|
||||
|
||||
$sections = $this->getSubmitSections($context);
|
||||
$categories = Repo::category()->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->getMany();
|
||||
|
||||
$submissionFilesListPanel = $this->getSubmissionFilesListPanel($request, $submission, $genres);
|
||||
$contributorsListPanel = $this->getContributorsListPanel($request, $submission, $publication, $formLocales);
|
||||
$reconfigureSubmissionForm = $this->getReconfigureForm($context, $submission, $publication, $sections, $categories);
|
||||
|
||||
$steps = $this->getSteps($request, $submission, $publication, $formLocales, $sections, $categories);
|
||||
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
|
||||
$templateMgr->setState([
|
||||
'categories' => Repo::category()->getBreadcrumbs($categories),
|
||||
'components' => [
|
||||
$submissionFilesListPanel['id'] => $submissionFilesListPanel,
|
||||
$contributorsListPanel->id => $contributorsListPanel->getConfig(),
|
||||
$reconfigureSubmissionForm->id => $reconfigureSubmissionForm->getConfig(),
|
||||
],
|
||||
'i18nConfirmSubmit' => $this->getConfirmSubmitMessage($submission, $context),
|
||||
'i18nDiscardChanges' => __('common.discardChanges'),
|
||||
'i18nDisconnected' => __('common.disconnected'),
|
||||
'i18nLastAutosaved' => __('common.lastSaved'),
|
||||
'i18nPageTitle' => __('submission.wizard.titleWithStep'),
|
||||
'i18nSubmit' => __('form.submit'),
|
||||
'i18nTitleSeparator' => __('common.titleSeparator'),
|
||||
'i18nUnableToSave' => __('submission.wizard.unableToSave'),
|
||||
'i18nUnsavedChanges' => __('common.unsavedChanges'),
|
||||
'i18nUnsavedChangesMessage' => __('common.unsavedChangesMessage'),
|
||||
'publication' => Repo::publication()->getSchemaMap($submission, $userGroups, $genres)->map($publication),
|
||||
'publicationApiUrl' => $this->getPublicationApiUrl($request, $submission->getId(), $publication->getId()),
|
||||
'reconfigurePublicationProps' => $this->getReconfigurePublicationProps(),
|
||||
'reconfigureSubmissionProps' => $this->getReconfigureSubmissionProps(),
|
||||
'submission' => Repo::submission()->getSchemaMap()->map($submission, $userGroups, $genres),
|
||||
'submissionApiUrl' => Repo::submission()->getUrlApi($request->getContext(), $submission->getId()),
|
||||
'submissionSavedUrl' => $this->getSubmissionSavedUrl($request, $submission->getId()),
|
||||
'submissionWizardUrl' => Repo::submission()->getUrlSubmissionWizard($context, $submission->getId()),
|
||||
'submitApiUrl' => $this->getSubmitApiUrl($request, $submission->getId()),
|
||||
'steps' => $steps,
|
||||
]);
|
||||
|
||||
$templateMgr->assign([
|
||||
'isCategoriesEnabled' => $context->getData('submitWithCategories') && $categories->count(),
|
||||
'locales' => $orderedLocales,
|
||||
'pageComponent' => 'SubmissionWizardPage',
|
||||
'pageTitle' => __('submission.wizard.title'),
|
||||
'submission' => $submission,
|
||||
'submittingTo' => $this->getSubmittingTo($context, $submission, $sections, $categories),
|
||||
'reviewSteps' => $this->getReviewStepsForSmarty($steps),
|
||||
]);
|
||||
|
||||
$templateMgr->display('submission/wizard.tpl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the submission completed screen
|
||||
*/
|
||||
protected function complete(array $args, Request $request, Submission $submission): void
|
||||
{
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
$templateMgr->assign([
|
||||
'pageTitle' => __('submission.submit.submissionComplete'),
|
||||
'pageWidth' => TemplateManager::PAGE_WIDTH_NARROW,
|
||||
'submission' => $submission,
|
||||
'workflowUrl' => $this->getWorkflowUrl($submission, $request->getUser()),
|
||||
]);
|
||||
$templateMgr->display('submission/complete.tpl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the saved for later screen
|
||||
*/
|
||||
public function saved(array $args, Request $request): void
|
||||
{
|
||||
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
|
||||
if (!$submission) {
|
||||
$request->getDispatcher()->handle404();
|
||||
}
|
||||
|
||||
$this->setupTemplate($request);
|
||||
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
$templateMgr->assign([
|
||||
'email' => $request->getUser()->getEmail(),
|
||||
'pageTitle' => __('submission.wizard.saved'),
|
||||
'pageWidth' => TemplateManager::PAGE_WIDTH_NARROW,
|
||||
'submission' => $submission,
|
||||
'submissionWizardUrl' => Repo::submission()->getUrlSubmissionWizard($request->getContext(), $submission->getId()),
|
||||
]);
|
||||
$templateMgr->display('submission/saved.tpl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all steps of the submission wizard
|
||||
*/
|
||||
protected function getSteps(Request $request, Submission $submission, Publication $publication, array $locales, array $sections, LazyCollection $categories): array
|
||||
{
|
||||
$publicationApiUrl = $this->getPublicationApiUrl($request, $submission->getId(), $publication->getId());
|
||||
$controlledVocabUrl = $this->getControlledVocabBaseUrl($request);
|
||||
|
||||
$steps = [];
|
||||
$steps[] = $this->getDetailsStep($request, $submission, $publication, $locales, $publicationApiUrl, $sections, $controlledVocabUrl);
|
||||
$steps[] = $this->getFilesStep($request, $submission, $publication, $locales, $publicationApiUrl);
|
||||
$steps[] = $this->getContributorsStep($request, $submission, $publication, $locales, $publicationApiUrl);
|
||||
$steps[] = $this->getEditorsStep($request, $submission, $publication, $locales, $publicationApiUrl, $categories);
|
||||
$steps[] = $this->getConfirmStep($request, $submission, $publication, $locales, $publicationApiUrl);
|
||||
|
||||
return $steps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to the API endpoint to submit this submission
|
||||
*/
|
||||
protected function getSubmitApiUrl(Request $request, int $submissionId): string
|
||||
{
|
||||
return $request
|
||||
->getDispatcher()
|
||||
->url(
|
||||
$request,
|
||||
Application::ROUTE_API,
|
||||
$request->getContext()->getPath(),
|
||||
'submissions/' . $submissionId . '/submit'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to the publication's API endpoint
|
||||
*/
|
||||
protected function getPublicationApiUrl(Request $request, int $submissionId, int $publicationId): string
|
||||
{
|
||||
return $request
|
||||
->getDispatcher()
|
||||
->url(
|
||||
$request,
|
||||
Application::ROUTE_API,
|
||||
$request->getContext()->getPath(),
|
||||
'submissions/' . $submissionId . '/publications/' . $publicationId
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL to the page that shows the submission
|
||||
* has been saved
|
||||
*/
|
||||
protected function getSubmissionSavedUrl(Request $request, int $submissionId): string
|
||||
{
|
||||
return $request
|
||||
->getDispatcher()
|
||||
->url(
|
||||
$request,
|
||||
Application::ROUTE_PAGE,
|
||||
$request->getContext()->getPath(),
|
||||
'submission',
|
||||
'saved',
|
||||
null,
|
||||
[
|
||||
'id' => $submissionId,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url to the submission's files API endpoint
|
||||
*/
|
||||
protected function getSubmissionFilesApiUrl(Request $request, int $submissionId): string
|
||||
{
|
||||
return $request
|
||||
->getDispatcher()
|
||||
->url(
|
||||
$request,
|
||||
Application::ROUTE_API,
|
||||
$request->getContext()->getPath(),
|
||||
'submissions/' . $submissionId . '/files'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base url to the controlled vocab suggestions API endpoint
|
||||
*
|
||||
* The entry `__vocab__` will be replaced with the user's search phrase.
|
||||
*/
|
||||
protected function getControlledVocabBaseUrl(Request $request): string
|
||||
{
|
||||
return $request->getDispatcher()->url(
|
||||
$request,
|
||||
Application::ROUTE_API,
|
||||
$request->getContext()->getData('urlPath'),
|
||||
'vocabs',
|
||||
null,
|
||||
null,
|
||||
['vocab' => '__vocab__']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state needed for the SubmissionFilesListPanel component
|
||||
*/
|
||||
protected function getSubmissionFilesListPanel(Request $request, Submission $submission, array $genres): array
|
||||
{
|
||||
$submissionFiles = Repo::submissionFile()
|
||||
->getCollector()
|
||||
->filterBySubmissionIds([$submission->getId()])
|
||||
->filterByFileStages([SubmissionFile::SUBMISSION_FILE_SUBMISSION])
|
||||
->getMany();
|
||||
|
||||
// Don't allow dependent files to be uploaded with the submission
|
||||
$genres = array_values(
|
||||
array_filter($genres, fn ($genre) => !$genre->getDependent())
|
||||
);
|
||||
|
||||
$form = new PKPSubmissionFileForm(
|
||||
$this->getSubmissionFilesApiUrl($request, $submission->getId()),
|
||||
$genres
|
||||
);
|
||||
|
||||
return [
|
||||
'addFileLabel' => __('common.addFile'),
|
||||
'apiUrl' => $this->getSubmissionFilesApiUrl($request, $submission->getId()),
|
||||
'cancelUploadLabel' => __('form.dropzone.dictCancelUpload'),
|
||||
'genrePromptLabel' => __('submission.submit.genre.label'),
|
||||
'emptyLabel' => __('submission.upload.instructions'),
|
||||
'emptyAddLabel' => __('common.upload.addFile'),
|
||||
'fileStage' => SubmissionFile::SUBMISSION_FILE_SUBMISSION,
|
||||
'form' => $form->getConfig(),
|
||||
'genres' => array_map(
|
||||
fn ($genre) => [
|
||||
'id' => (int) $genre->getId(),
|
||||
'name' => $genre->getLocalizedName(),
|
||||
'isPrimary' => !$genre->getSupplementary() && !$genre->getDependent(),
|
||||
],
|
||||
$genres
|
||||
),
|
||||
'id' => 'submissionFiles',
|
||||
'items' => Repo::submissionFile()
|
||||
->getSchemaMap()
|
||||
->summarizeMany($submissionFiles, $genres)
|
||||
->values(),
|
||||
'options' => [
|
||||
'maxFilesize' => Application::getIntMaxFileMBs(),
|
||||
'timeout' => ini_get('max_execution_time') ? ini_get('max_execution_time') * 1000 : 0,
|
||||
'dropzoneDictDefaultMessage' => __('form.dropzone.dictDefaultMessage'),
|
||||
'dropzoneDictFallbackMessage' => __('form.dropzone.dictFallbackMessage'),
|
||||
'dropzoneDictFallbackText' => __('form.dropzone.dictFallbackText'),
|
||||
'dropzoneDictFileTooBig' => __('form.dropzone.dictFileTooBig'),
|
||||
'dropzoneDictInvalidFileType' => __('form.dropzone.dictInvalidFileType'),
|
||||
'dropzoneDictResponseError' => __('form.dropzone.dictResponseError'),
|
||||
'dropzoneDictCancelUpload' => __('form.dropzone.dictCancelUpload'),
|
||||
'dropzoneDictUploadCanceled' => __('form.dropzone.dictUploadCanceled'),
|
||||
'dropzoneDictCancelUploadConfirmation' => __('form.dropzone.dictCancelUploadConfirmation'),
|
||||
'dropzoneDictRemoveFile' => __('form.dropzone.dictRemoveFile'),
|
||||
'dropzoneDictMaxFilesExceeded' => __('form.dropzone.dictMaxFilesExceeded'),
|
||||
],
|
||||
'otherLabel' => __('about.other'),
|
||||
'primaryLocale' => $request->getContext()->getPrimaryLocale(),
|
||||
'removeConfirmLabel' => __('submission.submit.removeConfirm'),
|
||||
'stageId' => WORKFLOW_STAGE_ID_SUBMISSION,
|
||||
'title' => __('submission.files'),
|
||||
'uploadProgressLabel' => __('submission.upload.percentComplete'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of the ContributorsListPanel component
|
||||
*/
|
||||
protected function getContributorsListPanel(Request $request, Submission $submission, Publication $publication, array $locales): ContributorsListPanel
|
||||
{
|
||||
return new ContributorsListPanel(
|
||||
'contributors',
|
||||
__('publication.contributors'),
|
||||
$submission,
|
||||
$request->getContext(),
|
||||
$locales,
|
||||
[], // Populated by publication state
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user groups that a user can submit in
|
||||
*/
|
||||
protected function getSubmitUserGroups(Context $context, User $user): LazyCollection
|
||||
{
|
||||
$userGroups = Repo::userGroup()
|
||||
->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->filterByUserIds([$user->getId()])
|
||||
->filterByRoleIds([Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_AUTHOR])
|
||||
->getMany();
|
||||
|
||||
// Users without a submitting role can submit as an
|
||||
// author role that allows self registration
|
||||
if (!$userGroups->count()) {
|
||||
$defaultUserGroup = Repo::userGroup()->getFirstSubmitAsAuthorUserGroup($context->getId());
|
||||
return LazyCollection::make(function () use ($defaultUserGroup) {
|
||||
if ($defaultUserGroup) {
|
||||
yield $defaultUserGroup->getId() => $defaultUserGroup;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return $userGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state for the files step
|
||||
*/
|
||||
protected function getFilesStep(Request $request, Submission $submission, Publication $publication, array $locales, string $publicationApiUrl): array
|
||||
{
|
||||
return [
|
||||
'id' => 'files',
|
||||
'name' => __('submission.upload.uploadFiles'),
|
||||
'reviewName' => __('submission.files'),
|
||||
'sections' => [
|
||||
[
|
||||
'id' => 'files',
|
||||
'name' => __('submission.upload.uploadFiles'),
|
||||
'type' => self::SECTION_TYPE_FILES,
|
||||
'description' => $request->getContext()->getLocalizedData('uploadFilesHelp'),
|
||||
],
|
||||
],
|
||||
'reviewTemplate' => '/submission/review-files.tpl',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state for the contributors step
|
||||
*/
|
||||
protected function getContributorsStep(Request $request, Submission $submission, Publication $publication, array $locales, string $publicationApiUrl): array
|
||||
{
|
||||
return [
|
||||
'id' => 'contributors',
|
||||
'name' => __('publication.contributors'),
|
||||
'reviewName' => __('publication.contributors'),
|
||||
'sections' => [
|
||||
[
|
||||
'id' => 'contributors',
|
||||
'name' => __('publication.contributors'),
|
||||
'type' => self::SECTION_TYPE_CONTRIBUTORS,
|
||||
'description' => $request->getContext()->getLocalizedData('contributorsHelp'),
|
||||
],
|
||||
],
|
||||
'reviewTemplate' => '/submission/review-contributors.tpl',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state for the details step
|
||||
*/
|
||||
protected function getDetailsStep(Request $request, Submission $submission, Publication $publication, array $locales, string $publicationApiUrl, array $sections, string $controlledVocabUrl): array
|
||||
{
|
||||
$titleAbstractForm = $this->getDetailsForm(
|
||||
$publicationApiUrl,
|
||||
$locales,
|
||||
$publication,
|
||||
$request->getContext(),
|
||||
$sections,
|
||||
$controlledVocabUrl
|
||||
);
|
||||
$this->removeButtonFromForm($titleAbstractForm);
|
||||
|
||||
$sections = [
|
||||
[
|
||||
'id' => $titleAbstractForm->id,
|
||||
'name' => __('submission.details'),
|
||||
'type' => self::SECTION_TYPE_FORM,
|
||||
'description' => $request->getContext()->getLocalizedData('detailsHelp'),
|
||||
'form' => $this->getLocalizedForm($titleAbstractForm, $submission, $request->getContext()),
|
||||
],
|
||||
];
|
||||
|
||||
if (in_array($request->getContext()->getData('citations'), [Context::METADATA_REQUEST, Context::METADATA_REQUIRE])) {
|
||||
$citationsForm = new PKPCitationsForm(
|
||||
$publicationApiUrl,
|
||||
$publication,
|
||||
$request->getContext()->getData('citations') === Context::METADATA_REQUIRE
|
||||
);
|
||||
$this->removeButtonFromForm($citationsForm);
|
||||
$sections[] = [
|
||||
'id' => $citationsForm->id,
|
||||
'name' => '',
|
||||
'type' => self::SECTION_TYPE_FORM,
|
||||
'description' => '',
|
||||
'form' => $citationsForm->getConfig(),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => 'details',
|
||||
'name' => __('common.details'),
|
||||
'reviewName' => __('common.details'),
|
||||
'sections' => $sections,
|
||||
'reviewTemplate' => '/submission/review-details.tpl',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state for the For the Editors step
|
||||
*
|
||||
* If no metadata is enabled during submission, the metadata
|
||||
* form is not shown.
|
||||
*/
|
||||
protected function getEditorsStep(Request $request, Submission $submission, Publication $publication, array $locales, string $publicationApiUrl, LazyCollection $categories): array
|
||||
{
|
||||
$metadataForm = $this->getForTheEditorsForm(
|
||||
$publicationApiUrl,
|
||||
$locales,
|
||||
$publication,
|
||||
$submission,
|
||||
$request->getContext(),
|
||||
$request->getDispatcher()->url(
|
||||
$request,
|
||||
Application::ROUTE_API,
|
||||
$request->getContext()->getData('urlPath'),
|
||||
'vocabs',
|
||||
null,
|
||||
null,
|
||||
['vocab' => '__vocab__']
|
||||
),
|
||||
$categories
|
||||
);
|
||||
$this->removeButtonFromForm($metadataForm);
|
||||
|
||||
$commentsForm = new CommentsForTheEditors(
|
||||
Repo::submission()->getUrlApi($request->getContext(), $submission->getId()),
|
||||
$submission
|
||||
);
|
||||
$this->removeButtonFromForm($commentsForm);
|
||||
|
||||
$hasMetadataForm = count($metadataForm->fields);
|
||||
|
||||
$metadataFormData = $this->getLocalizedForm($metadataForm, $submission, $request->getContext());
|
||||
$commentsFormData = $this->getLocalizedForm($commentsForm, $submission, $request->getContext());
|
||||
|
||||
$sections = [
|
||||
[
|
||||
'id' => $hasMetadataForm ? $metadataForm->id : $commentsForm->id,
|
||||
'name' => __('submission.forTheEditors'),
|
||||
'type' => self::SECTION_TYPE_FORM,
|
||||
'description' => $request->getContext()->getLocalizedData('forTheEditorsHelp'),
|
||||
'form' => $hasMetadataForm ? $metadataFormData : $commentsFormData,
|
||||
],
|
||||
];
|
||||
|
||||
if ($hasMetadataForm) {
|
||||
$sections[] = [
|
||||
'id' => $commentsForm->id,
|
||||
'name' => '',
|
||||
'type' => self::SECTION_TYPE_FORM,
|
||||
'description' => '',
|
||||
'form' => $commentsFormData,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => 'editors',
|
||||
'name' => __('submission.forTheEditors'),
|
||||
'reviewName' => __('submission.forTheEditors'),
|
||||
'sections' => $sections,
|
||||
'reviewTemplate' => '/submission/review-editors.tpl',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state for the Confirm step
|
||||
*/
|
||||
protected function getConfirmStep(Request $request, Submission $submission, Publication $publication, array $locales, string $publicationApiUrl): array
|
||||
{
|
||||
$sections = [
|
||||
[
|
||||
'id' => 'review',
|
||||
'name' => __('submission.reviewAndSubmit'),
|
||||
'type' => self::SECTION_TYPE_REVIEW,
|
||||
'description' => $request->getContext()->getLocalizedData('reviewHelp'),
|
||||
]
|
||||
];
|
||||
|
||||
$confirmForm = new ConfirmSubmission(
|
||||
FormComponent::ACTION_EMIT,
|
||||
$request->getContext()
|
||||
);
|
||||
|
||||
if (!empty($confirmForm->fields)) {
|
||||
$this->removeButtonFromForm($confirmForm);
|
||||
$sections[] = [
|
||||
'id' => $confirmForm->id,
|
||||
'name' => __('author.submit.confirmation'),
|
||||
'type' => self::SECTION_TYPE_CONFIRM,
|
||||
'description' => '<p>' . __('submission.wizard.confirm') . '</p>',
|
||||
'form' => $confirmForm->getConfig(),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => 'review',
|
||||
'name' => __('submission.review'),
|
||||
'sections' => $sections,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to remove the save button forms in the wizard
|
||||
*
|
||||
* This creates a default group/page for each form and assigns each #
|
||||
* field and group to that page.
|
||||
*/
|
||||
protected function removeButtonFromForm(FormComponent $form): void
|
||||
{
|
||||
$form->addPage([
|
||||
'id' => 'default',
|
||||
])
|
||||
->addGroup([
|
||||
'id' => 'default',
|
||||
'pageId' => 'default'
|
||||
]);
|
||||
|
||||
foreach ($form->fields as $field) {
|
||||
$field->groupId = 'default';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get details about the steps that are required by the smarty template
|
||||
*/
|
||||
protected function getReviewStepsForSmarty(array $steps): array
|
||||
{
|
||||
$reviewSteps = [];
|
||||
foreach ($steps as $step) {
|
||||
if ($step['id'] === 'review') {
|
||||
continue;
|
||||
}
|
||||
$reviewSteps[] = [
|
||||
'id' => $step['id'],
|
||||
'reviewTemplate' => $step['reviewTemplate'],
|
||||
'reviewName' => $step['reviewName'],
|
||||
];
|
||||
}
|
||||
return $reviewSteps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an error page
|
||||
*/
|
||||
protected function showErrorPage(string $titleLocaleKey, string $message): void
|
||||
{
|
||||
$this->_isBackendPage = false;
|
||||
$templateMgr = TemplateManager::getManager(Application::get()->getRequest());
|
||||
$templateMgr->assign([
|
||||
'pageTitle' => $titleLocaleKey,
|
||||
'messageTranslated' => $message,
|
||||
]);
|
||||
$templateMgr->display('frontend/pages/message.tpl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate workflow URL for the current user
|
||||
*
|
||||
* Returns the author dashboard if the user has an author assignment
|
||||
* and the editorial workflow if not.
|
||||
*/
|
||||
protected function getWorkflowUrl(Submission $submission, User $user): string
|
||||
{
|
||||
/** @var StageAssignmentDAO $stageAssignmentDao */
|
||||
$stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO');
|
||||
$results = $stageAssignmentDao->getBySubmissionAndRoleIds($submission->getId(), [Role::ROLE_ID_AUTHOR], WORKFLOW_STAGE_ID_SUBMISSION, $user->getId());
|
||||
|
||||
$request = Application::get()->getRequest();
|
||||
|
||||
if (count($results->toArray())) {
|
||||
return Repo::submission()->getUrlAuthorWorkflow($request->getContext(), $submission->getId());
|
||||
}
|
||||
|
||||
return Repo::submission()->getUrlEditorialWorkflow($request->getContext(), $submission->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sections that this user can submit to
|
||||
*/
|
||||
protected function getSubmitSections(Context $context): array
|
||||
{
|
||||
$allSections = Repo::section()
|
||||
->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->excludeInactive()
|
||||
->getMany();
|
||||
|
||||
$submitSections = [];
|
||||
/** @var Section $section */
|
||||
foreach ($allSections as $section) {
|
||||
if ($section->getEditorRestricted() && !$this->isEditor()) {
|
||||
continue;
|
||||
}
|
||||
$submitSections[] = $section;
|
||||
}
|
||||
|
||||
return $submitSections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "are you sure?" message shown to the user
|
||||
* before they complete their submission
|
||||
*/
|
||||
protected function getConfirmSubmitMessage(Submission $submission, Context $context): string
|
||||
{
|
||||
return __('submission.wizard.confirmSubmit', ['context' => htmlspecialchars($context->getLocalizedName())]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the current user an editor
|
||||
*/
|
||||
protected function isEditor(): bool
|
||||
{
|
||||
return !empty(
|
||||
array_intersect(
|
||||
Section::getEditorRestrictedRoles(),
|
||||
$this->getAuthorizedContextObject(Application::ASSOC_TYPE_USER_ROLES)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the form configuration data with the correct
|
||||
* locale settings based on the submission's locale
|
||||
*
|
||||
* Uses the submission locale as the primary and
|
||||
* visible locale, and puts that locale first in the
|
||||
* list of supported locales.
|
||||
*
|
||||
* Call this instead of $form->getConfig() to display
|
||||
* a form with the correct submission locales
|
||||
*/
|
||||
protected function getLocalizedForm(FormComponent $form, Submission $submission, Context $context): array
|
||||
{
|
||||
$config = $form->getConfig();
|
||||
|
||||
$config['primaryLocale'] = $submission->getLocale();
|
||||
$config['visibleLocales'] = [$submission->getLocale()];
|
||||
|
||||
$supportedFormLocales = [];
|
||||
foreach ($context->getSupportedSubmissionLocaleNames() as $localeKey => $name) {
|
||||
$supportedFormLocales[] = [
|
||||
'key' => $localeKey,
|
||||
'label' => $name,
|
||||
];
|
||||
}
|
||||
|
||||
usort($supportedFormLocales, fn ($a, $b) => $a['key'] === $submission->getLocale() ? -1 : 1);
|
||||
|
||||
$config['supportedFormLocales'] = $supportedFormLocales;
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string describing the sections, languages, etc
|
||||
* that the submission is in
|
||||
*/
|
||||
abstract protected function getSubmittingTo(Context $context, Submission $submission, array $sections, LazyCollection $categories): string;
|
||||
|
||||
/**
|
||||
* Get the form to reconfigure a submission that has already been started
|
||||
*/
|
||||
abstract protected function getReconfigureForm(Context $context, Submission $submission, Publication $publication, array $sections, LazyCollection $categories): ReconfigureSubmission;
|
||||
|
||||
/**
|
||||
* Get the form for entering the title/abstract details
|
||||
*/
|
||||
abstract protected function getDetailsForm(string $publicationApiUrl, array $locales, Publication $publication, Context $context, array $sections, string $suggestionUrlBase): TitleAbstractForm;
|
||||
|
||||
/**
|
||||
* Get the form for entering information for the editors
|
||||
*/
|
||||
abstract protected function getForTheEditorsForm(string $publicationApiUrl, array $locales, Publication $publication, Submission $submission, Context $context, string $suggestionUrlBase, LazyCollection $categories): ForTheEditors;
|
||||
|
||||
/**
|
||||
* Get the properties that should be saved to the Submission
|
||||
* from the ReconfigureSubmission form
|
||||
*/
|
||||
abstract protected function getReconfigurePublicationProps(): array;
|
||||
|
||||
/**
|
||||
* Get the properties that should be saved to the Submission
|
||||
* from the ReconfigureSubmission form
|
||||
*/
|
||||
abstract protected function getReconfigureSubmissionProps(): array;
|
||||
}
|
||||
Reference in New Issue
Block a user