mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
71
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7e69624c6 | ||
|
|
e9c2ebbcf5 | ||
|
|
879ddb3074 | ||
|
|
8c1f6aabb7 | ||
|
|
f707be6ed3 | ||
|
|
bcb4ffa404 | ||
|
|
c0d4b58eea | ||
|
|
e2ab6a05ab | ||
|
|
6bbb522a87 | ||
|
|
7f2d3beb31 | ||
|
|
3d4917727b | ||
|
|
41ead533b8 | ||
|
|
c47f65d27c | ||
|
|
116ba6bc7b | ||
|
|
adc94cf1b4 | ||
|
|
257733aec0 | ||
|
|
fbbf846eb9 | ||
|
|
fbf985ea90 | ||
|
|
f061f724e0 | ||
|
|
125585831b | ||
|
|
3c418c1607 | ||
|
|
8f8c008e8b | ||
|
|
84ba7febe7 | ||
|
|
7b79642f4b | ||
|
|
949347764a | ||
|
|
32c4debffc | ||
|
|
2850879428 | ||
|
|
1c0c8f0eb6 | ||
|
|
00e3fe12f4 | ||
|
|
5c895579ed | ||
|
|
104a9b6074 | ||
|
|
2b08db9a38 | ||
|
|
9d652d9e79 | ||
|
|
e1fffa775e | ||
|
|
2e60698ec1 | ||
|
|
90521c6bd7 | ||
|
|
558f7f06b4 | ||
|
|
19194dabc0 | ||
|
|
e1230f7465 | ||
|
|
def25a8c9b | ||
|
|
675227d25a | ||
|
|
4e5ad33d73 | ||
|
|
54260b5a9a | ||
|
|
67b95c4b39 | ||
|
|
90c4bad826 | ||
|
|
791f0dda79 | ||
|
|
79c043ec1f | ||
|
|
755e86020f | ||
|
|
96e69b55e1 | ||
|
|
c210b2b874 | ||
|
|
c0ef832784 | ||
|
|
bb7234fa98 | ||
|
|
dd6bd745df | ||
|
|
a8f3b63ded | ||
|
|
aa42608528 | ||
|
|
172d25d67c | ||
|
|
92c93357cf | ||
|
|
6faad29907 | ||
|
|
07738bdcf9 | ||
|
|
c6ca830801 | ||
|
|
44234da995 | ||
|
|
22dfcb78c4 | ||
|
|
60da24e521 | ||
|
|
f703a0db18 | ||
|
|
2a8ab8d610 | ||
|
|
5bf20289a5 | ||
|
|
8a601ee058 | ||
|
|
95861d068d | ||
|
|
313adc7023 | ||
|
|
bb40455cb7 | ||
|
|
86053e9028 |
@@ -33,6 +33,7 @@ _APP_DB_SCHEMA=appwrite
|
||||
_APP_DB_USER=user
|
||||
_APP_DB_PASS=password
|
||||
_APP_DB_ROOT_PASS=rootsecretpassword
|
||||
_APP_DATABASE_BATCH_SIZE=10_000
|
||||
_APP_STORAGE_DEVICE=Local
|
||||
_APP_STORAGE_S3_ACCESS_KEY=
|
||||
_APP_STORAGE_S3_SECRET=
|
||||
|
||||
@@ -4537,14 +4537,21 @@
|
||||
"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.",
|
||||
"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.",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Document",
|
||||
"description": "Document, or Documents List",
|
||||
"content": {
|
||||
"application\/json": {
|
||||
"schema": {
|
||||
"$ref": "#\/components\/schemas\/document"
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#\/components\/schemas\/document"
|
||||
},
|
||||
{
|
||||
"$ref": "#\/components\/schemas\/documentList"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4571,6 +4578,33 @@
|
||||
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
|
||||
"offline-key": "{documentId}",
|
||||
"offline-response-key": "$id",
|
||||
"multiplex": {
|
||||
"createDocument": {
|
||||
"name": "Create Document",
|
||||
"parameters": [
|
||||
"documentId",
|
||||
"data",
|
||||
"permissions"
|
||||
],
|
||||
"required": [
|
||||
"documentId",
|
||||
"data"
|
||||
],
|
||||
"response": "document",
|
||||
"description": "\/docs\/references\/databases\/create-document.md"
|
||||
},
|
||||
"createDocuments": {
|
||||
"name": "Create Documents",
|
||||
"parameters": [
|
||||
"documents"
|
||||
],
|
||||
"required": [
|
||||
"documents"
|
||||
],
|
||||
"response": "documentList",
|
||||
"description": "\/docs\/references\/databases\/create-documents.md"
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
@@ -4620,6 +4654,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).",
|
||||
@@ -4628,11 +4670,206 @@
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"documentId",
|
||||
"data"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"summary": "Update documents",
|
||||
"operationId": "databasesUpdateDocuments",
|
||||
"tags": [
|
||||
"databases"
|
||||
],
|
||||
"description": "Update all documents that match your queries, If none are submitted then all documents are updated. Using the patch method you can pass only specific fields that will get 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,
|
||||
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
|
||||
"offline-key": "",
|
||||
"offline-response-key": "$id",
|
||||
"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": "{}"
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
|
||||
"x-example": "[\"read(\"any\")\"]",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"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,
|
||||
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
|
||||
"offline-key": "{documentId}",
|
||||
"offline-response-key": "$id",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4859,7 +5096,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocument",
|
||||
"weight": 113,
|
||||
"weight": 114,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -4945,7 +5182,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"weight": 306,
|
||||
"weight": 308,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5033,7 +5270,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"weight": 305,
|
||||
"weight": 307,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5150,7 +5387,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"weight": 307,
|
||||
"weight": 309,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5226,7 +5463,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "query",
|
||||
"weight": 331,
|
||||
"weight": 333,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"deprecated": false,
|
||||
@@ -5280,7 +5517,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "mutation",
|
||||
"weight": 330,
|
||||
"weight": 332,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"deprecated": false,
|
||||
@@ -5334,7 +5571,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "get",
|
||||
"weight": 117,
|
||||
"weight": 119,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5388,7 +5625,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCodes",
|
||||
"weight": 118,
|
||||
"weight": 120,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5442,7 +5679,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listContinents",
|
||||
"weight": 122,
|
||||
"weight": 124,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5496,7 +5733,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountries",
|
||||
"weight": 119,
|
||||
"weight": 121,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5550,7 +5787,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountriesEU",
|
||||
"weight": 120,
|
||||
"weight": 122,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5604,7 +5841,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountriesPhones",
|
||||
"weight": 121,
|
||||
"weight": 123,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5658,7 +5895,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCurrencies",
|
||||
"weight": 123,
|
||||
"weight": 125,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5712,7 +5949,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listLanguages",
|
||||
"weight": 124,
|
||||
"weight": 126,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5766,7 +6003,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createSubscriber",
|
||||
"weight": 382,
|
||||
"weight": 384,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5851,7 +6088,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteSubscriber",
|
||||
"weight": 386,
|
||||
"weight": 388,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5928,7 +6165,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listFiles",
|
||||
"weight": 208,
|
||||
"weight": 210,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6016,7 +6253,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createFile",
|
||||
"weight": 207,
|
||||
"weight": 209,
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"deprecated": false,
|
||||
@@ -6116,7 +6353,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFile",
|
||||
"weight": 209,
|
||||
"weight": 211,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6190,7 +6427,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateFile",
|
||||
"weight": 214,
|
||||
"weight": 216,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6281,7 +6518,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteFile",
|
||||
"weight": 215,
|
||||
"weight": 217,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6350,7 +6587,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFileDownload",
|
||||
"weight": 211,
|
||||
"weight": 213,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6419,7 +6656,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFilePreview",
|
||||
"weight": 210,
|
||||
"weight": 212,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6637,7 +6874,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFileView",
|
||||
"weight": 212,
|
||||
"weight": 214,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6713,7 +6950,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "list",
|
||||
"weight": 219,
|
||||
"weight": 221,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6791,7 +7028,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "create",
|
||||
"weight": 218,
|
||||
"weight": 220,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6878,7 +7115,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "get",
|
||||
"weight": 220,
|
||||
"weight": 222,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6942,7 +7179,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateName",
|
||||
"weight": 222,
|
||||
"weight": 224,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7018,7 +7255,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "delete",
|
||||
"weight": 224,
|
||||
"weight": 226,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7084,7 +7321,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listMemberships",
|
||||
"weight": 226,
|
||||
"weight": 228,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7172,7 +7409,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createMembership",
|
||||
"weight": 225,
|
||||
"weight": 227,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7285,7 +7522,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getMembership",
|
||||
"weight": 227,
|
||||
"weight": 229,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7359,7 +7596,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateMembership",
|
||||
"weight": 228,
|
||||
"weight": 230,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7448,7 +7685,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteMembership",
|
||||
"weight": 230,
|
||||
"weight": 232,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7524,7 +7761,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateMembershipStatus",
|
||||
"weight": 229,
|
||||
"weight": 231,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7624,7 +7861,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getPrefs",
|
||||
"weight": 221,
|
||||
"weight": 223,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7687,7 +7924,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
@@ -4709,12 +4709,19 @@
|
||||
"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.",
|
||||
"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.",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Document",
|
||||
"description": "Document, or Documents List",
|
||||
"schema": {
|
||||
"$ref": "#\/definitions\/document"
|
||||
"x-oneOf": [
|
||||
{
|
||||
"$ref": "#\/definitions\/document"
|
||||
},
|
||||
{
|
||||
"$ref": "#\/definitions\/documentList"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4739,6 +4746,33 @@
|
||||
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
|
||||
"offline-key": "{documentId}",
|
||||
"offline-response-key": "$id",
|
||||
"multiplex": {
|
||||
"createDocument": {
|
||||
"name": "Create Document",
|
||||
"parameters": [
|
||||
"documentId",
|
||||
"data",
|
||||
"permissions"
|
||||
],
|
||||
"required": [
|
||||
"documentId",
|
||||
"data"
|
||||
],
|
||||
"response": "document",
|
||||
"description": "\/docs\/references\/databases\/create-document.md"
|
||||
},
|
||||
"createDocuments": {
|
||||
"name": "Create Documents",
|
||||
"parameters": [
|
||||
"documents"
|
||||
],
|
||||
"required": [
|
||||
"documents"
|
||||
],
|
||||
"response": "documentList",
|
||||
"description": "\/docs\/references\/databases\/create-documents.md"
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"Project": []
|
||||
}
|
||||
@@ -4776,15 +4810,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).",
|
||||
@@ -4794,11 +4837,202 @@
|
||||
"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 none are submitted then all documents are updated. Using the patch method you can pass only specific fields that will get 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,
|
||||
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
|
||||
"offline-key": "",
|
||||
"offline-response-key": "$id",
|
||||
"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": "{}"
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
|
||||
"default": null,
|
||||
"x-example": "[\"read(\"any\")\"]",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"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,
|
||||
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
|
||||
"offline-key": "{documentId}",
|
||||
"offline-response-key": "$id",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -5019,7 +5253,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocument",
|
||||
"weight": 113,
|
||||
"weight": 114,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5101,7 +5335,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"weight": 306,
|
||||
"weight": 308,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5186,7 +5420,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"weight": 305,
|
||||
"weight": 307,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5307,7 +5541,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"weight": 307,
|
||||
"weight": 309,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5381,7 +5615,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "query",
|
||||
"weight": 331,
|
||||
"weight": 333,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"deprecated": false,
|
||||
@@ -5457,7 +5691,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "mutation",
|
||||
"weight": 330,
|
||||
"weight": 332,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"deprecated": false,
|
||||
@@ -5533,7 +5767,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "get",
|
||||
"weight": 117,
|
||||
"weight": 119,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5589,7 +5823,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCodes",
|
||||
"weight": 118,
|
||||
"weight": 120,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5645,7 +5879,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listContinents",
|
||||
"weight": 122,
|
||||
"weight": 124,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5701,7 +5935,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountries",
|
||||
"weight": 119,
|
||||
"weight": 121,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5757,7 +5991,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountriesEU",
|
||||
"weight": 120,
|
||||
"weight": 122,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5813,7 +6047,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCountriesPhones",
|
||||
"weight": 121,
|
||||
"weight": 123,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5869,7 +6103,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listCurrencies",
|
||||
"weight": 123,
|
||||
"weight": 125,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5925,7 +6159,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listLanguages",
|
||||
"weight": 124,
|
||||
"weight": 126,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -5981,7 +6215,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createSubscriber",
|
||||
"weight": 382,
|
||||
"weight": 384,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6070,7 +6304,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteSubscriber",
|
||||
"weight": 386,
|
||||
"weight": 388,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6145,7 +6379,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listFiles",
|
||||
"weight": 208,
|
||||
"weight": 210,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6230,7 +6464,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createFile",
|
||||
"weight": 207,
|
||||
"weight": 209,
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"deprecated": false,
|
||||
@@ -6324,7 +6558,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFile",
|
||||
"weight": 209,
|
||||
"weight": 211,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6396,7 +6630,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateFile",
|
||||
"weight": 214,
|
||||
"weight": 216,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6487,7 +6721,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteFile",
|
||||
"weight": 215,
|
||||
"weight": 217,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6561,7 +6795,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFileDownload",
|
||||
"weight": 211,
|
||||
"weight": 213,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6635,7 +6869,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFilePreview",
|
||||
"weight": 210,
|
||||
"weight": 212,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6836,7 +7070,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getFileView",
|
||||
"weight": 212,
|
||||
"weight": 214,
|
||||
"cookies": false,
|
||||
"type": "location",
|
||||
"deprecated": false,
|
||||
@@ -6910,7 +7144,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "list",
|
||||
"weight": 219,
|
||||
"weight": 221,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -6987,7 +7221,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "create",
|
||||
"weight": 218,
|
||||
"weight": 220,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7081,7 +7315,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "get",
|
||||
"weight": 220,
|
||||
"weight": 222,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7145,7 +7379,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateName",
|
||||
"weight": 222,
|
||||
"weight": 224,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7222,7 +7456,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "delete",
|
||||
"weight": 224,
|
||||
"weight": 226,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7288,7 +7522,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "listMemberships",
|
||||
"weight": 226,
|
||||
"weight": 228,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7373,7 +7607,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "createMembership",
|
||||
"weight": 225,
|
||||
"weight": 227,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7490,7 +7724,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getMembership",
|
||||
"weight": 227,
|
||||
"weight": 229,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7562,7 +7796,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateMembership",
|
||||
"weight": 228,
|
||||
"weight": 230,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7650,7 +7884,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "deleteMembership",
|
||||
"weight": 230,
|
||||
"weight": 232,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7724,7 +7958,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "updateMembershipStatus",
|
||||
"weight": 229,
|
||||
"weight": 231,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7822,7 +8056,7 @@
|
||||
},
|
||||
"x-appwrite": {
|
||||
"method": "getPrefs",
|
||||
"weight": 221,
|
||||
"weight": 223,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
@@ -7885,7 +8119,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
@@ -46,6 +46,7 @@ use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\Structure;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\FloatValidator;
|
||||
@@ -2844,7 +2845,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')
|
||||
@@ -2854,34 +2854,70 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT)
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
|
||||
->label('sdk.namespace', 'databases')
|
||||
->label('sdk.method', 'createDocument')
|
||||
->label('sdk.method', [
|
||||
'createDocument' => [
|
||||
'name' => 'Create Document',
|
||||
'parameters' => [
|
||||
'documentId',
|
||||
'data',
|
||||
'permissions',
|
||||
],
|
||||
'required' => ['documentId', 'data'],
|
||||
'response' => Response::MODEL_DOCUMENT,
|
||||
'description' => '/docs/references/databases/create-document.md',
|
||||
],
|
||||
'createDocuments' => [
|
||||
'name' => 'Create Documents',
|
||||
'parameters' => [
|
||||
'documents'
|
||||
],
|
||||
'required' => ['documents'],
|
||||
'response' => Response::MODEL_DOCUMENT_LIST,
|
||||
'description' => '/docs/references/databases/create-documents.md'
|
||||
],
|
||||
])
|
||||
->label('sdk.description', '/docs/references/databases/create-document.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_DOCUMENT)
|
||||
->label('sdk.response.model', [Response::MODEL_DOCUMENT, Response::MODEL_DOCUMENT_LIST])
|
||||
->label('sdk.offline.model', '/databases/{databaseId}/collections/{collectionId}/documents')
|
||||
->label('sdk.offline.key', '{documentId}')
|
||||
->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_ARRAY_DOCUMENTS_SIZE), '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('queueForUsage')
|
||||
->inject('project')
|
||||
->inject('mode')
|
||||
->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, Usage $queueForUsage, string $mode) {
|
||||
|
||||
->action(function (string $databaseId, ?string $documentId, string $collectionId, string|array|null $data, ?array $documents, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, Usage $queueForUsage, Document $project, string $mode) {
|
||||
$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::DOCUMENT_INVALID_STRUCTURE, '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, use $id inside the documents');
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
$isBulk = false;
|
||||
$documents = [$data];
|
||||
}
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
@@ -2905,43 +2941,46 @@ 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) {
|
||||
// Map aggregate permissions to into the set of individual permissions they represent.
|
||||
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);
|
||||
};
|
||||
|
||||
$checkPermissions = function (Document $collection, Document $document, string $permission) use (&$checkPermissions, $dbForProject, $database) {
|
||||
$documentSecurity = $collection->getAttribute('documentSecurity', false);
|
||||
@@ -3023,10 +3062,29 @@ 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 is required inside documents 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);
|
||||
} catch (StructureException $e) {
|
||||
throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $e->getMessage());
|
||||
} catch (DuplicateException $e) {
|
||||
@@ -3035,8 +3093,15 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
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());
|
||||
|
||||
@@ -3068,28 +3133,26 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
}
|
||||
};
|
||||
|
||||
$processDocument($collection, $document);
|
||||
foreach ($documents as $document) {
|
||||
$processDocument($collection, $document);
|
||||
}
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($document, Response::MODEL_DOCUMENT);
|
||||
|
||||
$relationships = \array_map(
|
||||
fn ($document) => $document->getAttribute('key'),
|
||||
\array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
)
|
||||
);
|
||||
|
||||
$queueForEvents
|
||||
->setParam('databaseId', $databaseId)
|
||||
->setParam('collectionId', $collection->getId())
|
||||
->setParam('documentId', $document->getId())
|
||||
->setContext('collection', $collection)
|
||||
->setContext('database', $database)
|
||||
->setPayload($response->getPayload(), sensitive: $relationships);
|
||||
if ($isBulk) {
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->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
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($documents[0], Response::MODEL_DOCUMENT);
|
||||
}
|
||||
|
||||
$queueForUsage
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
|
||||
@@ -3172,7 +3235,6 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
return false;
|
||||
}
|
||||
|
||||
$document->removeAttribute('$collection');
|
||||
$document->setAttribute('$databaseId', $database->getId());
|
||||
$document->setAttribute('$collectionId', $collection->getId());
|
||||
|
||||
@@ -3688,6 +3750,141 @@ 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.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
|
||||
->label('sdk.namespace', 'databases')
|
||||
->label('sdk.method', 'updateDocuments')
|
||||
->label('sdk.description', '/docs/references/databases/update-documents.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_DOCUMENT_LIST)
|
||||
->label('sdk.offline.model', '/databases/{databaseId}/collections/{collectionId}/documents')
|
||||
->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('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, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', 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 $permissions, array $queries, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Document $project) {
|
||||
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
|
||||
|
||||
if (empty($data) && \is_null($permissions)) {
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_PAYLOAD);
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
// 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
|
||||
)
|
||||
);
|
||||
|
||||
$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')
|
||||
@@ -3808,6 +4005,115 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
|
||||
$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.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
|
||||
->label('sdk.namespace', 'databases')
|
||||
->label('sdk.method', 'deleteDocuments')
|
||||
->label('sdk.description', '/docs/references/databases/delete-documents.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.model', Response::MODEL_DOCUMENT_LIST)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.offline.model', '/databases/{databaseId}/collections/{collectionId}/documents')
|
||||
->label('sdk.offline.key', '{documentId}')
|
||||
->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('queueForUsage')
|
||||
->inject('project')
|
||||
->action(function (string $databaseId, string $collectionId, array $queries, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Usage $queueForUsage, 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);
|
||||
}
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
$documents = $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $queries) {
|
||||
return $dbForProject->deleteDocuments(
|
||||
'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
|
||||
$queries,
|
||||
intval(System::getEnv('_APP_DATABASE_BATCH_SIZE', 10_000))
|
||||
);
|
||||
});
|
||||
|
||||
// DB Storage Calculation
|
||||
$queueForUsage
|
||||
->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'])
|
||||
|
||||
@@ -90,10 +90,17 @@ $eventDatabaseListener = function (Document $document, Response $response, Event
|
||||
|
||||
$usageDatabaseListener = function (string $event, Document $document, Usage $queueForUsage) {
|
||||
$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':
|
||||
$queueForUsage
|
||||
@@ -496,6 +503,7 @@ App::init()
|
||||
|
||||
$dbForProject
|
||||
->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForUsage))
|
||||
->on(Database::EVENT_DOCUMENTS_CREATE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForUsage))
|
||||
->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForUsage))
|
||||
->on(Database::EVENT_DOCUMENT_CREATE, 'create-trigger-events', fn ($event, $document) => $eventDatabaseListener(
|
||||
$document,
|
||||
|
||||
@@ -113,6 +113,7 @@ const APP_LIMIT_COMPRESSION = 20_000_000; //20MB
|
||||
const APP_LIMIT_ARRAY_PARAMS_SIZE = 100; // Default maximum of how many elements can there be in API parameter that expects array value
|
||||
const APP_LIMIT_ARRAY_LABELS_SIZE = 1000; // Default maximum of how many labels elements can there be in API parameter that expects array value
|
||||
const APP_LIMIT_ARRAY_ELEMENT_SIZE = 4096; // Default maximum length of element in array parameter represented by maximum URL length.
|
||||
const APP_LIMIT_ARRAY_DOCUMENTS_SIZE = 10_000; // Default maximum of how many documents can be inserted in a single request
|
||||
const APP_LIMIT_SUBQUERY = 1000;
|
||||
const APP_LIMIT_SUBSCRIBERS_SUBQUERY = 1_000_000;
|
||||
const APP_LIMIT_WRITE_RATE_DEFAULT = 60; // Default maximum write rate per rate period
|
||||
|
||||
+5
-1
@@ -51,7 +51,7 @@
|
||||
"utopia-php/cache": "0.11.*",
|
||||
"utopia-php/cli": "0.15.*",
|
||||
"utopia-php/config": "0.2.*",
|
||||
"utopia-php/database": "0.53.16",
|
||||
"utopia-php/database": "0.53.27",
|
||||
"utopia-php/domains": "0.5.*",
|
||||
"utopia-php/dsn": "0.2.1",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
@@ -96,6 +96,10 @@
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "8.3"
|
||||
},
|
||||
"allow-plugins": {
|
||||
"php-http/discovery": false,
|
||||
"tbachert/spi": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+1908
-402
File diff suppressed because it is too large
Load Diff
@@ -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 none are submitted then all documents are updated. Using the patch method you can pass only specific fields that will get updated.
|
||||
Generated
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@appwrite.io/repo",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@appwrite.io/repo"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Appwrite\Messaging\Adapter;
|
||||
|
||||
use Appwrite\Messaging\Adapter;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
@@ -132,6 +133,7 @@ class Realtime extends Adapter
|
||||
public static function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options = []): void
|
||||
{
|
||||
if (empty($channels) || empty($roles) || empty($projectId)) {
|
||||
Console::error('Missing required parameters for Realtime event');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -122,8 +122,12 @@ class OpenAPI3 extends Format
|
||||
$scope = $route->getLabel('scope', '');
|
||||
$consumes = [$route->getLabel('sdk.request.type', 'application/json')];
|
||||
|
||||
|
||||
$method = $route->getLabel('sdk.method', \uniqid());
|
||||
|
||||
if (!empty($method) && is_array($method)) {
|
||||
$method = array_keys($method)[0];
|
||||
}
|
||||
|
||||
$desc = (!empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__ . '/../../../../' . $route->getLabel('sdk.description', '')) : null;
|
||||
$produces = $route->getLabel('sdk.response.type', null);
|
||||
$model = $route->getLabel('sdk.response.model', 'none');
|
||||
@@ -178,6 +182,10 @@ class OpenAPI3 extends Format
|
||||
],
|
||||
];
|
||||
|
||||
if (is_array($route->getLabel('sdk.method', ''))) {
|
||||
$temp['x-appwrite']['multiplex'] = $route->getLabel('sdk.method', '');
|
||||
}
|
||||
|
||||
foreach ($this->models as $value) {
|
||||
if (\is_array($model)) {
|
||||
$model = \array_map(fn ($m) => $m === $value->getType() ? $value : $m, $model);
|
||||
|
||||
@@ -121,6 +121,11 @@ class Swagger2 extends Format
|
||||
$consumes = [$route->getLabel('sdk.request.type', 'application/json')];
|
||||
|
||||
$method = $route->getLabel('sdk.method', \uniqid());
|
||||
|
||||
if (!empty($method) && is_array($method)) {
|
||||
$method = array_keys($method)[0];
|
||||
}
|
||||
|
||||
$desc = (!empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__ . '/../../../../' . $route->getLabel('sdk.description', '')) : null;
|
||||
$produces = $route->getLabel('sdk.response.type', null);
|
||||
$model = $route->getLabel('sdk.response.model', 'none');
|
||||
@@ -181,6 +186,10 @@ class Swagger2 extends Format
|
||||
$temp['produces'][] = $produces;
|
||||
}
|
||||
|
||||
if (is_array($route->getLabel('sdk.method', ''))) {
|
||||
$temp['x-appwrite']['multiplex'] = $route->getLabel('sdk.method', '');
|
||||
}
|
||||
|
||||
foreach ($this->models as $value) {
|
||||
if (\is_array($model)) {
|
||||
$model = \array_map(fn ($m) => $m === $value->getType() ? $value : $m, $model);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { check } from "k6";
|
||||
import http from "k6/http";
|
||||
|
||||
const amount = 100_000;
|
||||
const databaseId = "674918b20017411b94b2";
|
||||
const collectionId = "674918b4002b46c47d5d";
|
||||
|
||||
const documents = Array(amount).fill({
|
||||
$id: "unique()",
|
||||
name: "asd",
|
||||
});
|
||||
|
||||
export default function () {
|
||||
const payload = JSON.stringify({
|
||||
documents,
|
||||
});
|
||||
|
||||
const res = http.post(`http://localhost/v1/databases/${databaseId}/collections/${collectionId}/documents`,
|
||||
payload,
|
||||
{
|
||||
headers: {
|
||||
"X-Appwrite-Key": "standard_fa89c4834660f39e95ca2c2996fe7dd4ff498725e37c09323234c009570c1719f1c10610bf3541cf9ead120c107e41397a4eae1c787c83bdf577857bbc5963341641c77f582cc41e11a0d50eb4c2e4b1fda74418a8b9a253d6e63008e33560ba35310b9dc2fed5f09ca599e646f744cc6308b8ccd27ff04f9e498ec5a5f2c3db",
|
||||
"X-Appwrite-Project": "674818bc0017934d58dd",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
check(res, {
|
||||
"status is 200": (r) => r.status === 201,
|
||||
});
|
||||
}
|
||||
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']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,6 +650,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$user = $this->getUser();
|
||||
$session = $user['session'] ?? '';
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$documentIds = [];
|
||||
|
||||
$client = $this->getWebsocket(['documents', 'collections'], [
|
||||
'origin' => 'http://localhost',
|
||||
@@ -739,6 +740,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