Skip to content

Commit 0e0e7aa

Browse files
timedin-demickenordin
authored andcommitted
fix: move up/down for subquestions
fix: reordering and dragging Signed-off-by: TimedIn <git@timedin.net>
1 parent 4ce5313 commit 0e0e7aa

3 files changed

Lines changed: 483 additions & 74 deletions

File tree

lib/Controller/ApiController.php

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,125 @@ public function reorderQuestions(int $formId, array $newOrder): DataResponse {
934934
return new DataResponse($response);
935935
}
936936

937+
/**
938+
* Updates the Order of all Questions in a Branch of a conditional
939+
*
940+
* @param int $formId Id of the form to reorder
941+
* @param string $branchId Id of the branch.
942+
* @param int $parentQuestionId Id of the parent trigger question.
943+
* @param list<int> $newOrder Array of Question-Ids in new order.
944+
* @return DataResponse<Http::STATUS_OK, array<string, FormsOrder>, array{}>
945+
* @throws OCSBadRequestException The given array contains duplicates
946+
* @throws OCSBadRequestException The length of the given array does not match the number of stored questions
947+
* @throws OCSBadRequestException Question doesn't belong to given Form
948+
* @throws OCSBadRequestException One question has already been marked as deleted
949+
* @throws OCSForbiddenException This form is archived and can not be modified
950+
* @throws OCSForbiddenException User has no permissions to get this form
951+
* @throws OCSNotFoundException Could not find form
952+
* @throws OCSNotFoundException Could not find question
953+
*
954+
* 200: the question ids of the given form in the new order
955+
*/
956+
#[CORS()]
957+
#[NoAdminRequired()]
958+
#[BruteForceProtection(action: 'form')]
959+
#[ApiRoute(verb: 'PATCH', url: '/api/v3/forms/{formId}/subquestions')]
960+
public function reorderSubQuestions(int $formId, string $branchId, int $parentQuestionId, array $newOrder): DataResponse {
961+
$this->logger->debug('Reordering Sub-Questions on Form {formId}, Parent-Question {parentQuestionId}, Branch {branchId} as Question-Ids {newOrder}', [
962+
'formId' => $formId,
963+
'parentQuestionId' => $parentQuestionId,
964+
'branchId' => $branchId,
965+
'newOrder' => $newOrder
966+
]);
967+
968+
$form = $this->formsService->getFormIfAllowed($formId, Constants::PERMISSION_EDIT);
969+
$this->formsService->obtainFormLock($form);
970+
971+
if ($this->formsService->isFormArchived($form)) {
972+
$this->logger->debug('This form is archived and can not be modified');
973+
throw new OCSForbiddenException('This form is archived and can not be modified');
974+
}
975+
976+
// Check if array contains duplicates
977+
if (array_unique($newOrder) !== $newOrder) {
978+
$this->logger->debug('The given array contains duplicates');
979+
throw new OCSBadRequestException('The given array contains duplicates');
980+
}
981+
982+
// Check if all questions are given in Array.
983+
$questions = $this->questionMapper->findByBranch($parentQuestionId, $branchId);
984+
if (sizeof($questions) !== sizeof($newOrder)) {
985+
$this->logger->debug('The length of the given array does not match the number of stored questions');
986+
throw new OCSBadRequestException('The length of the given array does not match the number of stored questions');
987+
}
988+
989+
$questions = []; // Clear Array of Entities
990+
$response = []; // Array of ['questionId' => ['order' => newOrder]]
991+
992+
// Store array of Question-Entities and check the Questions FormId & old Order.
993+
foreach ($newOrder as $arrayKey => $questionId) {
994+
try {
995+
$questions[$arrayKey] = $this->questionMapper->findById($questionId);
996+
} catch (IMapperException $e) {
997+
$this->logger->debug('Could not find question {questionId}', [
998+
'questionId' => $questionId
999+
]);
1000+
throw new OCSNotFoundException('Could not find question');
1001+
}
1002+
1003+
// Abort if a question is not part of the Form.
1004+
if ($questions[$arrayKey]->getFormId() !== $formId) {
1005+
$this->logger->debug('This Question is not part of the given form: {questionId}', [
1006+
'questionId' => $questionId
1007+
]);
1008+
throw new OCSBadRequestException('Question doesn\'t belong to given Form');
1009+
}
1010+
// Abort if a question is not part of the Parent Question.
1011+
if ($questions[$arrayKey]->getParentQuestionId() !== $parentQuestionId) {
1012+
$this->logger->debug('This Question is not part of the given parent question: {parentQuestionId}', [
1013+
'parentQuestionId' => $parentQuestionId
1014+
]);
1015+
throw new OCSBadRequestException('Question doesn\'t belong to given Parent Question');
1016+
}
1017+
1018+
// Abort if a question is not part of the Branch.
1019+
if ($questions[$arrayKey]->getBranchId() !== $branchId) {
1020+
$this->logger->debug('This Question is not part of the given branch: {branchId}', [
1021+
'branchId' => $branchId
1022+
]);
1023+
throw new OCSBadRequestException('Question doesn\'t belong to given Branch');
1024+
}
1025+
1026+
// Abort if a question is already marked as deleted (order==0)
1027+
$oldOrder = $questions[$arrayKey]->getOrder();
1028+
if ($oldOrder === 0) {
1029+
$this->logger->debug('This question has already been marked as deleted: Id: {questionId}', [
1030+
'questionId' => $questions[$arrayKey]->getId()
1031+
]);
1032+
throw new OCSBadRequestException('One question has already been marked as deleted');
1033+
}
1034+
1035+
// Only set order, if it changed.
1036+
if ($oldOrder !== $arrayKey + 1) {
1037+
// Set Order. ArrayKey counts from zero, order counts from 1.
1038+
$questions[$arrayKey]->setOrder($arrayKey + 1);
1039+
}
1040+
}
1041+
1042+
// Write to Database
1043+
foreach ($questions as $question) {
1044+
$this->questionMapper->update($question);
1045+
1046+
$response[(string)$question->getId()] = [
1047+
'order' => $question->getOrder()
1048+
];
1049+
}
1050+
1051+
$this->formMapper->update($form);
1052+
1053+
return new DataResponse($response);
1054+
}
1055+
9371056
// Options
9381057

9391058
/**

openapi.json

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2689,6 +2689,224 @@
26892689
}
26902690
}
26912691
},
2692+
"/ocs/v2.php/apps/forms/api/v3/forms/{formId}/subquestions": {
2693+
"patch": {
2694+
"operationId": "api-reorder-sub-questions",
2695+
"summary": "Updates the Order of all Questions in a Branch of a conditional",
2696+
"description": "This endpoint allows CORS requests",
2697+
"tags": [
2698+
"api"
2699+
],
2700+
"security": [
2701+
{
2702+
"basic_auth": []
2703+
}
2704+
],
2705+
"requestBody": {
2706+
"required": true,
2707+
"content": {
2708+
"application/json": {
2709+
"schema": {
2710+
"type": "object",
2711+
"required": [
2712+
"branchId",
2713+
"parentQuestionId",
2714+
"newOrder"
2715+
],
2716+
"properties": {
2717+
"branchId": {
2718+
"type": "string",
2719+
"description": "Id of the branch."
2720+
},
2721+
"parentQuestionId": {
2722+
"type": "integer",
2723+
"format": "int64",
2724+
"description": "Id of the parent trigger question."
2725+
},
2726+
"newOrder": {
2727+
"type": "array",
2728+
"description": "Array of Question-Ids in new order.",
2729+
"items": {
2730+
"type": "integer",
2731+
"format": "int64"
2732+
}
2733+
}
2734+
}
2735+
}
2736+
}
2737+
}
2738+
},
2739+
"parameters": [
2740+
{
2741+
"name": "formId",
2742+
"in": "path",
2743+
"description": "Id of the form to reorder",
2744+
"required": true,
2745+
"schema": {
2746+
"type": "integer",
2747+
"format": "int64"
2748+
}
2749+
},
2750+
{
2751+
"name": "OCS-APIRequest",
2752+
"in": "header",
2753+
"description": "Required to be true for the API request to pass",
2754+
"required": true,
2755+
"schema": {
2756+
"type": "boolean",
2757+
"default": true
2758+
}
2759+
}
2760+
],
2761+
"responses": {
2762+
"200": {
2763+
"description": "the question ids of the given form in the new order",
2764+
"content": {
2765+
"application/json": {
2766+
"schema": {
2767+
"type": "object",
2768+
"required": [
2769+
"ocs"
2770+
],
2771+
"properties": {
2772+
"ocs": {
2773+
"type": "object",
2774+
"required": [
2775+
"meta",
2776+
"data"
2777+
],
2778+
"properties": {
2779+
"meta": {
2780+
"$ref": "#/components/schemas/OCSMeta"
2781+
},
2782+
"data": {
2783+
"type": "object",
2784+
"additionalProperties": {
2785+
"$ref": "#/components/schemas/Order"
2786+
}
2787+
}
2788+
}
2789+
}
2790+
}
2791+
}
2792+
}
2793+
}
2794+
},
2795+
"400": {
2796+
"description": "One question has already been marked as deleted",
2797+
"content": {
2798+
"application/json": {
2799+
"schema": {
2800+
"type": "object",
2801+
"required": [
2802+
"ocs"
2803+
],
2804+
"properties": {
2805+
"ocs": {
2806+
"type": "object",
2807+
"required": [
2808+
"meta",
2809+
"data"
2810+
],
2811+
"properties": {
2812+
"meta": {
2813+
"$ref": "#/components/schemas/OCSMeta"
2814+
},
2815+
"data": {}
2816+
}
2817+
}
2818+
}
2819+
}
2820+
}
2821+
}
2822+
},
2823+
"403": {
2824+
"description": "User has no permissions to get this form",
2825+
"content": {
2826+
"application/json": {
2827+
"schema": {
2828+
"type": "object",
2829+
"required": [
2830+
"ocs"
2831+
],
2832+
"properties": {
2833+
"ocs": {
2834+
"type": "object",
2835+
"required": [
2836+
"meta",
2837+
"data"
2838+
],
2839+
"properties": {
2840+
"meta": {
2841+
"$ref": "#/components/schemas/OCSMeta"
2842+
},
2843+
"data": {}
2844+
}
2845+
}
2846+
}
2847+
}
2848+
}
2849+
}
2850+
},
2851+
"404": {
2852+
"description": "Could not find question",
2853+
"content": {
2854+
"application/json": {
2855+
"schema": {
2856+
"type": "object",
2857+
"required": [
2858+
"ocs"
2859+
],
2860+
"properties": {
2861+
"ocs": {
2862+
"type": "object",
2863+
"required": [
2864+
"meta",
2865+
"data"
2866+
],
2867+
"properties": {
2868+
"meta": {
2869+
"$ref": "#/components/schemas/OCSMeta"
2870+
},
2871+
"data": {}
2872+
}
2873+
}
2874+
}
2875+
}
2876+
}
2877+
}
2878+
},
2879+
"401": {
2880+
"description": "Current user is not logged in",
2881+
"content": {
2882+
"application/json": {
2883+
"schema": {
2884+
"type": "object",
2885+
"required": [
2886+
"ocs"
2887+
],
2888+
"properties": {
2889+
"ocs": {
2890+
"type": "object",
2891+
"required": [
2892+
"meta",
2893+
"data"
2894+
],
2895+
"properties": {
2896+
"meta": {
2897+
"$ref": "#/components/schemas/OCSMeta"
2898+
},
2899+
"data": {}
2900+
}
2901+
}
2902+
}
2903+
}
2904+
}
2905+
}
2906+
}
2907+
}
2908+
}
2909+
},
26922910
"/ocs/v2.php/apps/forms/api/v3/forms/{formId}/questions/{questionId}/options": {
26932911
"post": {
26942912
"operationId": "api-new-option",

0 commit comments

Comments
 (0)