зеркало из https://github.com/nextcloud/forms.git
chore: remove API v2
Signed-off-by: Christian Hartmann <chris-hartmann@gmx.de>
This commit is contained in:
Родитель
cc5eadc534
Коммит
80fa593094
|
@ -59,7 +59,7 @@ return [
|
|||
// CORS Preflight
|
||||
['name' => 'api#preflightedCors', 'url' => $apiBase . '{path}', 'verb' => 'OPTIONS', 'requirements' => [
|
||||
'path' => '.+',
|
||||
'apiVersion' => 'v2(\.[1-5])?|v3'
|
||||
'apiVersion' => 'v3'
|
||||
]],
|
||||
|
||||
// API routes v3
|
||||
|
@ -103,138 +103,5 @@ return [
|
|||
['name' => 'api#deleteSubmission', 'url' => $apiBase . 'forms/{formId}/submissions/{submissionId}', 'verb' => 'DELETE', 'requirements' => $requirements_v3],
|
||||
['name' => 'api#exportSubmissionsToCloud', 'url' => $apiBase . 'forms/{formId}/submissions/export', 'verb' => 'POST', 'requirements' => $requirements_v3],
|
||||
['name' => 'api#uploadFiles', 'url' => $apiBase . 'forms/{formId}/submissions/files/{questionId}', 'verb' => 'POST', 'requirements' => $requirements_v3],
|
||||
|
||||
// Legacy v2 routes (TODO: remove with Forms v5)
|
||||
// Forms
|
||||
['name' => 'api#getFormsLegacy', 'url' => $apiBase . 'forms', 'verb' => 'GET', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?'
|
||||
]],
|
||||
['name' => 'api#newFormLegacy', 'url' => $apiBase . 'form', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion_path' => 'v2(\.[1-5])?'
|
||||
]],
|
||||
['name' => 'api#getFormLegacy', 'url' => $apiBase . 'form/{id}', 'verb' => 'GET', 'requirements' => [
|
||||
'apiVersion_path' => 'v2(\.[1-5])?',
|
||||
'id' => '\d+'
|
||||
]],
|
||||
['name' => 'api#cloneFormLegacy', 'url' => $apiBase . 'form/clone/{id}', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?',
|
||||
'id' => '\d+'
|
||||
]],
|
||||
['name' => 'api#updateFormLegacy', 'url' => $apiBase . 'form/update', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?'
|
||||
]],
|
||||
['name' => 'api#updateFormLegacy', 'url' => $apiBase . 'form/update', 'verb' => 'PATCH', 'requirements' => [
|
||||
'apiVersion' => 'v2\.[2-5]'
|
||||
]],
|
||||
['name' => 'api#transferOwnerLegacy', 'url' => $apiBase . 'form/transfer', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2\.[2-5]'
|
||||
]],
|
||||
['name' => 'api#deleteFormLegacy', 'url' => $apiBase . 'form/{id}', 'verb' => 'DELETE', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?',
|
||||
'id' => '\d+'
|
||||
]],
|
||||
['name' => 'api#getPartialFormLegacy', 'url' => $apiBase . 'partial_form/{hash}', 'verb' => 'GET', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?',
|
||||
'hash' => '[a-zA-Z0-9]{16}'
|
||||
]],
|
||||
['name' => 'api#getSharedFormsLegacy', 'url' => $apiBase . 'shared_forms', 'verb' => 'GET', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?'
|
||||
]],
|
||||
|
||||
// Questions
|
||||
['name' => 'api#newQuestionLegacy', 'url' => $apiBase . 'question', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?'
|
||||
]],
|
||||
// TODO: Remove POST in next API release
|
||||
['name' => 'api#updateQuestionLegacy', 'url' => $apiBase . 'question/update', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?'
|
||||
]],
|
||||
['name' => 'api#updateQuestionLegacy', 'url' => $apiBase . 'question/update', 'verb' => 'PATCH', 'requirements' => [
|
||||
'apiVersion' => 'v2\.[2-5]'
|
||||
]],
|
||||
// TODO: Remove POST in next API release
|
||||
['name' => 'api#reorderQuestionsLegacy', 'url' => $apiBase . 'question/reorder', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?'
|
||||
]],
|
||||
['name' => 'api#reorderQuestionsLegacy', 'url' => $apiBase . 'question/reorder', 'verb' => 'PUT', 'requirements' => [
|
||||
'apiVersion' => 'v2\.[2-5]'
|
||||
]],
|
||||
['name' => 'api#deleteQuestionLegacy', 'url' => $apiBase . 'question/{id}', 'verb' => 'DELETE', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?',
|
||||
'id' => '\d+'
|
||||
]],
|
||||
['name' => 'api#cloneQuestionLegacy', 'url' => $apiBase . 'question/clone/{id}', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2\.[3-5]',
|
||||
'id' => '\d+'
|
||||
]],
|
||||
|
||||
// Options
|
||||
['name' => 'api#newOptionLegacy', 'url' => $apiBase . 'option', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?'
|
||||
]],
|
||||
// TODO: Remove POST in next API release
|
||||
['name' => 'api#updateOptionLegacy', 'url' => $apiBase . 'option/update', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?'
|
||||
]],
|
||||
['name' => 'api#updateOptionLegacy', 'url' => $apiBase . 'option/update', 'verb' => 'PATCH', 'requirements' => [
|
||||
'apiVersion' => 'v2\.[2-5]'
|
||||
]],
|
||||
['name' => 'api#deleteOptionLegacy', 'url' => $apiBase . 'option/{id}', 'verb' => 'DELETE', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?',
|
||||
'id' => '\d+'
|
||||
]],
|
||||
|
||||
// Shares
|
||||
['name' => 'shareApi#newShareLegacy', 'url' => $apiBase . 'share', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?'
|
||||
]],
|
||||
['name' => 'shareApi#deleteShareLegacy', 'url' => $apiBase . 'share/{id}', 'verb' => 'DELETE', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?',
|
||||
'id' => '\d+'
|
||||
]],
|
||||
// TODO: Remove POST in next API release
|
||||
['name' => 'shareApi#updateShareLegacy', 'url' => $apiBase . 'share/update', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2\.[1-5]'
|
||||
]],
|
||||
['name' => 'shareApi#updateShareLegacy', 'url' => $apiBase . 'share/update', 'verb' => 'PATCH', 'requirements' => [
|
||||
'apiVersion' => 'v2\.[2-5]'
|
||||
]],
|
||||
|
||||
// Submissions
|
||||
['name' => 'api#getSubmissionsLegacy', 'url' => $apiBase . 'submissions/{hash}', 'verb' => 'GET', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?',
|
||||
'hash' => '[a-zA-Z0-9]{16}'
|
||||
]],
|
||||
['name' => 'api#exportSubmissionsLegacy', 'url' => $apiBase . 'submissions/export/{hash}', 'verb' => 'GET', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?',
|
||||
'hash' => '[a-zA-Z0-9]{16}'
|
||||
]],
|
||||
['name' => 'api#exportSubmissionsToCloudLegacy', 'url' => $apiBase . 'submissions/export', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?'
|
||||
]],
|
||||
['name' => 'api#deleteAllSubmissionsLegacy', 'url' => $apiBase . 'submissions/{formId}', 'verb' => 'DELETE', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?',
|
||||
'formId' => '\d+'
|
||||
]],
|
||||
['name' => 'api#uploadFilesLegacy', 'url' => $apiBase . 'uploadFiles/{formId}/{questionId}', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2.5',
|
||||
'formId' => '\d+',
|
||||
'questionId' => '\d+'
|
||||
]],
|
||||
['name' => 'api#insertSubmissionLegacy', 'url' => $apiBase . 'submission/insert', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?'
|
||||
]],
|
||||
['name' => 'api#deleteSubmissionLegacy', 'url' => $apiBase . 'submission/{id}', 'verb' => 'DELETE', 'requirements' => [
|
||||
'apiVersion' => 'v2(\.[1-5])?',
|
||||
'id' => '\d+'
|
||||
]],
|
||||
// Submissions linking with file in cloud
|
||||
['name' => 'api#linkFileLegacy', 'url' => $apiBase . 'form/link/{fileFormat}', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2.[4-5]',
|
||||
'fileFormat' => 'csv|ods|xlsx'
|
||||
]],
|
||||
['name' => 'api#unlinkFileLegacy', 'url' => $apiBase . 'form/unlink', 'verb' => 'POST', 'requirements' => [
|
||||
'apiVersion' => 'v2.[4-5]',
|
||||
]]
|
||||
]
|
||||
];
|
||||
|
|
851
docs/API.md
851
docs/API.md
|
@ -1,851 +0,0 @@
|
|||
# Forms Public API
|
||||
|
||||
## API v2 is now deprecated and will be removed with Forms v5. Please see documentation for [API v3](API_v3.md)
|
||||
|
||||
This file contains the API-Documentation. For more information on the returned Data-Structures, please refer to the [corresponding Documentation](DataStructure.md).
|
||||
|
||||
## Generals
|
||||
|
||||
- Base URL for all calls to the forms API is `<nextcloud_base_url>/ocs/v2.php/apps/forms`
|
||||
- All Requests need to provide some authentication information.
|
||||
- All Requests to OCS-Endpoints require the Header `OCS-APIRequest: true`
|
||||
- Unless otherwise specified, all parameters are mandatory.
|
||||
|
||||
- By default, the API returns data formatted as _xml_. If formatting as _json_ is desired, the request should contain the header `Accept: application/json`. For simple representation, the output presented in this document is all formatted as _json_.
|
||||
- The OCS-Endpoint _always returns_ an object called `ocs`. This contains an object `meta` holding some meta-data, as well as an object `data` holding the actual data. In this document, the response-blocks only show the `data`, if not explicitely stated different.
|
||||
|
||||
```
|
||||
"ocs": {
|
||||
"meta": {
|
||||
"status": "ok",
|
||||
"statuscode": 200,
|
||||
"message": "OK"
|
||||
},
|
||||
"data": <Actual data>
|
||||
}
|
||||
```
|
||||
|
||||
## API changes
|
||||
|
||||
### Deprecation info
|
||||
|
||||
- Starting with Forms v4.3 API v2 will be deprecated and removed with Forms v5: Please see the documentation for [API v3](API_v3.md)
|
||||
- Starting with API v2.2 all endpoints that update data will use PATCH/PUT as method. POST is now deprecated and will be removed in API v3
|
||||
|
||||
### Breaking Changes on API v2
|
||||
|
||||
- The `mandatory` property of questions has been removed. It is replaced by `isRequired`.
|
||||
- Completely new way of handling access & shares.
|
||||
|
||||
### Other API changes
|
||||
|
||||
- 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
|
||||
- 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:
|
||||
- `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
|
||||
- In API version 2.4 the following endpoints were changed:
|
||||
- `GET /api/v2.4/submissions/export/{hash}` was extended with optional parameter `fileFormat` to export submissions in different formats
|
||||
- `GET /api/v2.4/submissions/export` was extended with optional parameter `fileFormat` to export submissions to cloud in different formats
|
||||
- `GET /api/v2.4/form/{id}` was extended with optional parameters `fileFormat`, `fileId`, `filePath` to link form to a file
|
||||
- In API version 2.3 the endpoint `/api/v2.3/question/clone` was added to clone a question
|
||||
- In API version 2.2 the endpoint `/api/v2.2/form/transfer` was added to transfer ownership of a form
|
||||
- In API version 2.1 the endpoint `/api/v2.1/share/update` was added to update a Share
|
||||
|
||||
## Form Endpoints
|
||||
|
||||
### List owned Forms
|
||||
|
||||
Returns condensed objects of all Forms beeing owned by the authenticated user.
|
||||
|
||||
- Endpoint: `/api/v2.5/forms`
|
||||
- Method: `GET`
|
||||
- Parameters: None
|
||||
- Response: Array of condensed Form Objects, sorted as newest first.
|
||||
|
||||
```
|
||||
"data": [
|
||||
{
|
||||
"id": 6,
|
||||
"hash": "yWeMwcwCwoqRs8T2",
|
||||
"title": "Form 2",
|
||||
"expires": 0,
|
||||
"permissions": [
|
||||
"edit",
|
||||
"results",
|
||||
"submit"
|
||||
],
|
||||
"partial": true,
|
||||
"state": 0
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"hash": "em4djk8B9BpXnkYG",
|
||||
"title": "Form 1",
|
||||
"expires": 0,
|
||||
"permissions": [
|
||||
"edit",
|
||||
"results",
|
||||
"submit"
|
||||
],
|
||||
"partial": true,
|
||||
"state": 0
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### List shared Forms
|
||||
|
||||
Returns condensed objects of all Forms, that are shared & shown to the authenticated user and that have not expired yet.
|
||||
|
||||
- Endpoint: `/api/v2.5/shared_forms`
|
||||
- Method: `GET`
|
||||
- Parameters: None
|
||||
- Response: Array of condensed Form Objects, sorted as newest first, similar to [List owned Forms](#list-owned-forms).
|
||||
|
||||
```
|
||||
See above, 'List owned forms'
|
||||
```
|
||||
|
||||
### Get a partial Form
|
||||
|
||||
Returns a single partial form object, corresponding to owned/shared form-listings.
|
||||
|
||||
- Endpoint: `/api/v2.5/partial_form/{hash}`
|
||||
- Method: `GET`
|
||||
- Url-Parameter:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _hash_ | String | Hash of the form to request |
|
||||
- Response: Partial form object, similar to form-list elements.
|
||||
|
||||
```
|
||||
"data": {
|
||||
"id": 6,
|
||||
"hash": "yWeMwcwCwoqRs8T2",
|
||||
"title": "Form 2",
|
||||
"expires": 0,
|
||||
"permissions": [
|
||||
"submit"
|
||||
],
|
||||
"partial": true,
|
||||
"state": 0
|
||||
}
|
||||
```
|
||||
|
||||
### Create a new Form
|
||||
|
||||
- Endpoint: `/api/v2.5/form`
|
||||
- Method: `POST`
|
||||
- Parameters: None
|
||||
- Response: The new form object, similar to requesting an existing form.
|
||||
|
||||
```
|
||||
See next section, 'Request full data of a form'
|
||||
```
|
||||
|
||||
### Request full data of a form
|
||||
|
||||
Returns the full-depth object of the requested form (without submissions).
|
||||
|
||||
- Endpoint: `/api/v2.5/form/{id}`
|
||||
- Url-Parameter:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _id_ | Integer | ID of the form to request |
|
||||
- Method: `GET`
|
||||
- Response: A full object of the form, including access, questions and options in full depth.
|
||||
|
||||
```
|
||||
"data": {
|
||||
"id": 3,
|
||||
"hash": "em4djk8B9BpXnkYG",
|
||||
"title": "Form 1",
|
||||
"description": "Description Text",
|
||||
"ownerId": "jonas",
|
||||
"submissionMessage": "Thank **you** for submitting the form."
|
||||
"created": 1611240961,
|
||||
"access": {
|
||||
"permitAllUsers": false,
|
||||
"showToAllUsers": false
|
||||
},
|
||||
"expires": 0,
|
||||
"fileFormat": "csv",
|
||||
"fileId": 157,
|
||||
"filePath": "foo/bar",
|
||||
"isAnonymous": false,
|
||||
"submitMultiple": true,
|
||||
"showExpiration": false,
|
||||
"canSubmit": true,
|
||||
"state": 0,
|
||||
"permissions": [
|
||||
"edit",
|
||||
"results",
|
||||
"submit"
|
||||
],
|
||||
"questions": [
|
||||
{
|
||||
"id": 1,
|
||||
"formId": 3,
|
||||
"order": 1,
|
||||
"type": "dropdown",
|
||||
"isRequired": false,
|
||||
"text": "Question 1",
|
||||
"name": "something",
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"questionId": 1,
|
||||
"text": "Option 1",
|
||||
"order": null
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"questionId": 1,
|
||||
"text": "Option 2",
|
||||
"order": null
|
||||
}
|
||||
],
|
||||
"accept": [],
|
||||
"extraSettings": {}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"formId": 3,
|
||||
"order": 2,
|
||||
"type": "file",
|
||||
"isRequired": true,
|
||||
"text": "Question 2",
|
||||
"name": "something_other",
|
||||
"options": [],
|
||||
"extraSettings": {}
|
||||
"accept": ["image/*", ".pdf"],
|
||||
}
|
||||
],
|
||||
"shares": [
|
||||
{
|
||||
"id": 1,
|
||||
"formId": 3,
|
||||
"shareType": 0,
|
||||
"shareWith": "user1",
|
||||
"displayName": "User 1 Displayname"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"formId": 3,
|
||||
"shareType": 3,
|
||||
"shareWith": "dYcTWjrSsxjMFFQzFAywzq5J",
|
||||
"displayName": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Clone a form
|
||||
|
||||
Creates a clone of a form (without submissions).
|
||||
|
||||
- Endpoint: `/api/v2.5/form/clone/{id}`
|
||||
- Url-Parameter:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _id_ | Integer | ID of the form to clone |
|
||||
- Method: `POST`
|
||||
- Response: Returns the full object of the new form. See [Request full data of a Form](#request-full-data-of-a-form)
|
||||
|
||||
```
|
||||
See section 'Request full data of a form'.
|
||||
```
|
||||
|
||||
### Update form properties
|
||||
|
||||
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.5/form/update`
|
||||
- Method: `PATCH`
|
||||
- _Method: `POST` deprecated_
|
||||
- Parameters:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _id_ | Integer | ID of the form to update |
|
||||
| _keyValuePairs_ | Array | Array of key-value pairs to update |
|
||||
- Restrictions: It is **not allowed** to update one of the following key-value pairs: _id, hash, ownerId, created_
|
||||
- Response: **Status-Code OK**, as well as the id of the updated form.
|
||||
|
||||
```
|
||||
"data": 3
|
||||
```
|
||||
|
||||
### Transfer form ownership
|
||||
|
||||
Transfer the ownership of a form to another user
|
||||
|
||||
- Endpoint: `/api/v2.5/form/transfer`
|
||||
- Method: `POST`
|
||||
- Parameters:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _formId_ | Integer | ID of the form to tranfer |
|
||||
| _uid_ | Integer | ID of the new form owner |
|
||||
- Restrictions: The initiator must be the current form owner.
|
||||
- Response: **Status-Code OK**, as well as the id of the new owner.
|
||||
|
||||
```
|
||||
"data": "user1"
|
||||
```
|
||||
|
||||
### Delete a form
|
||||
|
||||
- Endpoint: `/api/v2.5/form/{id}`
|
||||
- Url-Parameter:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _id_ | Integer | ID of the form to delete |
|
||||
- Method: `DELETE`
|
||||
- Response: **Status-Code OK**, as well as the id of the deleted form.
|
||||
|
||||
```
|
||||
"data": 3
|
||||
```
|
||||
|
||||
### Link a form to a file
|
||||
|
||||
- Endpoint: `/api/v2.5/form/link/{fileFormat}`
|
||||
- Url-Parameter:
|
||||
| Parameter | Type | Description |
|
||||
|--------------|---------|--------------|
|
||||
| _fileFormat_ | String | csv|ods|xlsx |
|
||||
- Method: `POST`
|
||||
- Parameters:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|--------------------------------------------|
|
||||
| _hash_ | String | Hash of the form to update |
|
||||
| _path_ | String | Path within User-Dir, to store the file to |
|
||||
- Response: The new question object.
|
||||
|
||||
```
|
||||
"data": {
|
||||
"fileFormat": "csv",
|
||||
"fileId": 157,
|
||||
"filePath": "foo/bar",
|
||||
"fileName": "Form 1 (responses).csv"
|
||||
}
|
||||
```
|
||||
|
||||
### Unlink file from form
|
||||
|
||||
- Endpoint: `/api/v2.5/form/unlink`
|
||||
- Method: `POST`
|
||||
- Parameters:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|----------------------------|
|
||||
| _hash_ | String | Hash of the form to update |
|
||||
- Response: **Status-Code OK**
|
||||
|
||||
## Question Endpoints
|
||||
|
||||
Contains only manipulative question-endpoints. To retrieve questions, request the full form data.
|
||||
|
||||
### Create a new question
|
||||
|
||||
- Endpoint: `/api/v2.5/question`
|
||||
- Method: `POST`
|
||||
- Parameters:
|
||||
| Parameter | Type | Optional | Description |
|
||||
|-----------|---------|----------|-------------|
|
||||
| _formId_ | Integer | | ID of the form, the new question will belong to |
|
||||
| _type_ | [QuestionType](DataStructure.md#question-types) | | The question-type of the new question |
|
||||
| _text_ | String | yes | _Optional_ The text of the new question. |
|
||||
- Response: The new question object.
|
||||
|
||||
```
|
||||
"data": {
|
||||
"id": 3,
|
||||
"formId": 3,
|
||||
"order": 3,
|
||||
"type": "short",
|
||||
"isRequired": false,
|
||||
"name": "",
|
||||
"text": "",
|
||||
"options": []
|
||||
"extraSettings": {}
|
||||
}
|
||||
```
|
||||
|
||||
### Update question properties
|
||||
|
||||
Update a single or multiple properties of a question-object.
|
||||
|
||||
- Endpoint: `/api/v2.5/question/update`
|
||||
- Method: `PATCH`
|
||||
- _Method: `POST` deprecated_
|
||||
- Parameters:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _id_ | Integer | ID of the question to update |
|
||||
| _keyValuePairs_ | Array | Array of key-value pairs to update |
|
||||
- Restrictions: It is **not allowed** to update one of the following key-value pairs: _id, formId, order_.
|
||||
- Response: **Status-Code OK**, as well as the id of the updated question.
|
||||
|
||||
```
|
||||
"data": 1
|
||||
```
|
||||
|
||||
### Reorder questions
|
||||
|
||||
Reorders all Questions of a single form
|
||||
|
||||
- Endpoint: `/api/v2.5/question/reorder`
|
||||
- Method: `PUT`
|
||||
- _Method: `POST` deprecated_
|
||||
- Parameters:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _formId_ | Integer | ID of the form, the questions belong to |
|
||||
| _newOrder_ | Array | Array of **all** Question-IDs, ordered in the desired order |
|
||||
- Restrictions: The Array **must** contain all Question-IDs corresponding to the specified form and **must not** contain any duplicates.
|
||||
- Response: Array of questionIDs and their corresponding order.
|
||||
|
||||
```
|
||||
"data": {
|
||||
"1": {
|
||||
"order": 1
|
||||
},
|
||||
"2": {
|
||||
"order": 3
|
||||
},
|
||||
"3": {
|
||||
"order": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Delete a question
|
||||
|
||||
- Endpoint: `/api/v2.5/question/{id}`
|
||||
- Url-Parameter:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _id_ | Integer | ID of the question to delete |
|
||||
- Method: `DELETE`
|
||||
- Response: **Status-Code OK**, as well as the id of the deleted question.
|
||||
|
||||
```
|
||||
"data": 4
|
||||
```
|
||||
|
||||
### Clone a question
|
||||
|
||||
Creates a clone of a question with all its options.
|
||||
|
||||
- Endpoint: `/api/v2.5/question/clone/{id}`
|
||||
- Url-Parameter:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _id_ | Integer | ID of the question to clone |
|
||||
- Method: `POST`
|
||||
- Response: Returns cloned question object with the new ID set.
|
||||
|
||||
```
|
||||
See section 'Create a new question'.
|
||||
```
|
||||
|
||||
## Option Endpoints
|
||||
|
||||
Contains only manipulative question-endpoints. To retrieve options, request the full form data.
|
||||
|
||||
### Create a new Option
|
||||
|
||||
- Endpoint: `/api/v2.5/option`
|
||||
- Method: `POST`
|
||||
- Parameters:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _questionId_ | Integer | ID of the question, the new option will belong to |
|
||||
| _text_ | String | The text of the new option |
|
||||
- Response: The new option object
|
||||
|
||||
```
|
||||
"data": {
|
||||
"id": 7,
|
||||
"questionId": 1,
|
||||
"text": "test"
|
||||
}
|
||||
```
|
||||
|
||||
### Update option properties
|
||||
|
||||
Update a single or all properties of an option-object
|
||||
|
||||
- Endpoint: `/api/v2.5/option/update`
|
||||
- Method: `PATCH`
|
||||
- _Method: `POST` deprecated_
|
||||
- Parameters:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _id_ | Integer | ID of the option to update |
|
||||
| _keyValuePairs_ | Array | Array of key-value pairs to update |
|
||||
- Restrictions: It is **not allowed** to update one of the following key-value pairs: _id, questionId_.
|
||||
- Response: **Status-Code OK**, as well as the id of the updated option.
|
||||
|
||||
```
|
||||
"data": 7
|
||||
```
|
||||
|
||||
### Delete an option
|
||||
|
||||
- Endpoint: `/api/v2.5/option/{id}`
|
||||
- Url-Parameter:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _id_ | Integer | ID of the option to delete |
|
||||
- Method: `DELETE`
|
||||
- Response: **Status-Code OK**, as well as the id of the deleted option.
|
||||
|
||||
```
|
||||
"data": 7
|
||||
```
|
||||
|
||||
## Sharing Endpoints
|
||||
|
||||
### Add a new Share
|
||||
|
||||
- Endpoint: `/api/v2.5/share`
|
||||
- Method: `POST`
|
||||
- Parameters:
|
||||
| Parameter | Type | Description |
|
||||
|--------------|----------|-------------|
|
||||
| _formId_ | Integer | Id of the form to share |
|
||||
| _shareType_ | String | NC-shareType, out of the used shareTypes. |
|
||||
| _shareWith_ | String | User/Group for the share. Not used for link-shares. |
|
||||
| _permissions_ | String[] | Permissions of the sharees, see [DataStructure](DataStructure.md#Permissions). |
|
||||
- Response: **Status-Code OK**, as well as the new share object.
|
||||
|
||||
```
|
||||
"data": {
|
||||
"id": 3,
|
||||
"formId": 3,
|
||||
"shareType": 0,
|
||||
"shareWith": "user3",
|
||||
"permissions": ["submit"],
|
||||
"displayName": "User 3 Displayname"
|
||||
}
|
||||
```
|
||||
|
||||
### Delete a Share
|
||||
|
||||
- Endpoint: `/api/v2.5/share/{id}`
|
||||
- Url-Parameter:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _id_ | Integer | ID of the share to delete |
|
||||
- Method: `DELETE`
|
||||
- Response: **Status-Code OK**, as well as the id of the deleted share.
|
||||
|
||||
```
|
||||
"data": 5
|
||||
```
|
||||
|
||||
### Update a Share
|
||||
|
||||
- Endpoint: `/api/v2.5/share/update`
|
||||
- Parameters:
|
||||
| Parameter | Type | Description |
|
||||
|------------------|----------|-------------|
|
||||
| _id_ | Integer | ID of the share to update |
|
||||
| *keyValuePairs*¹ | Array | Array of key-value pairs to update |
|
||||
|
||||
¹Currently only the _permissions_ can be updated.
|
||||
|
||||
- Method: `PATCH`
|
||||
- _Method: `POST` deprecated_
|
||||
- Response: **Status-Code OK**, as well as the id of the share object.
|
||||
|
||||
```
|
||||
"data": 5
|
||||
```
|
||||
|
||||
## Submission Endpoints
|
||||
|
||||
### Get Form Submissions
|
||||
|
||||
Get all Submissions to a Form
|
||||
|
||||
- Endpoint: `/api/v2.5/submissions/{hash}`
|
||||
- Url-Parameter:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _hash_ | String | Hash of the form to get the submissions for |
|
||||
- Method: `GET`
|
||||
- Response: An Array of all submissions, sorted as newest first, as well as an array of the corresponding questions.
|
||||
|
||||
```
|
||||
"data": {
|
||||
"submissions": [
|
||||
{
|
||||
"id": 6,
|
||||
"formId": 3,
|
||||
"userId": "jonas",
|
||||
"timestamp": 1611274453,
|
||||
"answers": [
|
||||
{
|
||||
"id": 8,
|
||||
"submissionId": 6,
|
||||
"questionId": 1,
|
||||
"text": "Option 3"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"submissionId": 6,
|
||||
"questionId": 2,
|
||||
"text": "One more."
|
||||
},
|
||||
],
|
||||
"userDisplayName": "jonas"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"formId": 3,
|
||||
"userId": "jonas",
|
||||
"timestamp": 1611274433,
|
||||
"answers": [
|
||||
{
|
||||
"id": 5,
|
||||
"submissionId": 5,
|
||||
"questionId": 1,
|
||||
"text": "Option 2"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"submissionId": 5,
|
||||
"questionId": 2,
|
||||
"text": "This is an answer."
|
||||
},
|
||||
],
|
||||
"userDisplayName": "jonas"
|
||||
}
|
||||
],
|
||||
"questions": [
|
||||
{
|
||||
"id": 1,
|
||||
"formId": 3,
|
||||
"order": 1,
|
||||
"type": "dropdown",
|
||||
"isRequired": false,
|
||||
"text": "Question 1",
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"questionId": 1,
|
||||
"text": "Option 1",
|
||||
"order": null
|
||||
},
|
||||
{
|
||||
"id": 27,
|
||||
"questionId": 1,
|
||||
"text": "Option 2",
|
||||
"order": null
|
||||
},
|
||||
{
|
||||
"id": 30,
|
||||
"questionId": 1,
|
||||
"text": "Option 3",
|
||||
"order": null
|
||||
}
|
||||
],
|
||||
"extraSettings": {}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"formId": 3,
|
||||
"order": 2,
|
||||
"type": "short",
|
||||
"isRequired": true,
|
||||
"text": "Question 2",
|
||||
"options": [],
|
||||
"extraSettings": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Get Submissions as csv (Download)
|
||||
|
||||
Returns all submissions to the form in form of a csv-file.
|
||||
|
||||
- Endpoint: `/api/v2.5/submissions/export/{hash}`
|
||||
- Url-Parameter:
|
||||
| Parameter | Type | Description |
|
||||
|--------------|---------|-------------|
|
||||
| _hash_ | String | Hash of the form to get the submissions for |
|
||||
| _fileFormat_ | String | csv|ods|xlsx |
|
||||
- Method: `GET`
|
||||
- Response: A Data Download Response containing the headers `Content-Disposition: attachment; filename="Form 1 (responses).csv"` and `Content-Type: text/csv;charset=UTF-8`. The actual data contains all submissions to the referred form, formatted as comma separated and escaped csv.
|
||||
|
||||
```
|
||||
"User display name","Timestamp","Question 1","Question 2"
|
||||
"jonas","Friday, January 22, 2021 at 12:47:29 AM GMT+0:00","Option 2","Answer"
|
||||
"jonas","Friday, January 22, 2021 at 12:45:57 AM GMT+0:00","Option 3","NextAnswer"
|
||||
```
|
||||
|
||||
### Export Submissions to Cloud (Files-App)
|
||||
|
||||
Creates a csv file and stores it to the cloud, resp. Files-App.
|
||||
|
||||
- Endpoint: `/api/v2.5/submissions/export`
|
||||
- Method: `POST`
|
||||
- Parameters:
|
||||
| Parameter | Type | Description |
|
||||
|--------------|---------|-------------|
|
||||
| _hash_ | String | Hash of the form to get the submissions for |
|
||||
| _path_ | String | Path within User-Dir, to store the file to |
|
||||
| _fileFormat_ | String | csv|ods|xlsx |
|
||||
- Response: Stores the file to the given path and returns the fileName.
|
||||
|
||||
```
|
||||
"data": "Form 2 (responses).csv"
|
||||
```
|
||||
|
||||
### Delete Submissions
|
||||
|
||||
Delete all Submissions to a form
|
||||
|
||||
- Endpoint: `/api/v2.5/submissions/{formId}`
|
||||
- Url-Parameter:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _formId_ | Integer | ID of the form to delete the submissions for |
|
||||
- Method: `DELETE`
|
||||
- Response: **Status-Code OK**, as well as the id of the corresponding form.
|
||||
|
||||
```
|
||||
"data": 3
|
||||
```
|
||||
|
||||
### Upload a file
|
||||
|
||||
Upload a files to answer before form submitting
|
||||
|
||||
- Endpoint: `/api/2.5/uploadFiles/{formId}/{questionId}`
|
||||
- Method: `POST`
|
||||
- Parameters:
|
||||
| Parameter | Type | Description |
|
||||
|--------------|----------------|-------------|
|
||||
| _formId_ | Integer | ID of the form to upload the file to |
|
||||
| _questionId_ | Integer | ID of the question to upload the file to |
|
||||
| _files_ | Array of files | Files to upload |
|
||||
- Response: **Status-Code OK**, as well as the id of the uploaded file and it's name.
|
||||
|
||||
```
|
||||
"data": {"uploadedFileId": integer, "fileName": "string"}
|
||||
```
|
||||
|
||||
### Insert a Submission
|
||||
|
||||
Store Submission to Database
|
||||
|
||||
- Endpoint: `/api/v2.5/submission/insert`
|
||||
- Method: `POST`
|
||||
- Parameters:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _formId_ | Integer | ID of the form to submit into |
|
||||
| _answers_ | Array | Array of Answers |
|
||||
| _shareHash_ | String | optional, only neccessary for submissions to a public share link |
|
||||
|
||||
The Array of Answers has the following structure:
|
||||
|
||||
- QuestionID as key
|
||||
- An **array** of values as value --> Even for short Text Answers, wrapped into Array.
|
||||
- For Question-Types with pre-defined answers (`multiple`, `multiple_unique`, `dropdown`), the array contains the corresponding option-IDs.
|
||||
|
||||
- For File-Uploads, the array contains the objects with key `uploadedFileId` (value from Upload a file endpoint).
|
||||
|
||||
````
|
||||
{
|
||||
"1":[27,32], // dropdown or multiple
|
||||
"2":["ShortTextAnswer"], // All Text-Based Question-Types
|
||||
"3":[ // File-Upload
|
||||
{"uploadedFileId": integer},
|
||||
{"uploadedFileId": integer}
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
- Response: **Status-Code OK**.
|
||||
|
||||
### Delete a single Submission
|
||||
|
||||
- Endpoint: `/api/v2.5/submission/{id}`
|
||||
- Url-Parameter:
|
||||
| Parameter | Type | Description |
|
||||
|-----------|---------|-------------|
|
||||
| _id_ | Integer | ID of the submission to delete |
|
||||
- Method: `DELETE`
|
||||
- Response: **Status-Code OK**, as well as the id of the deleted submission.
|
||||
|
||||
````
|
||||
|
||||
"data": 5
|
||||
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
All Endpoints return one of the following Error-Responses, if the request is not properly raised. This also results in a different `ocs:meta` object.
|
||||
|
||||
### 400 - Bad Request
|
||||
|
||||
This returns in case the Request is not properly set. This can e.g. include:
|
||||
|
||||
- The corresponding form can not be found
|
||||
- Request Parameters are wrong (including formatting or type of parameters)
|
||||
|
||||
```
|
||||
|
||||
"ocs": {
|
||||
"meta": {
|
||||
"status": "failure",
|
||||
"statuscode": 400,
|
||||
"message": ""
|
||||
},
|
||||
"data": []
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 403 - Forbidden
|
||||
|
||||
This returns in case the authenticated user is not allowed to access this resource/endpoint. This can e.g. include:
|
||||
|
||||
- The user has no write access to the form (only form owner is allowed to edit)
|
||||
- The user is not allowed to submit to the form (access-settings, form expired, already submitted)
|
||||
|
||||
```
|
||||
|
||||
"ocs": {
|
||||
"meta": {
|
||||
"status": "failure",
|
||||
"statuscode": 403,
|
||||
"message": ""
|
||||
},
|
||||
"data": []
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 412 - Precondition Failed
|
||||
|
||||
This Error is not produed by the Forms-API, but comes from Nextclouds OCS API. Typically this is the result when missing the Request-Header `OCS-APIRequest: true`.
|
||||
|
||||
```
|
||||
|
||||
{
|
||||
"message": "CSRF check failed"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```
|
|
@ -40,7 +40,7 @@ class Capabilities implements ICapability {
|
|||
return [
|
||||
'forms' => [
|
||||
'version' => $this->appManager->getAppVersion('forms'),
|
||||
'apiVersions' => ['v2','v2.1','v2.2','v2.3','v2.4','v2.5','v3']
|
||||
'apiVersions' => ['v3']
|
||||
]
|
||||
];
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -336,258 +336,6 @@ class ShareApiController extends OCSController {
|
|||
return new DataResponse($shareId);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Legacy API v2 methods (TODO: remove with Forms v5)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @CORS
|
||||
* @NoAdminRequired
|
||||
*
|
||||
* Add a new share
|
||||
*
|
||||
* @param int $formId The form to share
|
||||
* @param int $shareType Nextcloud-ShareType
|
||||
* @param string $shareWith ID of user/group/... to share with. For Empty shareWith and shareType Link, this will be set as RandomID.
|
||||
* @return DataResponse
|
||||
* @throws OCSBadRequestException
|
||||
* @throws OCSForbiddenException
|
||||
*/
|
||||
public function newShareLegacy(int $formId, int $shareType, string $shareWith = '', array $permissions = [Constants::PERMISSION_SUBMIT]): DataResponse {
|
||||
$this->logger->debug('Adding new share: formId: {formId}, shareType: {shareType}, shareWith: {shareWith}, permissions: {permissions}', [
|
||||
'formId' => $formId,
|
||||
'shareType' => $shareType,
|
||||
'shareWith' => $shareWith,
|
||||
'permissions' => $permissions,
|
||||
]);
|
||||
|
||||
// Only accept usable shareTypes
|
||||
if (array_search($shareType, Constants::SHARE_TYPES_USED) === false) {
|
||||
$this->logger->debug('Invalid shareType');
|
||||
throw new OCSBadRequestException('Invalid shareType');
|
||||
}
|
||||
|
||||
// Block LinkShares if not allowed
|
||||
if ($shareType === IShare::TYPE_LINK && !$this->configService->getAllowPublicLink()) {
|
||||
$this->logger->debug('Link Share not allowed.');
|
||||
throw new OCSForbiddenException('Link Share not allowed.');
|
||||
}
|
||||
|
||||
try {
|
||||
$form = $this->formMapper->findById($formId);
|
||||
} catch (IMapperException $e) {
|
||||
$this->logger->debug('Could not find form', ['exception' => $e]);
|
||||
throw new OCSBadRequestException('Could not find form');
|
||||
}
|
||||
|
||||
// Check for permission to share form
|
||||
if ($form->getOwnerId() !== $this->currentUser->getUID()) {
|
||||
$this->logger->debug('This form is not owned by the current user');
|
||||
throw new OCSForbiddenException();
|
||||
}
|
||||
|
||||
if (!$this->validatePermissions($permissions, $shareType)) {
|
||||
throw new OCSBadRequestException('Invalid permission given');
|
||||
}
|
||||
|
||||
// Create public-share hash, if necessary.
|
||||
if ($shareType === IShare::TYPE_LINK) {
|
||||
$shareWith = $this->secureRandom->generate(
|
||||
24,
|
||||
ISecureRandom::CHAR_HUMAN_READABLE
|
||||
);
|
||||
}
|
||||
|
||||
// Check for valid shareWith, needs to be done separately per shareType
|
||||
switch ($shareType) {
|
||||
case IShare::TYPE_USER:
|
||||
if (!($this->userManager->get($shareWith) instanceof IUser)) {
|
||||
$this->logger->debug('Invalid user to share with.');
|
||||
throw new OCSBadRequestException('Invalid user to share with.');
|
||||
}
|
||||
break;
|
||||
|
||||
case IShare::TYPE_GROUP:
|
||||
if (!($this->groupManager->get($shareWith) instanceof IGroup)) {
|
||||
$this->logger->debug('Invalid group to share with.');
|
||||
throw new OCSBadRequestException('Invalid group to share with.');
|
||||
}
|
||||
break;
|
||||
|
||||
case IShare::TYPE_LINK:
|
||||
// Check if hash already exists. (Unfortunately not possible here by unique index on db.)
|
||||
try {
|
||||
// Try loading a share to the hash.
|
||||
$nonex = $this->shareMapper->findPublicShareByHash($shareWith);
|
||||
|
||||
// If we come here, a share has been found --> The share hash already exists, thus aborting.
|
||||
$this->logger->debug('Share Hash already exists.');
|
||||
throw new OCSException('Share Hash exists. Please retry.');
|
||||
} catch (DoesNotExistException $e) {
|
||||
// Just continue, this is what we expect to happen (share hash not existing yet).
|
||||
}
|
||||
break;
|
||||
|
||||
case IShare::TYPE_CIRCLE:
|
||||
if (!$this->circlesService->isCirclesEnabled()) {
|
||||
$this->logger->debug('Teams app is disabled, sharing to teams not possible.');
|
||||
throw new OCSException('Teams app is disabled.');
|
||||
}
|
||||
$circle = $this->circlesService->getCircle($shareWith);
|
||||
if (is_null($circle)) {
|
||||
$this->logger->debug('Invalid team to share with.');
|
||||
throw new OCSBadRequestException('Invalid team to share with.');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// This passed the check for used shareTypes, but has not been found here.
|
||||
$this->logger->warning('Unknown, but used shareType: {shareType}. Please file an issue on GitHub.', [ 'shareType' => $shareType ]);
|
||||
throw new OCSException('Unknown shareType.');
|
||||
}
|
||||
|
||||
$share = new Share();
|
||||
$share->setFormId($formId);
|
||||
$share->setShareType($shareType);
|
||||
$share->setShareWith($shareWith);
|
||||
$share->setPermissions($permissions);
|
||||
|
||||
/** @var Share */
|
||||
$share = $this->shareMapper->insert($share);
|
||||
$this->formMapper->update($form);
|
||||
|
||||
// Create share-notifications (activity)
|
||||
$this->formsService->notifyNewShares($form, $share);
|
||||
|
||||
// Append displayName for Frontend
|
||||
$shareData = $share->read();
|
||||
$shareData['displayName'] = $this->formsService->getShareDisplayName($shareData);
|
||||
|
||||
return new DataResponse($shareData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @CORS
|
||||
* @NoAdminRequired
|
||||
*
|
||||
* Delete a share
|
||||
*
|
||||
* @param int $id of the share to delete
|
||||
* @return DataResponse
|
||||
* @throws OCSBadRequestException
|
||||
* @throws OCSForbiddenException
|
||||
*/
|
||||
public function deleteShareLegacy(int $id): DataResponse {
|
||||
$this->logger->debug('Deleting share: {id}', [
|
||||
'id' => $id
|
||||
]);
|
||||
|
||||
try {
|
||||
$share = $this->shareMapper->findById($id);
|
||||
$form = $this->formMapper->findById($share->getFormId());
|
||||
} catch (IMapperException $e) {
|
||||
$this->logger->debug('Could not find share', ['exception' => $e]);
|
||||
throw new OCSBadRequestException('Could not find share');
|
||||
}
|
||||
|
||||
if ($form->getOwnerId() !== $this->currentUser->getUID()) {
|
||||
$this->logger->debug('This form is not owned by the current user');
|
||||
throw new OCSForbiddenException();
|
||||
}
|
||||
|
||||
$this->shareMapper->delete($share);
|
||||
$this->formMapper->update($form);
|
||||
|
||||
return new DataResponse($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @CORS
|
||||
* @NoAdminRequired
|
||||
*
|
||||
* Update permissions of a share
|
||||
*
|
||||
* @param int $id of the share to update
|
||||
* @param array $keyValuePairs Array of key=>value pairs to update.
|
||||
* @return DataResponse
|
||||
* @throws OCSBadRequestException
|
||||
* @throws OCSForbiddenException
|
||||
*/
|
||||
public function updateShareLegacy(int $id, array $keyValuePairs): DataResponse {
|
||||
$this->logger->debug('Updating share: {id}, permissions: {permissions}', [
|
||||
'id' => $id,
|
||||
'keyValuePairs' => $keyValuePairs
|
||||
]);
|
||||
|
||||
try {
|
||||
$formShare = $this->shareMapper->findById($id);
|
||||
$form = $this->formMapper->findById($formShare->getFormId());
|
||||
} catch (IMapperException $e) {
|
||||
$this->logger->debug('Could not find share', ['exception' => $e]);
|
||||
throw new OCSBadRequestException('Could not find share');
|
||||
}
|
||||
|
||||
if ($form->getOwnerId() !== $this->currentUser->getUID()) {
|
||||
$this->logger->debug('This form is not owned by the current user');
|
||||
throw new OCSForbiddenException();
|
||||
}
|
||||
|
||||
// Don't allow empty array
|
||||
if (sizeof($keyValuePairs) === 0) {
|
||||
$this->logger->info('Empty keyValuePairs, will not update.');
|
||||
throw new OCSForbiddenException();
|
||||
}
|
||||
|
||||
//Don't allow to change other properties than permissions
|
||||
if (count($keyValuePairs) > 1 || !key_exists('permissions', $keyValuePairs)) {
|
||||
$this->logger->debug('Not allowed to update other properties than permissions');
|
||||
throw new OCSForbiddenException();
|
||||
}
|
||||
|
||||
if (!$this->validatePermissions($keyValuePairs['permissions'], $formShare->getShareType())) {
|
||||
throw new OCSBadRequestException('Invalid permission given');
|
||||
}
|
||||
|
||||
$formShare->setPermissions($keyValuePairs['permissions']);
|
||||
$formShare = $this->shareMapper->update($formShare);
|
||||
|
||||
if (in_array($formShare->getShareType(), [IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_USERGROUP, IShare::TYPE_CIRCLE], true)) {
|
||||
$userFolder = $this->rootFolder->getUserFolder($form->getOwnerId());
|
||||
$uploadedFilesFolderPath = $this->formsService->getFormUploadedFilesFolderPath($form);
|
||||
if ($userFolder->nodeExists($uploadedFilesFolderPath)) {
|
||||
$folder = $userFolder->get($uploadedFilesFolderPath);
|
||||
} else {
|
||||
$folder = $userFolder->newFolder($uploadedFilesFolderPath);
|
||||
}
|
||||
/** @var \OCP\Files\Folder $folder */
|
||||
|
||||
if (in_array(Constants::PERMISSION_RESULTS, $keyValuePairs['permissions'], true)) {
|
||||
$folderShare = $this->shareManager->newShare();
|
||||
$folderShare->setShareType($formShare->getShareType());
|
||||
$folderShare->setSharedWith($formShare->getShareWith());
|
||||
$folderShare->setSharedBy($form->getOwnerId());
|
||||
$folderShare->setPermissions(\OCP\Constants::PERMISSION_READ);
|
||||
$folderShare->setNode($folder);
|
||||
$folderShare->setShareOwner($form->getOwnerId());
|
||||
|
||||
$this->shareManager->createShare($folderShare);
|
||||
} else {
|
||||
$folderShares = $this->shareManager->getSharesBy($form->getOwnerId(), $formShare->getShareType(), $folder);
|
||||
foreach ($folderShares as $folderShare) {
|
||||
if ($folderShare->getSharedWith() === $formShare->getShareWith()) {
|
||||
$this->shareManager->deleteShare($folderShare);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->formMapper->update($form);
|
||||
|
||||
return new DataResponse($formShare->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate user given permission array
|
||||
*
|
||||
|
@ -595,7 +343,7 @@ class ShareApiController extends OCSController {
|
|||
* @return bool True if permissions are valid, False otherwise
|
||||
* @throws OCSBadRequestException If invalid permission was given
|
||||
*/
|
||||
protected function validatePermissions(array $permissions, int $shareType): bool {
|
||||
private function validatePermissions(array $permissions, int $shareType): bool {
|
||||
if (count($permissions) === 0) {
|
||||
return false;
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -63,7 +63,6 @@ use OCA\Forms\Service\ConfigService;
|
|||
use OCA\Forms\Service\FormsService;
|
||||
use OCA\Forms\Service\SubmissionService;
|
||||
use OCA\Forms\Tests\Unit\MockedMapperException;
|
||||
use OCP\AppFramework\Db\IMapperException;
|
||||
use OCP\AppFramework\Http\DataDownloadResponse;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\OCS\OCSBadRequestException;
|
||||
|
@ -369,30 +368,6 @@ class ApiControllerTest extends TestCase {
|
|||
$this->apiController->exportSubmissionsToCloud(1, '');
|
||||
}
|
||||
|
||||
public function testUnlinkFile() {
|
||||
$form = new Form();
|
||||
$form->setId(1);
|
||||
$form->setHash('hash');
|
||||
$form->setOwnerId('currentUser');
|
||||
$form->setFileId(100);
|
||||
$form->setFileFormat('csv');
|
||||
|
||||
$this->formMapper->expects($this->once())
|
||||
->method('findByHash')
|
||||
->with('hash')
|
||||
->willReturn($form);
|
||||
|
||||
$this->formsService->expects($this->once())
|
||||
->method('canEditForm')
|
||||
->with($form)
|
||||
->willReturn(true);
|
||||
|
||||
$this->apiController->unlinkFileLegacy('hash');
|
||||
|
||||
$this->assertNull($form->getFileId());
|
||||
$this->assertNull($form->getFileFormat());
|
||||
}
|
||||
|
||||
public function testCreateNewForm_notAllowed() {
|
||||
$this->configService->expects($this->once())
|
||||
->method('canCreateForms')
|
||||
|
@ -638,21 +613,6 @@ class ApiControllerTest extends TestCase {
|
|||
->willReturn($canSubmit);
|
||||
}
|
||||
|
||||
public function testCloneQuestion_notFound() {
|
||||
$this->questionMapper->method('findById')->with(42)->willThrowException($this->createMock(IMapperException::class));
|
||||
$this->expectException(OCSNotFoundException::class);
|
||||
$this->apiController->cloneQuestionLegacy(42);
|
||||
}
|
||||
|
||||
public function testCloneQuestion_noPermission() {
|
||||
$form = Form::fromParams(['ownerId' => 'otherUser']);
|
||||
$question = Question::fromParams(['formId' => 1]);
|
||||
$this->questionMapper->method('findById')->with(42)->willReturn($question);
|
||||
$this->formMapper->method('findById')->with(1)->willReturn($form);
|
||||
$this->expectException(OCSForbiddenException::class);
|
||||
$this->apiController->cloneQuestionLegacy(42);
|
||||
}
|
||||
|
||||
public function testUploadFiles() {
|
||||
$form = new Form();
|
||||
$form->setId(1);
|
||||
|
@ -1039,7 +999,7 @@ class ApiControllerTest extends TestCase {
|
|||
->willReturn($form);
|
||||
|
||||
$this->expectException(OCSForbiddenException::class);
|
||||
$this->apiController->transferOwnerLegacy(1, 'newOwner');
|
||||
$this->apiController->updateForm(1, ['ownerId' => 'newOwner']);
|
||||
}
|
||||
|
||||
public function testTransferNewOwnerNotFound() {
|
||||
|
@ -1059,7 +1019,7 @@ class ApiControllerTest extends TestCase {
|
|||
->willReturn(null);
|
||||
|
||||
$this->expectException(OCSBadRequestException::class);
|
||||
$this->apiController->transferOwnerLegacy(1, 'newOwner');
|
||||
$this->apiController->updateForm(1, ['ownerId' => 'newOwner']);
|
||||
}
|
||||
|
||||
public function testTransferOwner() {
|
||||
|
@ -1079,7 +1039,7 @@ class ApiControllerTest extends TestCase {
|
|||
->with('newOwner')
|
||||
->willReturn($newOwner);
|
||||
|
||||
$this->assertEquals(new DataResponse('newOwner'), $this->apiController->transferOwnerLegacy(1, 'newOwner'));
|
||||
$this->assertEquals(new DataResponse('newOwner'), $this->apiController->updateForm(1, ['ownerId' => 'newOwner']));
|
||||
$this->assertEquals('newOwner', $form->getOwnerId());
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче