<?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;
}
|