diff --git a/lib/Capabilities.php b/lib/Capabilities.php index 62d739a5b..1d780f842 100644 --- a/lib/Capabilities.php +++ b/lib/Capabilities.php @@ -35,6 +35,7 @@ public function __construct( /** * Provide App Capabilities * @inheritdoc + * @return array{forms: array{version: string, apiVersions: array}} */ public function getCapabilities() { return [ diff --git a/lib/Controller/ApiController.php b/lib/Controller/ApiController.php index a1b3ddfff..3713366fe 100644 --- a/lib/Controller/ApiController.php +++ b/lib/Controller/ApiController.php @@ -44,6 +44,7 @@ use OCA\Forms\Db\SubmissionMapper; use OCA\Forms\Db\UploadedFile; use OCA\Forms\Db\UploadedFileMapper; +use OCA\Forms\ResponseDefinitions; use OCA\Forms\Service\ConfigService; use OCA\Forms\Service\FormsService; use OCA\Forms\Service\SubmissionService; @@ -73,6 +74,14 @@ use Psr\Log\LoggerInterface; +/** + * @psalm-import-type FormsPartialForm from ResponseDefinitions + * @psalm-import-type FormsForm from ResponseDefinitions + * @psalm-import-type FormsQuestion from ResponseDefinitions + * @psalm-import-type FormsOption from ResponseDefinitions + * @psalm-import-type FormsSubmissions from ResponseDefinitions + * @psalm-import-type FormsUploadedFile from ResponseDefinitions + */ class ApiController extends OCSController { private ?IUser $currentUser; @@ -112,38 +121,43 @@ public function preflightedCors() { // API v3 methods // Forms /** - * Read Form-List of owned forms - * Return only with necessary information for Listing. - * @return DataResponse + * Get all forms available to the user (owned/shared) + * + * @param string $type The type of forms to retrieve. Defaults to `owned`. + * Possible values: + * - `owned`: Forms owned by the user. + * - `shared`: Forms shared with the user. + * @return DataResponse, Http::STATUS_PARTIAL_CONTENT, array<>> + * @throws OCSBadRequestException wrong Form type supplied */ #[CORS()] #[NoAdminRequired()] #[ApiRoute(verb: 'GET', url: '/api/v3/forms')] public function getForms(string $type = 'owned'): DataResponse { + $result = []; + if ($type === 'owned') { $forms = $this->formMapper->findAllByOwnerId($this->currentUser->getUID()); - $result = []; foreach ($forms as $form) { $result[] = $this->formsService->getPartialFormArray($form); } - return new DataResponse($result); } elseif ($type === 'shared') { $forms = $this->formsService->getSharedForms($this->currentUser); $result = array_values(array_map(fn (Form $form): array => $this->formsService->getPartialFormArray($form), $forms)); - return new DataResponse($result); } else { throw new OCSBadRequestException(); } + + return new DataResponse($result, Http::STATUS_PARTIAL_CONTENT); } /** - * Create a new Form and return the Form to edit. - * Return a cloned Form if the parameter $fromId is set + * Create a new form and return the form + * Return a copy of the form if the parameter $fromId is set * - * @param int $fromId (optional) ID of the Form that should be cloned - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @param ?int $fromId (optional) Id of the form that should be cloned + * @return DataResponse> + * @throws OCSForbiddenException The user is not allowed to create forms */ #[CORS()] #[NoAdminRequired()] @@ -209,16 +223,17 @@ public function newForm(?int $fromId = null): DataResponse { } } } - return $this->getForm($form->getId()); + + return new DataResponse($this->formsService->getForm($form), Http::STATUS_CREATED); } /** - * Read all information to edit a Form (form, questions, options, except submissions/answers). + * Read all information to edit a Form (form, questions, options, except submissions/answers) * * @param int $formId Id of the form - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @return DataResponse, Http::STATUS_OK, array<>> + * @throws OCSBadRequestException Could not find form + * @throws OCSForbiddenException User has no permissions to get this form */ #[CORS()] #[NoAdminRequired()] @@ -236,19 +251,20 @@ public function getForm(int $formId): DataResponse { throw new OCSForbiddenException(); } - $formData = $this->formsService->getForm($form); - - return new DataResponse($formData); + return new DataResponse($this->formsService->getForm($form)); } /** - * Writes the given key-value pairs into Database. + * Writes the given key-value pairs into Database * * @param int $formId FormId of form to update - * @param array $keyValuePairs Array of key=>value pairs to update. - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @param array $keyValuePairs Array of key=>value pairs to update. + * @return DataResponse> + * @throws OCSBadRequestException Could not find new form owner + * @throws OCSForbiddenException Empty keyValuePairs provided + * @throws OCSForbiddenException Not allowed to update id, hash, created, fileId or lastUpdated. OwnerId only allowed if no other key provided. + * @throws OCSForbiddenException User is not allowed to modify the form + * @throws OCSNotFoundException Form not found */ #[CORS()] #[NoAdminRequired()] @@ -333,9 +349,9 @@ public function updateForm(int $formId, array $keyValuePairs): DataResponse { * Delete a form * * @param int $formId the form id - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @return DataResponse> + * @throws OCSForbiddenException User is not allowed to delete the form + * @throws OCSNotFoundException Form not found */ #[CORS()] #[NoAdminRequired()] @@ -355,10 +371,10 @@ public function deleteForm(int $formId): DataResponse { /** * Read all questions (including options) * - * @param int $formId FormId - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @param int $formId the form id + * @return DataResponse, Http::STATUS_OK, array<>> + * @throws OCSForbiddenException User has no permissions to get this form + * @throws OCSNotFoundException Could not find form */ #[CORS()] #[NoAdminRequired()] @@ -368,7 +384,7 @@ public function getQuestions(int $formId): DataResponse { $form = $this->formMapper->findById($formId); } catch (IMapperException $e) { $this->logger->debug('Could not find form'); - throw new OCSBadRequestException(); + throw new OCSNotFoundException(); } if (!$this->formsService->hasUserAccess($form)) { @@ -386,9 +402,10 @@ public function getQuestions(int $formId): DataResponse { * * @param int $formId FormId * @param int $questionId QuestionId - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @return DataResponse> + * @throws OCSBadRequestException Question doesn\'t belong to given Form + * @throws OCSForbiddenException User has no permissions to get this form + * @throws OCSNotFoundException Could not find form */ #[CORS()] #[NoAdminRequired()] @@ -398,7 +415,7 @@ public function getQuestion(int $formId, int $questionId): DataResponse { $form = $this->formMapper->findById($formId); } catch (IMapperException $e) { $this->logger->debug('Could not find form'); - throw new OCSBadRequestException(); + throw new OCSNotFoundException(); } if (!$this->formsService->hasUserAccess($form)) { @@ -409,7 +426,7 @@ public function getQuestion(int $formId, int $questionId): DataResponse { $question = $this->formsService->getQuestion($questionId); if ($question['formId'] !== $formId) { - throw new OCSBadRequestException('Question doesn\'t belong to given Form'); + throw new OCSBadRequestException('Question doesn\'t belong to given form'); } return new DataResponse($question); @@ -421,10 +438,14 @@ public function getQuestion(int $formId, int $questionId): DataResponse { * @param int $formId the form id * @param string $type the new question type * @param string $text the new question title - * @param int $fromId (optional) id of the question that should be cloned - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @param ?int $fromId (optional) id of the question that should be cloned + * @return DataResponse> + * @throws OCSBadRequestException Invalid type + * @throws OCSBadRequestException Datetime question type no longer supported + * @throws OCSForbiddenException User has no permissions to get this form + * @throws OCSForbiddenException This form is archived and can not be modified + * @throws OCSNotFoundException Could not find form + * @throws OCSNotFoundException Could not find question */ #[CORS()] #[NoAdminRequired()] @@ -518,19 +539,26 @@ public function newQuestion(int $formId, ?string $type = null, string $text = '' $this->formMapper->update($form); - return new DataResponse($response); + return new DataResponse($response, Http::STATUS_CREATED); } /** - * Writes the given key-value pairs into Database. - * Key 'order' should only be changed by reorderQuestions() and is not allowed here. + * Writes the given key-value pairs into Database + * Key `order` should only be changed by reorderQuestions() and is not allowed here * * @param int $formId the form id * @param int $questionId id of question to update - * @param array $keyValuePairs Array of key=>value pairs to update. - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @param array $keyValuePairs Array of key=>value pairs to update. + * @return DataResponse> + * @throws OCSBadRequestException Question doesn\'t belong to given Form + * @throws OCSBadRequestException Invalid extraSettings, will not update. + * @throws OCSForbiddenException Empty keyValuePairs, will not update + * @throws OCSForbiddenException Not allowed to update `id` or `formId` + * @throws OCSForbiddenException Please use reorderQuestions() to change order + * @throws OCSForbiddenException This form is archived and can not be modified + * @throws OCSForbiddenException User has no permissions to get this form + * @throws OCSNotFoundException Could not find form + * @throws OCSNotFoundException Could not find question */ #[CORS()] #[NoAdminRequired()] @@ -546,7 +574,7 @@ public function updateQuestion(int $formId, int $questionId, array $keyValuePair $question = $this->questionMapper->findById($questionId); } catch (IMapperException $e) { $this->logger->debug('Could not find question'); - throw new OCSBadRequestException('Could not find question'); + throw new OCSNotFoundException('Could not find question'); } if ($question->getFormId() !== $formId) { @@ -556,19 +584,19 @@ public function updateQuestion(int $formId, int $questionId, array $keyValuePair $form = $this->getFormIfAllowed($formId); if ($this->formsService->isFormArchived($form)) { $this->logger->debug('This form is archived and can not be modified'); - throw new OCSForbiddenException(); + throw new OCSForbiddenException('This form is archived and can not be modified'); } // Don't allow empty array if (sizeof($keyValuePairs) === 0) { $this->logger->info('Empty keyValuePairs, will not update.'); - throw new OCSForbiddenException(); + throw new OCSBacRequestException('This form is archived and can not be modified'); } //Don't allow to change id or formId if (key_exists('id', $keyValuePairs) || key_exists('formId', $keyValuePairs)) { $this->logger->debug('Not allowed to update \'id\' or \'formId\''); - throw new OCSForbiddenException(); + throw new OCSForbiddenException('Not allowed to update \'id\' or \'formId\''); } // Don't allow to reorder here @@ -597,9 +625,12 @@ public function updateQuestion(int $formId, int $questionId, array $keyValuePair * * @param int $formId the form id * @param int $questionId the question id - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @return DataResponse> + * @throws OCSBadRequestException Question doesn\'t belong to given Form + * @throws OCSForbiddenException This form is archived and can not be modified + * @throws OCSForbiddenException User has no permissions to get this form + * @throws OCSNotFoundException Could not find form + * @throws OCSNotFoundException Could not find question */ #[CORS()] #[NoAdminRequired()] @@ -613,7 +644,7 @@ public function deleteQuestion(int $formId, int $questionId): DataResponse { $question = $this->questionMapper->findById($questionId); } catch (IMapperException $e) { $this->logger->debug('Could not find question'); - throw new OCSBadRequestException('Could not find question'); + throw new OCSNotFoundException('Could not find question'); } if ($question->getFormId() !== $formId) { @@ -623,7 +654,7 @@ public function deleteQuestion(int $formId, int $questionId): DataResponse { $form = $this->getFormIfAllowed($formId); if ($this->formsService->isFormArchived($form)) { $this->logger->debug('This form is archived and can not be modified'); - throw new OCSForbiddenException(); + throw new OCSForbiddenException('This form is archived and can not be modified'); } // Store Order of deleted Question @@ -649,13 +680,19 @@ public function deleteQuestion(int $formId, int $questionId): DataResponse { } /** - * Updates the Order of all Questions of a Form. + * Updates the Order of all Questions of a Form * * @param int $formId Id of the form to reorder - * @param Array $newOrder Array of Question-Ids in new order. - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @param array $newOrder Array of Question-Ids in new order. + * @return DataResponse, Http::STATUS_OK, array<>> + * @throws OCSBadRequestException The given array contains duplicates + * @throws OCSBadRequestException The length of the given array does not match the number of stored questions + * @throws OCSBadRequestException Question doesn\'t belong to given Form + * @throws OCSBadRequestException One question has already been marked as deleted + * @throws OCSForbiddenException This form is archived and can not be modified + * @throws OCSForbiddenException User has no permissions to get this form + * @throws OCSNotFoundException Could not find form + * @throws OCSNotFoundException Could not find question */ #[CORS()] #[NoAdminRequired()] @@ -669,7 +706,7 @@ public function reorderQuestions(int $formId, array $newOrder): DataResponse { $form = $this->getFormIfAllowed($formId); if ($this->formsService->isFormArchived($form)) { $this->logger->debug('This form is archived and can not be modified'); - throw new OCSForbiddenException(); + throw new OCSForbiddenException('This form is archived and can not be modified'); } // Check if array contains duplicates @@ -693,27 +730,27 @@ public function reorderQuestions(int $formId, array $newOrder): DataResponse { try { $questions[$arrayKey] = $this->questionMapper->findById($questionId); } catch (IMapperException $e) { - $this->logger->debug('Could not find question. Id: {questionId}', [ + $this->logger->debug('Could not find question {questionId}', [ 'questionId' => $questionId ]); - throw new OCSBadRequestException(); + throw new OCSNotFoundException('Could not find question'); } // Abort if a question is not part of the Form. if ($questions[$arrayKey]->getFormId() !== $formId) { - $this->logger->debug('This Question is not part of the given Form: questionId: {questionId}', [ + $this->logger->debug('This Question is not part of the given form: {questionId}', [ 'questionId' => $questionId ]); - throw new OCSBadRequestException(); + throw new OCSBadRequestException('Question doesn\'t belong to given Form'); } // Abort if a question is already marked as deleted (order==0) $oldOrder = $questions[$arrayKey]->getOrder(); if ($oldOrder === 0) { - $this->logger->debug('This Question has already been marked as deleted: Id: {questionId}', [ + $this->logger->debug('This question has already been marked as deleted: Id: {questionId}', [ 'questionId' => $questions[$arrayKey]->getId() ]); - throw new OCSBadRequestException(); + throw new OCSBadRequestException('One question has already been marked as deleted'); } // Only set order, if it changed. @@ -745,9 +782,12 @@ public function reorderQuestions(int $formId, array $newOrder): DataResponse { * @param int $formId id of the form * @param int $questionId id of the question * @param array $optionTexts the new option text - * @return DataResponse Returns a DataResponse containing the added options - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @return DataResponse, Http::STATUS_CREATED, array<>> Returns a DataResponse containing the added options + * @throws OCSBadRequestException This question is not part ot the given form + * @throws OCSForbiddenException This form is archived and can not be modified + * @throws OCSForbiddenException Current user has no permission to edit + * @throws OCSNotFoundException Could not find form + * @throws OCSNotFoundException Could not find question */ #[CORS()] #[NoAdminRequired()] @@ -762,21 +802,21 @@ public function newOption(int $formId, int $questionId, array $optionTexts): Dat $form = $this->getFormIfAllowed($formId); if ($this->formsService->isFormArchived($form)) { $this->logger->debug('This form is archived and can not be modified'); - throw new OCSForbiddenException(); + throw new OCSForbiddenException('This form is archived and can not be modified'); } try { $question = $this->questionMapper->findById($questionId); } catch (IMapperException $e) { $this->logger->debug('Could not find question'); - throw new OCSBadRequestException('Could not find question'); + throw new OCSNotFoundException('Could not find question'); } if ($question->getFormId() !== $formId) { - $this->logger->debug('This Question is not part of the given Form: questionId: {questionId}', [ + $this->logger->debug('This question is not part of the given form: questionId: {questionId}', [ 'questionId' => $questionId ]); - throw new OCSBadRequestException(); + throw new OCSBadRequestException('This question is not part ot the given form'); } // Retrieve all options sorted by 'order'. Takes the order of the last array-element and adds one. @@ -808,19 +848,24 @@ public function newOption(int $formId, int $questionId, array $optionTexts): Dat $this->formMapper->update($form); - return new DataResponse($addedOptions); + return new DataResponse($addedOptions, Http::STATUS_CREATED); } /** - * Writes the given key-value pairs into Database. + * Writes the given key-value pairs into Database * * @param int $formId id of form * @param int $questionId id of question * @param int $optionId id of option to update - * @param array $keyValuePairs Array of key=>value pairs to update. - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @param array{key: string, value: mixed} $keyValuePairs Array of key=>value pairs to update. + * @return DataResponse> Returns the id of the updated option + * @throws OCSBadRequestException The given option id doesn't match the question or form + * @throws OCSForbiddenException This form is archived and can not be modified + * @throws OCSForbiddenException Current user has no permission to edit + * @throws OCSForbiddenException Empty keyValuePairs, will not update + * @throws OCSForbiddenException Not allowed to update id or questionId + * @throws OCSNotFoundException Could not find form + * @throws OCSNotFoundException Could not find option or question */ #[CORS()] #[NoAdminRequired()] @@ -836,7 +881,7 @@ public function updateOption(int $formId, int $questionId, int $optionId, array $form = $this->getFormIfAllowed($formId); if ($this->formsService->isFormArchived($form)) { $this->logger->debug('This form is archived and can not be modified'); - throw new OCSForbiddenException(); + throw new OCSForbiddenException('This form is archived and can not be modified'); } try { @@ -844,24 +889,24 @@ public function updateOption(int $formId, int $questionId, int $optionId, array $question = $this->questionMapper->findById($questionId); } catch (IMapperException $e) { $this->logger->debug('Could not find option or question'); - throw new OCSBadRequestException('Could not find option or question'); + throw new OCSNotFoundException('Could not find option or question'); } if ($option->getQuestionId() !== $questionId || $question->getFormId() !== $formId) { $this->logger->debug('The given option id doesn\'t match the question or form.'); - throw new OCSBadRequestException(); + throw new OCSBadRequestException('The given option id doesn\'t match the question or form.'); } // Don't allow empty array if (sizeof($keyValuePairs) === 0) { - $this->logger->info('Empty keyValuePairs, will not update.'); - throw new OCSForbiddenException(); + $this->logger->info('Empty keyValuePairs, will not update'); + throw new OCSForbiddenException('Empty keyValuePairs, will not update'); } //Don't allow to change id or questionId if (key_exists('id', $keyValuePairs) || key_exists('questionId', $keyValuePairs)) { $this->logger->debug('Not allowed to update id or questionId'); - throw new OCSForbiddenException(); + throw new OCSForbiddenException('Not allowed to update id or questionId'); } // Create OptionEntity with given Params & Id. @@ -882,9 +927,12 @@ public function updateOption(int $formId, int $questionId, int $optionId, array * @param int $formId id of form * @param int $questionId id of question * @param int $optionId id of option to update - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @return DataResponse> Returns the id of the deleted option + * @throws OCSBadRequestException The given option id doesn't match the question or form + * @throws OCSForbiddenException This form is archived and can not be modified + * @throws OCSForbiddenException Current user has no permission to edit + * @throws OCSNotFoundException Could not find form + * @throws OCSNotFoundException Could not find question or option */ #[CORS()] #[NoAdminRequired()] @@ -897,20 +945,20 @@ public function deleteOption(int $formId, int $questionId, int $optionId): DataR $form = $this->getFormIfAllowed($formId); if ($this->formsService->isFormArchived($form)) { $this->logger->debug('This form is archived and can not be modified'); - throw new OCSForbiddenException(); + throw new OCSForbiddenException('This form is archived and can not be modified'); } try { $option = $this->optionMapper->findById($optionId); $question = $this->questionMapper->findById($questionId); } catch (IMapperException $e) { - $this->logger->debug('Could not find form, question or option'); - throw new OCSBadRequestException('Could not find form, question or option'); + $this->logger->debug('Could not find option or question'); + throw new OCSBadRequestException('Could not find option or question'); } if ($option->getQuestionId() !== $questionId || $question->getFormId() !== $formId) { $this->logger->debug('The given option id doesn\'t match the question or form.'); - throw new OCSBadRequestException(); + throw new OCSBadRequestException('The given option id doesn\'t match the question or form.'); } $this->optionMapper->delete($option); @@ -932,7 +980,16 @@ public function deleteOption(int $formId, int $questionId, int $optionId): DataR * Reorder options for a given question * @param int $formId id of form * @param int $questionId id of question - * @param Array $newOrder Order to use + * @param array $newOrder Array of option ids in new order. + * @return DataResponse, Http::STATUS_OK, array<>> + * @throws OCSBadRequestException The given question id doesn't match the form + * @throws OCSBadRequestException The given array contains duplicates + * @throws OCSBadRequestException The length of the given array does not match the number of stored options + * @throws OCSBadRequestException This option is not part of the given question + * @throws OCSForbiddenException This form is archived and can not be modified + * @throws OCSForbiddenException Current user has no permission to edit + * @throws OCSNotFoundException Could not find form + * @throws OCSNotFoundException Could not find question */ #[CORS()] #[NoAdminRequired()] @@ -941,14 +998,14 @@ public function reorderOptions(int $formId, int $questionId, array $newOrder) { $form = $this->getFormIfAllowed($formId); if ($this->formsService->isFormArchived($form)) { $this->logger->debug('This form is archived and can not be modified'); - throw new OCSForbiddenException(); + throw new OCSForbiddenException('This form is archived and can not be modified'); } try { $question = $this->questionMapper->findById($questionId); } catch (IMapperException $e) { - $this->logger->debug('Could not find form or question', ['exception' => $e]); - throw new OCSNotFoundException('Could not find form or question'); + $this->logger->debug('Could not find question'); + throw new OCSNotFoundException('Could not find question'); } if ($question->getFormId() !== $formId) { @@ -980,18 +1037,17 @@ public function reorderOptions(int $formId, int $questionId, array $newOrder) { $this->logger->debug('Could not find option. Id: {optionId}', [ 'optionId' => $optionId ]); - throw new OCSBadRequestException(); + throw new OCSNotFoundException('Could not find option'); } - // Abort if a question is not part of the Form. + // Abort if a option is not part of the question. if ($options[$arrayKey]->getQuestionId() !== $questionId) { - $this->logger->debug('This Option is not part of the given Question: formId: {formId}', [ + $this->logger->debug('This option is not part of the given question: formId: {formId}', [ 'formId' => $formId ]); - throw new OCSBadRequestException(); + throw new OCSBadRequestException('This option is not part of the given question'); } - // Abort if a question is already marked as deleted (order==0) $oldOrder = $options[$arrayKey]->getOrder(); // Only set order, if it changed. @@ -1021,9 +1077,14 @@ public function reorderOptions(int $formId, int $questionId, array $newOrder) { * Get all the submissions of a given form * * @param int $formId of the form - * @return DataResponse|DataDownloadResponse - * @throws OCSNotFoundException - * @throws OCSForbiddenException + * @param ?string $fileFormat the file format that should be used for the download. Defaults to `null` + * Possible values: + * - `csv`: Comma-separated value + * - `ods`: OpenDocument Spreadsheet + * - `xlsx`: Excel Open XML Spreadsheet + * @return DataResponse|DataDownloadResponse> + * @throws OCSNotFoundException Could not find form + * @throws OCSForbiddenException The current user has no permission to get the results for this form */ #[CORS()] #[NoAdminRequired()] @@ -1038,7 +1099,7 @@ public function getSubmissions(int $formId, ?string $fileFormat = null): DataRes if (!$this->formsService->canSeeResults($form)) { $this->logger->debug('The current user has no permission to get the results for this form'); - throw new OCSForbiddenException(); + throw new OCSForbiddenException('The current user has no permission to get the results for this form'); } if ($fileFormat !== null) { @@ -1082,9 +1143,9 @@ public function getSubmissions(int $formId, ?string $fileFormat = null): DataRes * Delete all submissions of a specified form * * @param int $formId the form id - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @return DataResponse> + * @throws OCSNotFoundException Could not find form + * @throws OCSForbiddenException This form is not owned by the current user and user has no `results_delete` permission */ #[CORS()] #[NoAdminRequired()] @@ -1098,13 +1159,13 @@ public function deleteAllSubmissions(int $formId): DataResponse { $form = $this->formMapper->findById($formId); } catch (IMapperException $e) { $this->logger->debug('Could not find form'); - throw new OCSBadRequestException(); + throw new OCSNotFoundException('Could not find form'); } // The current user has permissions to remove submissions if (!$this->formsService->canDeleteResults($form)) { $this->logger->debug('This form is not owned by the current user and user has no `results_delete` permission'); - throw new OCSForbiddenException(); + throw new OCSForbiddenException('This form is not owned by the current user and user has no `results_delete` permission'); } // Delete all submissions (incl. Answers) @@ -1118,11 +1179,15 @@ public function deleteAllSubmissions(int $formId): DataResponse { * Process a new submission * * @param int $formId the form id - * @param array $answers [question_id => arrayOfString] + * @param array> $answers [question_id => arrayOfString] * @param string $shareHash public share-hash -> Necessary to submit on public link-shares. - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @return DataResponse, Http::STATUS_CREATED, array<>> + * @throws OCSBadRequestException At least one submitted answer is not valid + * @throws OCSForbiddenException Already submitted + * @throws OCSForbiddenException Not allowed to access this form + * @throws OCSForbiddenException This form is no longer taking answers + * @throws OCSForbiddenException This form is not owned by the current user and user has no `results_delete` permission + * @throws OCSNotFoundException Could not find form */ #[CORS()] #[NoAdminRequired()] @@ -1207,7 +1272,7 @@ public function newSubmission(int $formId, array $answers, string $shareHash = ' } } - return new DataResponse(); + return new DataResponse(null, Http::STATUS_CREATED); } /** @@ -1215,9 +1280,10 @@ public function newSubmission(int $formId, array $answers, string $shareHash = ' * * @param int $formId the form id * @param int $submissionId the submission id - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @return DataResponse> + * @throws OCSBadRequestException Submission doesn't belong to given form + * @throws OCSNotFoundException Could not find form or submission + * @throws OCSForbiddenException This form is not owned by the current user and user has no `results_delete` permission */ #[CORS()] #[NoAdminRequired()] @@ -1232,7 +1298,7 @@ public function deleteSubmission(int $formId, int $submissionId): DataResponse { $form = $this->formMapper->findById($formId); } catch (IMapperException $e) { $this->logger->debug('Could not find form or submission'); - throw new OCSBadRequestException(); + throw new OCSNotFoundException('Could not find form or submission'); } if ($formId !== $submission->getFormId()) { @@ -1243,7 +1309,7 @@ public function deleteSubmission(int $formId, int $submissionId): DataResponse { // The current user has permissions to remove submissions if (!$this->formsService->canDeleteResults($form)) { $this->logger->debug('This form is not owned by the current user and user has no `results_delete` permission'); - throw new OCSForbiddenException(); + throw new OCSForbiddenException('This form is not owned by the current user and user has no `results_delete` permission'); } // Delete submission (incl. Answers) @@ -1259,9 +1325,9 @@ public function deleteSubmission(int $formId, int $submissionId): DataResponse { * @param int $formId of the form * @param string $path The Cloud-Path to export to * @param string $fileFormat File format used for export - * @return DataResponse - * @throws OCSBadRequestException - * @throws OCSForbiddenException + * @return DataResponse> + * @throws OCSForbiddenException The current user has no permission to get the results for this form + * @throws OCSNotFoundException Could not find form */ #[CORS()] #[NoAdminRequired()] @@ -1271,12 +1337,12 @@ public function exportSubmissionsToCloud(int $formId, string $path, string $file $form = $this->formMapper->findById($formId); } catch (IMapperException $e) { $this->logger->debug('Could not find form'); - throw new OCSNotFoundException(); + throw new OCSNotFoundException('Could not find form'); } if (!$this->formsService->canSeeResults($form)) { $this->logger->debug('The current user has no permission to get the results for this form'); - throw new OCSForbiddenException(); + throw new OCSForbiddenException('The current user has no permission to get the results for this form'); } $file = $this->submissionService->writeFileToCloud($form, $path, $fileFormat); @@ -1290,7 +1356,15 @@ public function exportSubmissionsToCloud(int $formId, string $path, string $file * @param int $formId id of the form * @param int $questionId id of the question * @param string $shareHash hash of the form share - * @return DataResponse + * @return DataResponse> + * @throws OCSBadRequestException No files provided + * @throws OCSBadRequestException Question doesn't belong to the given form + * @throws OCSBadRequestException Invalid file provided + * @throws OCSBadRequestException Failed to upload the file + * @throws OCSBadRequestException File size exceeds the maximum allowed size + * @throws OCSBadRequestException File type is not allowed + * @throws OCSForbiddenException Already submitted + * @throws OCSNotFoundException Could not find question */ #[CORS()] #[NoAdminRequired()] @@ -1325,7 +1399,7 @@ public function uploadFiles(int $formId, int $questionId, string $shareHash = '' $this->logger->debug('Could not find question with id {questionId}', [ 'questionId' => $questionId ]); - throw new OCSBadRequestException(previous: $e instanceof \Exception ? $e : null); + throw new OCSNotFoundException('Could not find question'); } if ($formId !== $question->getFormId()) { @@ -1486,7 +1560,7 @@ private function loadFormForSubmission(int $formId, string $shareHash): Form { $form = $this->formMapper->findById($formId); } catch (IMapperException $e) { $this->logger->debug('Could not find form'); - throw new OCSBadRequestException(previous: $e instanceof \Exception ? $e : null); + throw new OCSNotFoundException('Could not find form'); } // Does the user have access to the form (Either by logged-in user, or by providing public share-hash.) diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php new file mode 100644 index 000000000..e31089512 --- /dev/null +++ b/lib/ResponseDefinitions.php @@ -0,0 +1,106 @@ + + * + * @author Christian Hartmann + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Forms; + +/** + * @psalm-type FormsForm = array{ + * "id": int, + * "hash": string, + * "title": string, + * "description": string, + * "ownerId": string, + * "created": int, + * "access": stdClass, + * "expires": int, + * "isAnonymous": bool, + * "submitMultiple": bool, + * "showExpiration": bool, + * "canSubmit": bool, + * "permissions": array, + * "questions": array, + * "state": int, + * "shares": array, + * "submissions": array, + * } + * + * @psalm-type FormsPartialForm = array{ + * "id": int, + * "hash": string, + * "title": string, + * "expires": int, + * "permissions": array, + * "partial": bool, + * "state": int + * } + * + * @psalm-type FormsQuestion = array{ + * "id": int, + * "formId": int, + * "order": int, + * "type": string, + * "isRequired": bool, + * "text": string, + * "name": string, + * "options": array, + * "accept": array, + * "extraSettings": stdClass + * } + * + * @psalm-type FormsOption = array{ + * "id": int, + * "questionId": int, + * "text": string, + * "order": ?int + * } + * + * @psalm-type FormsSubmissions = { + * "submissions": array, + * "questions": array + * } + * + * @psalm-type FormsSubmission = array{ + * "id": int, + * "formId": int, + * "userId": string, + * "timestamp": int, + * "answers": array, + * "userDisplayName": string + * } + * + * @psalm-type FormsAnswer = array{ + * "id": int, + * "submissionId": int, + * "questionId": int, + * "text": string + * } + * + * @psalm-type FormsUploadedFile = array{ + * "uploadedFileId": int, + * "fileName": string + * } + * + * @psalm-type FormsQuestionFileType = string + */ +class ResponseDefinitions { +} diff --git a/openapi.json b/openapi.json new file mode 100644 index 000000000..75110c59c --- /dev/null +++ b/openapi.json @@ -0,0 +1,3051 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "forms", + "version": "0.0.1", + "description": "📝 Simple surveys and questionnaires, self-hosted", + "license": { + "name": "agpl" + } + }, + "components": { + "securitySchemes": { + "basic_auth": { + "type": "http", + "scheme": "basic" + }, + "bearer_auth": { + "type": "http", + "scheme": "bearer" + } + }, + "schemas": { + "Capabilities": { + "type": "object", + "required": [ + "forms" + ], + "properties": { + "forms": { + "type": "object", + "required": [ + "version", + "apiVersions" + ], + "properties": { + "version": { + "type": "string" + }, + "apiVersions": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "OCSMeta": { + "type": "object", + "required": [ + "status", + "statuscode" + ], + "properties": { + "status": { + "type": "string" + }, + "statuscode": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "totalitems": { + "type": "string" + }, + "itemsperpage": { + "type": "string" + } + } + } + } + }, + "paths": { + "/ocs/v2.php/apps/forms/api/v3/forms": { + "get": { + "operationId": "api-get-forms", + "summary": "Get all forms available to the user (owned/shared)", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "type", + "in": "query", + "description": "The type of forms to retrieve. Defaults to `owned`. Possible values: - `owned`: Forms owned by the user. - `shared`: Forms shared with the user.", + "schema": { + "type": "string", + "default": "owned" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "wrong Form type supplied", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "api-new-form", + "summary": "Create a new form and return the form Return a copy of the form if the parameter $fromId is set", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "fromId": { + "type": "integer", + "format": "int64", + "nullable": true, + "description": "(optional) Id of the form that should be cloned" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "403": { + "description": "The user is not allowed to create forms", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forms/api/v3/forms/{formId}": { + "get": { + "operationId": "api-get-form", + "summary": "Read all information to edit a Form (form, questions, options, except submissions/answers)", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "Id of the form", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "Could not find form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "User has no permissions to get this form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "patch": { + "operationId": "api-update-form", + "summary": "Writes the given key-value pairs into Database", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "keyValuePairs" + ], + "properties": { + "keyValuePairs": { + "type": "object", + "description": "Array of key=>value pairs to update.", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "FormId of form to update", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "Could not find new form owner", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "User is not allowed to modify the form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Form not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "api-delete-form", + "summary": "Delete a form", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "the form id", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "403": { + "description": "User is not allowed to delete the form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Form not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forms/api/v3/forms/{formId}/questions": { + "get": { + "operationId": "api-get-questions", + "summary": "Read all questions (including options)", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "the form id", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "403": { + "description": "User has no permissions to get this form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "api-new-question", + "summary": "Add a new question", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "the new question type" + }, + "text": { + "type": "string", + "default": "", + "description": "the new question title" + }, + "fromId": { + "type": "integer", + "format": "int64", + "nullable": true, + "description": "(optional) id of the question that should be cloned" + } + } + } + } + } + }, + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "the form id", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "Datetime question type no longer supported", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "This form is archived and can not be modified", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find question", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "patch": { + "operationId": "api-reorder-questions", + "summary": "Updates the Order of all Questions of a Form", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "newOrder" + ], + "properties": { + "newOrder": { + "type": "object", + "description": "Array of Question-Ids in new order.", + "additionalProperties": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "Id of the form to reorder", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "One question has already been marked as deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "User has no permissions to get this form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find question", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forms/api/v3/forms/{formId}/questions/{questionId}": { + "get": { + "operationId": "api-get-question", + "summary": "Read a specific question (including options)", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "FormId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "questionId", + "in": "path", + "description": "QuestionId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "Question doesn\\'t belong to given Form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "User has no permissions to get this form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "patch": { + "operationId": "api-update-question", + "summary": "Writes the given key-value pairs into Database Key `order` should only be changed by reorderQuestions() and is not allowed here", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "keyValuePairs" + ], + "properties": { + "keyValuePairs": { + "type": "object", + "description": "Array of key=>value pairs to update.", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "the form id", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "questionId", + "in": "path", + "description": "id of question to update", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "Invalid extraSettings, will not update.", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "User has no permissions to get this form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find question", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "api-delete-question", + "summary": "Delete a question", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "the form id", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "questionId", + "in": "path", + "description": "the question id", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "Question doesn\\'t belong to given Form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "User has no permissions to get this form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find question", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forms/api/v3/forms/{formId}/questions/{questionId}/options": { + "post": { + "operationId": "api-new-option", + "summary": "Add a new option to a question", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "optionTexts" + ], + "properties": { + "optionTexts": { + "type": "array", + "description": "the new option text", + "items": { + "type": "string" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "id of the form", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "questionId", + "in": "path", + "description": "id of the question", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "This question is not part ot the given form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "Current user has no permission to edit", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find question", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "patch": { + "operationId": "api-reorder-options", + "summary": "Reorder options for a given question", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "newOrder" + ], + "properties": { + "newOrder": { + "type": "object", + "description": "Array of option ids in new order.", + "additionalProperties": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "id of form", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "questionId", + "in": "path", + "description": "id of question", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "This option is not part of the given question", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "Current user has no permission to edit", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find question", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forms/api/v3/forms/{formId}/questions/{questionId}/options/{optionId}": { + "patch": { + "operationId": "api-update-option", + "summary": "Writes the given key-value pairs into Database", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "keyValuePairs" + ], + "properties": { + "keyValuePairs": { + "type": "object", + "description": "Array of key=>value pairs to update.", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "object" + } + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "id of form", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "questionId", + "in": "path", + "description": "id of question", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "optionId", + "in": "path", + "description": "id of option to update", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "The given option id doesn't match the question or form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "Not allowed to update id or questionId", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find option or question", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "api-delete-option", + "summary": "Delete an option", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "id of form", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "questionId", + "in": "path", + "description": "id of question", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "optionId", + "in": "path", + "description": "id of option to update", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "The given option id doesn't match the question or form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "Current user has no permission to edit", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find question or option", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forms/api/v3/forms/{formId}/submissions": { + "get": { + "operationId": "api-get-submissions", + "summary": "Get all the submissions of a given form", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "of the form", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "fileFormat", + "in": "query", + "description": "the file format that should be used for the download. Defaults to `null` Possible values: - `csv`: Comma-separated value - `ods`: OpenDocument Spreadsheet - `xlsx`: Excel Open XML Spreadsheet", + "schema": { + "type": "string", + "nullable": true + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "404": { + "description": "Could not find form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "The current user has no permission to get the results for this form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "api-delete-all-submissions", + "summary": "Delete all submissions of a specified form", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "the form id", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "404": { + "description": "Could not find form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "This form is not owned by the current user and user has no `results_delete` permission", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "api-new-submission", + "summary": "Process a new submission", + "tags": [ + "api" + ], + "security": [ + {}, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "answers" + ], + "properties": { + "answers": { + "type": "object", + "description": "[question_id => arrayOfString]", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "shareHash": { + "type": "string", + "default": "", + "description": "public share-hash -> Necessary to submit on public link-shares." + } + } + } + } + } + }, + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "the form id", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "At least one submitted answer is not valid", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "This form is not owned by the current user and user has no `results_delete` permission", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forms/api/v3/forms/{formId}/submissions/{submissionId}": { + "delete": { + "operationId": "api-delete-submission", + "summary": "Delete a specific submission", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "the form id", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "submissionId", + "in": "path", + "description": "the submission id", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "Submission doesn't belong to given form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find form or submission", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "This form is not owned by the current user and user has no `results_delete` permission", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forms/api/v3/forms/{formId}/submissions/export": { + "post": { + "operationId": "api-export-submissions-to-cloud", + "summary": "Export Submissions to the Cloud", + "tags": [ + "api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "path", + "fileFormat" + ], + "properties": { + "path": { + "type": "string", + "description": "The Cloud-Path to export to" + }, + "fileFormat": { + "type": "string", + "description": "File format used for export" + } + } + } + } + } + }, + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "of the form", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "403": { + "description": "The current user has no permission to get the results for this form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find form", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forms/api/v3/forms/{formId}/submissions/files/{questionId}": { + "post": { + "operationId": "api-upload-files", + "summary": "Uploads a temporary files to the server during form filling", + "tags": [ + "api" + ], + "security": [ + {}, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "shareHash": { + "type": "string", + "default": "", + "description": "hash of the form share" + } + } + } + } + } + }, + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "id of the form", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "questionId", + "in": "path", + "description": "id of the question", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "File type is not allowed", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "Already submitted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "Could not find question", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forms/api/v3/forms/{formId}/shares": { + "post": { + "operationId": "share_api-new-share", + "summary": "Add a new share", + "tags": [ + "share_api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "shareType" + ], + "properties": { + "shareType": { + "type": "integer", + "format": "int64", + "description": "Nextcloud-ShareType" + }, + "shareWith": { + "type": "string", + "default": "", + "description": "ID of user/group/... to share with. For Empty shareWith and shareType Link, this will be set as RandomID." + } + } + } + } + } + }, + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "The form to share", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forms/api/v3/forms/{formId}/shares/{shareId}": { + "patch": { + "operationId": "share_api-update-share", + "summary": "Update permissions of a share", + "tags": [ + "share_api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "keyValuePairs" + ], + "properties": { + "keyValuePairs": { + "type": "object", + "description": "Array of key=>value pairs to update." + } + } + } + } + } + }, + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "of the form", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "shareId", + "in": "path", + "description": "of the share to update", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "share_api-delete-share", + "summary": "Delete a share", + "tags": [ + "share_api" + ], + "security": [ + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "formId", + "in": "path", + "description": "of the form", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "shareId", + "in": "path", + "description": "of the share to delete", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "400": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "403": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + } + }, + "tags": [] +}