From 385cf9535276001b1d080117b877f71e1bdcbcc6 Mon Sep 17 00:00:00 2001 From: Taslan Graham Date: Wed, 28 Aug 2024 23:34:08 -0500 Subject: [PATCH 1/2] pkp/pkp-lib#10336 Expose publication forms via API --- .../submissions/PKPSubmissionController.php | 242 ++++++++++++++++++ pages/workflow/PKPWorkflowHandler.php | 2 +- 2 files changed, 243 insertions(+), 1 deletion(-) diff --git a/api/v1/submissions/PKPSubmissionController.php b/api/v1/submissions/PKPSubmissionController.php index 132e8800c11..82710c0c75c 100644 --- a/api/v1/submissions/PKPSubmissionController.php +++ b/api/v1/submissions/PKPSubmissionController.php @@ -21,6 +21,7 @@ use APP\facades\Repo; use APP\mail\variables\ContextEmailVariable; use APP\notification\NotificationManager; +use APP\publication\Publication; use APP\section\Section; use APP\submission\Collector; use APP\submission\Submission; @@ -30,6 +31,12 @@ use Illuminate\Support\Enumerable; use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Route; +use PKP\components\forms\FormComponent; +use PKP\components\forms\publication\PKPCitationsForm; +use PKP\components\forms\publication\PKPMetadataForm; +use PKP\components\forms\publication\PKPPublicationIdentifiersForm; +use PKP\components\forms\publication\PKPPublicationLicenseForm; +use PKP\context\Context; use PKP\core\Core; use PKP\core\PKPApplication; use PKP\core\PKPBaseController; @@ -42,6 +49,7 @@ use PKP\notification\Notification; use PKP\notification\NotificationSubscriptionSettingsDAO; use PKP\plugins\Hook; +use PKP\plugins\PluginRegistry; use PKP\security\authorization\ContextAccessPolicy; use PKP\security\authorization\DecisionWritePolicy; use PKP\security\authorization\internal\SubmissionCompletePolicy; @@ -92,6 +100,11 @@ class PKPSubmissionController extends PKPBaseController 'editContributor', 'saveContributorsOrder', 'addDecision', + + 'getPublicationMetadataForms', + 'getPublicationReferenceForms', + 'getPublicationIdentifierForms', + 'getPublicationLicenseForms' ]; /** @var array Handlers that must be authorized to write to a publication */ @@ -143,6 +156,20 @@ public function getRouteGroupMiddleware(): array */ public function getGroupRoutes(): void { + Route::middleware([ + self::roleAuthorizer([ + Role::ROLE_ID_MANAGER, + Role::ROLE_ID_SUB_EDITOR, + Role::ROLE_ID_AUTHOR, + ]), + ])->group(function () { + Route::prefix('{submissionId}/publications/{publicationId}/_components')->group(function () { + Route::get('metadata', $this->getPublicationMetadataForms(...))->name('submission.publication._components.metadata'); + Route::get('references', $this->getPublicationReferenceForms(...))->name('submission.publication._components.reference'); + Route::get('identifiers', $this->getPublicationIdentifierForms(...))->name('submission.publication._components.identifiers'); + Route::get('permissionDisclosure', $this->getPublicationLicenseForms(...))->name('submission.publication._components.permissionDisclosure'); + })->whereNumber(['submissionId', 'publicationId']); + }); Route::middleware([ self::roleAuthorizer([ Role::ROLE_ID_MANAGER, @@ -321,6 +348,8 @@ public function authorize(PKPRequest $request, array &$args, array $roleAssignme $this->addPolicy(new DecisionWritePolicy($request, $args, (int) $request->getUserVar('decision'), $request->getUser())); } + + // TODO if request in array of new endpoints then add SubmissionCompletePolicy && WorkflowStageAccessPolicy return parent::authorize($request, $args, $roleAssignments); } @@ -1654,6 +1683,7 @@ public function addDecision(Request $illuminateRequest): JsonResponse return response()->json(Repo::decision()->getSchemaMap()->map($decision), Response::HTTP_OK); } + protected function getFirstUserGroupInRole(Enumerable $userGroups, int $role): ?UserGroup { return $userGroups->first(fn (UserGroup $userGroup) => $userGroup->getRoleId() === $role); @@ -1706,4 +1736,216 @@ protected function getWriteDisabledErrors(string $schemaName, array $params): ar return $errors; } + + /** + * Get Publication Metadata Forms + */ + protected function getPublicationMetadataForms(Request $illuminateRequest): JsonResponse + { + $request = $this->getRequest(); + $submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION); + $publication = Repo::publication()->get((int)$illuminateRequest->route('publicationId')); + + if (!$publication || !$submission) { + return response()->json([ + 'error' => __('api.404.resourceNotFound'), + ], Response::HTTP_NOT_FOUND); + } + + if ($submission->getId() !== $publication->getData('submissionId')) { + return response()->json([ + 'error' => __('api.publications.403.submissionsDidNotMatch'), + ], Response::HTTP_FORBIDDEN); + } + + $submissionContext = $request->getContext(); + + if ($submission->getData('contextId') !== $submissionContext->getId()) { + $submissionContext = app()->get('context')->get($submission->getData('contextId')); + } + + $submissionLocale = $submission->getData('locale'); + $publicationApiUrl = $this->getPublicationUrl($request, $submissionContext, $submission, $publication); + $locales = $this->getLocales($submissionContext, $submission); + $vocabSuggestionUrlBase = $request->getDispatcher()->url($request, PKPApplication::ROUTE_API, $submissionContext->getData('urlPath'), 'vocabs', null, null, ['vocab' => '__vocab__', 'submissionId' => $submission->getId()]); + + $metadataForm = new PKPMetadataForm($publicationApiUrl, $locales, $publication, $submissionContext, $vocabSuggestionUrlBase, true); + + return response()->json($this->getLocalizedForm($metadataForm, $submissionLocale, $locales), Response::HTTP_OK); + } + + /** + * Get Publication Reference Forms. + */ + protected function getPublicationReferenceForms(Request $illuminateRequest): JsonResponse + { + $request = $this->getRequest(); + $submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION); + $publication = Repo::publication()->get((int)$illuminateRequest->route('publicationId')); + + if (!$publication || !$submission) { + return response()->json([ + 'error' => __('api.404.resourceNotFound'), + ], Response::HTTP_NOT_FOUND); + } + + if ($submission->getId() !== $publication->getData('submissionId')) { + return response()->json([ + 'error' => __('api.publications.403.submissionsDidNotMatch'), + ], Response::HTTP_FORBIDDEN); + } + + $submissionContext = $request->getContext(); + if ($submission->getData('contextId') !== $submissionContext->getId()) { + $submissionContext = app()->get('context')->get($submission->getData('contextId')); + } + + $publicationApiUrl = $this->getPublicationUrl($request, $submissionContext, $submission, $publication); + $citationsForm = new PKPCitationsForm($publicationApiUrl, $publication); + + return response()->json($citationsForm->getConfig(), Response::HTTP_OK); + } + + + /** + * Get Publication License Forms + */ + protected function getPublicationLicenseForms(Request $illuminateRequest): JsonResponse + { + $request = $this->getRequest(); + $submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION); + $publication = Repo::publication()->get((int)$illuminateRequest->route('publicationId')); + + if (!$publication || !$submission) { + return response()->json([ + 'error' => __('api.404.resourceNotFound'), + ], Response::HTTP_NOT_FOUND); + } + + if ($submission->getId() !== $publication->getData('submissionId')) { + return response()->json([ + 'error' => __('api.publications.403.submissionsDidNotMatch'), + ], Response::HTTP_FORBIDDEN); + } + + $submissionContext = $request->getContext(); + if ($submission->getData('contextId') !== $submissionContext->getId()) { + $submissionContext = app()->get('context')->get($submission->getData('contextId')); + } + + $publicationApiUrl = $this->getPublicationUrl($request, $submissionContext, $submission, $publication); + $submissionLocale = $submission->getData('locale'); + $locales = $this->getLocales($submissionContext, $submission); + $authorUserGroups = Repo::userGroup()->getByRoleIds([Role::ROLE_ID_AUTHOR], $submission->getData('contextId')); + + $publicationLicenseForm = new PKPPublicationLicenseForm($publicationApiUrl, $locales, $publication, $submissionContext, $authorUserGroups); + + return response()->json($this->getLocalizedForm($publicationLicenseForm, $submissionLocale, $locales), Response::HTTP_OK); + } + + /** + * Get Publication Identifier Forms. + */ + protected function getPublicationIdentifierForms(Request $illuminateRequest): JsonResponse + { + $request = $this->getRequest(); + + // Check if there are any enabled Identifiers + $identifiersEnabled = false; + $pubIdPlugins = PluginRegistry::getPlugins('pubIds'); + foreach ($pubIdPlugins as $pubIdPlugin) { + if ($pubIdPlugin->isObjectTypeEnabled('Publication', $request->getContext()->getId())) { + $identifiersEnabled = true; + break; + } + } + + if (!$identifiersEnabled) { + return response()->json([ + 'error' => __('api.403.unauthorized'), + ], Response::HTTP_NOT_FOUND); + } + + $submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION); + $publication = Repo::publication()->get((int)$illuminateRequest->route('publicationId')); + + if (!$publication || !$submission) { + return response()->json([ + 'error' => __('api.404.resourceNotFound'), + ], Response::HTTP_NOT_FOUND); + } + + if ($submission->getId() !== $publication->getData('submissionId')) { + return response()->json([ + 'error' => __('api.publications.403.submissionsDidNotMatch'), + ], Response::HTTP_FORBIDDEN); + } + + $submissionContext = $request->getContext(); + if ($submission->getData('contextId') !== $submissionContext->getId()) { + $submissionContext = app()->get('context')->get($submission->getData('contextId')); + } + + $publicationApiUrl = $this->getPublicationUrl($request, $submissionContext, $submission, $publication); + $locales = $this->getLocales($submissionContext, $submission); + + $identifiersForm = new PKPPublicationIdentifiersForm($publicationApiUrl, $locales, $publication, $submissionContext); + + return response()->json($identifiersForm->getConfig(), Response::HTTP_OK); + } + + protected function getLocales(Context $submissionContext, Submission $submission) + { + return collect($submissionContext->getSupportedSubmissionMetadataLocaleNames() + $submission->getPublicationLanguageNames()) + ->map(fn (string $name, string $locale) => ['key' => $locale, 'label' => $name]) + ->sortBy('key') + ->values() + ->toArray(); + } + + /** + * Get URL for a given Publication + */ + public function getPublicationUrl(PKPRequest $request, Context $submissionContext, Submission $submission, Publication $publication): string + { + return $request->getDispatcher()->url($request, Application::ROUTE_API, $submissionContext->getPath(), 'submissions/' . $submission->getId() . '/publications/' . $publication->getId()); + } + + /** + * Get the form configuration data with the correct + * locale settings based on the publication's locale + * + * Uses the publication 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 publication locales + */ + protected function getLocalizedForm(FormComponent $form, string $submissionLocale, array $locales): array + { + $config = $form->getConfig(); + + $config['primaryLocale'] = $submissionLocale; + $config['visibleLocales'] = [$submissionLocale]; + $config['supportedFormLocales'] = collect($locales) + ->sortBy([fn (array $a, array $b) => $b['key'] === $submissionLocale ? 1 : -1]) + ->values() + ->toArray(); + + return $config; + } + + /*** + * Get the Context for a given submission. + */ + protected function getSubmissionContext(PKPRequest $request, Submission $submission) + { + $submissionContext = $request->getContext(); + if ($submission->getData('contextId') !== $submissionContext->getId()) { + $submissionContext = app()->get('context')->get($submission->getData('contextId')); + } + + return $submissionContext; + } } diff --git a/pages/workflow/PKPWorkflowHandler.php b/pages/workflow/PKPWorkflowHandler.php index 7831785a78f..6cbf4696986 100644 --- a/pages/workflow/PKPWorkflowHandler.php +++ b/pages/workflow/PKPWorkflowHandler.php @@ -11,7 +11,7 @@ * * @ingroup pages_reviewer * - * @brief Handle requests for the submssion workflow. + * @brief Handle requests for the submission workflow. */ namespace PKP\pages\workflow; From 9bac544bf858c39150bdb430f66767205e905062 Mon Sep 17 00:00:00 2001 From: Taslan Graham Date: Thu, 29 Aug 2024 20:08:00 -0500 Subject: [PATCH 2/2] pkp/pkp-lib#10336 Add endpoint for TitleAbstractForm and move common logic into utility method --- .../submissions/PKPSubmissionController.php | 274 ++++++++++-------- locale/en/api.po | 3 + 2 files changed, 159 insertions(+), 118 deletions(-) diff --git a/api/v1/submissions/PKPSubmissionController.php b/api/v1/submissions/PKPSubmissionController.php index 82710c0c75c..9b8bb930dd8 100644 --- a/api/v1/submissions/PKPSubmissionController.php +++ b/api/v1/submissions/PKPSubmissionController.php @@ -36,6 +36,7 @@ use PKP\components\forms\publication\PKPMetadataForm; use PKP\components\forms\publication\PKPPublicationIdentifiersForm; use PKP\components\forms\publication\PKPPublicationLicenseForm; +use PKP\components\forms\publication\TitleAbstractForm; use PKP\context\Context; use PKP\core\Core; use PKP\core\PKPApplication; @@ -53,6 +54,7 @@ use PKP\security\authorization\ContextAccessPolicy; use PKP\security\authorization\DecisionWritePolicy; use PKP\security\authorization\internal\SubmissionCompletePolicy; +use PKP\security\authorization\PublicationAccessPolicy; use PKP\security\authorization\PublicationWritePolicy; use PKP\security\authorization\StageRolePolicy; use PKP\security\authorization\SubmissionAccessPolicy; @@ -75,8 +77,8 @@ class PKPSubmissionController extends PKPBaseController /** @var int Max items that can be requested */ public const MAX_COUNT = 100; - /** @var array Handlers that must be authorized to access a submission */ - public $requiresSubmissionAccess = [ + /** Handlers that must be authorized to access a submission */ + public array $requiresSubmissionAccess = [ 'get', 'edit', 'saveForLater', @@ -100,11 +102,11 @@ class PKPSubmissionController extends PKPBaseController 'editContributor', 'saveContributorsOrder', 'addDecision', - - 'getPublicationMetadataForms', - 'getPublicationReferenceForms', - 'getPublicationIdentifierForms', - 'getPublicationLicenseForms' + 'getPublicationReferenceForm', + 'getPublicationMetadataForm', + 'getPublicationIdentifierForm', + 'getPublicationLicenseForm', + 'getPublicationTitleAbstractForm' ]; /** @var array Handlers that must be authorized to write to a publication */ @@ -156,20 +158,6 @@ public function getRouteGroupMiddleware(): array */ public function getGroupRoutes(): void { - Route::middleware([ - self::roleAuthorizer([ - Role::ROLE_ID_MANAGER, - Role::ROLE_ID_SUB_EDITOR, - Role::ROLE_ID_AUTHOR, - ]), - ])->group(function () { - Route::prefix('{submissionId}/publications/{publicationId}/_components')->group(function () { - Route::get('metadata', $this->getPublicationMetadataForms(...))->name('submission.publication._components.metadata'); - Route::get('references', $this->getPublicationReferenceForms(...))->name('submission.publication._components.reference'); - Route::get('identifiers', $this->getPublicationIdentifierForms(...))->name('submission.publication._components.identifiers'); - Route::get('permissionDisclosure', $this->getPublicationLicenseForms(...))->name('submission.publication._components.permissionDisclosure'); - })->whereNumber(['submissionId', 'publicationId']); - }); Route::middleware([ self::roleAuthorizer([ Role::ROLE_ID_MANAGER, @@ -289,6 +277,25 @@ public function getGroupRoutes(): void Route::delete('{submissionId}/publications/{publicationId}/contributors/{contributorId}', $this->deleteContributor(...)) ->name('submission.publication.contributor.delete') ->whereNumber(['submissionId', 'publicationId', 'contributorId']); + + Route::prefix('{submissionId}/publications/{publicationId}/_components')->group(function () { + Route::get('metadata', $this->getPublicationMetadataForm(...))->name('submission.publication._components.metadata'); + Route::get('reference', $this->getPublicationReferenceForm(...))->name('submission.publication._components.reference'); + Route::get('titleAbstract', $this->getPublicationTitleAbstractForm(...))->name('submission.publication._components.titleAbstract'); + })->whereNumber(['submissionId', 'publicationId']); + }); + + Route::middleware([ + self::roleAuthorizer([ + Role::ROLE_ID_MANAGER, + Role::ROLE_ID_SUB_EDITOR, + Role::ROLE_ID_ASSISTANT, + ]), + ])->group(function () { + Route::prefix('{submissionId}/publications/{publicationId}/_components')->group(function () { + Route::get('identifier', $this->getPublicationIdentifierForm(...))->name('submission.publication._components.identifiers'); + Route::get('permissionDisclosure', $this->getPublicationLicenseForm(...))->name('submission.publication._components.permissionDisclosure'); + })->whereNumber(['submissionId', 'publicationId']); }); Route::middleware([ @@ -348,8 +355,20 @@ public function authorize(PKPRequest $request, array &$args, array $roleAssignme $this->addPolicy(new DecisionWritePolicy($request, $args, (int) $request->getUserVar('decision'), $request->getUser())); } + if (in_array( + $actionName, + [ + 'getPublicationReferenceForm', + 'getPublicationMetadataForm', + 'getPublicationIdentifierForm', + 'getPublicationLicenseForm', + 'getPublicationTitleAbstractForm', + ] + )) { + $this->addPolicy(new SubmissionCompletePolicy($request, $args)); + $this->addPolicy(new PublicationAccessPolicy($request, $args, $roleAssignments)); + } - // TODO if request in array of new endpoints then add SubmissionCompletePolicy && WorkflowStageAccessPolicy return parent::authorize($request, $args, $roleAssignments); } @@ -1683,7 +1702,6 @@ public function addDecision(Request $illuminateRequest): JsonResponse return response()->json(Repo::decision()->getSchemaMap()->map($decision), Response::HTTP_OK); } - protected function getFirstUserGroupInRole(Enumerable $userGroups, int $role): ?UserGroup { return $userGroups->first(fn (UserGroup $userGroup) => $userGroup->getRoleId() === $role); @@ -1738,69 +1756,46 @@ protected function getWriteDisabledErrors(string $schemaName, array $params): ar } /** - * Get Publication Metadata Forms + * Get Publication Metadata Form component */ - protected function getPublicationMetadataForms(Request $illuminateRequest): JsonResponse + protected function getPublicationMetadataForm(Request $illuminateRequest): JsonResponse { - $request = $this->getRequest(); - $submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION); - $publication = Repo::publication()->get((int)$illuminateRequest->route('publicationId')); + $data = $this->getSubmissionAndPublicationData($illuminateRequest); - if (!$publication || !$submission) { - return response()->json([ - 'error' => __('api.404.resourceNotFound'), - ], Response::HTTP_NOT_FOUND); + if (isset($data['error'])) { + return response()->json([ 'error' => $data['error'],], $data['status']); } - if ($submission->getId() !== $publication->getData('submissionId')) { - return response()->json([ - 'error' => __('api.publications.403.submissionsDidNotMatch'), - ], Response::HTTP_FORBIDDEN); - } - - $submissionContext = $request->getContext(); - - if ($submission->getData('contextId') !== $submissionContext->getId()) { - $submissionContext = app()->get('context')->get($submission->getData('contextId')); - } + $submission = $data['submission']; /** @var Submission $submission */ + $publication = $data['publication']; /** @var Publication $publication*/ + $context = $data['context']; /** @var Context $context*/ + $publicationApiUrl = $data['publicationApiUrl']; /** @var String $publicationApiUrl*/ $submissionLocale = $submission->getData('locale'); - $publicationApiUrl = $this->getPublicationUrl($request, $submissionContext, $submission, $publication); - $locales = $this->getLocales($submissionContext, $submission); - $vocabSuggestionUrlBase = $request->getDispatcher()->url($request, PKPApplication::ROUTE_API, $submissionContext->getData('urlPath'), 'vocabs', null, null, ['vocab' => '__vocab__', 'submissionId' => $submission->getId()]); + $locales = $this->getPublicationFormLocales($context, $submission); - $metadataForm = new PKPMetadataForm($publicationApiUrl, $locales, $publication, $submissionContext, $vocabSuggestionUrlBase, true); + $request = $this->getRequest(); + $vocabSuggestionUrlBase = $request->getDispatcher()->url($request, PKPApplication::ROUTE_API, $context->getData('urlPath'), 'vocabs', null, null, ['vocab' => '__vocab__', 'submissionId' => $submission->getId()]); + + $metadataForm = new PKPMetadataForm($publicationApiUrl, $locales, $publication, $context, $vocabSuggestionUrlBase); return response()->json($this->getLocalizedForm($metadataForm, $submissionLocale, $locales), Response::HTTP_OK); } /** - * Get Publication Reference Forms. + * Get Publication Reference/Citation Form component */ - protected function getPublicationReferenceForms(Request $illuminateRequest): JsonResponse + protected function getPublicationReferenceForm(Request $illuminateRequest): JsonResponse { - $request = $this->getRequest(); - $submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION); - $publication = Repo::publication()->get((int)$illuminateRequest->route('publicationId')); + $data = $this->getSubmissionAndPublicationData($illuminateRequest); - if (!$publication || !$submission) { - return response()->json([ - 'error' => __('api.404.resourceNotFound'), - ], Response::HTTP_NOT_FOUND); + if (isset($data['error'])) { + return response()->json([ 'error' => $data['error'],], $data['status']); } - if ($submission->getId() !== $publication->getData('submissionId')) { - return response()->json([ - 'error' => __('api.publications.403.submissionsDidNotMatch'), - ], Response::HTTP_FORBIDDEN); - } + $publication = $data['publication']; /** @var Publication $publication*/ + $publicationApiUrl = $data['publicationApiUrl']; /** @var String $publicationApiUrl*/ - $submissionContext = $request->getContext(); - if ($submission->getData('contextId') !== $submissionContext->getId()) { - $submissionContext = app()->get('context')->get($submission->getData('contextId')); - } - - $publicationApiUrl = $this->getPublicationUrl($request, $submissionContext, $submission, $publication); $citationsForm = new PKPCitationsForm($publicationApiUrl, $publication); return response()->json($citationsForm->getConfig(), Response::HTTP_OK); @@ -1808,45 +1803,34 @@ protected function getPublicationReferenceForms(Request $illuminateRequest): Jso /** - * Get Publication License Forms + * Get Publication License Form component */ - protected function getPublicationLicenseForms(Request $illuminateRequest): JsonResponse + protected function getPublicationLicenseForm(Request $illuminateRequest): JsonResponse { - $request = $this->getRequest(); - $submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION); - $publication = Repo::publication()->get((int)$illuminateRequest->route('publicationId')); + $data = $this->getSubmissionAndPublicationData($illuminateRequest); - if (!$publication || !$submission) { - return response()->json([ - 'error' => __('api.404.resourceNotFound'), - ], Response::HTTP_NOT_FOUND); - } - - if ($submission->getId() !== $publication->getData('submissionId')) { - return response()->json([ - 'error' => __('api.publications.403.submissionsDidNotMatch'), - ], Response::HTTP_FORBIDDEN); + if (isset($data['error'])) { + return response()->json([ 'error' => $data['error'],], $data['status']); } - $submissionContext = $request->getContext(); - if ($submission->getData('contextId') !== $submissionContext->getId()) { - $submissionContext = app()->get('context')->get($submission->getData('contextId')); - } + $submission = $data['submission']; /** @var Submission $submission */ + $publication = $data['publication']; /** @var Publication $publication*/ + $context = $data['context']; /** @var Context $context*/ + $publicationApiUrl = $data['publicationApiUrl']; /** @var String $publicationApiUrl*/ - $publicationApiUrl = $this->getPublicationUrl($request, $submissionContext, $submission, $publication); $submissionLocale = $submission->getData('locale'); - $locales = $this->getLocales($submissionContext, $submission); + $locales = $this->getPublicationFormLocales($context, $submission); $authorUserGroups = Repo::userGroup()->getByRoleIds([Role::ROLE_ID_AUTHOR], $submission->getData('contextId')); - $publicationLicenseForm = new PKPPublicationLicenseForm($publicationApiUrl, $locales, $publication, $submissionContext, $authorUserGroups); + $publicationLicenseForm = new PKPPublicationLicenseForm($publicationApiUrl, $locales, $publication, $context, $authorUserGroups); return response()->json($this->getLocalizedForm($publicationLicenseForm, $submissionLocale, $locales), Response::HTTP_OK); } /** - * Get Publication Identifier Forms. + * Get Publication Identifier Form. */ - protected function getPublicationIdentifierForms(Request $illuminateRequest): JsonResponse + protected function getPublicationIdentifierForm(Request $illuminateRequest): JsonResponse { $request = $this->getRequest(); @@ -1862,43 +1846,51 @@ protected function getPublicationIdentifierForms(Request $illuminateRequest): Js if (!$identifiersEnabled) { return response()->json([ - 'error' => __('api.403.unauthorized'), - ], Response::HTTP_NOT_FOUND); + 'error' => __('api.publications.403.noEnabledIdentifiers'), + ], Response::HTTP_FORBIDDEN); } - $submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION); - $publication = Repo::publication()->get((int)$illuminateRequest->route('publicationId')); + $data = $this->getSubmissionAndPublicationData($illuminateRequest); - if (!$publication || !$submission) { - return response()->json([ - 'error' => __('api.404.resourceNotFound'), - ], Response::HTTP_NOT_FOUND); + if (isset($data['error'])) { + return response()->json([ 'error' => $data['error'],], $data['status']); } - if ($submission->getId() !== $publication->getData('submissionId')) { - return response()->json([ - 'error' => __('api.publications.403.submissionsDidNotMatch'), - ], Response::HTTP_FORBIDDEN); - } + $submission = $data['submission']; /** @var Submission $submission */ + $publication = $data['publication']; /** @var Publication $publication*/ + $context = $data['context']; /** @var Context $context*/ + $publicationApiUrl = $data['publicationApiUrl']; /** @var String $publicationApiUrl*/ + $locales = $this->getPublicationFormLocales($context, $submission); - $submissionContext = $request->getContext(); - if ($submission->getData('contextId') !== $submissionContext->getId()) { - $submissionContext = app()->get('context')->get($submission->getData('contextId')); - } + $identifiersForm = new PKPPublicationIdentifiersForm($publicationApiUrl, $locales, $publication, $context); - $publicationApiUrl = $this->getPublicationUrl($request, $submissionContext, $submission, $publication); - $locales = $this->getLocales($submissionContext, $submission); + return response()->json($identifiersForm->getConfig(), Response::HTTP_OK); + } + + /** + * Get Publication TitleAbstract Form component + */ + protected function getPublicationTitleAbstractForm(Request $illuminateRequest): JsonResponse + { + $data = $this->getSubmissionAndPublicationData($illuminateRequest); - $identifiersForm = new PKPPublicationIdentifiersForm($publicationApiUrl, $locales, $publication, $submissionContext); + if (isset($data['error'])) { + return response()->json([ 'error' => $data['error'],], $data['status']); + } - return response()->json($identifiersForm->getConfig(), Response::HTTP_OK); + $locales = $this->getPublicationFormLocales($data['context'], $data['submission']); + $titleAbstract = new TitleAbstractForm($data['publicationApiUrl'], $locales, $data['publication']); + + return response()->json($titleAbstract->getConfig(), Response::HTTP_OK); } - protected function getLocales(Context $submissionContext, Submission $submission) + /** + * Utility method used to get the metadata locale information for a submission publications and context + */ + protected function getPublicationFormLocales(Context $context, Submission $submission): array { - return collect($submissionContext->getSupportedSubmissionMetadataLocaleNames() + $submission->getPublicationLanguageNames()) + return collect($context->getSupportedSubmissionMetadataLocaleNames() + $submission->getPublicationLanguageNames()) ->map(fn (string $name, string $locale) => ['key' => $locale, 'label' => $name]) - ->sortBy('key') ->values() ->toArray(); } @@ -1906,9 +1898,9 @@ protected function getLocales(Context $submissionContext, Submission $submission /** * Get URL for a given Publication */ - public function getPublicationUrl(PKPRequest $request, Context $submissionContext, Submission $submission, Publication $publication): string + protected function getPublicationUrl(PKPRequest $request, Context $context, Submission $submission, Publication $publication): string { - return $request->getDispatcher()->url($request, Application::ROUTE_API, $submissionContext->getPath(), 'submissions/' . $submission->getId() . '/publications/' . $publication->getId()); + return $request->getDispatcher()->url($request, Application::ROUTE_API, $context->getPath(), 'submissions/' . $submission->getId() . '/publications/' . $publication->getId()); } /** @@ -1939,7 +1931,7 @@ protected function getLocalizedForm(FormComponent $form, string $submissionLocal /*** * Get the Context for a given submission. */ - protected function getSubmissionContext(PKPRequest $request, Submission $submission) + protected function getContext(PKPRequest $request, Submission $submission): Context { $submissionContext = $request->getContext(); if ($submission->getData('contextId') !== $submissionContext->getId()) { @@ -1948,4 +1940,50 @@ protected function getSubmissionContext(PKPRequest $request, Submission $submiss return $submissionContext; } + + /** + * Used by handlers for '{submissionId}/publications/{publicationId}/_components/xxx' + * to perform common validation and retrieve submission and publication data + * + * Performs validations on the submission and publication data derived from the request. + * If the validations pass, it returns the necessary data (submission, publication, context, etc). + * If the validations fail, it returns error information. + * + * @return array An array with validated data or error details for client response. + */ + protected function getSubmissionAndPublicationData(Request $illuminateRequest): array + { + $request = $this->getRequest(); + $submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION); + $publication = Repo::publication()->get((int)$illuminateRequest->route('publicationId')); + + if (!$publication || !$submission) { + return [ + 'error' => __('api.404.resourceNotFound'), + 'status' => Response::HTTP_NOT_FOUND, + ]; + } + + if ($submission->getId() !== $publication->getData('submissionId')) { + return [ + 'error' => __('api.publications.403.submissionsDidNotMatch'), + 'status' => Response::HTTP_FORBIDDEN, + ]; + } + + $submissionContext = $request->getContext(); + if ($submission->getData('contextId') !== $submissionContext->getId()) { + $submissionContext = app()->get('context')->get($submission->getData('contextId')); + } + + $publicationApiUrl = $this->getPublicationUrl($request, $submissionContext, $submission, $publication); + + return [ + 'submission' => $submission, + 'publication' => $publication, + 'context' => $submissionContext, + 'publicationApiUrl' => $publicationApiUrl, + ]; + } + } diff --git a/locale/en/api.po b/locale/en/api.po index 25b84c7a2cb..bf05f2c3a4c 100644 --- a/locale/en/api.po +++ b/locale/en/api.po @@ -334,3 +334,6 @@ msgstr "The reviewer for the assignment could not be found" msgid "api.submission.400.sectionDoesNotExist" msgstr "The provided section does not exist." + +msgid "api.publications.403.noEnabledIdentifiers" +msgstr "Publication identifiers form is unavailable as there are no enabled Identifiers."