mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge remote-tracking branch 'origin/feat-bulk-operations' into feat-test-migrations
This commit is contained in:
@@ -4367,7 +4367,7 @@
|
||||
"tags": [
|
||||
"databases"
|
||||
],
|
||||
"description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Document",
|
||||
@@ -4398,6 +4398,51 @@
|
||||
"server"
|
||||
],
|
||||
"packaging": false,
|
||||
"methods": [
|
||||
{
|
||||
"name": "createDocument",
|
||||
"parameters": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documentId",
|
||||
"data",
|
||||
"permissions"
|
||||
],
|
||||
"required": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documentId",
|
||||
"data"
|
||||
],
|
||||
"responses": [
|
||||
{
|
||||
"code": 201,
|
||||
"model": "#\/components\/schemas\/document"
|
||||
}
|
||||
],
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n"
|
||||
},
|
||||
{
|
||||
"name": "createDocuments",
|
||||
"parameters": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"required": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"responses": [
|
||||
{
|
||||
"code": 201,
|
||||
"model": "#\/components\/schemas\/documentList"
|
||||
}
|
||||
],
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n"
|
||||
}
|
||||
],
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
@@ -4447,6 +4492,14 @@
|
||||
"description": "Document data as JSON object.",
|
||||
"x-example": "{}"
|
||||
},
|
||||
"documents": {
|
||||
"type": "array",
|
||||
"description": "Array of documents data as JSON object.",
|
||||
"x-example": null,
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
|
||||
@@ -4455,11 +4508,192 @@
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"documentId",
|
||||
"data"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"summary": "Update documents",
|
||||
"operationId": "databasesUpdateDocuments",
|
||||
"tags": [
|
||||
"databases"
|
||||
],
|
||||
"description": "Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Documents List",
|
||||
"content": {
|
||||
"application\/json": {
|
||||
"schema": {
|
||||
"$ref": "#\/components\/schemas\/documentList"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateDocuments",
|
||||
"weight": 113,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "databases\/update-documents.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-documents.md",
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
"scope": "documents.write",
|
||||
"platforms": [
|
||||
"client",
|
||||
"server",
|
||||
"server"
|
||||
],
|
||||
"packaging": false,
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Project": [],
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "databaseId",
|
||||
"description": "Database ID.",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"x-example": "<DATABASE_ID>"
|
||||
},
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "collectionId",
|
||||
"description": "Collection ID.",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"x-example": "<COLLECTION_ID>"
|
||||
},
|
||||
"in": "path"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application\/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"description": "Document data as JSON object. Include only attribute and value pairs to be updated.",
|
||||
"x-example": "{}"
|
||||
},
|
||||
"queries": {
|
||||
"type": "array",
|
||||
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.",
|
||||
"x-example": null,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"summary": "Delete documents",
|
||||
"operationId": "databasesDeleteDocuments",
|
||||
"tags": [
|
||||
"databases"
|
||||
],
|
||||
"description": "Bulk delete documents using queries, if no queries are passed then all documents are deleted.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Documents List",
|
||||
"content": {
|
||||
"application\/json": {
|
||||
"schema": {
|
||||
"$ref": "#\/components\/schemas\/documentList"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocuments",
|
||||
"weight": 115,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "databases\/delete-documents.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-documents.md",
|
||||
"rate-limit": 60,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
"scope": "documents.write",
|
||||
"platforms": [
|
||||
"client",
|
||||
"server",
|
||||
"server"
|
||||
],
|
||||
"packaging": false,
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Project": [],
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "databaseId",
|
||||
"description": "Database ID.",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"x-example": "<DATABASE_ID>"
|
||||
},
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "collectionId",
|
||||
"description": "Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"x-example": "<COLLECTION_ID>"
|
||||
},
|
||||
"in": "path"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application\/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"queries": {
|
||||
"type": "array",
|
||||
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.",
|
||||
"x-example": null,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4680,7 +4914,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocument",
|
||||
"weight": 113,
|
||||
"weight": 114,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -4763,7 +4997,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"weight": 306,
|
||||
"weight": 308,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -4848,7 +5082,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"weight": 305,
|
||||
"weight": 307,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -4962,7 +5196,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"weight": 307,
|
||||
"weight": 309,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5035,7 +5269,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "query",
|
||||
"weight": 331,
|
||||
"weight": 333,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"deprecated": false,
|
||||
@@ -5086,7 +5320,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "mutation",
|
||||
"weight": 330,
|
||||
"weight": 332,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"deprecated": false,
|
||||
@@ -5137,7 +5371,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "get",
|
||||
"weight": 117,
|
||||
"weight": 119,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5188,7 +5422,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCodes",
|
||||
"weight": 118,
|
||||
"weight": 120,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5239,7 +5473,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listContinents",
|
||||
"weight": 122,
|
||||
"weight": 124,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5290,7 +5524,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountries",
|
||||
"weight": 119,
|
||||
"weight": 121,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5341,7 +5575,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountriesEU",
|
||||
"weight": 120,
|
||||
"weight": 122,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5392,7 +5626,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountriesPhones",
|
||||
"weight": 121,
|
||||
"weight": 123,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5443,7 +5677,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCurrencies",
|
||||
"weight": 123,
|
||||
"weight": 125,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5494,7 +5728,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listLanguages",
|
||||
"weight": 124,
|
||||
"weight": 126,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5545,7 +5779,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createSubscriber",
|
||||
"weight": 376,
|
||||
"weight": 378,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5627,7 +5861,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteSubscriber",
|
||||
"weight": 380,
|
||||
"weight": 382,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5701,7 +5935,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listFiles",
|
||||
"weight": 208,
|
||||
"weight": 210,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5786,7 +6020,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createFile",
|
||||
"weight": 207,
|
||||
"weight": 209,
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"deprecated": false,
|
||||
@@ -5883,7 +6117,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFile",
|
||||
"weight": 209,
|
||||
"weight": 211,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5954,7 +6188,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateFile",
|
||||
"weight": 214,
|
||||
"weight": 216,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6042,7 +6276,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteFile",
|
||||
"weight": 215,
|
||||
"weight": 217,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6108,7 +6342,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFileDownload",
|
||||
"weight": 211,
|
||||
"weight": 213,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6174,7 +6408,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFilePreview",
|
||||
"weight": 210,
|
||||
"weight": 212,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6390,7 +6624,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFileView",
|
||||
"weight": 212,
|
||||
"weight": 214,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6463,7 +6697,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "list",
|
||||
"weight": 219,
|
||||
"weight": 221,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6538,7 +6772,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "create",
|
||||
"weight": 218,
|
||||
"weight": 220,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6622,7 +6856,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "get",
|
||||
"weight": 220,
|
||||
"weight": 222,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6683,7 +6917,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateName",
|
||||
"weight": 222,
|
||||
"weight": 224,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6756,7 +6990,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "delete",
|
||||
"weight": 224,
|
||||
"weight": 226,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6819,7 +7053,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listMemberships",
|
||||
"weight": 226,
|
||||
"weight": 228,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6904,7 +7138,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createMembership",
|
||||
"weight": 225,
|
||||
"weight": 227,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7014,7 +7248,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getMembership",
|
||||
"weight": 227,
|
||||
"weight": 229,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7085,7 +7319,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateMembership",
|
||||
"weight": 228,
|
||||
"weight": 230,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7171,7 +7405,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteMembership",
|
||||
"weight": 230,
|
||||
"weight": 232,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7244,7 +7478,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateMembershipStatus",
|
||||
"weight": 229,
|
||||
"weight": 231,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7341,7 +7575,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getPrefs",
|
||||
"weight": 221,
|
||||
"weight": 223,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7401,7 +7635,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updatePrefs",
|
||||
"weight": 223,
|
||||
"weight": 225,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4367,7 +4367,7 @@
|
||||
"tags": [
|
||||
"databases"
|
||||
],
|
||||
"description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Document",
|
||||
@@ -4398,6 +4398,51 @@
|
||||
"server"
|
||||
],
|
||||
"packaging": false,
|
||||
"methods": [
|
||||
{
|
||||
"name": "createDocument",
|
||||
"parameters": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documentId",
|
||||
"data",
|
||||
"permissions"
|
||||
],
|
||||
"required": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documentId",
|
||||
"data"
|
||||
],
|
||||
"responses": [
|
||||
{
|
||||
"code": 201,
|
||||
"model": "#\/components\/schemas\/document"
|
||||
}
|
||||
],
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n"
|
||||
},
|
||||
{
|
||||
"name": "createDocuments",
|
||||
"parameters": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"required": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"responses": [
|
||||
{
|
||||
"code": 201,
|
||||
"model": "#\/components\/schemas\/documentList"
|
||||
}
|
||||
],
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n"
|
||||
}
|
||||
],
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
@@ -4447,6 +4492,14 @@
|
||||
"description": "Document data as JSON object.",
|
||||
"x-example": "{}"
|
||||
},
|
||||
"documents": {
|
||||
"type": "array",
|
||||
"description": "Array of documents data as JSON object.",
|
||||
"x-example": null,
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
|
||||
@@ -4455,11 +4508,192 @@
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"documentId",
|
||||
"data"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"summary": "Update documents",
|
||||
"operationId": "databasesUpdateDocuments",
|
||||
"tags": [
|
||||
"databases"
|
||||
],
|
||||
"description": "Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Documents List",
|
||||
"content": {
|
||||
"application\/json": {
|
||||
"schema": {
|
||||
"$ref": "#\/components\/schemas\/documentList"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateDocuments",
|
||||
"weight": 113,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "databases\/update-documents.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-documents.md",
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
"scope": "documents.write",
|
||||
"platforms": [
|
||||
"client",
|
||||
"server",
|
||||
"server"
|
||||
],
|
||||
"packaging": false,
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Project": [],
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "databaseId",
|
||||
"description": "Database ID.",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"x-example": "<DATABASE_ID>"
|
||||
},
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "collectionId",
|
||||
"description": "Collection ID.",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"x-example": "<COLLECTION_ID>"
|
||||
},
|
||||
"in": "path"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application\/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"description": "Document data as JSON object. Include only attribute and value pairs to be updated.",
|
||||
"x-example": "{}"
|
||||
},
|
||||
"queries": {
|
||||
"type": "array",
|
||||
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.",
|
||||
"x-example": null,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"summary": "Delete documents",
|
||||
"operationId": "databasesDeleteDocuments",
|
||||
"tags": [
|
||||
"databases"
|
||||
],
|
||||
"description": "Bulk delete documents using queries, if no queries are passed then all documents are deleted.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Documents List",
|
||||
"content": {
|
||||
"application\/json": {
|
||||
"schema": {
|
||||
"$ref": "#\/components\/schemas\/documentList"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocuments",
|
||||
"weight": 115,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "databases\/delete-documents.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-documents.md",
|
||||
"rate-limit": 60,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
"scope": "documents.write",
|
||||
"platforms": [
|
||||
"client",
|
||||
"server",
|
||||
"server"
|
||||
],
|
||||
"packaging": false,
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Project": [],
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "databaseId",
|
||||
"description": "Database ID.",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"x-example": "<DATABASE_ID>"
|
||||
},
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "collectionId",
|
||||
"description": "Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"x-example": "<COLLECTION_ID>"
|
||||
},
|
||||
"in": "path"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application\/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"queries": {
|
||||
"type": "array",
|
||||
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.",
|
||||
"x-example": null,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4680,7 +4914,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocument",
|
||||
"weight": 113,
|
||||
"weight": 114,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -4763,7 +4997,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"weight": 306,
|
||||
"weight": 308,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -4848,7 +5082,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"weight": 305,
|
||||
"weight": 307,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -4962,7 +5196,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"weight": 307,
|
||||
"weight": 309,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5035,7 +5269,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "query",
|
||||
"weight": 331,
|
||||
"weight": 333,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"deprecated": false,
|
||||
@@ -5086,7 +5320,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "mutation",
|
||||
"weight": 330,
|
||||
"weight": 332,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"deprecated": false,
|
||||
@@ -5137,7 +5371,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "get",
|
||||
"weight": 117,
|
||||
"weight": 119,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5188,7 +5422,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCodes",
|
||||
"weight": 118,
|
||||
"weight": 120,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5239,7 +5473,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listContinents",
|
||||
"weight": 122,
|
||||
"weight": 124,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5290,7 +5524,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountries",
|
||||
"weight": 119,
|
||||
"weight": 121,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5341,7 +5575,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountriesEU",
|
||||
"weight": 120,
|
||||
"weight": 122,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5392,7 +5626,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountriesPhones",
|
||||
"weight": 121,
|
||||
"weight": 123,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5443,7 +5677,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCurrencies",
|
||||
"weight": 123,
|
||||
"weight": 125,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5494,7 +5728,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listLanguages",
|
||||
"weight": 124,
|
||||
"weight": 126,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5545,7 +5779,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createSubscriber",
|
||||
"weight": 376,
|
||||
"weight": 378,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5627,7 +5861,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteSubscriber",
|
||||
"weight": 380,
|
||||
"weight": 382,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5701,7 +5935,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listFiles",
|
||||
"weight": 208,
|
||||
"weight": 210,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5786,7 +6020,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createFile",
|
||||
"weight": 207,
|
||||
"weight": 209,
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"deprecated": false,
|
||||
@@ -5883,7 +6117,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFile",
|
||||
"weight": 209,
|
||||
"weight": 211,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5954,7 +6188,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateFile",
|
||||
"weight": 214,
|
||||
"weight": 216,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6042,7 +6276,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteFile",
|
||||
"weight": 215,
|
||||
"weight": 217,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6108,7 +6342,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFileDownload",
|
||||
"weight": 211,
|
||||
"weight": 213,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6174,7 +6408,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFilePreview",
|
||||
"weight": 210,
|
||||
"weight": 212,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6390,7 +6624,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFileView",
|
||||
"weight": 212,
|
||||
"weight": 214,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6463,7 +6697,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "list",
|
||||
"weight": 219,
|
||||
"weight": 221,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6538,7 +6772,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "create",
|
||||
"weight": 218,
|
||||
"weight": 220,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6622,7 +6856,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "get",
|
||||
"weight": 220,
|
||||
"weight": 222,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6683,7 +6917,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateName",
|
||||
"weight": 222,
|
||||
"weight": 224,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6756,7 +6990,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "delete",
|
||||
"weight": 224,
|
||||
"weight": 226,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6819,7 +7053,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listMemberships",
|
||||
"weight": 226,
|
||||
"weight": 228,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6904,7 +7138,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createMembership",
|
||||
"weight": 225,
|
||||
"weight": 227,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7014,7 +7248,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getMembership",
|
||||
"weight": 227,
|
||||
"weight": 229,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7085,7 +7319,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateMembership",
|
||||
"weight": 228,
|
||||
"weight": 230,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7171,7 +7405,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteMembership",
|
||||
"weight": 230,
|
||||
"weight": 232,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7244,7 +7478,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateMembershipStatus",
|
||||
"weight": 229,
|
||||
"weight": 231,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7341,7 +7575,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getPrefs",
|
||||
"weight": 221,
|
||||
"weight": 223,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7401,7 +7635,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updatePrefs",
|
||||
"weight": 223,
|
||||
"weight": 225,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4549,7 +4549,7 @@
|
||||
"tags": [
|
||||
"databases"
|
||||
],
|
||||
"description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Document",
|
||||
@@ -4576,6 +4576,51 @@
|
||||
"server"
|
||||
],
|
||||
"packaging": false,
|
||||
"methods": [
|
||||
{
|
||||
"name": "createDocument",
|
||||
"parameters": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documentId",
|
||||
"data",
|
||||
"permissions"
|
||||
],
|
||||
"required": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documentId",
|
||||
"data"
|
||||
],
|
||||
"responses": [
|
||||
{
|
||||
"code": 201,
|
||||
"model": "#\/definitions\/document"
|
||||
}
|
||||
],
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n"
|
||||
},
|
||||
{
|
||||
"name": "createDocuments",
|
||||
"parameters": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"required": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"responses": [
|
||||
{
|
||||
"code": 201,
|
||||
"model": "#\/definitions\/documentList"
|
||||
}
|
||||
],
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n"
|
||||
}
|
||||
],
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
@@ -4613,15 +4658,24 @@
|
||||
"documentId": {
|
||||
"type": "string",
|
||||
"description": "Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.",
|
||||
"default": null,
|
||||
"default": "",
|
||||
"x-example": "<DOCUMENT_ID>"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"description": "Document data as JSON object.",
|
||||
"default": {},
|
||||
"default": [],
|
||||
"x-example": "{}"
|
||||
},
|
||||
"documents": {
|
||||
"type": "array",
|
||||
"description": "Array of documents data as JSON object.",
|
||||
"default": [],
|
||||
"x-example": null,
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
|
||||
@@ -4631,11 +4685,187 @@
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"documentId",
|
||||
"data"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"patch": {
|
||||
"summary": "Update documents",
|
||||
"operationId": "databasesUpdateDocuments",
|
||||
"consumes": [
|
||||
"application\/json"
|
||||
],
|
||||
"produces": [
|
||||
"application\/json"
|
||||
],
|
||||
"tags": [
|
||||
"databases"
|
||||
],
|
||||
"description": "Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Documents List",
|
||||
"schema": {
|
||||
"$ref": "#\/definitions\/documentList"
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateDocuments",
|
||||
"weight": 113,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "databases\/update-documents.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-documents.md",
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
"scope": "documents.write",
|
||||
"platforms": [
|
||||
"client",
|
||||
"server",
|
||||
"server"
|
||||
],
|
||||
"packaging": false,
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Project": [],
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "databaseId",
|
||||
"description": "Database ID.",
|
||||
"required": true,
|
||||
"type": "string",
|
||||
"x-example": "<DATABASE_ID>",
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "collectionId",
|
||||
"description": "Collection ID.",
|
||||
"required": true,
|
||||
"type": "string",
|
||||
"x-example": "<COLLECTION_ID>",
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"description": "Document data as JSON object. Include only attribute and value pairs to be updated.",
|
||||
"default": [],
|
||||
"x-example": "{}"
|
||||
},
|
||||
"queries": {
|
||||
"type": "array",
|
||||
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.",
|
||||
"default": [],
|
||||
"x-example": null,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"delete": {
|
||||
"summary": "Delete documents",
|
||||
"operationId": "databasesDeleteDocuments",
|
||||
"consumes": [
|
||||
"application\/json"
|
||||
],
|
||||
"produces": [
|
||||
"application\/json"
|
||||
],
|
||||
"tags": [
|
||||
"databases"
|
||||
],
|
||||
"description": "Bulk delete documents using queries, if no queries are passed then all documents are deleted.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Documents List",
|
||||
"schema": {
|
||||
"$ref": "#\/definitions\/documentList"
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocuments",
|
||||
"weight": 115,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "databases\/delete-documents.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-documents.md",
|
||||
"rate-limit": 60,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
"scope": "documents.write",
|
||||
"platforms": [
|
||||
"client",
|
||||
"server",
|
||||
"server"
|
||||
],
|
||||
"packaging": false,
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Project": [],
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "databaseId",
|
||||
"description": "Database ID.",
|
||||
"required": true,
|
||||
"type": "string",
|
||||
"x-example": "<DATABASE_ID>",
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "collectionId",
|
||||
"description": "Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).",
|
||||
"required": true,
|
||||
"type": "string",
|
||||
"x-example": "<COLLECTION_ID>",
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"queries": {
|
||||
"type": "array",
|
||||
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.",
|
||||
"default": [],
|
||||
"x-example": null,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -4850,7 +5080,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocument",
|
||||
"weight": 113,
|
||||
"weight": 114,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -4929,7 +5159,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"weight": 306,
|
||||
"weight": 308,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5011,7 +5241,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"weight": 305,
|
||||
"weight": 307,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5129,7 +5359,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"weight": 307,
|
||||
"weight": 309,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5200,7 +5430,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "query",
|
||||
"weight": 331,
|
||||
"weight": 333,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"deprecated": false,
|
||||
@@ -5273,7 +5503,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "mutation",
|
||||
"weight": 330,
|
||||
"weight": 332,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"deprecated": false,
|
||||
@@ -5346,7 +5576,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "get",
|
||||
"weight": 117,
|
||||
"weight": 119,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5399,7 +5629,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCodes",
|
||||
"weight": 118,
|
||||
"weight": 120,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5452,7 +5682,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listContinents",
|
||||
"weight": 122,
|
||||
"weight": 124,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5505,7 +5735,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountries",
|
||||
"weight": 119,
|
||||
"weight": 121,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5558,7 +5788,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountriesEU",
|
||||
"weight": 120,
|
||||
"weight": 122,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5611,7 +5841,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountriesPhones",
|
||||
"weight": 121,
|
||||
"weight": 123,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5664,7 +5894,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCurrencies",
|
||||
"weight": 123,
|
||||
"weight": 125,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5717,7 +5947,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listLanguages",
|
||||
"weight": 124,
|
||||
"weight": 126,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5770,7 +6000,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createSubscriber",
|
||||
"weight": 376,
|
||||
"weight": 378,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5854,7 +6084,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteSubscriber",
|
||||
"weight": 380,
|
||||
"weight": 382,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5926,7 +6156,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listFiles",
|
||||
"weight": 208,
|
||||
"weight": 210,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6008,7 +6238,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createFile",
|
||||
"weight": 207,
|
||||
"weight": 209,
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"deprecated": false,
|
||||
@@ -6099,7 +6329,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFile",
|
||||
"weight": 209,
|
||||
"weight": 211,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6168,7 +6398,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateFile",
|
||||
"weight": 214,
|
||||
"weight": 216,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6256,7 +6486,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteFile",
|
||||
"weight": 215,
|
||||
"weight": 217,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6327,7 +6557,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFileDownload",
|
||||
"weight": 211,
|
||||
"weight": 213,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6398,7 +6628,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFilePreview",
|
||||
"weight": 210,
|
||||
"weight": 212,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6597,7 +6827,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFileView",
|
||||
"weight": 212,
|
||||
"weight": 214,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6668,7 +6898,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "list",
|
||||
"weight": 219,
|
||||
"weight": 221,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6742,7 +6972,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "create",
|
||||
"weight": 218,
|
||||
"weight": 220,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6833,7 +7063,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "get",
|
||||
"weight": 220,
|
||||
"weight": 222,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6894,7 +7124,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateName",
|
||||
"weight": 222,
|
||||
"weight": 224,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6968,7 +7198,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "delete",
|
||||
"weight": 224,
|
||||
"weight": 226,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7031,7 +7261,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listMemberships",
|
||||
"weight": 226,
|
||||
"weight": 228,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7113,7 +7343,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createMembership",
|
||||
"weight": 225,
|
||||
"weight": 227,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7227,7 +7457,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getMembership",
|
||||
"weight": 227,
|
||||
"weight": 229,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7296,7 +7526,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateMembership",
|
||||
"weight": 228,
|
||||
"weight": 230,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7381,7 +7611,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteMembership",
|
||||
"weight": 230,
|
||||
"weight": 232,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7452,7 +7682,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateMembershipStatus",
|
||||
"weight": 229,
|
||||
"weight": 231,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7547,7 +7777,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getPrefs",
|
||||
"weight": 221,
|
||||
"weight": 223,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7607,7 +7837,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updatePrefs",
|
||||
"weight": 223,
|
||||
"weight": 225,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4549,7 +4549,7 @@
|
||||
"tags": [
|
||||
"databases"
|
||||
],
|
||||
"description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Document",
|
||||
@@ -4576,6 +4576,51 @@
|
||||
"server"
|
||||
],
|
||||
"packaging": false,
|
||||
"methods": [
|
||||
{
|
||||
"name": "createDocument",
|
||||
"parameters": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documentId",
|
||||
"data",
|
||||
"permissions"
|
||||
],
|
||||
"required": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documentId",
|
||||
"data"
|
||||
],
|
||||
"responses": [
|
||||
{
|
||||
"code": 201,
|
||||
"model": "#\/definitions\/document"
|
||||
}
|
||||
],
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n"
|
||||
},
|
||||
{
|
||||
"name": "createDocuments",
|
||||
"parameters": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"required": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"responses": [
|
||||
{
|
||||
"code": 201,
|
||||
"model": "#\/definitions\/documentList"
|
||||
}
|
||||
],
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n"
|
||||
}
|
||||
],
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
@@ -4613,15 +4658,24 @@
|
||||
"documentId": {
|
||||
"type": "string",
|
||||
"description": "Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.",
|
||||
"default": null,
|
||||
"default": "",
|
||||
"x-example": "<DOCUMENT_ID>"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"description": "Document data as JSON object.",
|
||||
"default": {},
|
||||
"default": [],
|
||||
"x-example": "{}"
|
||||
},
|
||||
"documents": {
|
||||
"type": "array",
|
||||
"description": "Array of documents data as JSON object.",
|
||||
"default": [],
|
||||
"x-example": null,
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"description": "An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
|
||||
@@ -4631,11 +4685,187 @@
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"documentId",
|
||||
"data"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"patch": {
|
||||
"summary": "Update documents",
|
||||
"operationId": "databasesUpdateDocuments",
|
||||
"consumes": [
|
||||
"application\/json"
|
||||
],
|
||||
"produces": [
|
||||
"application\/json"
|
||||
],
|
||||
"tags": [
|
||||
"databases"
|
||||
],
|
||||
"description": "Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Documents List",
|
||||
"schema": {
|
||||
"$ref": "#\/definitions\/documentList"
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateDocuments",
|
||||
"weight": 113,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "databases\/update-documents.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/update-documents.md",
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
"scope": "documents.write",
|
||||
"platforms": [
|
||||
"client",
|
||||
"server",
|
||||
"server"
|
||||
],
|
||||
"packaging": false,
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Project": [],
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "databaseId",
|
||||
"description": "Database ID.",
|
||||
"required": true,
|
||||
"type": "string",
|
||||
"x-example": "<DATABASE_ID>",
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "collectionId",
|
||||
"description": "Collection ID.",
|
||||
"required": true,
|
||||
"type": "string",
|
||||
"x-example": "<COLLECTION_ID>",
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"description": "Document data as JSON object. Include only attribute and value pairs to be updated.",
|
||||
"default": [],
|
||||
"x-example": "{}"
|
||||
},
|
||||
"queries": {
|
||||
"type": "array",
|
||||
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.",
|
||||
"default": [],
|
||||
"x-example": null,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"delete": {
|
||||
"summary": "Delete documents",
|
||||
"operationId": "databasesDeleteDocuments",
|
||||
"consumes": [
|
||||
"application\/json"
|
||||
],
|
||||
"produces": [
|
||||
"application\/json"
|
||||
],
|
||||
"tags": [
|
||||
"databases"
|
||||
],
|
||||
"description": "Bulk delete documents using queries, if no queries are passed then all documents are deleted.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Documents List",
|
||||
"schema": {
|
||||
"$ref": "#\/definitions\/documentList"
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocuments",
|
||||
"weight": 115,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "databases\/delete-documents.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/delete-documents.md",
|
||||
"rate-limit": 60,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
"scope": "documents.write",
|
||||
"platforms": [
|
||||
"client",
|
||||
"server",
|
||||
"server"
|
||||
],
|
||||
"packaging": false,
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Project": [],
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "databaseId",
|
||||
"description": "Database ID.",
|
||||
"required": true,
|
||||
"type": "string",
|
||||
"x-example": "<DATABASE_ID>",
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "collectionId",
|
||||
"description": "Collection ID. You can create a new collection using the Database service [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection).",
|
||||
"required": true,
|
||||
"type": "string",
|
||||
"x-example": "<COLLECTION_ID>",
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"queries": {
|
||||
"type": "array",
|
||||
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long.",
|
||||
"default": [],
|
||||
"x-example": null,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -4850,7 +5080,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocument",
|
||||
"weight": 113,
|
||||
"weight": 114,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -4929,7 +5159,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"weight": 306,
|
||||
"weight": 308,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5011,7 +5241,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"weight": 305,
|
||||
"weight": 307,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5129,7 +5359,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"weight": 307,
|
||||
"weight": 309,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5200,7 +5430,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "query",
|
||||
"weight": 331,
|
||||
"weight": 333,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"deprecated": false,
|
||||
@@ -5273,7 +5503,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "mutation",
|
||||
"weight": 330,
|
||||
"weight": 332,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"deprecated": false,
|
||||
@@ -5346,7 +5576,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "get",
|
||||
"weight": 117,
|
||||
"weight": 119,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5399,7 +5629,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCodes",
|
||||
"weight": 118,
|
||||
"weight": 120,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5452,7 +5682,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listContinents",
|
||||
"weight": 122,
|
||||
"weight": 124,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5505,7 +5735,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountries",
|
||||
"weight": 119,
|
||||
"weight": 121,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5558,7 +5788,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountriesEU",
|
||||
"weight": 120,
|
||||
"weight": 122,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5611,7 +5841,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountriesPhones",
|
||||
"weight": 121,
|
||||
"weight": 123,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5664,7 +5894,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCurrencies",
|
||||
"weight": 123,
|
||||
"weight": 125,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5717,7 +5947,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listLanguages",
|
||||
"weight": 124,
|
||||
"weight": 126,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5770,7 +6000,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createSubscriber",
|
||||
"weight": 376,
|
||||
"weight": 378,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5854,7 +6084,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteSubscriber",
|
||||
"weight": 380,
|
||||
"weight": 382,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5926,7 +6156,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listFiles",
|
||||
"weight": 208,
|
||||
"weight": 210,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6008,7 +6238,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createFile",
|
||||
"weight": 207,
|
||||
"weight": 209,
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"deprecated": false,
|
||||
@@ -6099,7 +6329,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFile",
|
||||
"weight": 209,
|
||||
"weight": 211,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6168,7 +6398,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateFile",
|
||||
"weight": 214,
|
||||
"weight": 216,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6256,7 +6486,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteFile",
|
||||
"weight": 215,
|
||||
"weight": 217,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6327,7 +6557,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFileDownload",
|
||||
"weight": 211,
|
||||
"weight": 213,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6398,7 +6628,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFilePreview",
|
||||
"weight": 210,
|
||||
"weight": 212,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6597,7 +6827,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFileView",
|
||||
"weight": 212,
|
||||
"weight": 214,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6668,7 +6898,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "list",
|
||||
"weight": 219,
|
||||
"weight": 221,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6742,7 +6972,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "create",
|
||||
"weight": 218,
|
||||
"weight": 220,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6833,7 +7063,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "get",
|
||||
"weight": 220,
|
||||
"weight": 222,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6894,7 +7124,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateName",
|
||||
"weight": 222,
|
||||
"weight": 224,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6968,7 +7198,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "delete",
|
||||
"weight": 224,
|
||||
"weight": 226,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7031,7 +7261,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listMemberships",
|
||||
"weight": 226,
|
||||
"weight": 228,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7113,7 +7343,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createMembership",
|
||||
"weight": 225,
|
||||
"weight": 227,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7227,7 +7457,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getMembership",
|
||||
"weight": 227,
|
||||
"weight": 229,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7296,7 +7526,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateMembership",
|
||||
"weight": 228,
|
||||
"weight": 230,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7381,7 +7611,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteMembership",
|
||||
"weight": 230,
|
||||
"weight": 232,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7452,7 +7682,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateMembershipStatus",
|
||||
"weight": 229,
|
||||
"weight": 231,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7547,7 +7777,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getPrefs",
|
||||
"weight": 221,
|
||||
"weight": 223,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7607,7 +7837,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updatePrefs",
|
||||
"weight": 223,
|
||||
"weight": 225,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2006,6 +2006,7 @@ App::post('/v1/account/tokens/magic-url')
|
||||
|
||||
$senderEmail = System::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM);
|
||||
$senderName = System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server');
|
||||
|
||||
$replyTo = "";
|
||||
|
||||
if ($smtpEnabled) {
|
||||
|
||||
@@ -3115,7 +3115,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
->alias('/v1/database/collections/:collectionId/documents', ['databaseId' => 'default'])
|
||||
->desc('Create document')
|
||||
->groups(['api', 'database'])
|
||||
->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].create')
|
||||
->label('scope', 'documents.write')
|
||||
->label('resourceType', RESOURCE_TYPE_DATABASES)
|
||||
->label('audits.event', 'document.create')
|
||||
@@ -3137,33 +3136,79 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
model: Response::MODEL_DOCUMENT,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
contentType: ContentType::JSON,
|
||||
parameters: [
|
||||
'databaseId' => ['optional' => false],
|
||||
'collectionId' => ['optional' => false],
|
||||
'documentId' => ['optional' => false],
|
||||
'data' => ['optional' => false],
|
||||
'permissions' => ['optional' => true],
|
||||
]
|
||||
),
|
||||
new Method(
|
||||
namespace: 'databases',
|
||||
name: 'createDocuments',
|
||||
description: '/docs/references/databases/create-document.md',
|
||||
auth: [AuthType::SESSION, AuthType::KEY, AuthType::JWT],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_CREATED,
|
||||
model: Response::MODEL_DOCUMENT_LIST,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON,
|
||||
parameters: [
|
||||
'databaseId' => ['optional' => false],
|
||||
'collectionId' => ['optional' => false],
|
||||
'documents' => ['optional' => false],
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('documentId', '', new CustomId(), 'Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('documentId', '', new CustomId(), 'Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', true)
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.')
|
||||
->param('data', [], new JSON(), 'Document data as JSON object.')
|
||||
->param('data', [], new JSON(), 'Document data as JSON object.', true)
|
||||
->param('documents', [], new ArrayList(new JSON(), APP_LIMIT_DOCUMENTS_CREATE), 'Array of documents data as JSON object.', true)
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('user')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForStatsUsage')
|
||||
->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage) {
|
||||
->inject('project')
|
||||
->action(function (string $databaseId, ?string $documentId, string $collectionId, string|array|null $data, ?array $documents, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage, Document $project) {
|
||||
$data = \is_string($data)
|
||||
? \json_decode($data, true)
|
||||
: $data;
|
||||
|
||||
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
|
||||
$isBulk = true;
|
||||
|
||||
if (empty($data)) {
|
||||
if (empty($data) && empty($documents)) {
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
|
||||
if (isset($data['$id'])) {
|
||||
throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, '$id is not allowed for creating new documents, try update instead');
|
||||
if (!empty($data) && !empty($documents)) {
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'You can only send one of the following parameters: data, documents');
|
||||
}
|
||||
if (!empty($data) && empty($documentId)) {
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA, 'Document ID is required when creating a single document');
|
||||
}
|
||||
if (!empty($documents) && !empty($documentId)) {
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Param "documentId" is disallowed when creating multiple documents, set "$id" in each document instead');
|
||||
}
|
||||
if (!empty($documents) && !empty($permissions)) {
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Param "permissions" is disallowed when creating multiple documents, set "$permissions" in each document instead');
|
||||
}
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
if (!empty($data)) {
|
||||
$isBulk = false;
|
||||
$documents = [$data];
|
||||
}
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument(
|
||||
'databases',
|
||||
$databaseId
|
||||
));
|
||||
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
@@ -3184,43 +3229,45 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
Database::PERMISSION_DELETE,
|
||||
];
|
||||
|
||||
// Map aggregate permissions to into the set of individual permissions they represent.
|
||||
$permissions = Permission::aggregate($permissions, $allowedPermissions);
|
||||
|
||||
// Add permissions for current the user if none were provided.
|
||||
if (\is_null($permissions)) {
|
||||
$permissions = [];
|
||||
if (!empty($user->getId())) {
|
||||
foreach ($allowedPermissions as $permission) {
|
||||
$permissions[] = (new Permission($permission, 'user', $user->getId()))->toString();
|
||||
}
|
||||
$setPermissions = function (Document $document, ?array $permissions) use ($user, $allowedPermissions, $isAPIKey, $isPrivilegedUser, $isBulk) {
|
||||
if ($isBulk) {
|
||||
$permissions = $document['$permissions'] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
// Users can only manage their own roles, API keys and Admin users can manage any
|
||||
if (!$isAPIKey && !$isPrivilegedUser) {
|
||||
foreach (Database::PERMISSIONS as $type) {
|
||||
foreach ($permissions as $permission) {
|
||||
$permission = Permission::parse($permission);
|
||||
if ($permission->getPermission() != $type) {
|
||||
continue;
|
||||
}
|
||||
$role = (new Role(
|
||||
$permission->getRole(),
|
||||
$permission->getIdentifier(),
|
||||
$permission->getDimension()
|
||||
))->toString();
|
||||
if (!Authorization::isRole($role)) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', Authorization::getRoles()) . ')');
|
||||
$permissions = Permission::aggregate($permissions, $allowedPermissions);
|
||||
|
||||
// Add permissions for current the user if none were provided.
|
||||
if (\is_null($permissions)) {
|
||||
$permissions = [];
|
||||
if (!empty($user->getId())) {
|
||||
foreach ($allowedPermissions as $permission) {
|
||||
$permissions[] = (new Permission($permission, 'user', $user->getId()))->toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data['$collection'] = $collection->getId(); // Adding this param to make API easier for developers
|
||||
$data['$id'] = $documentId == 'unique()' ? ID::unique() : $documentId;
|
||||
$data['$permissions'] = $permissions;
|
||||
$document = new Document($data);
|
||||
// Users can only manage their own roles, API keys and Admin users can manage any
|
||||
if (!$isAPIKey && !$isPrivilegedUser) {
|
||||
foreach (Database::PERMISSIONS as $type) {
|
||||
foreach ($permissions as $permission) {
|
||||
$permission = Permission::parse($permission);
|
||||
if ($permission->getPermission() != $type) {
|
||||
continue;
|
||||
}
|
||||
$role = (new Role(
|
||||
$permission->getRole(),
|
||||
$permission->getIdentifier(),
|
||||
$permission->getDimension()
|
||||
))->toString();
|
||||
if (!Authorization::isRole($role)) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', Authorization::getRoles()) . ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$document->setAttribute('$permissions', $permissions);
|
||||
};
|
||||
|
||||
$operations = 0;
|
||||
|
||||
@@ -3306,21 +3353,50 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
}
|
||||
};
|
||||
|
||||
$checkPermissions($collection, $document, Database::PERMISSION_CREATE);
|
||||
$documents = array_map(function ($document) use ($collection, $permissions, $checkPermissions, $isBulk, $documentId, $setPermissions) {
|
||||
$document['$collection'] = $collection->getId();
|
||||
|
||||
if (!$isBulk) {
|
||||
$document['$id'] = $documentId == 'unique()' ? ID::unique() : $documentId;
|
||||
} else {
|
||||
if (empty($document['$id'])) {
|
||||
throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, '$id must be set in each document when creating bulk documents');
|
||||
}
|
||||
|
||||
$document['$id'] = $document['$id'] == 'unique()' ? ID::unique() : $document['$id'];
|
||||
}
|
||||
|
||||
$document = new Document($document);
|
||||
|
||||
$setPermissions($document, $permissions);
|
||||
$checkPermissions($collection, $document, Database::PERMISSION_CREATE);
|
||||
|
||||
return $document;
|
||||
}, $documents);
|
||||
|
||||
try {
|
||||
$document = $dbForProject->createDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $document);
|
||||
$dbForProject->createDocuments(
|
||||
'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
|
||||
$documents,
|
||||
APP_LIMIT_DATABASE_BATCH
|
||||
);
|
||||
} catch (StructureException $e) {
|
||||
throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $e->getMessage());
|
||||
} catch (DuplicateException $e) {
|
||||
} catch (DuplicateException) {
|
||||
throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS);
|
||||
} catch (NotFoundException $e) {
|
||||
} catch (NotFoundException) {
|
||||
throw new Exception(Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
->setParam('databaseId', $databaseId)
|
||||
->setParam('collectionId', $collection->getId())
|
||||
->setContext('collection', $collection)
|
||||
->setContext('database', $database);
|
||||
|
||||
// Add $collectionId and $databaseId for all documents
|
||||
$processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) {
|
||||
$processDocument = function (Document $collection, Document &$document) use (&$processDocument, $dbForProject, $database) {
|
||||
$document->removeAttribute('$collection');
|
||||
$document->setAttribute('$databaseId', $database->getId());
|
||||
$document->setAttribute('$collectionId', $collection->getId());
|
||||
|
||||
@@ -3352,34 +3428,35 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
}
|
||||
};
|
||||
|
||||
$processDocument($collection, $document);
|
||||
foreach ($documents as $document) {
|
||||
$processDocument($collection, $document);
|
||||
}
|
||||
|
||||
$queueForStatsUsage
|
||||
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, $operations)
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_WRITES), $operations)
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
|
||||
|
||||
$response->addHeader('X-Debug-Operations', $operations);
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($document, Response::MODEL_DOCUMENT);
|
||||
->addHeader('X-Debug-Operations', $operations);
|
||||
|
||||
$relationships = \array_map(
|
||||
fn ($document) => $document->getAttribute('key'),
|
||||
\array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
)
|
||||
);
|
||||
if ($isBulk) {
|
||||
$response->dynamic(new Document([
|
||||
'total' => count($documents),
|
||||
'documents' => $documents
|
||||
]), Response::MODEL_DOCUMENT_LIST);
|
||||
} else {
|
||||
$queueForEvents
|
||||
->setParam('documentId', $document->getId())
|
||||
->setEvent('databases.[databaseId].collections.[collectionId].documents.[documentId].create');
|
||||
|
||||
$response->dynamic(
|
||||
$documents[0],
|
||||
Response::MODEL_DOCUMENT
|
||||
);
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
->setParam('databaseId', $databaseId)
|
||||
->setParam('collectionId', $collection->getId())
|
||||
->setParam('documentId', $document->getId())
|
||||
->setContext('collection', $collection)
|
||||
->setContext('database', $database)
|
||||
->setPayload($response->getPayload(), sensitive: $relationships);
|
||||
});
|
||||
|
||||
App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
@@ -3467,7 +3544,6 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
|
||||
$operations++;
|
||||
|
||||
$document->removeAttribute('$collection');
|
||||
$document->setAttribute('$databaseId', $database->getId());
|
||||
$document->setAttribute('$collectionId', $collection->getId());
|
||||
|
||||
@@ -4037,6 +4113,155 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
|
||||
->setPayload($response->getPayload(), sensitive: $relationships);
|
||||
});
|
||||
|
||||
App::patch('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
->desc('Update documents')
|
||||
->groups(['api', 'database'])
|
||||
->label('scope', 'documents.write')
|
||||
->label('resourceType', RESOURCE_TYPE_DATABASES)
|
||||
->label('audits.event', 'documents.update')
|
||||
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
|
||||
->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
|
||||
->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT * 2)
|
||||
->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT)
|
||||
->label('sdk', new Method(
|
||||
namespace: 'databases',
|
||||
name: 'updateDocuments',
|
||||
description: '/docs/references/databases/update-documents.md',
|
||||
auth: [AuthType::SESSION, AuthType::KEY, AuthType::JWT],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_DOCUMENT_LIST,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('data', [], new JSON(), 'Document data as JSON object. Include only attribute and value pairs to be updated.', true)
|
||||
->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true)
|
||||
->inject('requestTimestamp')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('project')
|
||||
->action(function (string $databaseId, string $collectionId, string|array $data, array $queries, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Document $project) {
|
||||
$data = \is_string($data)
|
||||
? \json_decode($data, true)
|
||||
: $data;
|
||||
|
||||
if (empty($data)) {
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_PAYLOAD);
|
||||
}
|
||||
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId));
|
||||
|
||||
if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
|
||||
throw new Exception(Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$permissions = $data['$permissions'] ?? null;
|
||||
|
||||
// Map aggregate permissions into the multiple permissions they represent.
|
||||
$permissions = Permission::aggregate($permissions, [
|
||||
Database::PERMISSION_READ,
|
||||
Database::PERMISSION_UPDATE,
|
||||
Database::PERMISSION_DELETE,
|
||||
]);
|
||||
|
||||
// Users can only manage their own roles, API keys and Admin users can manage any
|
||||
$roles = Authorization::getRoles();
|
||||
if (!$isAPIKey && !$isPrivilegedUser && !\is_null($permissions)) {
|
||||
foreach (Database::PERMISSIONS as $type) {
|
||||
foreach ($permissions as $permission) {
|
||||
$permission = Permission::parse($permission);
|
||||
if ($permission->getPermission() != $type) {
|
||||
continue;
|
||||
}
|
||||
$role = (new Role(
|
||||
$permission->getRole(),
|
||||
$permission->getIdentifier(),
|
||||
$permission->getDimension()
|
||||
))->toString();
|
||||
if (!Authorization::isRole($role)) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!\is_null($permissions)) {
|
||||
$data['$permissions'] = $permissions;
|
||||
}
|
||||
|
||||
$partialDocument = new Document($data);
|
||||
|
||||
$documents = $dbForProject->withRequestTimestamp(
|
||||
$requestTimestamp,
|
||||
fn () => $dbForProject->updateDocuments(
|
||||
'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
|
||||
$partialDocument,
|
||||
$queries,
|
||||
APP_LIMIT_DATABASE_BATCH
|
||||
)
|
||||
);
|
||||
|
||||
$processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) {
|
||||
$document->setAttribute('$databaseId', $database->getId());
|
||||
$document->setAttribute('$collectionId', $collection->getId());
|
||||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
$related = $document->getAttribute($relationship->getAttribute('key'));
|
||||
|
||||
if (empty($related)) {
|
||||
continue;
|
||||
}
|
||||
if (!\is_array($related)) {
|
||||
$related = [$related];
|
||||
}
|
||||
|
||||
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
|
||||
$relatedCollection = Authorization::skip(
|
||||
fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId)
|
||||
);
|
||||
|
||||
foreach ($related as $relation) {
|
||||
if ($relation instanceof Document) {
|
||||
$processDocument($relatedCollection, $relation);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
foreach ($documents as $document) {
|
||||
$processDocument($collection, $document);
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => \count($documents),
|
||||
'documents' => $documents
|
||||
]), Response::MODEL_DOCUMENT_LIST);
|
||||
});
|
||||
|
||||
App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:documentId')
|
||||
->alias('/v1/database/collections/:collectionId/documents/:documentId', ['databaseId' => 'default'])
|
||||
->desc('Delete document')
|
||||
@@ -4162,9 +4387,129 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
|
||||
->setContext('database', $database)
|
||||
->setPayload($response->output($document, Response::MODEL_DOCUMENT), sensitive: $relationships);
|
||||
|
||||
$queueForStatsUsage
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
App::delete('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
->desc('Delete documents')
|
||||
->groups(['api', 'database'])
|
||||
->label('scope', 'documents.write')
|
||||
->label('resourceType', RESOURCE_TYPE_DATABASES)
|
||||
->label('audits.event', 'documents.delete')
|
||||
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
|
||||
->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
|
||||
->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT)
|
||||
->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT)
|
||||
->label('sdk', new Method(
|
||||
namespace: 'databases',
|
||||
name: 'deleteDocuments',
|
||||
description: '/docs/references/databases/delete-documents.md',
|
||||
auth: [AuthType::SESSION, AuthType::KEY, AuthType::JWT],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_DOCUMENT_LIST,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
|
||||
->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true)
|
||||
->inject('requestTimestamp')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForStatsUsage')
|
||||
->inject('project')
|
||||
->action(function (string $databaseId, string $collectionId, array $queries, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, StatsUsage $queueForStatsUsage, Document $project) {
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
|
||||
if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId));
|
||||
|
||||
if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
|
||||
throw new Exception(Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$documents = $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $queries) {
|
||||
return $dbForProject->deleteDocuments(
|
||||
'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
|
||||
$queries,
|
||||
APP_LIMIT_DATABASE_BATCH
|
||||
);
|
||||
});
|
||||
|
||||
// DB Storage Calculation
|
||||
$queueForStatsUsage
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
|
||||
|
||||
$processDocument = (function (Document $collection, Document &$document) use (&$processDocument, $dbForProject, $database): bool {
|
||||
if ($document->isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$document->setAttribute('$databaseId', $database->getId());
|
||||
$document->setAttribute('$collectionId', $collection->getId());
|
||||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
$related = $document->getAttribute($relationship->getAttribute('key'));
|
||||
|
||||
if (empty($related)) {
|
||||
continue;
|
||||
}
|
||||
if (!\is_array($related)) {
|
||||
$relations = [$related];
|
||||
} else {
|
||||
$relations = $related;
|
||||
}
|
||||
|
||||
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
|
||||
$relatedCollection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId));
|
||||
|
||||
foreach ($relations as $index => $doc) {
|
||||
if ($doc instanceof Document) {
|
||||
if (!$processDocument($relatedCollection, $doc)) {
|
||||
unset($relations[$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (\is_array($related)) {
|
||||
$document->setAttribute($relationship->getAttribute('key'), \array_values($relations));
|
||||
} elseif (empty($relations)) {
|
||||
$document->setAttribute($relationship->getAttribute('key'), null);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => \count($documents),
|
||||
'documents' => $documents,
|
||||
]), Response::MODEL_DOCUMENT_LIST);
|
||||
});
|
||||
|
||||
App::get('/v1/databases/usage')
|
||||
->desc('Get databases usage stats')
|
||||
->groups(['api', 'database', 'usage'])
|
||||
|
||||
@@ -92,10 +92,17 @@ $eventDatabaseListener = function (Document $project, Document $document, Respon
|
||||
|
||||
$usageDatabaseListener = function (string $event, Document $document, StatsUsage $queueForStatsUsage) {
|
||||
$value = 1;
|
||||
|
||||
if ($event === Database::EVENT_DOCUMENT_DELETE) {
|
||||
$value = -1;
|
||||
}
|
||||
|
||||
if ($event === Database::EVENT_DOCUMENTS_DELETE) {
|
||||
$value = -1 * $document->getAttribute('modified', 0);
|
||||
} elseif ($event === Database::EVENT_DOCUMENTS_CREATE) {
|
||||
$value = $document->getAttribute('modified', 0);
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case $document->getCollection() === 'teams':
|
||||
$queueForStatsUsage->addMetric(METRIC_TEAMS, $value); // per project
|
||||
@@ -508,6 +515,8 @@ App::init()
|
||||
$dbForProject
|
||||
->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage))
|
||||
->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage))
|
||||
->on(Database::EVENT_DOCUMENTS_CREATE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage))
|
||||
->on(Database::EVENT_DOCUMENTS_DELETE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage))
|
||||
->on(Database::EVENT_DOCUMENT_CREATE, 'create-trigger-events', fn ($event, $document) => $eventDatabaseListener(
|
||||
$project,
|
||||
$document,
|
||||
|
||||
@@ -26,6 +26,8 @@ const APP_LIMIT_SUBSCRIBERS_SUBQUERY = 1_000_000;
|
||||
const APP_LIMIT_WRITE_RATE_DEFAULT = 60; // Default maximum write rate per rate period
|
||||
const APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT = 60; // Default maximum write rate period in seconds
|
||||
const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return in list API calls
|
||||
const APP_LIMIT_DOCUMENTS_CREATE = 5_000; // Default maximum of how many documents can be inserted in a single request
|
||||
const APP_LIMIT_DATABASE_BATCH = 1_000; // Default batch size for database operations
|
||||
const APP_KEY_ACCESS = 24 * 60 * 60; // 24 hours
|
||||
const APP_USER_ACCESS = 24 * 60 * 60; // 24 hours
|
||||
const APP_PROJECT_ACCESS = 24 * 60 * 60; // 24 hours
|
||||
|
||||
+3
-3
@@ -30,7 +30,7 @@
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0.0",
|
||||
"php": ">=8.3.0",
|
||||
"ext-curl": "*",
|
||||
"ext-imagick": "*",
|
||||
"ext-mbstring": "*",
|
||||
@@ -99,8 +99,8 @@
|
||||
"php": "8.3"
|
||||
},
|
||||
"allow-plugins": {
|
||||
"php-http/discovery": false,
|
||||
"tbachert/spi": false
|
||||
"php-http/discovery": true,
|
||||
"tbachert/spi": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+2
-2
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "44c6436ced36b0b026139edba252052e",
|
||||
"content-hash": "54fc27a2c8d4f5ab4959dbc93be319e1",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -8406,7 +8406,7 @@
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=8.0.0",
|
||||
"php": ">=8.3.0",
|
||||
"ext-curl": "*",
|
||||
"ext-imagick": "*",
|
||||
"ext-mbstring": "*",
|
||||
|
||||
@@ -1 +1 @@
|
||||
Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.
|
||||
Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Bulk delete documents using queries, if no queries are passed then all documents are deleted.
|
||||
@@ -0,0 +1 @@
|
||||
Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.
|
||||
@@ -85,13 +85,19 @@ App::post('/v1/account/create')
|
||||
|
||||
```php
|
||||
App::post('/v1/account/jwt')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_SESSION])
|
||||
->label('sdk.namespace', 'account')
|
||||
->label('sdk.method', 'createJWT')
|
||||
->label('sdk.description', '/docs/references/account/create-jwt.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_JWT)
|
||||
->label('sdk', new Method(
|
||||
namespace: 'account',
|
||||
name: 'createJWT',
|
||||
description: '/docs/references/account/create-jwt.md',
|
||||
auth: [],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_CREATED,
|
||||
model: Response::MODEL_JWT,
|
||||
)
|
||||
],
|
||||
responseType: ResponseType::JSON,
|
||||
))
|
||||
```
|
||||
|
||||
#### Cache
|
||||
|
||||
@@ -131,10 +131,8 @@ class OpenAPI3 extends Format
|
||||
|
||||
$additionalMethods = null;
|
||||
if (is_array($sdk)) {
|
||||
$mainSdk = array_shift($sdk);
|
||||
$additionalMethods = $sdk;
|
||||
|
||||
$sdk = $mainSdk;
|
||||
$sdk = $sdk[0];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,14 +200,16 @@ class OpenAPI3 extends Format
|
||||
|
||||
|
||||
if (!empty($additionalMethods)) {
|
||||
$temp['x-appwrite']['additional-methods'] = [];
|
||||
$temp['x-appwrite']['methods'] = [];
|
||||
foreach ($additionalMethods as $method) {
|
||||
/** @var \Appwrite\SDK\Method $method */
|
||||
$desc = $method->getDescriptionFilePath();
|
||||
$additionalMethod = [
|
||||
'name' => $method->getMethodName(),
|
||||
'parameters' => [],
|
||||
'required' => [],
|
||||
'responses' => []
|
||||
'responses' => [],
|
||||
'description' => ($desc) ? \file_get_contents($desc) : '',
|
||||
];
|
||||
|
||||
foreach ($method->getParameters() as $name => $param) {
|
||||
@@ -222,13 +222,20 @@ class OpenAPI3 extends Format
|
||||
|
||||
foreach ($method->getResponses() as $response) {
|
||||
/** @var \Appwrite\SDK\Response $response */
|
||||
$additionalMethod['responses'][] = [
|
||||
'code' => $response->getCode(),
|
||||
'model' => '#/components/schemas/' . $response->getModel()
|
||||
];
|
||||
if (\is_array($response->getModel())) {
|
||||
$additionalMethod['responses'][] = [
|
||||
'code' => $response->getCode(),
|
||||
'model' => \array_map(fn ($m) => '#/components/schemas/' . $m, $response->getModel())
|
||||
];
|
||||
} else {
|
||||
$additionalMethod['responses'][] = [
|
||||
'code' => $response->getCode(),
|
||||
'model' => '#/components/schemas/' . $response->getModel()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$temp['x-appwrite']['additional-methods'][] = $additionalMethod;
|
||||
$temp['x-appwrite']['methods'][] = $additionalMethod;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -130,10 +130,8 @@ class Swagger2 extends Format
|
||||
|
||||
$additionalMethods = null;
|
||||
if (is_array($sdk)) {
|
||||
$mainSdk = array_shift($sdk);
|
||||
$additionalMethods = $sdk;
|
||||
|
||||
$sdk = $mainSdk;
|
||||
$sdk = $sdk[0];
|
||||
}
|
||||
|
||||
$consumes = [$sdk->getRequestType()];
|
||||
@@ -203,15 +201,17 @@ class Swagger2 extends Format
|
||||
}
|
||||
|
||||
if (!empty($additionalMethods)) {
|
||||
$temp['x-appwrite']['additional-methods'] = [];
|
||||
$temp['x-appwrite']['methods'] = [];
|
||||
foreach ($additionalMethods as $method) {
|
||||
/** @var \Appwrite\SDK\Method $method */
|
||||
$desc = $method->getDescriptionFilePath();
|
||||
|
||||
$additionalMethod = [
|
||||
'name' => $method->getMethodName(),
|
||||
'parameters' => [],
|
||||
'required' => [],
|
||||
'responses' => [],
|
||||
'description' => $method->getDescription(),
|
||||
'description' => ($desc) ? \file_get_contents($desc) : '',
|
||||
];
|
||||
|
||||
foreach ($method->getParameters() as $name => $param) {
|
||||
@@ -224,13 +224,20 @@ class Swagger2 extends Format
|
||||
|
||||
foreach ($method->getResponses() as $response) {
|
||||
/** @var \Appwrite\SDK\Response $response */
|
||||
$additionalMethod['responses'][] = [
|
||||
'code' => $response->getCode(),
|
||||
'model' => '#/definitions/' . $response->getModel()
|
||||
];
|
||||
if (\is_array($response->getModel())) {
|
||||
$additionalMethod['responses'][] = [
|
||||
'code' => $response->getCode(),
|
||||
'model' => \array_map(fn ($m) => '#/definitions/' . $m, $response->getModel())
|
||||
];
|
||||
} else {
|
||||
$additionalMethod['responses'][] = [
|
||||
'code' => $response->getCode(),
|
||||
'model' => '#/definitions/' . $response->getModel()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$temp['x-appwrite']['additional-methods'][] = $additionalMethod;
|
||||
$temp['x-appwrite']['methods'][] = $additionalMethod;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
import { check, sleep } from "k6";
|
||||
import http from "k6/http";
|
||||
import { provisionProject, provisionDatabase, cleanup, unique } from "./utils.js";
|
||||
|
||||
const millionRecords = 1_000_000;
|
||||
const batchSize = 10_000;
|
||||
const numBatches = millionRecords / batchSize;
|
||||
|
||||
export function setup() {
|
||||
const resources = provisionProject({
|
||||
endpoint: 'http://localhost/v1',
|
||||
email: 'test@test.com',
|
||||
password: 'password123',
|
||||
name: 'Test User',
|
||||
projectName: 'Large Document Creation Test'
|
||||
});
|
||||
|
||||
const { databaseId, collectionId } = provisionDatabase({
|
||||
endpoint: 'http://localhost/v1',
|
||||
apiHeaders: resources.apiHeaders
|
||||
});
|
||||
|
||||
// Wait to ensure that provisioning is complete
|
||||
sleep(5);
|
||||
|
||||
// Create an index for the collection
|
||||
const index = {
|
||||
key: "name",
|
||||
type: "fulltext",
|
||||
orders: ["ASC"],
|
||||
attributes: ["name", "email"]
|
||||
};
|
||||
|
||||
const indexRes = http.post(`http://localhost/v1/databases/${databaseId}/collections/${collectionId}/indexes`,
|
||||
JSON.stringify(index), {
|
||||
headers: resources.apiHeaders
|
||||
});
|
||||
|
||||
console.log(indexRes.status);
|
||||
|
||||
check(indexRes, {
|
||||
"status is 202": (r) => r.status === 202,
|
||||
});
|
||||
|
||||
console.log(`----- Inserting ${millionRecords} documents in ${numBatches} batches of ${batchSize} -----`);
|
||||
|
||||
const timeStart = new Date();
|
||||
|
||||
const requests = [];
|
||||
for (let i = 0; i < numBatches; i++) {
|
||||
const docs = Array.from({ length: batchSize }, () => ({
|
||||
$id: unique(),
|
||||
name: "bulk_document",
|
||||
age: Math.floor(Math.random() * 100),
|
||||
email: `${unique()}@test.com`,
|
||||
height: Math.random() * 100
|
||||
}));
|
||||
requests.push({
|
||||
method: "POST",
|
||||
url: `http://localhost/v1/databases/${databaseId}/collections/${collectionId}/documents`,
|
||||
body: JSON.stringify({ documents: docs }),
|
||||
params: {
|
||||
headers: resources.apiHeaders,
|
||||
timeout: '300s'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const responses = http.batch(requests);
|
||||
responses.forEach((res, index) => {
|
||||
if (res.status !== 201) {
|
||||
throw new Error(`Batch ${index + 1} failed with status ${res.status}`);
|
||||
}
|
||||
});
|
||||
|
||||
const timeEnd = new Date();
|
||||
const timeTaken = timeEnd - timeStart;
|
||||
console.log(`Created 1 million documents in ${timeTaken} milliseconds`);
|
||||
|
||||
return {
|
||||
databaseId,
|
||||
collectionId,
|
||||
apiHeaders: resources.apiHeaders,
|
||||
resources
|
||||
};
|
||||
}
|
||||
|
||||
export default function (data) {
|
||||
const docs = Array.from({ length: 10000 }, () => ({
|
||||
$id: unique(),
|
||||
name: "performance_document",
|
||||
age: Math.floor(Math.random() * 100),
|
||||
email: `${unique()}@test.com`,
|
||||
height: Math.random() * 100
|
||||
}));
|
||||
|
||||
const payload = JSON.stringify({ documents: docs });
|
||||
const res = http.post(
|
||||
`http://localhost/v1/databases/${data.databaseId}/collections/${data.collectionId}/documents`,
|
||||
payload,
|
||||
{
|
||||
headers: data.apiHeaders,
|
||||
timeout: '300s'
|
||||
}
|
||||
);
|
||||
|
||||
check(res, {
|
||||
"status is 201": (r) => r.status === 201
|
||||
});
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
export function teardown(data) {
|
||||
cleanup(data.resources);
|
||||
}
|
||||
|
||||
export const options = {
|
||||
scenarios: {
|
||||
large_document_creation: {
|
||||
executor: 'per-vu-iterations',
|
||||
vus: 1,
|
||||
iterations: 20,
|
||||
exec: 'default'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,82 @@
|
||||
import { check, sleep } from "k6";
|
||||
import http from "k6/http";
|
||||
import { provisionProject, provisionDatabase, cleanup, unique } from "./utils.js";
|
||||
|
||||
const amount = 10_000;
|
||||
|
||||
export function setup() {
|
||||
const resources = provisionProject({
|
||||
endpoint: 'http://localhost/v1',
|
||||
email: 'test@test.com',
|
||||
password: 'password123',
|
||||
name: 'Test User',
|
||||
projectName: 'Bulk Operations Test'
|
||||
});
|
||||
|
||||
const { databaseId, collectionId } = provisionDatabase({
|
||||
endpoint: 'http://localhost/v1',
|
||||
apiHeaders: resources.apiHeaders
|
||||
});
|
||||
|
||||
sleep(3); // Await Attributes to be provisioned
|
||||
|
||||
console.log(`----- Amount of documents: ${amount} -----`);
|
||||
|
||||
return {
|
||||
databaseId,
|
||||
collectionId,
|
||||
apiHeaders: resources.apiHeaders,
|
||||
resources
|
||||
};
|
||||
}
|
||||
|
||||
export function teardown(data) {
|
||||
cleanup(data.resources);
|
||||
}
|
||||
|
||||
let documents = Array(amount).fill({
|
||||
$id: "unique()",
|
||||
name: "asd",
|
||||
});
|
||||
|
||||
documents = documents.map((document) => {
|
||||
return {
|
||||
...document,
|
||||
age: Math.floor(Math.random() * 100),
|
||||
email: `${unique()}@test.com`,
|
||||
height: Math.random() * 100,
|
||||
};
|
||||
});
|
||||
|
||||
export default function (data) {
|
||||
const payload = JSON.stringify({
|
||||
documents,
|
||||
});
|
||||
|
||||
const res = http.post(
|
||||
`http://localhost/v1/databases/${data.databaseId}/collections/${data.collectionId}/documents`,
|
||||
payload,
|
||||
{
|
||||
headers: data.apiHeaders
|
||||
}
|
||||
);
|
||||
|
||||
check(res, {
|
||||
"status is 201": (r) => r.status === 201,
|
||||
});
|
||||
|
||||
return {
|
||||
resources: data.resources
|
||||
};
|
||||
}
|
||||
|
||||
export const options = {
|
||||
scenarios: {
|
||||
bulk_create: {
|
||||
executor: 'per-vu-iterations',
|
||||
vus: 1,
|
||||
iterations: 20,
|
||||
exec: 'default'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,144 @@
|
||||
import { check, sleep } from "k6";
|
||||
import http from "k6/http";
|
||||
import { Trend } from "k6/metrics";
|
||||
import { provisionProject, provisionDatabase, cleanup, unique } from "./utils.js";
|
||||
|
||||
// Custom Trend metric for light response time tracking
|
||||
export const lightResponseTime = new Trend("light_response_time", true);
|
||||
|
||||
const BULK_AMOUNT = 100_000; // Heavy operation amount
|
||||
const LIGHT_AMOUNT = 10; // Light operation amount
|
||||
|
||||
export function setup() {
|
||||
// Set up two separate projects - one for bulk operations (noisy neighbor) and one for light operations
|
||||
const heavyResources = provisionProject({
|
||||
endpoint: 'http://localhost/v1',
|
||||
email: 'heavy@test.com',
|
||||
password: 'password123',
|
||||
name: 'Heavy User',
|
||||
projectName: 'Noisy Neighbor - Heavy'
|
||||
});
|
||||
|
||||
const lightResources = provisionProject({
|
||||
endpoint: 'http://localhost/v1',
|
||||
email: 'light@test.com',
|
||||
password: 'password123',
|
||||
name: 'Light User',
|
||||
projectName: 'Noisy Neighbor - Light'
|
||||
});
|
||||
|
||||
// Set up databases for both projects
|
||||
const heavy = provisionDatabase({
|
||||
endpoint: 'http://localhost/v1',
|
||||
apiHeaders: heavyResources.apiHeaders
|
||||
});
|
||||
|
||||
const light = provisionDatabase({
|
||||
endpoint: 'http://localhost/v1',
|
||||
apiHeaders: lightResources.apiHeaders
|
||||
});
|
||||
|
||||
sleep(3); // Await Attributes to be provisioned
|
||||
|
||||
console.log(`----- Heavy operations: ${BULK_AMOUNT} documents | Light operations: ${LIGHT_AMOUNT} document -----`);
|
||||
|
||||
return {
|
||||
heavy: {
|
||||
databaseId: heavy.databaseId,
|
||||
collectionId: heavy.collectionId,
|
||||
apiHeaders: heavyResources.apiHeaders,
|
||||
resources: heavyResources
|
||||
},
|
||||
light: {
|
||||
databaseId: light.databaseId,
|
||||
collectionId: light.collectionId,
|
||||
apiHeaders: lightResources.apiHeaders,
|
||||
resources: lightResources
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function teardown(data) {
|
||||
cleanup(data.heavy.resources);
|
||||
cleanup(data.light.resources);
|
||||
}
|
||||
|
||||
// Create document payloads
|
||||
function createDocuments(amount) {
|
||||
let documents = Array(amount).fill({
|
||||
$id: "unique()",
|
||||
name: "test",
|
||||
});
|
||||
|
||||
return documents.map((document) => ({
|
||||
...document,
|
||||
age: Math.floor(Math.random() * 100),
|
||||
email: `${unique()}@test.com`,
|
||||
height: Math.random() * 100,
|
||||
}));
|
||||
}
|
||||
|
||||
// Heavy operation function
|
||||
export function heavy(data) {
|
||||
const documents = createDocuments(BULK_AMOUNT);
|
||||
const payload = JSON.stringify({ documents });
|
||||
|
||||
const res = http.post(
|
||||
`http://localhost/v1/databases/${data.heavy.databaseId}/collections/${data.heavy.collectionId}/documents`,
|
||||
payload,
|
||||
{
|
||||
headers: data.heavy.apiHeaders
|
||||
}
|
||||
);
|
||||
|
||||
check(res, {
|
||||
"heavy operation status is 201": (r) => r.status === 201,
|
||||
});
|
||||
}
|
||||
|
||||
// Light operation function
|
||||
export function light(data) {
|
||||
const documents = createDocuments(LIGHT_AMOUNT);
|
||||
const payload = JSON.stringify({ documents });
|
||||
|
||||
const startTime = new Date();
|
||||
const res = http.post(
|
||||
`http://localhost/v1/databases/${data.light.databaseId}/collections/${data.light.collectionId}/documents`,
|
||||
payload,
|
||||
{
|
||||
headers: data.light.apiHeaders
|
||||
}
|
||||
);
|
||||
const duration = new Date() - startTime;
|
||||
|
||||
// Record the light operation response time using the custom Trend metric
|
||||
lightResponseTime.add(duration);
|
||||
|
||||
check(res, {
|
||||
"light operation status is 201": (r) => r.status === 201,
|
||||
});
|
||||
}
|
||||
|
||||
export const options = {
|
||||
scenarios: {
|
||||
// Heavy bulk operations running continuously
|
||||
heavy_load: {
|
||||
executor: 'constant-vus',
|
||||
vus: 5,
|
||||
duration: '30s',
|
||||
exec: 'heavy'
|
||||
},
|
||||
// Light operations to measure impact
|
||||
light_operations: {
|
||||
executor: 'constant-arrival-rate',
|
||||
rate: 5,
|
||||
timeUnit: '1s',
|
||||
duration: '30s',
|
||||
preAllocatedVUs: 10,
|
||||
exec: 'light'
|
||||
}
|
||||
},
|
||||
thresholds: {
|
||||
http_req_duration: ['p(95)<2000'], // 95% of requests should complete within 2s
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,336 @@
|
||||
import http from 'k6/http';
|
||||
import { check } from 'k6';
|
||||
|
||||
/**
|
||||
* @typedef {Object} AuthHeaders
|
||||
* @property {string} 'Content-Type' - Content type header
|
||||
* @property {string} 'Cookie' - Session cookie
|
||||
* @property {string} 'X-Appwrite-Project' - Project ID header
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ApiHeaders
|
||||
* @property {string} 'Content-Type' - Content type header
|
||||
* @property {string} 'X-Appwrite-Project' - Project ID header
|
||||
* @property {string} 'X-Appwrite-Key' - API key header
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ProvisionedResources
|
||||
* @property {string} userId - The ID of the created user
|
||||
* @property {string} teamId - The ID of the created team
|
||||
* @property {string} projectId - The ID of the created project
|
||||
* @property {string} cookies - Session cookies for authentication
|
||||
* @property {AuthHeaders} headers - Headers for cookie-based authentication
|
||||
* @property {string} apiKey - The API key secret
|
||||
* @property {ApiHeaders} apiHeaders - Headers for API key authentication
|
||||
*/
|
||||
|
||||
function assert(response, checkName, condition) {
|
||||
const result = check(response, {
|
||||
[checkName]: condition
|
||||
});
|
||||
if (!result) {
|
||||
console.error(`Assertion failed: ${checkName}`);
|
||||
console.error(`Response status: ${response.status}`);
|
||||
console.error(`Response body: ${response.body}`);
|
||||
throw new Error(`Assertion failed: ${checkName}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provisions an Appwrite project setup including:
|
||||
* - Account creation
|
||||
* - Session creation
|
||||
* - Team creation
|
||||
* - Project creation
|
||||
* - API Key creation
|
||||
*
|
||||
* @param {Object} config Configuration object
|
||||
* @param {string} config.endpoint Base endpoint URL (e.g., 'http://localhost:80/v1')
|
||||
* @param {string} config.email Email for account creation
|
||||
* @param {string} config.password Password for account creation
|
||||
* @param {string} config.name Name for account creation
|
||||
* @param {string} config.projectName Name for the project
|
||||
* @returns {ProvisionedResources} Object containing all created resource IDs and session information
|
||||
*/
|
||||
export function provisionProject(config) {
|
||||
const {
|
||||
endpoint,
|
||||
email,
|
||||
password,
|
||||
name,
|
||||
projectName,
|
||||
} = config;
|
||||
|
||||
// Step 1: Create Account
|
||||
const accountResponse = http.post(`${endpoint}/account`, JSON.stringify({
|
||||
userId: 'unique()',
|
||||
email,
|
||||
password,
|
||||
name
|
||||
}), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
});
|
||||
|
||||
assert(accountResponse, 'account created successfully', (r) => r.status === 201 || r.status === 409);
|
||||
|
||||
const userId = accountResponse.json('$id');
|
||||
|
||||
// Step 2: Create Session
|
||||
const sessionResponse = http.post(`${endpoint}/account/sessions/email`, JSON.stringify({
|
||||
email,
|
||||
password
|
||||
}), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
});
|
||||
|
||||
assert(sessionResponse, 'session created successfully', (r) => r.status === 201);
|
||||
|
||||
// Keep manual control of the cookies to allow for simultaneous requests
|
||||
const jar = http.cookieJar();
|
||||
jar.clear(`${endpoint}`);
|
||||
|
||||
// Extract cookies for subsequent requests
|
||||
const cookies = sessionResponse.headers['Set-Cookie'];
|
||||
|
||||
// Common headers for authenticated requests
|
||||
const authHeaders = {
|
||||
'Content-Type': 'application/json',
|
||||
'Cookie': cookies
|
||||
};
|
||||
|
||||
// Step 3: Create Team
|
||||
const teamResponse = http.post(`${endpoint}/teams`, JSON.stringify({
|
||||
teamId: 'unique()',
|
||||
name: `${projectName} Team`
|
||||
}), {
|
||||
headers: authHeaders
|
||||
});
|
||||
|
||||
assert(teamResponse, 'team created successfully', (r) => r.status === 201);
|
||||
|
||||
const teamId = teamResponse.json('$id');
|
||||
|
||||
// Step 4: Create Project
|
||||
const projectResponse = http.post(`${endpoint}/projects`, JSON.stringify({
|
||||
projectId: 'unique()',
|
||||
name: projectName,
|
||||
teamId: teamId
|
||||
}), {
|
||||
headers: authHeaders
|
||||
});
|
||||
|
||||
assert(projectResponse, 'project created successfully', (r) => r.status === 201);
|
||||
|
||||
const projectId = projectResponse.json('$id');
|
||||
|
||||
// Step 5: Create API Key
|
||||
const apiKeyResponse = http.post(`${endpoint}/projects/${projectId}/keys`, JSON.stringify({
|
||||
name: 'Test API Key',
|
||||
scopes: SCOPES, // All permissions
|
||||
}), {
|
||||
headers: authHeaders
|
||||
});
|
||||
|
||||
assert(apiKeyResponse, 'api key created successfully', (r) => r.status === 201);
|
||||
|
||||
const apiKey = apiKeyResponse.json('secret');
|
||||
|
||||
// Create a new headers object for API key authentication
|
||||
const apiHeaders = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Appwrite-Project': projectId,
|
||||
'X-Appwrite-Key': apiKey
|
||||
};
|
||||
|
||||
// Return all created resources and session info
|
||||
return {
|
||||
endpoint,
|
||||
userId,
|
||||
teamId,
|
||||
projectId,
|
||||
cookies,
|
||||
headers: authHeaders,
|
||||
apiKey,
|
||||
apiHeaders
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Example usage:
|
||||
*
|
||||
* const config = {
|
||||
* endpoint: 'http://localhost:80/v1',
|
||||
* email: 'test@example.com',
|
||||
* password: 'complex-password',
|
||||
* name: 'Test User',
|
||||
* projectName: 'Test Project'
|
||||
* };
|
||||
*
|
||||
* const resources = provisionProject(config);
|
||||
*/
|
||||
|
||||
const SCOPES = [
|
||||
"sessions.write",
|
||||
"users.read",
|
||||
"users.write",
|
||||
"teams.read",
|
||||
"teams.write",
|
||||
"databases.read",
|
||||
"databases.write",
|
||||
"collections.read",
|
||||
"collections.write",
|
||||
"attributes.read",
|
||||
"attributes.write",
|
||||
"indexes.read",
|
||||
"indexes.write",
|
||||
"documents.read",
|
||||
"documents.write",
|
||||
"files.read",
|
||||
"files.write",
|
||||
"buckets.read",
|
||||
"buckets.write",
|
||||
"functions.read",
|
||||
"functions.write",
|
||||
"execution.read",
|
||||
"execution.write",
|
||||
"targets.read",
|
||||
"targets.write",
|
||||
"providers.read",
|
||||
"providers.write",
|
||||
"messages.read",
|
||||
"messages.write",
|
||||
"topics.read",
|
||||
"topics.write",
|
||||
"subscribers.read",
|
||||
"subscribers.write",
|
||||
"locale.read",
|
||||
"avatars.read",
|
||||
"health.read",
|
||||
"migrations.read",
|
||||
"migrations.write"
|
||||
]
|
||||
|
||||
export function provisionDatabase(config) {
|
||||
const {
|
||||
endpoint,
|
||||
apiHeaders
|
||||
} = config;
|
||||
|
||||
// Create database
|
||||
const databaseResponse = http.post(
|
||||
`${endpoint}/databases`,
|
||||
JSON.stringify({
|
||||
databaseId: 'unique()',
|
||||
name: 'Bulk Test DB'
|
||||
}),
|
||||
{ headers: apiHeaders }
|
||||
);
|
||||
|
||||
assert(databaseResponse, 'database created successfully', (r) => r.status === 201);
|
||||
|
||||
const databaseId = databaseResponse.json('$id');
|
||||
|
||||
// Create collection
|
||||
const collectionResponse = http.post(
|
||||
`${endpoint}/databases/${databaseId}/collections`,
|
||||
JSON.stringify({
|
||||
collectionId: 'unique()',
|
||||
name: 'Bulk Test Collection',
|
||||
permissions: ['read("any")', 'write("any")'],
|
||||
documentSecurity: false
|
||||
}),
|
||||
{ headers: apiHeaders }
|
||||
);
|
||||
|
||||
assert(collectionResponse, 'collection created successfully', (r) => r.status === 201);
|
||||
|
||||
const collectionId = collectionResponse.json('$id');
|
||||
|
||||
// Create name attribute
|
||||
const nameAttributeResponse = http.post(
|
||||
`${endpoint}/databases/${databaseId}/collections/${collectionId}/attributes/string`,
|
||||
JSON.stringify({
|
||||
key: 'name',
|
||||
size: 100,
|
||||
required: false,
|
||||
default: null,
|
||||
array: false,
|
||||
encrypt: false
|
||||
}),
|
||||
{ headers: apiHeaders }
|
||||
);
|
||||
|
||||
assert(nameAttributeResponse, 'name attribute created successfully', (r) => r.status === 202);
|
||||
|
||||
// Create age attribute
|
||||
const ageAttributeResponse = http.post(
|
||||
`${endpoint}/databases/${databaseId}/collections/${collectionId}/attributes/integer`,
|
||||
JSON.stringify({
|
||||
key: 'age',
|
||||
required: false,
|
||||
}),
|
||||
{ headers: apiHeaders }
|
||||
);
|
||||
|
||||
assert(ageAttributeResponse, 'age attribute created successfully', (r) => r.status === 202);
|
||||
|
||||
// Create email attribute
|
||||
const emailAttributeResponse = http.post(
|
||||
`${endpoint}/databases/${databaseId}/collections/${collectionId}/attributes/email`,
|
||||
JSON.stringify({
|
||||
key: 'email',
|
||||
required: false,
|
||||
}),
|
||||
{ headers: apiHeaders }
|
||||
);
|
||||
|
||||
assert(emailAttributeResponse, 'email attribute created successfully', (r) => r.status === 202);
|
||||
|
||||
// Create height attribute
|
||||
const heightAttributeResponse = http.post(
|
||||
`${endpoint}/databases/${databaseId}/collections/${collectionId}/attributes/float`,
|
||||
JSON.stringify({
|
||||
key: 'height',
|
||||
required: false,
|
||||
}),
|
||||
{ headers: apiHeaders }
|
||||
);
|
||||
|
||||
assert(heightAttributeResponse, 'height attribute created successfully', (r) => r.status === 202);
|
||||
|
||||
return {
|
||||
databaseId,
|
||||
collectionId
|
||||
};
|
||||
}
|
||||
|
||||
export function cleanup(config) {
|
||||
const {
|
||||
endpoint,
|
||||
teamId,
|
||||
headers
|
||||
} = config;
|
||||
|
||||
// Delete Organization
|
||||
const organizationResponse = http.del(
|
||||
`${endpoint}/teams/${teamId}`,
|
||||
null,
|
||||
{
|
||||
headers
|
||||
}
|
||||
);
|
||||
|
||||
assert(organizationResponse, 'organization deleted successfully', (r) => r.status === 204);
|
||||
}
|
||||
|
||||
export function unique() {
|
||||
const timestamp = Date.now().toString(36);
|
||||
const randomPart = Math.random().toString(36).substring(2, 15);
|
||||
return `${timestamp}-${randomPart}`;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@ use Utopia\Database\Database;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
class DatabasesCustomClientTest extends Scope
|
||||
{
|
||||
@@ -890,4 +891,623 @@ class DatabasesCustomClientTest extends Scope
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testBulkCreatePermissions(): void
|
||||
{
|
||||
// Create database
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Bulk Create'
|
||||
]);
|
||||
|
||||
$this->assertNotEmpty($database['body']['$id']);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'Bulk Create',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
|
||||
|
||||
$data = [
|
||||
'$id' => $collection['body']['$id'],
|
||||
'databaseId' => $collection['body']['databaseId']
|
||||
];
|
||||
|
||||
// Await attribute
|
||||
$numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'number',
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $numberAttribute['headers']['status-code']);
|
||||
|
||||
sleep(2);
|
||||
|
||||
// TEST FAIL - Can't create document with missing collection level permissions
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'documents' => [
|
||||
[
|
||||
'$id' => ID::unique(),
|
||||
'number' => 1,
|
||||
],
|
||||
[
|
||||
'$id' => ID::unique(),
|
||||
'number' => 2,
|
||||
],
|
||||
[
|
||||
'$id' => ID::unique(),
|
||||
'number' => 3,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
$this->assertEquals('The current user is not authorized to perform the requested action.', $response['body']['message']);
|
||||
|
||||
// TEST FAIL - Can't create document with missing document level permissions
|
||||
$collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Bulk Creates Perms',
|
||||
'documentSecurity' => true
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $collection['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'documents' => [
|
||||
[
|
||||
'$id' => ID::unique(),
|
||||
'number' => 1,
|
||||
],
|
||||
[
|
||||
'$id' => ID::unique(),
|
||||
'number' => 2,
|
||||
],
|
||||
[
|
||||
'$id' => ID::unique(),
|
||||
'number' => 3,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
$this->assertEquals('The current user is not authorized to perform the requested action.', $response['body']['message']);
|
||||
|
||||
// TEST FAIL - Can't create document with permissions that aren't our own.
|
||||
$collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Bulk Creates Perms',
|
||||
'documentSecurity' => true,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $collection['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'documents' => [
|
||||
[
|
||||
'$id' => ID::unique(),
|
||||
'number' => 1,
|
||||
'$permissions' => [
|
||||
Permission::create(Role::user('aaaaaa')),
|
||||
Permission::read(Role::user('aaaaaa')),
|
||||
Permission::update(Role::user('aaaaaa')),
|
||||
Permission::delete(Role::user('aaaaaa')),
|
||||
]
|
||||
],
|
||||
[
|
||||
'$id' => ID::unique(),
|
||||
'number' => 2,
|
||||
'$permissions' => [
|
||||
Permission::create(Role::user('aaaaaa')),
|
||||
Permission::read(Role::user('aaaaaa')),
|
||||
Permission::update(Role::user('aaaaaa')),
|
||||
Permission::delete(Role::user('aaaaaa')),
|
||||
]
|
||||
],
|
||||
[
|
||||
'$id' => ID::unique(),
|
||||
'number' => 3,
|
||||
'$permissions' => [
|
||||
Permission::create(Role::user('aaaaaa')),
|
||||
Permission::read(Role::user('aaaaaa')),
|
||||
Permission::update(Role::user('aaaaaa')),
|
||||
Permission::delete(Role::user('aaaaaa')),
|
||||
]
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
// TEST SUCCESS - Can create document with our own permissions.
|
||||
$response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'documents' => [
|
||||
[
|
||||
'$id' => ID::unique(),
|
||||
'number' => 1,
|
||||
'$permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
],
|
||||
[
|
||||
'$id' => ID::unique(),
|
||||
'number' => 2,
|
||||
'$permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
],
|
||||
[
|
||||
'$id' => ID::unique(),
|
||||
'number' => 3,
|
||||
'$permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertCount(3, $response['body']['documents']);
|
||||
}
|
||||
|
||||
// Bulk Updates
|
||||
public function testBulkUpdatesPermissions(): void
|
||||
{
|
||||
// Create database
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Bulk Update Perms'
|
||||
]);
|
||||
|
||||
$this->assertNotEmpty($database['body']['$id']);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
$collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'Bulk Updates Perms',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id']))
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
|
||||
$data = [
|
||||
'$id' => $collection['body']['$id'],
|
||||
'databaseId' => $collection['body']['databaseId']
|
||||
];
|
||||
|
||||
// Await attribute
|
||||
$numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'number',
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $numberAttribute['headers']['status-code']);
|
||||
|
||||
sleep(2);
|
||||
|
||||
// TEST: Update all documents with invalid collection level permissions
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'number' => 100
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
$collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Bulk Updates Perms',
|
||||
'documentSecurity' => true
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $collection['headers']['status-code']);
|
||||
|
||||
// TEST: Make sure we can update only documents we have permissions for
|
||||
for ($i = 0; $i < 6; $i++) {
|
||||
$doc = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'documentId' => ID::unique(),
|
||||
'data' => [
|
||||
'number' => $i,
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::update(Role::user($this->getUser()['$id']))
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $doc['headers']['status-code']);
|
||||
}
|
||||
|
||||
$doc = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'documentId' => ID::unique(),
|
||||
'data' => [
|
||||
'number' => 6,
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::update(Role::user('user2')),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $doc['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'number' => 100
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertCount(6, $response['body']['documents']);
|
||||
|
||||
$documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [Query::notEqual('number', 100)->toString()]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $documents['headers']['status-code']);
|
||||
$this->assertEquals(1, $documents['body']['total']);
|
||||
}
|
||||
|
||||
public function testBulkUpdatesRelationship()
|
||||
{
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Bulk Updates'
|
||||
]);
|
||||
|
||||
$this->assertNotEmpty($database['body']['$id']);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'Collection1',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::any()),
|
||||
Permission::read(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection1['headers']['status-code']);
|
||||
|
||||
$collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'Collection2',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::any()),
|
||||
Permission::read(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection1['headers']['status-code']);
|
||||
|
||||
$collection1 = $collection1['body']['$id'];
|
||||
$collection2 = $collection2['body']['$id'];
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/attributes/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'relatedCollectionId' => $collection2,
|
||||
'type' => Database::RELATION_ONE_TO_MANY,
|
||||
'key' => 'collection2',
|
||||
'onDelete' => Database::RELATION_MUTATE_RESTRICT,
|
||||
'twoWay' => true,
|
||||
'twoWayKey' => 'collection1',
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/attributes/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'name',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection2 . '/attributes/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'name',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
sleep(3);
|
||||
|
||||
$document1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'documentId' => ID::unique(),
|
||||
'data' => [
|
||||
'name' => 'Document 1',
|
||||
'collection2' => [
|
||||
[
|
||||
'name' => 'Document 2',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $document1['headers']['status-code']);
|
||||
$document1 = $document1['body']['$id'];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1 . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'name' => 'Document 1 Updated',
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertCount(1, $response['body']['documents']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collection2 . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
$document2 = $response['body']['documents'][0];
|
||||
|
||||
$this->assertEquals('Document 2', $document2['name']);
|
||||
$this->assertEquals('Document 1 Updated', $document2['collection1']['name']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection2 . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'name' => 'Document 2 Updated',
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collection1 . '/documents/' . $document1, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals('Document 1 Updated', $response['body']['name']);
|
||||
|
||||
$document2 = $response['body']['collection2'][0];
|
||||
$this->assertEquals('Document 2 Updated', $document2['name']);
|
||||
}
|
||||
|
||||
public function testBulkDeletesPermissions(): void
|
||||
{
|
||||
// Create database
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Bulk Deletes Perms'
|
||||
]);
|
||||
|
||||
$this->assertNotEmpty($database['body']['$id']);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'Bulk Deletes Perms',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id']))
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
|
||||
$data = [
|
||||
'$id' => $collection['body']['$id'],
|
||||
'databaseId' => $collection['body']['databaseId']
|
||||
];
|
||||
|
||||
// Await attribute
|
||||
$numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'number',
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $numberAttribute['headers']['status-code']);
|
||||
|
||||
sleep(2);
|
||||
|
||||
// TEST: Delete all documents with invalid collection level permissions
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
$collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Bulk Deletes Perms',
|
||||
'documentSecurity' => true
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $collection['headers']['status-code']);
|
||||
|
||||
// TEST: Make sure we can delete only documents we have permissions for
|
||||
for ($i = 0; $i < 6; $i++) {
|
||||
$doc = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'documentId' => ID::unique(),
|
||||
'data' => [
|
||||
'number' => $i,
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::delete(Role::user($this->getUser()['$id']))
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $doc['headers']['status-code']);
|
||||
}
|
||||
|
||||
$doc = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'documentId' => ID::unique(),
|
||||
'data' => [
|
||||
'number' => 6,
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::delete(Role::user('user2'))
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $doc['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(6, $response['body']['total']);
|
||||
|
||||
$documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $documents['headers']['status-code']);
|
||||
$this->assertEquals(1, $documents['body']['total']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,6 +674,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$user = $this->getUser();
|
||||
$session = $user['session'] ?? '';
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$documentIds = [];
|
||||
|
||||
$client = $this->getWebsocket(['documents', 'collections'], [
|
||||
'origin' => 'http://localhost',
|
||||
@@ -763,6 +764,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$documentId = $document['body']['$id'];
|
||||
$documentIds[] = $documentId;
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
|
||||
Reference in New Issue
Block a user