feat: Allow to reorder options for "multiple" question type

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Signed-off-by: Christian Hartmann <chris-hartmann@gmx.de>
This commit is contained in:
Ferdinand Thiessen 2024-04-22 01:28:59 +02:00 коммит произвёл Christian Hartmann
Родитель 683a5198fe
Коммит 7aba08d095
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 01CF79F7199D2C63
12 изменённых файлов: 363 добавлений и 106 удалений

Просмотреть файл

@ -59,7 +59,7 @@ return [
// CORS Preflight // CORS Preflight
['name' => 'api#preflightedCors', 'url' => $apiBase . '{path}', 'verb' => 'OPTIONS', 'requirements' => [ ['name' => 'api#preflightedCors', 'url' => $apiBase . '{path}', 'verb' => 'OPTIONS', 'requirements' => [
'path' => '.+', 'path' => '.+',
'apiVersion' => 'v2(\.[1-4])?|v3' 'apiVersion' => 'v2(\.[1-5])?|v3'
]], ]],
// API routes v3 // API routes v3
@ -84,7 +84,7 @@ return [
// ['name' => 'api#getOption', 'url' => $apiBase . 'forms/{formId}/questions/{questionId}/options/{optionId}', 'verb' => 'GET', 'requirements' => $requirements_v3], // ['name' => 'api#getOption', 'url' => $apiBase . 'forms/{formId}/questions/{questionId}/options/{optionId}', 'verb' => 'GET', 'requirements' => $requirements_v3],
['name' => 'api#updateOption', 'url' => $apiBase . 'forms/{formId}/questions/{questionId}/options/{optionId}', 'verb' => 'PATCH', 'requirements' => $requirements_v3], ['name' => 'api#updateOption', 'url' => $apiBase . 'forms/{formId}/questions/{questionId}/options/{optionId}', 'verb' => 'PATCH', 'requirements' => $requirements_v3],
['name' => 'api#deleteOption', 'url' => $apiBase . 'forms/{formId}/questions/{questionId}/options/{optionId}', 'verb' => 'DELETE', 'requirements' => $requirements_v3], ['name' => 'api#deleteOption', 'url' => $apiBase . 'forms/{formId}/questions/{questionId}/options/{optionId}', 'verb' => 'DELETE', 'requirements' => $requirements_v3],
// ['name' => 'api#reorderOptions', 'url' => $apiBase . 'forms/{formId}/questions/{questionId}/options', 'verb' => 'PATCH', 'requirements' => $requirements_v3], ['name' => 'api#reorderOptions', 'url' => $apiBase . 'forms/{formId}/questions/{questionId}/options', 'verb' => 'PATCH', 'requirements' => $requirements_v3],
// Shares // Shares
// ['name' => 'shareApi#getUserShares', 'url' => $apiBase . 'shares', 'verb' => 'GET', 'requirements' => $requirements_v3], // ['name' => 'shareApi#getUserShares', 'url' => $apiBase . 'shares', 'verb' => 'GET', 'requirements' => $requirements_v3],
@ -107,113 +107,113 @@ return [
// Legacy v2 routes (TODO: remove with Forms v5) // Legacy v2 routes (TODO: remove with Forms v5)
// Forms // Forms
['name' => 'api#getFormsLegacy', 'url' => $apiBase . 'forms', 'verb' => 'GET', 'requirements' => [ ['name' => 'api#getFormsLegacy', 'url' => $apiBase . 'forms', 'verb' => 'GET', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?' 'apiVersion' => 'v2(\.[1-5])?'
]], ]],
['name' => 'api#newFormLegacy', 'url' => $apiBase . 'form', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#newFormLegacy', 'url' => $apiBase . 'form', 'verb' => 'POST', 'requirements' => [
'apiVersion_path' => 'v2(\.[1-4])?' 'apiVersion_path' => 'v2(\.[1-5])?'
]], ]],
['name' => 'api#getFormLegacy', 'url' => $apiBase . 'form/{id}', 'verb' => 'GET', 'requirements' => [ ['name' => 'api#getFormLegacy', 'url' => $apiBase . 'form/{id}', 'verb' => 'GET', 'requirements' => [
'apiVersion_path' => 'v2(\.[1-4])?', 'apiVersion_path' => 'v2(\.[1-5])?',
'id' => '\d+' 'id' => '\d+'
]], ]],
['name' => 'api#cloneFormLegacy', 'url' => $apiBase . 'form/clone/{id}', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#cloneFormLegacy', 'url' => $apiBase . 'form/clone/{id}', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?', 'apiVersion' => 'v2(\.[1-5])?',
'id' => '\d+' 'id' => '\d+'
]], ]],
['name' => 'api#updateFormLegacy', 'url' => $apiBase . 'form/update', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#updateFormLegacy', 'url' => $apiBase . 'form/update', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?' 'apiVersion' => 'v2(\.[1-5])?'
]], ]],
['name' => 'api#updateFormLegacy', 'url' => $apiBase . 'form/update', 'verb' => 'PATCH', 'requirements' => [ ['name' => 'api#updateFormLegacy', 'url' => $apiBase . 'form/update', 'verb' => 'PATCH', 'requirements' => [
'apiVersion' => 'v2\.[2-4]' 'apiVersion' => 'v2\.[2-5]'
]], ]],
['name' => 'api#transferOwnerLegacy', 'url' => $apiBase . 'form/transfer', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#transferOwnerLegacy', 'url' => $apiBase . 'form/transfer', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2\.[2-4]' 'apiVersion' => 'v2\.[2-5]'
]], ]],
['name' => 'api#deleteFormLegacy', 'url' => $apiBase . 'form/{id}', 'verb' => 'DELETE', 'requirements' => [ ['name' => 'api#deleteFormLegacy', 'url' => $apiBase . 'form/{id}', 'verb' => 'DELETE', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?', 'apiVersion' => 'v2(\.[1-5])?',
'id' => '\d+' 'id' => '\d+'
]], ]],
['name' => 'api#getPartialFormLegacy', 'url' => $apiBase . 'partial_form/{hash}', 'verb' => 'GET', 'requirements' => [ ['name' => 'api#getPartialFormLegacy', 'url' => $apiBase . 'partial_form/{hash}', 'verb' => 'GET', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?', 'apiVersion' => 'v2(\.[1-5])?',
'hash' => '[a-zA-Z0-9]{16}' 'hash' => '[a-zA-Z0-9]{16}'
]], ]],
['name' => 'api#getSharedFormsLegacy', 'url' => $apiBase . 'shared_forms', 'verb' => 'GET', 'requirements' => [ ['name' => 'api#getSharedFormsLegacy', 'url' => $apiBase . 'shared_forms', 'verb' => 'GET', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?' 'apiVersion' => 'v2(\.[1-5])?'
]], ]],
// Questions // Questions
['name' => 'api#newQuestionLegacy', 'url' => $apiBase . 'question', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#newQuestionLegacy', 'url' => $apiBase . 'question', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?' 'apiVersion' => 'v2(\.[1-5])?'
]], ]],
// TODO: Remove POST in next API release // TODO: Remove POST in next API release
['name' => 'api#updateQuestionLegacy', 'url' => $apiBase . 'question/update', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#updateQuestionLegacy', 'url' => $apiBase . 'question/update', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?' 'apiVersion' => 'v2(\.[1-5])?'
]], ]],
['name' => 'api#updateQuestionLegacy', 'url' => $apiBase . 'question/update', 'verb' => 'PATCH', 'requirements' => [ ['name' => 'api#updateQuestionLegacy', 'url' => $apiBase . 'question/update', 'verb' => 'PATCH', 'requirements' => [
'apiVersion' => 'v2\.[2-4]' 'apiVersion' => 'v2\.[2-5]'
]], ]],
// TODO: Remove POST in next API release // TODO: Remove POST in next API release
['name' => 'api#reorderQuestionsLegacy', 'url' => $apiBase . 'question/reorder', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#reorderQuestionsLegacy', 'url' => $apiBase . 'question/reorder', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?' 'apiVersion' => 'v2(\.[1-5])?'
]], ]],
['name' => 'api#reorderQuestionsLegacy', 'url' => $apiBase . 'question/reorder', 'verb' => 'PUT', 'requirements' => [ ['name' => 'api#reorderQuestionsLegacy', 'url' => $apiBase . 'question/reorder', 'verb' => 'PUT', 'requirements' => [
'apiVersion' => 'v2\.[2-4]' 'apiVersion' => 'v2\.[2-5]'
]], ]],
['name' => 'api#deleteQuestionLegacy', 'url' => $apiBase . 'question/{id}', 'verb' => 'DELETE', 'requirements' => [ ['name' => 'api#deleteQuestionLegacy', 'url' => $apiBase . 'question/{id}', 'verb' => 'DELETE', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?', 'apiVersion' => 'v2(\.[1-5])?',
'id' => '\d+' 'id' => '\d+'
]], ]],
['name' => 'api#cloneQuestionLegacy', 'url' => $apiBase . 'question/clone/{id}', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#cloneQuestionLegacy', 'url' => $apiBase . 'question/clone/{id}', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2\.[3-4]', 'apiVersion' => 'v2\.[3-5]',
'id' => '\d+' 'id' => '\d+'
]], ]],
// Options // Options
['name' => 'api#newOptionLegacy', 'url' => $apiBase . 'option', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#newOptionLegacy', 'url' => $apiBase . 'option', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?' 'apiVersion' => 'v2(\.[1-5])?'
]], ]],
// TODO: Remove POST in next API release // TODO: Remove POST in next API release
['name' => 'api#updateOptionLegacy', 'url' => $apiBase . 'option/update', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#updateOptionLegacy', 'url' => $apiBase . 'option/update', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?' 'apiVersion' => 'v2(\.[1-5])?'
]], ]],
['name' => 'api#updateOptionLegacy', 'url' => $apiBase . 'option/update', 'verb' => 'PATCH', 'requirements' => [ ['name' => 'api#updateOptionLegacy', 'url' => $apiBase . 'option/update', 'verb' => 'PATCH', 'requirements' => [
'apiVersion' => 'v2\.[2-4]' 'apiVersion' => 'v2\.[2-5]'
]], ]],
['name' => 'api#deleteOptionLegacy', 'url' => $apiBase . 'option/{id}', 'verb' => 'DELETE', 'requirements' => [ ['name' => 'api#deleteOptionLegacy', 'url' => $apiBase . 'option/{id}', 'verb' => 'DELETE', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?', 'apiVersion' => 'v2(\.[1-5])?',
'id' => '\d+' 'id' => '\d+'
]], ]],
// Shares // Shares
['name' => 'shareApi#newShareLegacy', 'url' => $apiBase . 'share', 'verb' => 'POST', 'requirements' => [ ['name' => 'shareApi#newShareLegacy', 'url' => $apiBase . 'share', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?' 'apiVersion' => 'v2(\.[1-5])?'
]], ]],
['name' => 'shareApi#deleteShareLegacy', 'url' => $apiBase . 'share/{id}', 'verb' => 'DELETE', 'requirements' => [ ['name' => 'shareApi#deleteShareLegacy', 'url' => $apiBase . 'share/{id}', 'verb' => 'DELETE', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?', 'apiVersion' => 'v2(\.[1-5])?',
'id' => '\d+' 'id' => '\d+'
]], ]],
// TODO: Remove POST in next API release // TODO: Remove POST in next API release
['name' => 'shareApi#updateShareLegacy', 'url' => $apiBase . 'share/update', 'verb' => 'POST', 'requirements' => [ ['name' => 'shareApi#updateShareLegacy', 'url' => $apiBase . 'share/update', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2\.[1-4]' 'apiVersion' => 'v2\.[1-5]'
]], ]],
['name' => 'shareApi#updateShareLegacy', 'url' => $apiBase . 'share/update', 'verb' => 'PATCH', 'requirements' => [ ['name' => 'shareApi#updateShareLegacy', 'url' => $apiBase . 'share/update', 'verb' => 'PATCH', 'requirements' => [
'apiVersion' => 'v2\.[2-4]' 'apiVersion' => 'v2\.[2-5]'
]], ]],
// Submissions // Submissions
['name' => 'api#getSubmissionsLegacy', 'url' => $apiBase . 'submissions/{hash}', 'verb' => 'GET', 'requirements' => [ ['name' => 'api#getSubmissionsLegacy', 'url' => $apiBase . 'submissions/{hash}', 'verb' => 'GET', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?', 'apiVersion' => 'v2(\.[1-5])?',
'hash' => '[a-zA-Z0-9]{16}' 'hash' => '[a-zA-Z0-9]{16}'
]], ]],
['name' => 'api#exportSubmissionsLegacy', 'url' => $apiBase . 'submissions/export/{hash}', 'verb' => 'GET', 'requirements' => [ ['name' => 'api#exportSubmissionsLegacy', 'url' => $apiBase . 'submissions/export/{hash}', 'verb' => 'GET', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?', 'apiVersion' => 'v2(\.[1-5])?',
'hash' => '[a-zA-Z0-9]{16}' 'hash' => '[a-zA-Z0-9]{16}'
]], ]],
['name' => 'api#exportSubmissionsToCloudLegacy', 'url' => $apiBase . 'submissions/export', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#exportSubmissionsToCloudLegacy', 'url' => $apiBase . 'submissions/export', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?' 'apiVersion' => 'v2(\.[1-5])?'
]], ]],
['name' => 'api#deleteAllSubmissionsLegacy', 'url' => $apiBase . 'submissions/{formId}', 'verb' => 'DELETE', 'requirements' => [ ['name' => 'api#deleteAllSubmissionsLegacy', 'url' => $apiBase . 'submissions/{formId}', 'verb' => 'DELETE', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?', 'apiVersion' => 'v2(\.[1-5])?',
'formId' => '\d+' 'formId' => '\d+'
]], ]],
['name' => 'api#uploadFilesLegacy', 'url' => $apiBase . 'uploadFiles/{formId}/{questionId}', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#uploadFilesLegacy', 'url' => $apiBase . 'uploadFiles/{formId}/{questionId}', 'verb' => 'POST', 'requirements' => [
@ -222,19 +222,19 @@ return [
'questionId' => '\d+' 'questionId' => '\d+'
]], ]],
['name' => 'api#insertSubmissionLegacy', 'url' => $apiBase . 'submission/insert', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#insertSubmissionLegacy', 'url' => $apiBase . 'submission/insert', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?' 'apiVersion' => 'v2(\.[1-5])?'
]], ]],
['name' => 'api#deleteSubmissionLegacy', 'url' => $apiBase . 'submission/{id}', 'verb' => 'DELETE', 'requirements' => [ ['name' => 'api#deleteSubmissionLegacy', 'url' => $apiBase . 'submission/{id}', 'verb' => 'DELETE', 'requirements' => [
'apiVersion' => 'v2(\.[1-4])?', 'apiVersion' => 'v2(\.[1-5])?',
'id' => '\d+' 'id' => '\d+'
]], ]],
// Submissions linking with file in cloud // Submissions linking with file in cloud
['name' => 'api#linkFileLegacy', 'url' => $apiBase . 'form/link/{fileFormat}', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#linkFileLegacy', 'url' => $apiBase . 'form/link/{fileFormat}', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2.4', 'apiVersion' => 'v2.[4-5]',
'fileFormat' => 'csv|ods|xlsx' 'fileFormat' => 'csv|ods|xlsx'
]], ]],
['name' => 'api#unlinkFileLegacy', 'url' => $apiBase . 'form/unlink', 'verb' => 'POST', 'requirements' => [ ['name' => 'api#unlinkFileLegacy', 'url' => $apiBase . 'form/unlink', 'verb' => 'POST', 'requirements' => [
'apiVersion' => 'v2.4', 'apiVersion' => 'v2.[4-5]',
]] ]]
] ]
]; ];

Просмотреть файл

@ -41,6 +41,8 @@ This file contains the API-Documentation. For more information on the returned D
- In API version 2.5 the following endpoints were introduced: - In API version 2.5 the following endpoints were introduced:
- `POST /api/2.5/uploadFiles/{formId}/{questionId}` to upload files to answer before form submitting - `POST /api/2.5/uploadFiles/{formId}/{questionId}` to upload files to answer before form submitting
- In API version 2.5 the following change was made:
- Options now contain a property `order`
- In API version 2.4 the following endpoints were introduced: - In API version 2.4 the following endpoints were introduced:
- `POST /api/2.4/form/link/{fileFormat}` to link form to a file - `POST /api/2.4/form/link/{fileFormat}` to link form to a file
- `POST /api/2.4/form/unlink` to unlink form from a file - `POST /api/2.4/form/unlink` to unlink form from a file
@ -58,7 +60,7 @@ This file contains the API-Documentation. For more information on the returned D
Returns condensed objects of all Forms beeing owned by the authenticated user. Returns condensed objects of all Forms beeing owned by the authenticated user.
- Endpoint: `/api/v2.4/forms` - Endpoint: `/api/v2.5/forms`
- Method: `GET` - Method: `GET`
- Parameters: None - Parameters: None
- Response: Array of condensed Form Objects, sorted as newest first. - Response: Array of condensed Form Objects, sorted as newest first.
@ -98,7 +100,7 @@ Returns condensed objects of all Forms beeing owned by the authenticated user.
Returns condensed objects of all Forms, that are shared & shown to the authenticated user and that have not expired yet. Returns condensed objects of all Forms, that are shared & shown to the authenticated user and that have not expired yet.
- Endpoint: `/api/v2.4/shared_forms` - Endpoint: `/api/v2.5/shared_forms`
- Method: `GET` - Method: `GET`
- Parameters: None - Parameters: None
- Response: Array of condensed Form Objects, sorted as newest first, similar to [List owned Forms](#list-owned-forms). - Response: Array of condensed Form Objects, sorted as newest first, similar to [List owned Forms](#list-owned-forms).
@ -111,7 +113,7 @@ See above, 'List owned forms'
Returns a single partial form object, corresponding to owned/shared form-listings. Returns a single partial form object, corresponding to owned/shared form-listings.
- Endpoint: `/api/v2.4/partial_form/{hash}` - Endpoint: `/api/v2.5/partial_form/{hash}`
- Method: `GET` - Method: `GET`
- Url-Parameter: - Url-Parameter:
| Parameter | Type | Description | | Parameter | Type | Description |
@ -135,7 +137,7 @@ Returns a single partial form object, corresponding to owned/shared form-listing
### Create a new Form ### Create a new Form
- Endpoint: `/api/v2.4/form` - Endpoint: `/api/v2.5/form`
- Method: `POST` - Method: `POST`
- Parameters: None - Parameters: None
- Response: The new form object, similar to requesting an existing form. - Response: The new form object, similar to requesting an existing form.
@ -148,7 +150,7 @@ See next section, 'Request full data of a form'
Returns the full-depth object of the requested form (without submissions). Returns the full-depth object of the requested form (without submissions).
- Endpoint: `/api/v2.4/form/{id}` - Endpoint: `/api/v2.5/form/{id}`
- Url-Parameter: - Url-Parameter:
| Parameter | Type | Description | | Parameter | Type | Description |
|-----------|---------|-------------| |-----------|---------|-------------|
@ -196,12 +198,14 @@ Returns the full-depth object of the requested form (without submissions).
{ {
"id": 1, "id": 1,
"questionId": 1, "questionId": 1,
"text": "Option 1" "text": "Option 1",
"order": null
}, },
{ {
"id": 2, "id": 2,
"questionId": 1, "questionId": 1,
"text": "Option 2" "text": "Option 2",
"order": null
} }
], ],
"accept": [], "accept": [],
@ -243,7 +247,7 @@ Returns the full-depth object of the requested form (without submissions).
Creates a clone of a form (without submissions). Creates a clone of a form (without submissions).
- Endpoint: `/api/v2.4/form/clone/{id}` - Endpoint: `/api/v2.5/form/clone/{id}`
- Url-Parameter: - Url-Parameter:
| Parameter | Type | Description | | Parameter | Type | Description |
|-----------|---------|-------------| |-----------|---------|-------------|
@ -259,7 +263,7 @@ See section 'Request full data of a form'.
Update a single or multiple properties of a form-object. Concerns **only** the Form-Object, properties of Questions, Options and Submissions, as well as their creation or deletion, are handled separately. Update a single or multiple properties of a form-object. Concerns **only** the Form-Object, properties of Questions, Options and Submissions, as well as their creation or deletion, are handled separately.
- Endpoint: `/api/v2.4/form/update` - Endpoint: `/api/v2.5/form/update`
- Method: `PATCH` - Method: `PATCH`
- _Method: `POST` deprecated_ - _Method: `POST` deprecated_
- Parameters: - Parameters:
@ -278,7 +282,7 @@ Update a single or multiple properties of a form-object. Concerns **only** the F
Transfer the ownership of a form to another user Transfer the ownership of a form to another user
- Endpoint: `/api/v2.4/form/transfer` - Endpoint: `/api/v2.5/form/transfer`
- Method: `POST` - Method: `POST`
- Parameters: - Parameters:
| Parameter | Type | Description | | Parameter | Type | Description |
@ -294,7 +298,7 @@ Transfer the ownership of a form to another user
### Delete a form ### Delete a form
- Endpoint: `/api/v2.4/form/{id}` - Endpoint: `/api/v2.5/form/{id}`
- Url-Parameter: - Url-Parameter:
| Parameter | Type | Description | | Parameter | Type | Description |
|-----------|---------|-------------| |-----------|---------|-------------|
@ -308,7 +312,7 @@ Transfer the ownership of a form to another user
### Link a form to a file ### Link a form to a file
- Endpoint: `/api/v2.4/form/link/{fileFormat}` - Endpoint: `/api/v2.5/form/link/{fileFormat}`
- Url-Parameter: - Url-Parameter:
| Parameter | Type | Description | | Parameter | Type | Description |
|--------------|---------|--------------| |--------------|---------|--------------|
@ -332,7 +336,7 @@ Transfer the ownership of a form to another user
### Unlink file from form ### Unlink file from form
- Endpoint: `/api/v2.4/form/unlink` - Endpoint: `/api/v2.5/form/unlink`
- Method: `POST` - Method: `POST`
- Parameters: - Parameters:
| Parameter | Type | Description | | Parameter | Type | Description |
@ -346,7 +350,7 @@ Contains only manipulative question-endpoints. To retrieve questions, request th
### Create a new question ### Create a new question
- Endpoint: `/api/v2.4/question` - Endpoint: `/api/v2.5/question`
- Method: `POST` - Method: `POST`
- Parameters: - Parameters:
| Parameter | Type | Optional | Description | | Parameter | Type | Optional | Description |
@ -374,7 +378,7 @@ Contains only manipulative question-endpoints. To retrieve questions, request th
Update a single or multiple properties of a question-object. Update a single or multiple properties of a question-object.
- Endpoint: `/api/v2.4/question/update` - Endpoint: `/api/v2.5/question/update`
- Method: `PATCH` - Method: `PATCH`
- _Method: `POST` deprecated_ - _Method: `POST` deprecated_
- Parameters: - Parameters:
@ -393,7 +397,7 @@ Update a single or multiple properties of a question-object.
Reorders all Questions of a single form Reorders all Questions of a single form
- Endpoint: `/api/v2.4/question/reorder` - Endpoint: `/api/v2.5/question/reorder`
- Method: `PUT` - Method: `PUT`
- _Method: `POST` deprecated_ - _Method: `POST` deprecated_
- Parameters: - Parameters:
@ -420,7 +424,7 @@ Reorders all Questions of a single form
### Delete a question ### Delete a question
- Endpoint: `/api/v2.4/question/{id}` - Endpoint: `/api/v2.5/question/{id}`
- Url-Parameter: - Url-Parameter:
| Parameter | Type | Description | | Parameter | Type | Description |
|-----------|---------|-------------| |-----------|---------|-------------|
@ -436,7 +440,7 @@ Reorders all Questions of a single form
Creates a clone of a question with all its options. Creates a clone of a question with all its options.
- Endpoint: `/api/v2.4/question/clone/{id}` - Endpoint: `/api/v2.5/question/clone/{id}`
- Url-Parameter: - Url-Parameter:
| Parameter | Type | Description | | Parameter | Type | Description |
|-----------|---------|-------------| |-----------|---------|-------------|
@ -454,7 +458,7 @@ Contains only manipulative question-endpoints. To retrieve options, request the
### Create a new Option ### Create a new Option
- Endpoint: `/api/v2.4/option` - Endpoint: `/api/v2.5/option`
- Method: `POST` - Method: `POST`
- Parameters: - Parameters:
| Parameter | Type | Description | | Parameter | Type | Description |
@ -475,7 +479,7 @@ Contains only manipulative question-endpoints. To retrieve options, request the
Update a single or all properties of an option-object Update a single or all properties of an option-object
- Endpoint: `/api/v2.4/option/update` - Endpoint: `/api/v2.5/option/update`
- Method: `PATCH` - Method: `PATCH`
- _Method: `POST` deprecated_ - _Method: `POST` deprecated_
- Parameters: - Parameters:
@ -492,7 +496,7 @@ Update a single or all properties of an option-object
### Delete an option ### Delete an option
- Endpoint: `/api/v2.4/option/{id}` - Endpoint: `/api/v2.5/option/{id}`
- Url-Parameter: - Url-Parameter:
| Parameter | Type | Description | | Parameter | Type | Description |
|-----------|---------|-------------| |-----------|---------|-------------|
@ -508,7 +512,7 @@ Update a single or all properties of an option-object
### Add a new Share ### Add a new Share
- Endpoint: `/api/v2.4/share` - Endpoint: `/api/v2.5/share`
- Method: `POST` - Method: `POST`
- Parameters: - Parameters:
| Parameter | Type | Description | | Parameter | Type | Description |
@ -532,7 +536,7 @@ Update a single or all properties of an option-object
### Delete a Share ### Delete a Share
- Endpoint: `/api/v2.4/share/{id}` - Endpoint: `/api/v2.5/share/{id}`
- Url-Parameter: - Url-Parameter:
| Parameter | Type | Description | | Parameter | Type | Description |
|-----------|---------|-------------| |-----------|---------|-------------|
@ -546,7 +550,7 @@ Update a single or all properties of an option-object
### Update a Share ### Update a Share
- Endpoint: `/api/v2.4/share/update` - Endpoint: `/api/v2.5/share/update`
- Parameters: - Parameters:
| Parameter | Type | Description | | Parameter | Type | Description |
|------------------|----------|-------------| |------------------|----------|-------------|
@ -569,7 +573,7 @@ Update a single or all properties of an option-object
Get all Submissions to a Form Get all Submissions to a Form
- Endpoint: `/api/v2.4/submissions/{hash}` - Endpoint: `/api/v2.5/submissions/{hash}`
- Url-Parameter: - Url-Parameter:
| Parameter | Type | Description | | Parameter | Type | Description |
|-----------|---------|-------------| |-----------|---------|-------------|
@ -635,17 +639,20 @@ Get all Submissions to a Form
{ {
"id": 1, "id": 1,
"questionId": 1, "questionId": 1,
"text": "Option 1" "text": "Option 1",
"order": null
}, },
{ {
"id": 27, "id": 27,
"questionId": 1, "questionId": 1,
"text": "Option 2" "text": "Option 2",
"order": null
}, },
{ {
"id": 30, "id": 30,
"questionId": 1, "questionId": 1,
"text": "Option 3" "text": "Option 3",
"order": null
} }
], ],
"extraSettings": {} "extraSettings": {}
@ -668,7 +675,7 @@ Get all Submissions to a Form
Returns all submissions to the form in form of a csv-file. Returns all submissions to the form in form of a csv-file.
- Endpoint: `/api/v2.4/submissions/export/{hash}` - Endpoint: `/api/v2.5/submissions/export/{hash}`
- Url-Parameter: - Url-Parameter:
| Parameter | Type | Description | | Parameter | Type | Description |
|--------------|---------|-------------| |--------------|---------|-------------|
@ -687,7 +694,7 @@ Returns all submissions to the form in form of a csv-file.
Creates a csv file and stores it to the cloud, resp. Files-App. Creates a csv file and stores it to the cloud, resp. Files-App.
- Endpoint: `/api/v2.4/submissions/export` - Endpoint: `/api/v2.5/submissions/export`
- Method: `POST` - Method: `POST`
- Parameters: - Parameters:
| Parameter | Type | Description | | Parameter | Type | Description |
@ -705,7 +712,7 @@ Creates a csv file and stores it to the cloud, resp. Files-App.
Delete all Submissions to a form Delete all Submissions to a form
- Endpoint: `/api/v2.4/submissions/{formId}` - Endpoint: `/api/v2.5/submissions/{formId}`
- Url-Parameter: - Url-Parameter:
| Parameter | Type | Description | | Parameter | Type | Description |
|-----------|---------|-------------| |-----------|---------|-------------|
@ -739,7 +746,7 @@ Upload a files to answer before form submitting
Store Submission to Database Store Submission to Database
- Endpoint: `/api/v2.4/submission/insert` - Endpoint: `/api/v2.5/submission/insert`
- Method: `POST` - Method: `POST`
- Parameters: - Parameters:
| Parameter | Type | Description | | Parameter | Type | Description |
@ -771,7 +778,7 @@ Store Submission to Database
### Delete a single Submission ### Delete a single Submission
- Endpoint: `/api/v2.4/submission/{id}` - Endpoint: `/api/v2.5/submission/{id}`
- Url-Parameter: - Url-Parameter:
| Parameter | Type | Description | | Parameter | Type | Description |
|-----------|---------|-------------| |-----------|---------|-------------|

Просмотреть файл

@ -46,6 +46,7 @@ This file contains the API-Documentation. For more information on the returned D
- `GET /api/v3/forms/{formId}/questions` to get all questions of a form - `GET /api/v3/forms/{formId}/questions` to get all questions of a form
- `GET /api/v3/forms/{formId}/questions/{questionId}` to get a single question - `GET /api/v3/forms/{formId}/questions/{questionId}` to get a single question
- `POST /api/v3/forms/{formId}/questions/{questionId}/options` does now accept more options at once - `POST /api/v3/forms/{formId}/questions/{questionId}/options` does now accept more options at once
- `PATCH /api/v3/forms/{formId}/questions/{questionId}/options/reorder` to reorder the options
- `POST /api/v3/forms/{formId}/submissions/files/{questionId}` to upload a file to a file question before submitting the form - `POST /api/v3/forms/{formId}/submissions/files/{questionId}` to upload a file to a file question before submitting the form
- In API version 2.5 the following endpoints were introduced: - In API version 2.5 the following endpoints were introduced:
- `POST /api/v2.5/uploadFiles/{formId}/{questionId}` to upload files to answer before form submitting - `POST /api/v2.5/uploadFiles/{formId}/{questionId}` to upload files to answer before form submitting
@ -178,12 +179,14 @@ Returns the full-depth object of the requested form (without submissions).
{ {
"id": 1, "id": 1,
"questionId": 1, "questionId": 1,
"text": "Option 1" "text": "Option 1",
"order": null
}, },
{ {
"id": 2, "id": 2,
"questionId": 1, "questionId": 1,
"text": "Option 2" "text": "Option 2",
"order": null
} }
], ],
"accept": [], "accept": [],
@ -304,12 +307,14 @@ Returns the questions and options of the given form (without submissions).
{ {
"id": 1, "id": 1,
"questionId": 1, "questionId": 1,
"text": "Option 1" "text": "Option 1",
"order": null
}, },
{ {
"id": 2, "id": 2,
"questionId": 1, "questionId": 1,
"text": "Option 2" "text": "Option 2",
"order": null
} }
], ],
"accept": [], "accept": [],
@ -385,12 +390,14 @@ Returns the requested question and options of the given form (without submission
{ {
"id": 1, "id": 1,
"questionId": 1, "questionId": 1,
"text": "Option 1" "text": "Option 1",
"order": null
}, },
{ {
"id": 2, "id": 2,
"questionId": 1, "questionId": 1,
"text": "Option 2" "text": "Option 2"
"order": null
} }
], ],
"accept": [], "accept": [],
@ -549,6 +556,22 @@ Update a single or all properties of an option-object
"data": 7 "data": 7
``` ```
### Reorder options
- Endpoint: `/api/v3/forms/{formId}/questions/{questionId}/options/reorder`
- Method: `PATCH`
- Url-Parameter:
| Parameter | Type | Description |
|-----------|---------|-------------|
| _formId_ | Integer | ID of the form containing the question and option |
| _questionId_ | Integer | ID of the question, the new option will belong to |
- Parameters:
| Parameter | Type | Description |
|-----------|---------|-------------|
| _newOrder_ | Array | Array of **all** option IDs, ordered in the desired order |
- Restrictions: The Array **must** contain all option IDs corresponding to the specified question and **must not** contain any duplicates.
- Response: Array of optionIds and their corresponding order.
## Sharing Endpoints ## Sharing Endpoints
### Add a new Share ### Add a new Share
@ -685,17 +708,20 @@ Get all Submissions to a Form
{ {
"id": 1, "id": 1,
"questionId": 1, "questionId": 1,
"text": "Option 1" "text": "Option 1",
"order": null
}, },
{ {
"id": 27, "id": 27,
"questionId": 1, "questionId": 1,
"text": "Option 2" "text": "Option 2",
"order": null
}, },
{ {
"id": 30, "id": 30,
"questionId": 1, "questionId": 1,
"text": "Option 3" "text": "Option 3",
"order": null
} }
], ],
"extraSettings": {} "extraSettings": {}

Просмотреть файл

@ -764,12 +764,22 @@ class ApiController extends OCSController {
throw new OCSBadRequestException(); throw new OCSBadRequestException();
} }
// Retrieve all options sorted by 'order'. Takes the order of the last array-element and adds one.
$options = $this->optionMapper->findByQuestion($questionId);
$lastOption = array_pop($options);
if ($lastOption) {
$optionOrder = $lastOption->getOrder() + 1;
} else {
$optionOrder = 1;
}
$addedOptions = []; $addedOptions = [];
foreach ($optionTexts as $text) { foreach ($optionTexts as $text) {
$option = new Option(); $option = new Option();
$option->setQuestionId($questionId); $option->setQuestionId($questionId);
$option->setText($text); $option->setText($text);
$option->setOrder($optionOrder++);
try { try {
$option = $this->optionMapper->insert($option); $option = $this->optionMapper->insert($option);
@ -889,11 +899,104 @@ class ApiController extends OCSController {
} }
$this->optionMapper->delete($option); $this->optionMapper->delete($option);
// Reorder the remaining options
$options = array_values($this->optionMapper->findByQuestion($questionId));
foreach ($options as $order => $option) {
// Always start order with 1
$option->setOrder($order + 1);
$this->optionMapper->update($option);
}
$this->formMapper->update($form); $this->formMapper->update($form);
return new DataResponse($optionId); return new DataResponse($optionId);
} }
/**
* Reorder options for a given question
* @param int $formId id of form
* @param int $questionId id of question
* @param Array<int, int> $newOrder Order to use
*/
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();
}
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');
}
if ($question->getFormId() !== $formId) {
$this->logger->debug('The given question id doesn\'t match the form.');
throw new OCSBadRequestException();
}
// Check if array contains duplicates
if (array_unique($newOrder) !== $newOrder) {
$this->logger->debug('The given array contains duplicates');
throw new OCSBadRequestException('The given array contains duplicates');
}
$options = $this->optionMapper->findByQuestion($questionId);
if (sizeof($options) !== sizeof($newOrder)) {
$this->logger->debug('The length of the given array does not match the number of stored options');
throw new OCSBadRequestException('The length of the given array does not match the number of stored options');
}
$options = []; // Clear Array of Entities
$response = []; // Array of ['optionId' => ['order' => newOrder]]
// Store array of Option entities and check the Options questionId & old order.
foreach ($newOrder as $arrayKey => $optionId) {
try {
$options[$arrayKey] = $this->optionMapper->findById($optionId);
} catch (IMapperException $e) {
$this->logger->debug('Could not find option. Id: {optionId}', [
'optionId' => $optionId
]);
throw new OCSBadRequestException();
}
// Abort if a question is not part of the Form.
if ($options[$arrayKey]->getQuestionId() !== $questionId) {
$this->logger->debug('This Option is not part of the given Question: formId: {formId}', [
'formId' => $formId
]);
throw new OCSBadRequestException();
}
// Abort if a question is already marked as deleted (order==0)
$oldOrder = $options[$arrayKey]->getOrder();
// Only set order, if it changed.
if ($oldOrder !== $arrayKey + 1) {
// Set Order. ArrayKey counts from zero, order counts from 1.
$options[$arrayKey]->setOrder($arrayKey + 1);
}
}
// Write to Database
foreach ($options as $option) {
$this->optionMapper->update($option);
$response[$option->getId()] = [
'order' => $option->getOrder()
];
}
$this->formMapper->update($form);
return new DataResponse($response);
}
// Submissions // Submissions
/** /**
@ -1964,10 +2067,20 @@ class ApiController extends OCSController {
throw new OCSForbiddenException(); throw new OCSForbiddenException();
} }
// Retrieve all options sorted by 'order'. Takes the order of the last array-element and adds one.
$options = $this->optionMapper->findByQuestion($questionId);
$lastOption = array_pop($options);
if ($lastOption) {
$optionOrder = $lastOption->getOrder() + 1;
} else {
$optionOrder = 1;
}
$option = new Option(); $option = new Option();
$option->setQuestionId($questionId); $option->setQuestionId($questionId);
$option->setText($text); $option->setText($text);
$option->setOrder($optionOrder);
$option = $this->optionMapper->insert($option); $option = $this->optionMapper->insert($option);
$this->formMapper->update($form); $this->formMapper->update($form);
@ -2071,6 +2184,15 @@ class ApiController extends OCSController {
} }
$this->optionMapper->delete($option); $this->optionMapper->delete($option);
// Reorder the remaining options
$options = array_values($this->optionMapper->findByQuestion($option->getQuestionId()));
foreach ($options as $order => $option) {
// Always start order with 1
$option->setOrder($order + 1);
$this->optionMapper->update($option);
}
$this->formMapper->update($form); $this->formMapper->update($form);
return new DataResponse($id); return new DataResponse($id);

Просмотреть файл

@ -29,23 +29,29 @@ namespace OCA\Forms\Db;
use OCP\AppFramework\Db\Entity; use OCP\AppFramework\Db\Entity;
/** /**
* @method int getQuestionId() * @method int|float getQuestionId()
* @method void setQuestionId(int $value) * @method void setQuestionId(int|float $value)
* @method string getText() * @method string getText()
* @method void setText(string $value) * @method void setText(string $value)
* @method int getOrder();
* @method void setOrder(int $value)
*/ */
class Option extends Entity { class Option extends Entity {
/** @var int */ // For 32bit PHP long integers, like IDs, are represented by floats
protected $questionId; protected int|float|null $questionId;
/** @var string */ protected ?string $text;
protected $text; protected ?int $order;
/** /**
* Option constructor. * Option constructor.
*/ */
public function __construct() { public function __construct() {
$this->questionId = null;
$this->text = null;
$this->order = null;
$this->addType('questionId', 'integer'); $this->addType('questionId', 'integer');
$this->addType('order', 'integer');
$this->addType('text', 'string'); $this->addType('text', 'string');
} }
@ -53,6 +59,7 @@ class Option extends Entity {
return [ return [
'id' => $this->getId(), 'id' => $this->getId(),
'questionId' => $this->getQuestionId(), 'questionId' => $this->getQuestionId(),
'order' => $this->getOrder(),
'text' => (string)$this->getText(), 'text' => (string)$this->getText(),
]; ];
} }

Просмотреть файл

@ -27,7 +27,6 @@ declare(strict_types=1);
namespace OCA\Forms\Db; namespace OCA\Forms\Db;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\QBMapper; use OCP\AppFramework\Db\QBMapper;
use OCP\IDBConnection; use OCP\IDBConnection;
@ -45,11 +44,10 @@ class OptionMapper extends QBMapper {
} }
/** /**
* @param int $questionId * @param int|float $questionId
* @throws DoesNotExistException if not found
* @return Option[] * @return Option[]
*/ */
public function findByQuestion(int $questionId): array { public function findByQuestion(int|float $questionId): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
@ -57,7 +55,8 @@ class OptionMapper extends QBMapper {
->where( ->where(
$qb->expr()->eq('question_id', $qb->createNamedParameter($questionId)) $qb->expr()->eq('question_id', $qb->createNamedParameter($questionId))
) )
->orderBy('id'); ->orderBy('order')
->addOrderBy('id');
return $this->findEntities($qb); return $this->findEntities($qb);
} }
@ -73,7 +72,10 @@ class OptionMapper extends QBMapper {
$qb->executeStatement(); $qb->executeStatement();
} }
public function findById(int $optionId): Option { /**
* @param int|float $optionId The option ID (int but for 32bit systems PHP will use float)
*/
public function findById(int|float $optionId): Option {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')

Просмотреть файл

@ -90,7 +90,11 @@ class QuestionMapper extends QBMapper {
$qb->executeStatement(); $qb->executeStatement();
} }
public function findById(int $questionId): Question { /**
* Find Question by its ID
* @param int|float $questionId The question ID (int but for 32bit systems PHP uses float)
*/
public function findById(int|float $questionId): Question {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')

Просмотреть файл

@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2024 Ferdinand Thiessen <opensource@fthiessen.de>
*
* @author Ferdinand Thiessen <opensource@fthiessen.de>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Forms\Migration;
use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
/**
* Add "order" column for options
*/
class Version040300Date20240420155356 extends SimpleMigrationStep {
/**
* @param IOutput $output
* @param Closure(): ISchemaWrapper $schemaClosure
* @param array $options
* @return null|ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
$table = $schema->getTable('forms_v2_options');
// Abort if already existing.
if ($table->hasColumn('order')) {
return null;
}
// Create new column
$table->addColumn('order', Types::INTEGER, [
'notnull' => false,
'default' => null,
'unsigned' => true,
]);
// Add index for better performance
$table->addIndex(['question_id', 'order'], 'forms_options_question_order');
return $schema;
}
}

Просмотреть файл

@ -84,13 +84,16 @@ class ApiV2Test extends IntegrationBase {
'order' => 2, 'order' => 2,
'options' => [ 'options' => [
[ [
'text' => 'Option 1' 'text' => 'Option 1',
'order' => 1
], ],
[ [
'text' => 'Option 2' 'text' => 'Option 2',
'order' => 2
], ],
[ [
'text' => '' 'text' => '',
'order' => 3
] ]
], ],
'accept' => [], 'accept' => [],
@ -496,13 +499,16 @@ class ApiV2Test extends IntegrationBase {
'order' => 2, 'order' => 2,
'options' => [ 'options' => [
[ [
'text' => 'Option 1' 'text' => 'Option 1',
'order' => 1,
], ],
[ [
'text' => 'Option 2' 'text' => 'Option 2',
'order' => 2,
], ],
[ [
'text' => '' 'text' => '',
'order' => 3,
] ]
], ],
'accept' => [], 'accept' => [],
@ -906,7 +912,8 @@ class ApiV2Test extends IntegrationBase {
'newOption' => [ 'newOption' => [
'expected' => [ 'expected' => [
// 'questionId' => Done dynamically below. // 'questionId' => Done dynamically below.
'text' => 'A new Option.' 'text' => 'A new Option.',
'order' => 4,
] ]
] ]
]; ];
@ -995,6 +1002,8 @@ class ApiV2Test extends IntegrationBase {
$this->assertEquals($this->testForms[0]['questions'][1]['options'][0]['id'], $data); $this->assertEquals($this->testForms[0]['questions'][1]['options'][0]['id'], $data);
$fullFormExpected['lastUpdated'] = time(); $fullFormExpected['lastUpdated'] = time();
$fullFormExpected['questions'][1]['options'][0]['order'] = 1;
$fullFormExpected['questions'][1]['options'][1]['order'] = 2;
$this->testGetFullForm($fullFormExpected); $this->testGetFullForm($fullFormExpected);
} }

Просмотреть файл

@ -84,13 +84,16 @@ class ApiV3Test extends IntegrationBase {
'order' => 2, 'order' => 2,
'options' => [ 'options' => [
[ [
'text' => 'Option 1' 'text' => 'Option 1',
'order' => 1
], ],
[ [
'text' => 'Option 2' 'text' => 'Option 2',
'order' => 2
], ],
[ [
'text' => '' 'text' => '',
'order' => 3
] ]
], ],
'accept' => [], 'accept' => [],
@ -464,13 +467,16 @@ class ApiV3Test extends IntegrationBase {
'order' => 2, 'order' => 2,
'options' => [ 'options' => [
[ [
'text' => 'Option 1' 'text' => 'Option 1',
'order' => 1,
], ],
[ [
'text' => 'Option 2' 'text' => 'Option 2',
'order' => 2,
], ],
[ [
'text' => '' 'text' => '',
'order' => 3,
] ]
], ],
'accept' => [], 'accept' => [],
@ -870,7 +876,8 @@ class ApiV3Test extends IntegrationBase {
'newOption' => [ 'newOption' => [
'expected' => [ 'expected' => [
// 'questionId' => Done dynamically below. // 'questionId' => Done dynamically below.
'text' => 'A new Option.' 'text' => 'A new Option.',
'order' => 4,
] ]
] ]
]; ];
@ -957,6 +964,8 @@ class ApiV3Test extends IntegrationBase {
$this->assertEquals($this->testForms[0]['questions'][1]['options'][0]['id'], $data); $this->assertEquals($this->testForms[0]['questions'][1]['options'][0]['id'], $data);
$fullFormExpected['lastUpdated'] = time(); $fullFormExpected['lastUpdated'] = time();
$fullFormExpected['questions'][1]['options'][0]['order'] = 1;
$fullFormExpected['questions'][1]['options'][1]['order'] = 2;
$this->testGetFullForm($fullFormExpected); $this->testGetFullForm($fullFormExpected);
} }

Просмотреть файл

@ -104,7 +104,8 @@ class IntegrationBase extends TestCase {
$qb->insert('forms_v2_options') $qb->insert('forms_v2_options')
->values([ ->values([
'question_id' => $qb->createNamedParameter($questionId, IQueryBuilder::PARAM_INT), 'question_id' => $qb->createNamedParameter($questionId, IQueryBuilder::PARAM_INT),
'text' => $qb->createNamedParameter($option['text'], IQueryBuilder::PARAM_STR) 'text' => $qb->createNamedParameter($option['text'], IQueryBuilder::PARAM_STR),
'order' => $qb->createNamedParameter($option['order'], IQueryBuilder::PARAM_INT)
]); ]);
$qb->executeStatement(); $qb->executeStatement();
$this->testForms[$index]['questions'][$qIndex]['options'][$oIndex]['id'] = $qb->getLastInsertId(); $this->testForms[$index]['questions'][$qIndex]['options'][$oIndex]['id'] = $qb->getLastInsertId();

Просмотреть файл

@ -228,12 +228,14 @@ class FormsServiceTest extends TestCase {
[ [
'id' => 1, 'id' => 1,
'questionId' => 1, 'questionId' => 1,
'text' => 'Option 1' 'text' => 'Option 1',
'order' => null,
], ],
[ [
'id' => 2, 'id' => 2,
'questionId' => 1, 'questionId' => 1,
'text' => 'Option 2' 'text' => 'Option 2',
'order' => null,
] ]
], ],
'accept' => [], 'accept' => [],