From 62a3000ca4aa0dc8c347181a2b5ad79839f254eb Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Wed, 30 Apr 2025 08:28:37 +0200 Subject: [PATCH] feat: add question name to form answer output * Resolves https://github.com/nextcloud/forms/issues/2700 This allows to identify question from within the UI, as the user can see the name assigned to a question to identify it when using the submissions in external places like workflows. Signed-off-by: Ferdinand Thiessen --- docs/DataStructure.md | 26 +++++++++++---------- lib/Controller/ApiController.php | 20 +++++++++++++--- lib/ResponseDefinitions.php | 1 + openapi.json | 3 +++ tests/Integration/Api/ApiV3Test.php | 4 ++++ tests/Unit/Controller/ApiControllerTest.php | 6 +++-- 6 files changed, 43 insertions(+), 17 deletions(-) diff --git a/docs/DataStructure.md b/docs/DataStructure.md index 70d4855f7..bc6b6a186 100644 --- a/docs/DataStructure.md +++ b/docs/DataStructure.md @@ -164,19 +164,21 @@ A submission-object describes a single submission by a user to a form. The actual answers of users on submission. -| Property | Type | Restrictions | Description | -| ------------ | ------- | ------------- | ----------------------------------------------- | -| id | Integer | unique | An instance-wide unique id of the submission | -| submissionId | Integer | | The id of the submission, the answer belongs to | -| questionId | Integer | | The id of the question, the answer belongs to | -| text | String | max. 4096 ch. | The actual answer text, the user submitted | - -``` +| Property | Type | Restrictions | Description | +| ------------ | ------- | ------------- | ---------------------------------------------------- | +| id | Integer | unique | An instance-wide unique id of the submission | +| submissionId | Integer | | The id of the submission, the answer belongs to | +| questionId | Integer | | The id of the question, the answer belongs to | +| questionName | String | | The technical name that was assigned to the question | +| text | String | max. 4096 ch. | The actual answer text, the user submitted | + +```json { - "id": 5, - "submissionId": 5, - "questionId": 1, - "text": "Option 2" + "id": 5, + "submissionId": 5, + "questionId": 1, + "questionName": "preference", + "text": "Option 2" } ``` diff --git a/lib/Controller/ApiController.php b/lib/Controller/ApiController.php index c23f8efc0..6b1282c69 100644 --- a/lib/Controller/ApiController.php +++ b/lib/Controller/ApiController.php @@ -1172,10 +1172,24 @@ public function getSubmissions(int $formId, ?string $query = null, ?int $limit = $submissions = $this->submissionService->getSubmissions($formId, $userId, $query, $limit, $offset); $filteredSubmissionsCount = $this->submissionMapper->countSubmissions($formId, $userId, $query); } - $questions = $this->formsService->getQuestions($formId); + $questions = []; + foreach ($this->formsService->getQuestions($formId) as $question) { + $questions[$question['id']] = $question; + } + // Append Display Names - $submissions = array_map(function (array $submission) { + $submissions = array_map(function (array $submission) use ($questions) { + if (!empty($submission['answers'])) { + $submission['answers'] = array_map(function (array $answer) use ($questions) { + $name = $questions[$answer['questionId']]['name']; + if ($name) { + $answer['questionName'] = $name; + } + return $answer; + }, $submission['answers']); + } + if (substr($submission['userId'], 0, 10) === 'anon-user-') { // Anonymous User // TRANSLATORS On Results when listing the single Responses to the form, this text is shown as heading of the Response. @@ -1202,7 +1216,7 @@ public function getSubmissions(int $formId, ?string $query = null, ?int $limit = $response = [ 'submissions' => $submissions, - 'questions' => $questions, + 'questions' => array_values($questions), 'filteredSubmissionsCount' => $filteredSubmissionsCount, ]; diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index b4fc22e70..f4833aa50 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -63,6 +63,7 @@ * submissionId: int, * fileId: ?int, * questionId: int, + * questionName?: string, * text: string * } * diff --git a/openapi.json b/openapi.json index 8146c5024..772186baa 100644 --- a/openapi.json +++ b/openapi.json @@ -58,6 +58,9 @@ "type": "integer", "format": "int64" }, + "questionName": { + "type": "string" + }, "text": { "type": "string" } diff --git a/tests/Integration/Api/ApiV3Test.php b/tests/Integration/Api/ApiV3Test.php index 4641d9644..46c345d6c 100644 --- a/tests/Integration/Api/ApiV3Test.php +++ b/tests/Integration/Api/ApiV3Test.php @@ -1117,6 +1117,7 @@ public function dataGetSubmissions() { // 'questionId' => Checked dynamically 'text' => 'Option 1', 'fileId' => null, + 'questionName' => 'city', ] ] ], @@ -1137,6 +1138,7 @@ public function dataGetSubmissions() { // 'questionId' => Checked dynamically 'text' => 'Option 2', 'fileId' => null, + 'questionName' => 'city' ] ] ], @@ -1384,10 +1386,12 @@ public function testNewSubmission() { 'questionId' => $this->testForms[0]['questions'][1]['id'], 'text' => 'Option 1', 'fileId' => null, + 'questionName' => 'city', ], [ 'questionId' => $this->testForms[0]['questions'][2]['id'], 'text' => 'test.txt', + 'questionName' => 'file', ], ] ], $data['submissions'][0]); diff --git a/tests/Unit/Controller/ApiControllerTest.php b/tests/Unit/Controller/ApiControllerTest.php index e41f349b7..e1b1d5b00 100644 --- a/tests/Unit/Controller/ApiControllerTest.php +++ b/tests/Unit/Controller/ApiControllerTest.php @@ -223,7 +223,7 @@ public function dataGetSubmissions() { 'submissions' => [ ['userId' => 'anon-user-1'] ], - 'questions' => [['name' => 'questions']], + 'questions' => [['id' => 1, 'name' => 'questions']], 'expected' => [ 'submissions' => [ [ @@ -233,6 +233,7 @@ public function dataGetSubmissions() { ], 'questions' => [ [ + 'id' => 1, 'name' => 'questions', 'extraSettings' => new \stdClass(), ], @@ -244,7 +245,7 @@ public function dataGetSubmissions() { 'submissions' => [ ['userId' => 'jdoe'] ], - 'questions' => [['name' => 'questions']], + 'questions' => [['id' => 1, 'name' => 'questions']], 'expected' => [ 'submissions' => [ [ @@ -254,6 +255,7 @@ public function dataGetSubmissions() { ], 'questions' => [ [ + 'id' => 1, 'name' => 'questions', 'extraSettings' => new \stdClass(), ],