Merge branch '1.6.x' into pla-2009

This commit is contained in:
Chirag Aggarwal 2025-02-04 10:44:52 +05:30 committed by GitHub
commit deeabc2d86
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 1612 additions and 5306 deletions

2
.gitignore vendored
View file

@ -16,4 +16,4 @@ dev/yasd_init.php
.phpunit.result.cache
Makefile
appwrite.json
/.zed/
/.zed/

View file

@ -2548,6 +2548,17 @@ return [
'array' => false,
'filters' => [],
],
[
'$id' => 'transformedAt',
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 0,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['datetime'],
],
[
'$id' => ID::custom('search'),
'type' => Database::VAR_STRING,
@ -2617,6 +2628,13 @@ return [
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_transformedAt'),
'type' => Database::INDEX_KEY,
'attributes' => ['transformedAt'],
'lengths' => [],
'orders' => [],
]
]
],
];

View file

@ -58,9 +58,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -109,9 +106,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -196,9 +190,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -274,9 +265,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account\/identities",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -335,9 +323,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -400,9 +385,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -451,9 +433,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -519,9 +498,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -591,9 +567,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -659,9 +632,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -739,9 +709,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -809,9 +776,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -857,10 +821,10 @@
],
"description": "Complete the MFA challenge by providing the one-time password. Finish the process of MFA verification by providing the one-time password. To begin the flow, use [createMfaChallenge](\/docs\/references\/cloud\/client-web\/account#createMfaChallenge) method.",
"responses": {
"204": {
"description": "No content",
"200": {
"description": "Session",
"content": {
"": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/session"
}
@ -885,9 +849,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -963,9 +924,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1016,9 +974,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1067,9 +1022,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1118,9 +1070,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1171,9 +1120,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1243,9 +1189,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1320,9 +1263,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1398,9 +1338,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account\/prefs",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1449,9 +1386,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account\/prefs",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1524,9 +1458,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1600,9 +1531,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1684,9 +1612,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account\/sessions",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1728,9 +1653,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1781,9 +1703,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1832,9 +1751,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1908,9 +1824,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1977,9 +1890,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2120,9 +2030,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2196,9 +2103,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2272,9 +2176,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account\/sessions",
"offline-key": "{sessionId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2335,9 +2236,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2391,9 +2289,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2456,9 +2351,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2479,7 +2371,7 @@
"tags": [
"account"
],
"description": "",
"description": "Use this endpoint to register a device for push notifications. Provide a target ID (custom or generated using ID.unique()), a device identifier (usually a device token), and optionally specify which provider should send notifications to this target. The target is automatically linked to the current session and includes device information like brand and model.",
"responses": {
"201": {
"description": "Target",
@ -2499,7 +2391,7 @@
"type": "",
"deprecated": false,
"demo": "account\/create-push-target.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-push-target.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@ -2508,9 +2400,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2560,7 +2449,7 @@
"tags": [
"account"
],
"description": "",
"description": "Update the currently logged in user's push notification target. You can modify the target's identifier (device token) and provider ID (token, email, phone etc.). The target must exist and belong to the current user. If you change the provider ID, notifications will be sent through the new messaging provider instead.",
"responses": {
"200": {
"description": "Target",
@ -2580,7 +2469,7 @@
"type": "",
"deprecated": false,
"demo": "account\/update-push-target.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-push-target.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@ -2589,9 +2478,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2640,17 +2526,10 @@
"tags": [
"account"
],
"description": "",
"description": "Delete a push notification target for the currently logged in user. After deletion, the device will no longer receive push notifications. The target must exist and belong to the current user.",
"responses": {
"204": {
"description": "No content",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/target"
}
}
}
"description": "No content"
}
},
"x-appwrite": {
@ -2660,7 +2539,7 @@
"type": "",
"deprecated": false,
"demo": "account\/delete-push-target.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-push-target.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@ -2669,9 +2548,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2733,9 +2609,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2817,9 +2690,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2896,9 +2766,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3042,9 +2909,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3118,9 +2982,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3188,9 +3049,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3269,9 +3127,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3320,9 +3175,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3392,9 +3244,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3520,9 +3369,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3652,9 +3498,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3712,9 +3555,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4202,9 +4042,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4286,9 +4123,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4380,9 +4214,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4481,9 +4312,6 @@
"server"
],
"packaging": false,
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4568,9 +4396,6 @@
"server"
],
"packaging": false,
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
"offline-key": "{documentId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4677,9 +4502,6 @@
"server"
],
"packaging": false,
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
"offline-key": "{documentId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4774,9 +4596,6 @@
"server"
],
"packaging": false,
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
"offline-key": "{documentId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4875,9 +4694,6 @@
"server"
],
"packaging": false,
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
"offline-key": "{documentId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4961,9 +4777,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5049,9 +4862,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5166,9 +4976,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5242,9 +5049,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5296,9 +5100,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5350,9 +5151,6 @@
"server"
],
"packaging": false,
"offline-model": "\/localed",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5404,9 +5202,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/localeCode",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5458,9 +5253,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/continents",
"offline-key": "",
"offline-response-key": "code",
"auth": {
"Project": []
}
@ -5512,9 +5304,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/countries",
"offline-key": "",
"offline-response-key": "code",
"auth": {
"Project": []
}
@ -5566,9 +5355,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/countries\/eu",
"offline-key": "",
"offline-response-key": "code",
"auth": {
"Project": []
}
@ -5620,9 +5406,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/countries\/phones",
"offline-key": "",
"offline-response-key": "countryCode",
"auth": {
"Project": []
}
@ -5674,9 +5457,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/currencies",
"offline-key": "",
"offline-response-key": "code",
"auth": {
"Project": []
}
@ -5728,9 +5508,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/languages",
"offline-key": "",
"offline-response-key": "code",
"auth": {
"Project": []
}
@ -5783,9 +5560,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5868,9 +5642,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5944,9 +5715,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6032,9 +5800,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6132,9 +5897,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6206,9 +5968,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6297,9 +6056,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6366,9 +6122,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6435,9 +6188,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6611,6 +6361,7 @@
"gif",
"png",
"webp",
"heic",
"avif"
],
"x-enum-name": "ImageFormat",
@ -6653,9 +6404,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6729,9 +6477,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6807,9 +6552,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6894,9 +6636,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams",
"offline-key": "{teamId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6958,9 +6697,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams",
"offline-key": "{teamId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7034,9 +6770,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7100,9 +6833,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams\/{teamId}\/memberships",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7188,9 +6918,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7301,9 +7028,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams\/{teamId}\/memberships",
"offline-key": "{membershipId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7375,9 +7099,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7464,9 +7185,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7539,9 +7257,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7639,9 +7354,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams\/{teamId}\/prefs",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7702,9 +7414,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams\/{teamId}\/prefs",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -6361,6 +6361,7 @@
"gif",
"png",
"webp",
"heic",
"avif"
],
"x-enum-name": "ImageFormat",

View file

@ -13373,7 +13373,7 @@
"tags": [
"messaging"
],
"description": "Update an email message by its unique ID.\n",
"description": "Update an email message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.\n",
"responses": {
"200": {
"description": "Message",
@ -13691,7 +13691,7 @@
"tags": [
"messaging"
],
"description": "Update a push notification by its unique ID.\n",
"description": "Update a push notification by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.\n",
"responses": {
"200": {
"description": "Message",
@ -13976,7 +13976,7 @@
"tags": [
"messaging"
],
"description": "Update an SMS message by its unique ID.\n",
"description": "Update an SMS message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.\n",
"responses": {
"200": {
"description": "Message",
@ -25157,6 +25157,7 @@
"gif",
"png",
"webp",
"heic",
"avif"
],
"x-enum-name": "ImageFormat",
@ -35706,6 +35707,18 @@
"x-example": 0,
"format": "int32"
},
"databasesReadsTotal": {
"type": "integer",
"description": "Total number of databases reads.",
"x-example": 0,
"format": "int32"
},
"databasesWritesTotal": {
"type": "integer",
"description": "Total number of databases writes.",
"x-example": 0,
"format": "int32"
},
"databases": {
"type": "array",
"description": "Aggregated number of databases per period.",
@ -35737,6 +35750,22 @@
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
},
"databasesReads": {
"type": "array",
"description": "An array of aggregated number of database reads.",
"items": {
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
},
"databasesWrites": {
"type": "array",
"description": "An array of aggregated number of database writes.",
"items": {
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
}
},
"required": [
@ -35745,10 +35774,14 @@
"collectionsTotal",
"documentsTotal",
"storageTotal",
"databasesReadsTotal",
"databasesWritesTotal",
"databases",
"collections",
"documents",
"storage"
"storage",
"databasesReads",
"databasesWrites"
]
},
"usageDatabase": {
@ -35778,6 +35811,18 @@
"x-example": 0,
"format": "int32"
},
"databaseReadsTotal": {
"type": "integer",
"description": "Total number of databases reads.",
"x-example": 0,
"format": "int32"
},
"databaseWritesTotal": {
"type": "integer",
"description": "Total number of databases writes.",
"x-example": 0,
"format": "int32"
},
"collections": {
"type": "array",
"description": "Aggregated number of collections per period.",
@ -35801,6 +35846,22 @@
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
},
"databaseReads": {
"type": "array",
"description": "An array of aggregated number of database reads.",
"items": {
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
},
"databaseWrites": {
"type": "array",
"description": "An array of aggregated number of database writes.",
"items": {
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
}
},
"required": [
@ -35808,9 +35869,13 @@
"collectionsTotal",
"documentsTotal",
"storageTotal",
"databaseReadsTotal",
"databaseWritesTotal",
"collections",
"documents",
"storage"
"storage",
"databaseReads",
"databaseWrites"
]
},
"usageCollection": {
@ -36405,6 +36470,18 @@
"x-example": 0,
"format": "int32"
},
"databasesReadsTotal": {
"type": "integer",
"description": "Total number of databases reads.",
"x-example": 0,
"format": "int32"
},
"databasesWritesTotal": {
"type": "integer",
"description": "Total number of databases writes.",
"x-example": 0,
"format": "int32"
},
"requests": {
"type": "array",
"description": "Aggregated number of requests per period.",
@ -36504,6 +36581,22 @@
"$ref": "#\/components\/schemas\/metricBreakdown"
},
"x-example": []
},
"databasesReads": {
"type": "array",
"description": "An array of aggregated number of database reads.",
"items": {
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
},
"databasesWrites": {
"type": "array",
"description": "An array of aggregated number of database writes.",
"items": {
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
}
},
"required": [
@ -36519,6 +36612,8 @@
"bucketsTotal",
"executionsMbSecondsTotal",
"buildsMbSecondsTotal",
"databasesReadsTotal",
"databasesWritesTotal",
"requests",
"network",
"users",
@ -36531,7 +36626,9 @@
"functionsStorageBreakdown",
"authPhoneTotal",
"authPhoneEstimate",
"authPhoneCountryBreakdown"
"authPhoneCountryBreakdown",
"databasesReads",
"databasesWrites"
]
},
"headers": {

View file

@ -12287,7 +12287,7 @@
"tags": [
"messaging"
],
"description": "Update an email message by its unique ID.\n",
"description": "Update an email message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.\n",
"responses": {
"200": {
"description": "Message",
@ -12607,7 +12607,7 @@
"tags": [
"messaging"
],
"description": "Update a push notification by its unique ID.\n",
"description": "Update a push notification by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.\n",
"responses": {
"200": {
"description": "Message",
@ -12894,7 +12894,7 @@
"tags": [
"messaging"
],
"description": "Update an SMS message by its unique ID.\n",
"description": "Update an SMS message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.\n",
"responses": {
"200": {
"description": "Message",
@ -17577,6 +17577,7 @@
"gif",
"png",
"webp",
"heic",
"avif"
],
"x-enum-name": "ImageFormat",

View file

@ -102,9 +102,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -155,9 +152,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -248,9 +242,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -330,9 +321,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account\/identities",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -394,9 +382,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -459,9 +444,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -512,9 +494,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -581,9 +560,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -656,9 +632,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -724,9 +697,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -805,9 +775,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -875,9 +842,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -922,14 +886,19 @@
"consumes": [
"application\/json"
],
"produces": [],
"produces": [
"application\/json"
],
"tags": [
"account"
],
"description": "Complete the MFA challenge by providing the one-time password. Finish the process of MFA verification by providing the one-time password. To begin the flow, use [createMfaChallenge](\/docs\/references\/cloud\/client-web\/account#createMfaChallenge) method.",
"responses": {
"204": {
"description": "No content"
"200": {
"description": "Session",
"schema": {
"$ref": "#\/definitions\/session"
}
}
},
"x-appwrite": {
@ -949,9 +918,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1031,9 +997,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1086,9 +1049,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1139,9 +1099,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1192,9 +1149,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1247,9 +1201,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1322,9 +1273,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1403,9 +1351,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1485,9 +1430,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account\/prefs",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1538,9 +1480,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account\/prefs",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1616,9 +1555,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1696,9 +1632,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1785,9 +1718,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account\/sessions",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1833,9 +1763,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1888,9 +1815,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -1941,9 +1865,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2021,9 +1942,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2098,9 +2016,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2236,9 +2151,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2316,9 +2228,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2396,9 +2305,6 @@
"server"
],
"packaging": false,
"offline-model": "\/account\/sessions",
"offline-key": "{sessionId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2459,9 +2365,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2517,9 +2420,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2582,9 +2482,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2611,7 +2508,7 @@
"tags": [
"account"
],
"description": "",
"description": "Use this endpoint to register a device for push notifications. Provide a target ID (custom or generated using ID.unique()), a device identifier (usually a device token), and optionally specify which provider should send notifications to this target. The target is automatically linked to the current session and includes device information like brand and model.",
"responses": {
"201": {
"description": "Target",
@ -2627,7 +2524,7 @@
"type": "",
"deprecated": false,
"demo": "account\/create-push-target.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/create-push-target.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@ -2636,9 +2533,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2697,7 +2591,7 @@
"tags": [
"account"
],
"description": "",
"description": "Update the currently logged in user's push notification target. You can modify the target's identifier (device token) and provider ID (token, email, phone etc.). The target must exist and belong to the current user. If you change the provider ID, notifications will be sent through the new messaging provider instead.",
"responses": {
"200": {
"description": "Target",
@ -2713,7 +2607,7 @@
"type": "",
"deprecated": false,
"demo": "account\/update-push-target.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/update-push-target.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@ -2722,9 +2616,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2770,13 +2661,11 @@
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"produces": [],
"tags": [
"account"
],
"description": "",
"description": "Delete a push notification target for the currently logged in user. After deletion, the device will no longer receive push notifications. The target must exist and belong to the current user.",
"responses": {
"204": {
"description": "No content"
@ -2789,7 +2678,7 @@
"type": "",
"deprecated": false,
"demo": "account\/delete-push-target.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/account\/delete-push-target.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@ -2798,9 +2687,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2862,9 +2748,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -2951,9 +2834,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3040,9 +2920,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3181,9 +3058,6 @@
"client"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3261,9 +3135,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3334,9 +3205,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3419,9 +3287,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3472,9 +3337,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3555,9 +3417,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3684,9 +3543,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3817,9 +3673,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -3884,9 +3737,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4375,9 +4225,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4462,9 +4309,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4557,9 +4401,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4652,9 +4493,6 @@
"server"
],
"packaging": false,
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4736,9 +4574,6 @@
"server"
],
"packaging": false,
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
"offline-key": "{documentId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4844,9 +4679,6 @@
"server"
],
"packaging": false,
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
"offline-key": "{documentId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -4936,9 +4768,6 @@
"server"
],
"packaging": false,
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
"offline-key": "{documentId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5035,9 +4864,6 @@
"server"
],
"packaging": false,
"offline-model": "\/databases\/{databaseId}\/collections\/{collectionId}\/documents",
"offline-key": "{documentId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5117,9 +4943,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5202,9 +5025,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5323,9 +5143,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5397,9 +5214,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5473,9 +5287,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5549,9 +5360,6 @@
"server"
],
"packaging": false,
"offline-model": "\/localed",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5605,9 +5413,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/localeCode",
"offline-key": "current",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -5661,9 +5466,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/continents",
"offline-key": "",
"offline-response-key": "code",
"auth": {
"Project": []
}
@ -5717,9 +5519,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/countries",
"offline-key": "",
"offline-response-key": "code",
"auth": {
"Project": []
}
@ -5773,9 +5572,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/countries\/eu",
"offline-key": "",
"offline-response-key": "code",
"auth": {
"Project": []
}
@ -5829,9 +5625,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/countries\/phones",
"offline-key": "",
"offline-response-key": "countryCode",
"auth": {
"Project": []
}
@ -5885,9 +5678,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/currencies",
"offline-key": "",
"offline-response-key": "code",
"auth": {
"Project": []
}
@ -5941,9 +5731,6 @@
"server"
],
"packaging": false,
"offline-model": "\/locale\/languages",
"offline-key": "",
"offline-response-key": "code",
"auth": {
"Project": []
}
@ -5998,9 +5785,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6056,9 +5840,7 @@
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"produces": [],
"tags": [
"messaging"
],
@ -6087,9 +5869,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6161,9 +5940,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6246,9 +6022,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6340,9 +6113,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6412,9 +6182,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6503,9 +6270,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6577,9 +6341,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6651,9 +6412,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6802,6 +6560,7 @@
"gif",
"png",
"webp",
"heic",
"avif"
],
"x-enum-name": "ImageFormat",
@ -6852,9 +6611,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -6926,9 +6682,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7003,9 +6756,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7097,9 +6847,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams",
"offline-key": "{teamId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7161,9 +6908,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams",
"offline-key": "{teamId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7238,9 +6982,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7304,9 +7045,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams\/{teamId}\/memberships",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7389,9 +7127,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7506,9 +7241,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams\/{teamId}\/memberships",
"offline-key": "{membershipId}",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7578,9 +7310,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7666,9 +7395,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7739,9 +7465,6 @@
"server"
],
"packaging": false,
"offline-model": "",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7837,9 +7560,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams\/{teamId}\/prefs",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}
@ -7900,9 +7620,6 @@
"server"
],
"packaging": false,
"offline-model": "\/teams\/{teamId}\/prefs",
"offline-key": "",
"offline-response-key": "$id",
"auth": {
"Project": []
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -6560,6 +6560,7 @@
"gif",
"png",
"webp",
"heic",
"avif"
],
"x-enum-name": "ImageFormat",

View file

@ -13639,7 +13639,7 @@
"tags": [
"messaging"
],
"description": "Update an email message by its unique ID.\n",
"description": "Update an email message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.\n",
"responses": {
"200": {
"description": "Message",
@ -13987,7 +13987,7 @@
"tags": [
"messaging"
],
"description": "Update a push notification by its unique ID.\n",
"description": "Update a push notification by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.\n",
"responses": {
"200": {
"description": "Message",
@ -14297,7 +14297,7 @@
"tags": [
"messaging"
],
"description": "Update an SMS message by its unique ID.\n",
"description": "Update an SMS message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.\n",
"responses": {
"200": {
"description": "Message",
@ -25633,6 +25633,7 @@
"gif",
"png",
"webp",
"heic",
"avif"
],
"x-enum-name": "ImageFormat",
@ -36243,6 +36244,18 @@
"x-example": 0,
"format": "int32"
},
"databasesReadsTotal": {
"type": "integer",
"description": "Total number of databases reads.",
"x-example": 0,
"format": "int32"
},
"databasesWritesTotal": {
"type": "integer",
"description": "Total number of databases writes.",
"x-example": 0,
"format": "int32"
},
"databases": {
"type": "array",
"description": "Aggregated number of databases per period.",
@ -36278,6 +36291,24 @@
"$ref": "#\/definitions\/metric"
},
"x-example": []
},
"databasesReads": {
"type": "array",
"description": "An array of aggregated number of database reads.",
"items": {
"type": "object",
"$ref": "#\/definitions\/metric"
},
"x-example": []
},
"databasesWrites": {
"type": "array",
"description": "An array of aggregated number of database writes.",
"items": {
"type": "object",
"$ref": "#\/definitions\/metric"
},
"x-example": []
}
},
"required": [
@ -36286,10 +36317,14 @@
"collectionsTotal",
"documentsTotal",
"storageTotal",
"databasesReadsTotal",
"databasesWritesTotal",
"databases",
"collections",
"documents",
"storage"
"storage",
"databasesReads",
"databasesWrites"
]
},
"usageDatabase": {
@ -36319,6 +36354,18 @@
"x-example": 0,
"format": "int32"
},
"databaseReadsTotal": {
"type": "integer",
"description": "Total number of databases reads.",
"x-example": 0,
"format": "int32"
},
"databaseWritesTotal": {
"type": "integer",
"description": "Total number of databases writes.",
"x-example": 0,
"format": "int32"
},
"collections": {
"type": "array",
"description": "Aggregated number of collections per period.",
@ -36345,6 +36392,24 @@
"$ref": "#\/definitions\/metric"
},
"x-example": []
},
"databaseReads": {
"type": "array",
"description": "An array of aggregated number of database reads.",
"items": {
"type": "object",
"$ref": "#\/definitions\/metric"
},
"x-example": []
},
"databaseWrites": {
"type": "array",
"description": "An array of aggregated number of database writes.",
"items": {
"type": "object",
"$ref": "#\/definitions\/metric"
},
"x-example": []
}
},
"required": [
@ -36352,9 +36417,13 @@
"collectionsTotal",
"documentsTotal",
"storageTotal",
"databaseReadsTotal",
"databaseWritesTotal",
"collections",
"documents",
"storage"
"storage",
"databaseReads",
"databaseWrites"
]
},
"usageCollection": {
@ -36976,6 +37045,18 @@
"x-example": 0,
"format": "int32"
},
"databasesReadsTotal": {
"type": "integer",
"description": "Total number of databases reads.",
"x-example": 0,
"format": "int32"
},
"databasesWritesTotal": {
"type": "integer",
"description": "Total number of databases writes.",
"x-example": 0,
"format": "int32"
},
"requests": {
"type": "array",
"description": "Aggregated number of requests per period.",
@ -37086,6 +37167,24 @@
"$ref": "#\/definitions\/metricBreakdown"
},
"x-example": []
},
"databasesReads": {
"type": "array",
"description": "An array of aggregated number of database reads.",
"items": {
"type": "object",
"$ref": "#\/definitions\/metric"
},
"x-example": []
},
"databasesWrites": {
"type": "array",
"description": "An array of aggregated number of database writes.",
"items": {
"type": "object",
"$ref": "#\/definitions\/metric"
},
"x-example": []
}
},
"required": [
@ -37101,6 +37200,8 @@
"bucketsTotal",
"executionsMbSecondsTotal",
"buildsMbSecondsTotal",
"databasesReadsTotal",
"databasesWritesTotal",
"requests",
"network",
"users",
@ -37113,7 +37214,9 @@
"functionsStorageBreakdown",
"authPhoneTotal",
"authPhoneEstimate",
"authPhoneCountryBreakdown"
"authPhoneCountryBreakdown",
"databasesReads",
"databasesWrites"
]
},
"headers": {

View file

@ -12556,7 +12556,7 @@
"tags": [
"messaging"
],
"description": "Update an email message by its unique ID.\n",
"description": "Update an email message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.\n",
"responses": {
"200": {
"description": "Message",
@ -12906,7 +12906,7 @@
"tags": [
"messaging"
],
"description": "Update a push notification by its unique ID.\n",
"description": "Update a push notification by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.\n",
"responses": {
"200": {
"description": "Message",
@ -13218,7 +13218,7 @@
"tags": [
"messaging"
],
"description": "Update an SMS message by its unique ID.\n",
"description": "Update an SMS message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.\n",
"responses": {
"200": {
"description": "Message",
@ -18034,6 +18034,7 @@
"gif",
"png",
"webp",
"heic",
"avif"
],
"x-enum-name": "ImageFormat",

View file

@ -21,6 +21,7 @@ use Appwrite\Utopia\Response;
use Utopia\App;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Exception\Duplicate as DuplicateException;
use Utopia\Database\Exception\NotFound as NotFoundException;
@ -1075,6 +1076,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
->addMetric(str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_TRANSFORMATIONS), 1)
;
$transformedAt = $file->getAttribute('transformedAt', '');
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) {
$file->setAttribute('transformedAt', DateTime::now());
Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file));
}
$response
->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days
->setContentType($contentType)

View file

@ -231,7 +231,7 @@ App::init()
if ($keyType === API_KEY_DYNAMIC) {
// Dynamic key
$jwtObj = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 0);
$jwtObj = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 86400, 0);
try {
$payload = $jwtObj->decode($authKey);
@ -607,6 +607,12 @@ App::init()
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}
$transformedAt = $file->getAttribute('transformedAt', '');
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) {
$file->setAttribute('transformedAt', DateTime::now());
Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file));
}
}
$response

View file

@ -122,6 +122,7 @@ const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return
const APP_KEY_ACCESS = 24 * 60 * 60; // 24 hours
const APP_USER_ACCESS = 24 * 60 * 60; // 24 hours
const APP_PROJECT_ACCESS = 24 * 60 * 60; // 24 hours
const APP_FILE_ACCESS = 24 * 60 * 60; // 24 hours
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
const APP_CACHE_BUSTER = 4318;
const APP_VERSION_STABLE = '1.6.1';

View file

@ -45,13 +45,13 @@
"ext-sockets": "*",
"appwrite/php-runtimes": "0.16.*",
"appwrite/php-clamav": "2.0.*",
"utopia-php/abuse": "0.48.*",
"utopia-php/abuse": "0.47.*",
"utopia-php/analytics": "0.10.*",
"utopia-php/audit": "0.48.*",
"utopia-php/audit": "0.47.*",
"utopia-php/cache": "0.11.*",
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.57.*",
"utopia-php/database": "0.56.4",
"utopia-php/domains": "0.5.*",
"utopia-php/dsn": "0.2.1",
"utopia-php/framework": "0.33.*",
@ -59,7 +59,7 @@
"utopia-php/image": "0.7.*",
"utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.6.*",
"utopia-php/messaging": "0.13.*",
"utopia-php/messaging": "0.14.*",
"utopia-php/migration": "0.6.*",
"utopia-php/orchestration": "0.9.*",
"utopia-php/platform": "0.7.1",
@ -84,7 +84,7 @@
},
"require-dev": {
"ext-fileinfo": "*",
"appwrite/sdk-generator": "0.39.30",
"appwrite/sdk-generator": "0.39.32",
"phpunit/phpunit": "9.5.20",
"swoole/ide-helper": "5.1.2",
"textalk/websocket": "1.5.7",

195
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "8927ec7d3cfa460ce223e4c13cf61ada",
"content-hash": "e8d26e7e836db255ba42cf55c3798c97",
"packages": [
{
"name": "adhocore/jwt",
@ -1237,16 +1237,16 @@
},
{
"name": "open-telemetry/api",
"version": "1.2.0",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/api.git",
"reference": "351a30baa79699de3de3a814c8ccc7b52ccdfb1d"
"reference": "74b1a03263be8c5acb578f41da054b4bac3af4a0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/opentelemetry-php/api/zipball/351a30baa79699de3de3a814c8ccc7b52ccdfb1d",
"reference": "351a30baa79699de3de3a814c8ccc7b52ccdfb1d",
"url": "https://api.github.com/repos/opentelemetry-php/api/zipball/74b1a03263be8c5acb578f41da054b4bac3af4a0",
"reference": "74b1a03263be8c5acb578f41da054b4bac3af4a0",
"shasum": ""
},
"require": {
@ -1303,7 +1303,7 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
"time": "2025-01-08T23:50:34+00:00"
"time": "2025-01-20T23:35:16+00:00"
},
{
"name": "open-telemetry/context",
@ -1493,16 +1493,16 @@
},
{
"name": "open-telemetry/sdk",
"version": "1.2.0",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/sdk.git",
"reference": "9a1c3b866239dbff291e5cc555bb7793eab08127"
"reference": "96aeaee5b7cb8c0bc4af7ff4717b429f2d9f67e1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/9a1c3b866239dbff291e5cc555bb7793eab08127",
"reference": "9a1c3b866239dbff291e5cc555bb7793eab08127",
"url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/96aeaee5b7cb8c0bc4af7ff4717b429f2d9f67e1",
"reference": "96aeaee5b7cb8c0bc4af7ff4717b429f2d9f67e1",
"shasum": ""
},
"require": {
@ -1579,7 +1579,7 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
"time": "2025-01-08T23:50:34+00:00"
"time": "2025-01-09T23:17:14+00:00"
},
{
"name": "open-telemetry/sem-conv",
@ -3136,16 +3136,16 @@
},
{
"name": "utopia-php/abuse",
"version": "0.48.0",
"version": "0.47.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "8387c65cc7148af58adbbede06eedc1a7b568e57"
"reference": "2b52bb362234d4072b647ed57db1b3be030f57c2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/8387c65cc7148af58adbbede06eedc1a7b568e57",
"reference": "8387c65cc7148af58adbbede06eedc1a7b568e57",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/2b52bb362234d4072b647ed57db1b3be030f57c2",
"reference": "2b52bb362234d4072b647ed57db1b3be030f57c2",
"shasum": ""
},
"require": {
@ -3153,13 +3153,13 @@
"ext-pdo": "*",
"ext-redis": "*",
"php": ">=8.0",
"utopia-php/database": "0.57.*"
"utopia-php/database": "0.56.*"
},
"require-dev": {
"laravel/pint": "1.*",
"phpbench/phpbench": "1.*",
"phpstan/phpstan": "1.*",
"phpunit/phpunit": "9.*"
"laravel/pint": "1.5.*",
"phpbench/phpbench": "^1.2",
"phpstan/phpstan": "^1.9",
"phpunit/phpunit": "^9.4"
},
"type": "library",
"autoload": {
@ -3181,9 +3181,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.48.0"
"source": "https://github.com/utopia-php/abuse/tree/0.47.0"
},
"time": "2025-01-23T04:40:14+00:00"
"time": "2025-01-15T02:41:02+00:00"
},
{
"name": "utopia-php/analytics",
@ -3233,26 +3233,26 @@
},
{
"name": "utopia-php/audit",
"version": "0.48.0",
"version": "0.47.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "6aab185fce3ba7878b0f26cc8b4eefa1663fb395"
"reference": "1ebd5784ba68645073426f2f04a67726a1bde4d7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/6aab185fce3ba7878b0f26cc8b4eefa1663fb395",
"reference": "6aab185fce3ba7878b0f26cc8b4eefa1663fb395",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/1ebd5784ba68645073426f2f04a67726a1bde4d7",
"reference": "1ebd5784ba68645073426f2f04a67726a1bde4d7",
"shasum": ""
},
"require": {
"php": ">=8.0",
"utopia-php/database": "0.57.*"
"utopia-php/database": "0.56.*"
},
"require-dev": {
"laravel/pint": "1.*",
"phpstan/phpstan": "1.*",
"phpunit/phpunit": "9.*"
"laravel/pint": "1.5.*",
"phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^9.3"
},
"type": "library",
"autoload": {
@ -3274,9 +3274,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.48.0"
"source": "https://github.com/utopia-php/audit/tree/0.47.0"
},
"time": "2025-01-23T04:40:07+00:00"
"time": "2025-01-15T02:40:53+00:00"
},
{
"name": "utopia-php/cache",
@ -3476,16 +3476,16 @@
},
{
"name": "utopia-php/database",
"version": "0.57.2",
"version": "0.56.4",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "bd6f080dd9f4210349a6a862fa6da65a4d9d6339"
"reference": "240478a60797124a885ceac40046fe47c22415b7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/bd6f080dd9f4210349a6a862fa6da65a4d9d6339",
"reference": "bd6f080dd9f4210349a6a862fa6da65a4d9d6339",
"url": "https://api.github.com/repos/utopia-php/database/zipball/240478a60797124a885ceac40046fe47c22415b7",
"reference": "240478a60797124a885ceac40046fe47c22415b7",
"shasum": ""
},
"require": {
@ -3526,9 +3526,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.57.2"
"source": "https://github.com/utopia-php/database/tree/0.56.4"
},
"time": "2025-01-23T05:19:02+00:00"
"time": "2025-01-20T09:22:08+00:00"
},
{
"name": "utopia-php/domains",
@ -3878,16 +3878,16 @@
},
{
"name": "utopia-php/messaging",
"version": "0.13.0",
"version": "0.14.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/messaging.git",
"reference": "0e3e57351fe4fe875ef3ab9a01a7fff5f022de90"
"reference": "4ba356a3aa382802727f7e13e0f0152bcc1fc535"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/0e3e57351fe4fe875ef3ab9a01a7fff5f022de90",
"reference": "0e3e57351fe4fe875ef3ab9a01a7fff5f022de90",
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/4ba356a3aa382802727f7e13e0f0152bcc1fc535",
"reference": "4ba356a3aa382802727f7e13e0f0152bcc1fc535",
"shasum": ""
},
"require": {
@ -3923,41 +3923,41 @@
],
"support": {
"issues": "https://github.com/utopia-php/messaging/issues",
"source": "https://github.com/utopia-php/messaging/tree/0.13.0"
"source": "https://github.com/utopia-php/messaging/tree/0.14.1"
},
"time": "2024-12-05T08:36:07+00:00"
"time": "2025-01-28T06:14:28+00:00"
},
{
"name": "utopia-php/migration",
"version": "0.6.16",
"version": "0.6.15",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/migration.git",
"reference": "a1da9b75a0e406ea8caca0d61b57a4d206ea0715"
"reference": "e849ec3e7ad38f5f5273ebb0132b112639cdf01c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/a1da9b75a0e406ea8caca0d61b57a4d206ea0715",
"reference": "a1da9b75a0e406ea8caca0d61b57a4d206ea0715",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/e849ec3e7ad38f5f5273ebb0132b112639cdf01c",
"reference": "e849ec3e7ad38f5f5273ebb0132b112639cdf01c",
"shasum": ""
},
"require": {
"appwrite/appwrite": "11.*",
"appwrite/appwrite": "11.1.*",
"ext-curl": "*",
"ext-openssl": "*",
"php": ">=8.3",
"utopia-php/database": "0.57.*",
"php": "8.3.*",
"utopia-php/database": "0.56.*",
"utopia-php/dsn": "0.2.*",
"utopia-php/framework": "0.33.*",
"utopia-php/storage": "0.18.*"
},
"require-dev": {
"ext-pdo": "*",
"laravel/pint": "1.*",
"phpstan/phpstan": "1.*",
"phpunit/phpunit": "11.*",
"laravel/pint": "1.17.*",
"phpstan/phpstan": "1.11.*",
"phpunit/phpunit": "11.2.*",
"utopia-php/cli": "0.16.*",
"vlucas/phpdotenv": "5.*"
"vlucas/phpdotenv": "5.6.*"
},
"type": "library",
"autoload": {
@ -3979,9 +3979,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/migration/issues",
"source": "https://github.com/utopia-php/migration/tree/0.6.16"
"source": "https://github.com/utopia-php/migration/tree/0.6.15"
},
"time": "2025-01-23T04:34:02+00:00"
"time": "2025-01-15T04:55:08+00:00"
},
{
"name": "utopia-php/mongo",
@ -4807,16 +4807,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "0.39.30",
"version": "0.39.32",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "830198d501f51163514305befefb775106a7198b"
"reference": "2d02e1305ea5004fb0aec6b2618d6c597659b75c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/830198d501f51163514305befefb775106a7198b",
"reference": "830198d501f51163514305befefb775106a7198b",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/2d02e1305ea5004fb0aec6b2618d6c597659b75c",
"reference": "2d02e1305ea5004fb0aec6b2618d6c597659b75c",
"shasum": ""
},
"require": {
@ -4852,9 +4852,9 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
"source": "https://github.com/appwrite/sdk-generator/tree/0.39.30"
"source": "https://github.com/appwrite/sdk-generator/tree/0.39.32"
},
"time": "2025-01-20T06:10:03+00:00"
"time": "2025-01-29T04:04:19+00:00"
},
{
"name": "doctrine/annotations",
@ -5601,70 +5601,18 @@
},
"time": "2023-10-30T13:38:26+00:00"
},
{
"name": "phpbench/dom",
"version": "0.3.3",
"source": {
"type": "git",
"url": "https://github.com/phpbench/dom.git",
"reference": "786a96db538d0def931f5b19225233ec42ec7a72"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpbench/dom/zipball/786a96db538d0def931f5b19225233ec42ec7a72",
"reference": "786a96db538d0def931f5b19225233ec42ec7a72",
"shasum": ""
},
"require": {
"ext-dom": "*",
"php": "^7.3||^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.14",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^8.0||^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"PhpBench\\Dom\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Daniel Leech",
"email": "daniel@dantleech.com"
}
],
"description": "DOM wrapper to simplify working with the PHP DOM implementation",
"support": {
"issues": "https://github.com/phpbench/dom/issues",
"source": "https://github.com/phpbench/dom/tree/0.3.3"
},
"abandoned": true,
"time": "2023-03-06T23:46:57+00:00"
},
{
"name": "phpbench/phpbench",
"version": "1.3.1",
"version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/phpbench/phpbench.git",
"reference": "a3e1ef08d9d7736d43a7fbd444893d6a073c0ca0"
"reference": "4248817222514421cba466bfa7adc7d8932345d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpbench/phpbench/zipball/a3e1ef08d9d7736d43a7fbd444893d6a073c0ca0",
"reference": "a3e1ef08d9d7736d43a7fbd444893d6a073c0ca0",
"url": "https://api.github.com/repos/phpbench/phpbench/zipball/4248817222514421cba466bfa7adc7d8932345d4",
"reference": "4248817222514421cba466bfa7adc7d8932345d4",
"shasum": ""
},
"require": {
@ -5677,7 +5625,6 @@
"ext-tokenizer": "*",
"php": "^8.1",
"phpbench/container": "^2.2",
"phpbench/dom": "~0.3.3",
"psr/log": "^1.1 || ^2.0 || ^3.0",
"seld/jsonlint": "^1.1",
"symfony/console": "^6.1 || ^7.0",
@ -5696,8 +5643,8 @@
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^10.4",
"rector/rector": "^0.18.11 || ^1.0.0",
"phpunit/phpunit": "^10.4 || ^11.0",
"rector/rector": "^1.2",
"symfony/error-handler": "^6.1 || ^7.0",
"symfony/var-dumper": "^6.1 || ^7.0"
},
@ -5742,7 +5689,7 @@
],
"support": {
"issues": "https://github.com/phpbench/phpbench/issues",
"source": "https://github.com/phpbench/phpbench/tree/1.3.1"
"source": "https://github.com/phpbench/phpbench/tree/1.4.0"
},
"funding": [
{
@ -5750,7 +5697,7 @@
"type": "github"
}
],
"time": "2024-06-30T11:04:37+00:00"
"time": "2025-01-26T19:54:45+00:00"
},
{
"name": "phpdocumentor/reflection-common",

View file

@ -1 +1 @@
Update an email message by its unique ID.
Update an email message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.

View file

@ -1 +1 @@
Update a push notification by its unique ID.
Update a push notification by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.

View file

@ -1 +1 @@
Update an SMS message by its unique ID.
Update an SMS message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated.

View file

@ -22,6 +22,8 @@ use Utopia\Messaging\Adapter\Push\APNS;
use Utopia\Messaging\Adapter\Push as PushAdapter;
use Utopia\Messaging\Adapter\Push\FCM;
use Utopia\Messaging\Adapter\SMS as SMSAdapter;
use Utopia\Messaging\Adapter\SMS\Fast2SMS;
use Utopia\Messaging\Adapter\SMS\GEOSMS;
use Utopia\Messaging\Adapter\SMS\Mock;
use Utopia\Messaging\Adapter\SMS\Msg91;
use Utopia\Messaging\Adapter\SMS\Telesign;
@ -46,6 +48,8 @@ class Messaging extends Action
{
private ?Local $localDevice = null;
private ?SMSAdapter $adapter = null;
public static function getName(): string
{
return 'messaging';
@ -56,6 +60,9 @@ class Messaging extends Action
*/
public function __construct()
{
$this->adapter = $this->createInternalSMSAdapter();
$this
->desc('Messaging worker')
->inject('message')
@ -381,100 +388,38 @@ class Messaging extends Action
private function sendInternalSMSMessage(Document $message, Document $project, array $recipients, Log $log): void
{
if (empty(System::getEnv('_APP_SMS_PROVIDER')) || empty(System::getEnv('_APP_SMS_FROM'))) {
throw new \Exception('Skipped SMS processing. Missing "_APP_SMS_PROVIDER" or "_APP_SMS_FROM" environment variables.');
if ($this->adapter === null) {
Console::warning('Skipped SMS processing. SMS adapter is not set.');
return;
}
if ($project->isEmpty()) {
throw new \Exception('Project not set in payload');
}
Console::log('Project: ' . $project->getId());
Console::log('Processing project: ' . $project->getId());
$denyList = System::getEnv('_APP_SMS_PROJECTS_DENY_LIST', '');
$denyList = explode(',', $denyList);
if (\in_array($project->getId(), $denyList)) {
Console::error('Project is in the deny list. Skipping...');
return;
}
$smsDSN = new DSN(System::getEnv('_APP_SMS_PROVIDER'));
$host = $smsDSN->getHost();
$password = $smsDSN->getPassword();
$user = $smsDSN->getUser();
$log->addTag('type', $host);
$from = System::getEnv('_APP_SMS_FROM');
$provider = new Document([
'$id' => ID::unique(),
'provider' => $host,
'type' => MESSAGE_TYPE_SMS,
'name' => 'Internal SMS',
'enabled' => true,
'credentials' => match ($host) {
'twilio' => [
'accountSid' => $user,
'authToken' => $password,
// Twilio Messaging Service SIDs always start with MG
// https://www.twilio.com/docs/messaging/services
'messagingServiceSid' => \str_starts_with($from, 'MG') ? $from : null
],
'textmagic' => [
'username' => $user,
'apiKey' => $password
],
'telesign' => [
'customerId' => $user,
'apiKey' => $password
],
'msg91' => [
'senderId' => $user,
'authKey' => $password,
'templateId' => $smsDSN->getParam('templateId', $from),
],
'vonage' => [
'apiKey' => $user,
'apiSecret' => $password
],
default => null
},
'options' => match ($host) {
'twilio' => [
'from' => \str_starts_with($from, 'MG') ? null : $from
],
default => [
'from' => $from
]
}
]);
$adapter = $this->getSmsAdapter($provider);
$batches = \array_chunk(
$from = System::getEnv('_APP_SMS_FROM', '');
$sms = new SMS(
$recipients,
$adapter->getMaxMessagesPerRequest()
$message->getAttribute('data')['content'],
$from
);
batch(\array_map(function ($batch) use ($message, $provider, $adapter) {
return function () use ($batch, $message, $provider, $adapter) {
$message->setAttribute('to', $batch);
$data = $this->buildSmsMessage($message, $provider);
try {
$adapter->send($data);
} catch (\Throwable $th) {
throw new \Exception('Failed sending to targets with error: ' . $th->getMessage());
}
};
}, $batches));
try {
$result = $this->adapter->send($sms);
} catch (\Throwable $th) {
throw new \Exception('Failed sending to targets with error: ' . $th->getMessage());
}
}
private function getSmsAdapter(Document $provider): ?SMSAdapter
{
$credentials = $provider->getAttribute('credentials');
@ -504,6 +449,12 @@ class Messaging extends Action
$credentials['apiKey'] ?? '',
$credentials['apiSecret'] ?? ''
),
'fast2sms' => new Fast2SMS(
$credentials['apiKey'] ?? '',
$credentials['senderId'] ?? '',
$credentials['messageId'] ?? '',
$credentials['useDLT'] ?? true
),
default => null
};
}
@ -720,4 +671,127 @@ class Messaging extends Action
return $this->localDevice;
}
private function createInternalSMSAdapter(): ?SMSAdapter
{
if (empty(System::getEnv('_APP_SMS_PROVIDER')) || empty(System::getEnv('_APP_SMS_FROM'))) {
Console::warning('Skipped SMS processing. Missing "_APP_SMS_PROVIDER" or "_APP_SMS_FROM" environment variables.');
return null;
}
$providers = System::getEnv('_APP_SMS_PROVIDER', '');
$dsns = [];
if (!empty($providers)) {
$providers = explode(',', $providers);
foreach ($providers as $provider) {
$dsns[] = new DSN($provider);
}
}
if (count($dsns) === 1) {
$provider = $this->createProviderFromDSN($dsns[0]);
$adapter = $this->getSmsAdapter($provider);
return $adapter;
}
$defaultDSN = null;
$localDSNs = [];
/** @var DSN $dsn */
foreach ($dsns as $dsn) {
if ($dsn->getParam('local', '') === 'default') {
$defaultDSN = $dsn;
} else {
$localDSNs[] = $dsn;
}
}
if ($defaultDSN === null) {
throw new \Exception('No default SMS provider found');
}
$defaultProvider = $this->createProviderFromDSN($defaultDSN);
$adapter = $this->getSmsAdapter($defaultProvider);
$geosms = new GEOSMS($adapter);
/** @var DSN $localDSN */
foreach ($localDSNs as $localDSN) {
try {
$provider = $this->createProviderFromDSN($localDSN);
$adapter = $this->getSmsAdapter($provider);
} catch (\Exception) {
Console::warning('Unable to create adapter: ' . $localDSN->getHost());
continue;
}
$callingCode = $localDSN->getParam('local', '');
if (empty($callingCode)) {
Console::warning('Unable to register adapter: ' . $localDSN->getHost() . '. Missing `local` parameter.');
continue;
}
$geosms->setLocal($callingCode, $adapter);
}
return $geosms;
}
private function createProviderFromDSN(DSN $dsn): Document
{
$host = $dsn->getHost();
$password = $dsn->getPassword();
$user = $dsn->getUser();
$from = System::getEnv('_APP_SMS_FROM');
$provider = new Document([
'$id' => ID::unique(),
'provider' => $host,
'type' => MESSAGE_TYPE_SMS,
'name' => 'Internal SMS',
'enabled' => true,
'credentials' => match ($host) {
'twilio' => [
'accountSid' => $user,
'authToken' => $password,
// Twilio Messaging Service SIDs always start with MG
// https://www.twilio.com/docs/messaging/services
'messagingServiceSid' => \str_starts_with($from, 'MG') ? $from : null
],
'textmagic' => [
'username' => $user,
'apiKey' => $password
],
'telesign' => [
'customerId' => $user,
'apiKey' => $password
],
'msg91' => [
'senderId' => $user,
'authKey' => $password,
'templateId' => $dsn->getParam('templateId', $from),
],
'vonage' => [
'apiKey' => $user,
'apiSecret' => $password
],
'fast2sms' => [
'senderId' => $user,
'apiKey' => $password,
'messageId' => $dsn->getParam('messageId'),
'useDLT' => $dsn->getParam('useDLT'),
],
default => null
},
'options' => match ($host) {
'twilio' => [
'from' => \str_starts_with($from, 'MG') ? null : $from
],
default => [
'from' => $from
]
}
]);
return $provider;
}
}

View file

@ -2,10 +2,9 @@
namespace Appwrite\Platform\Workers;
use Ahc\Jwt\JWT;
use Appwrite\Event\Event;
use Appwrite\Messaging\Adapter\Realtime;
use Appwrite\Permission;
use Appwrite\Role;
use Exception;
use Utopia\CLI\Console;
use Utopia\Config\Config;
@ -15,7 +14,6 @@ use Utopia\Database\Exception\Authorization;
use Utopia\Database\Exception\Conflict;
use Utopia\Database\Exception\Restricted;
use Utopia\Database\Exception\Structure;
use Utopia\Database\Helpers\ID;
use Utopia\Migration\Destination;
use Utopia\Migration\Destinations\Appwrite as DestinationAppwrite;
use Utopia\Migration\Exception as MigrationException;
@ -27,6 +25,7 @@ use Utopia\Migration\Sources\Supabase;
use Utopia\Migration\Transfer;
use Utopia\Platform\Action;
use Utopia\Queue\Message;
use Utopia\System\System;
class Migrations extends Action
{
@ -206,48 +205,32 @@ class Migrations extends Action
* @throws \Utopia\Database\Exception
* @throws Exception
*/
protected function generateAPIKey(Document $project): Document
protected function generateAPIKey(Document $project): string
{
$generatedSecret = bin2hex(\random_bytes(128));
$key = new Document([
'$id' => ID::unique(),
'$permissions' => [
Permission::read(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
'projectInternalId' => $project->getInternalId(),
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 86400, 0);
$apiKey = $jwt->encode([
'projectId' => $project->getId(),
'name' => 'Transfer API Key',
'scopes' => [
'users.read',
'users.write',
'teams.read',
'teams.write',
'databases.read',
'databases.write',
'collections.read',
'collections.write',
'documents.read',
'documents.write',
'buckets.read',
'buckets.write',
'files.read',
'files.write',
'functions.read',
'functions.write',
],
'expire' => null,
'sdks' => [],
'accessedAt' => null,
'secret' => $generatedSecret,
'databases.read',
'databases.write',
'collections.read',
'collections.write',
'documents.read',
'documents.write'
]
]);
$this->dbForPlatform->createDocument('keys', $key);
$this->dbForPlatform->purgeCachedDocument('projects', $project->getId());
return $key;
return API_KEY_DYNAMIC . '_' . $apiKey;
}
/**
@ -275,7 +258,7 @@ class Migrations extends Action
$credentials['projectId'] = $credentials['projectId'] ?? $projectDocument->getId();
$credentials['endpoint'] = $credentials['endpoint'] ?? 'http://appwrite/v1';
$credentials['apiKey'] = $credentials['apiKey'] ?? $tempAPIKey['secret'];
$credentials['apiKey'] = $credentials['apiKey'] ?? $tempAPIKey;
$migration->setAttribute('credentials', $credentials);
}
@ -285,7 +268,7 @@ class Migrations extends Action
$this->updateMigrationDocument($migration, $projectDocument);
$source = $this->processSource($migration);
$destination = $this->processDestination($migration, $tempAPIKey->getAttribute('secret'));
$destination = $this->processDestination($migration, $tempAPIKey);
$source->report();
@ -381,10 +364,6 @@ class Migrations extends Action
$migration->setAttribute('errors', $errorMessages);
}
} finally {
if (! $tempAPIKey->isEmpty()) {
$this->removeAPIKey($tempAPIKey);
}
$this->updateMigrationDocument($migration, $projectDocument);
if ($migration->getAttribute('status', '') === 'failed') {

View file

@ -30,13 +30,16 @@ class Usage extends Action
*/
public function __construct()
{
$this
->desc('Usage worker')
->inject('message')
->inject('project')
->inject('getProjectDB')
->inject('queueForUsageDump')
->callback([$this, 'action']);
->desc('Usage worker')
->inject('message')
->inject('project')
->inject('getProjectDB')
->inject('queueForUsageDump')
->callback(function (Message $message, Document $project, callable $getProjectDB, UsageDump $queueForUsageDump) {
$this->action($message, $project, $getProjectDB, $queueForUsageDump);
});
$this->aggregationInterval = (int) System::getEnv('_APP_USAGE_AGGREGATION_INTERVAL', '20');
$this->lastTriggeredTime = time();
@ -58,6 +61,7 @@ class Usage extends Action
throw new Exception('Missing payload');
}
if (empty($project->getAttribute('database'))) {
var_dump($payload);
return;

View file

@ -7,7 +7,7 @@ use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Exception\NotFound;
use Utopia\Database\Exception\Duplicate;
use Utopia\Platform\Action;
use Utopia\Queue\Message;
use Utopia\System\System;
@ -38,7 +38,9 @@ class UsageDump extends Action
$this
->inject('message')
->inject('getProjectDB')
->callback([$this, 'action']);
->callback(function (Message $message, callable $getProjectDB) {
$this->action($message, $getProjectDB);
});
}
/**
@ -55,247 +57,230 @@ class UsageDump extends Action
throw new Exception('Missing payload');
}
try {
foreach ($payload['stats'] ?? [] as $stats) {
$project = new Document($stats['project'] ?? []);
$numberOfKeys = !empty($stats['keys']) ? \count($stats['keys']) : 0;
$receivedAt = $stats['receivedAt'] ?? 'NONE';
if ($numberOfKeys === 0) {
continue;
}
foreach ($payload['stats'] ?? [] as $stats) {
$project = new Document($stats['project'] ?? []);
/**
* End temp bug fallback
*/
$numberOfKeys = !empty($stats['keys']) ? count($stats['keys']) : 0;
$receivedAt = $stats['receivedAt'] ?? 'NONE';
if ($numberOfKeys === 0) {
continue;
}
console::log('['.DateTime::now().'] Id: '.$project->getId(). ' InternalId: '.$project->getInternalId(). ' Db: '.$project->getAttribute('database').' ReceivedAt: '.$receivedAt. ' Keys: '.$numberOfKeys);
try {
$dbForProject = $getProjectDB($project);
$projectDocuments = [];
$databaseCache = [];
$collectionSizeCache = [];
Console::log('['.DateTime::now().'] Id: '.$project->getId(). ' InternalId: '.$project->getInternalId(). ' Db: '.$project->getAttribute('database').' ReceivedAt: '.$receivedAt. ' Keys: '.$numberOfKeys . ' Started');
$start = \microtime(true);
foreach ($stats['keys'] ?? [] as $key => $value) {
if ($value == 0) {
continue;
}
if (str_contains($key, METRIC_DATABASES_STORAGE)) {
try {
$this->handleDatabaseStorage($key, $dbForProject);
} catch (\Exception $e) {
console::error('[' . DateTime::now() . '] failed to calculate database storage for key [' . $key . '] ' . $e->getMessage());
}
continue;
}
foreach ($this->periods as $period => $format) {
$time = 'inf' === $period ? null : \date($format, \time());
$time = 'inf' === $period ? null : date($format, time());
$id = \md5("{$time}_{$period}_{$key}");
if (\str_contains($key, METRIC_DATABASES_STORAGE)) {
$this->handleDatabaseStorage(
$id,
$key,
$time,
$period,
$dbForProject,
$projectDocuments,
$databaseCache,
$collectionSizeCache
);
continue;
try {
$dbForProject->createDocument('stats', new Document([
'$id' => $id,
'period' => $period,
'time' => $time,
'metric' => $key,
'value' => $value,
'region' => System::getEnv('_APP_REGION', 'default'),
]));
} catch (Duplicate $th) {
if ($value < 0) {
$dbForProject->decreaseDocumentAttribute(
'stats',
$id,
'value',
abs($value)
);
} else {
$dbForProject->increaseDocumentAttribute(
'stats',
$id,
'value',
$value
);
}
}
$projectDocuments[] = new Document([
'$id' => $id,
'period' => $period,
'time' => $time,
'metric' => $key,
'value' => $value,
'region' => System::getEnv('_APP_REGION', 'default'),
]);
}
}
$dbForProject->createOrUpdateDocumentsWithIncrease(
collection: 'stats',
attribute: 'value',
documents: $projectDocuments
);
$end = \microtime(true);
Console::log('['.DateTime::now().'] Id: '.$project->getId(). ' InternalId: '.$project->getInternalId(). ' Db: '.$project->getAttribute('database').' ReceivedAt: '.$receivedAt. ' Keys: '.$numberOfKeys. ' Time: '.($end - $start).'s');
} catch (\Exception $e) {
console::error('[' . DateTime::now() . '] project [' . $project->getInternalId() . '] database [' . $project['database'] . '] ' . ' ' . $e->getMessage());
}
} catch (\Exception $e) {
Console::error('[' . DateTime::now() . '] Error processing stats: ' . $e->getMessage());
}
}
private function handleDatabaseStorage(
string $id,
string $key,
?string $time,
string $period,
Database $dbForProject,
array &$projectDocuments,
array &$databaseCache,
array &$collectionSizeCache,
): void {
$data = \explode('.', $key);
$value = 0;
$previousValue = 0;
private function handleDatabaseStorage(string $key, Database $dbForProject): void
{
$data = explode('.', $key);
$start = microtime(true);
try {
$previousValue = $dbForProject
->getDocument('stats', $id)
->getAttribute('value', 0);
} catch (\Exception) {
// No previous value
}
$updateMetric = function (Database $dbForProject, int $value, string $key, string $period, string|null $time) {
$id = \md5("{$time}_{$period}_{$key}");
switch (\count($data)) {
case METRIC_COLLECTION_LEVEL_STORAGE:
$databaseInternalId = $data[0];
$collectionInternalId = $data[1];
$collectionId = "database_{$databaseInternalId}_collection_{$collectionInternalId}";
try {
$dbForProject->createDocument('stats', new Document([
'$id' => $id,
'period' => $period,
'time' => $time,
'metric' => $key,
'value' => $value,
'region' => System::getEnv('_APP_REGION', 'default'),
]));
} catch (Duplicate $th) {
if ($value < 0) {
$dbForProject->decreaseDocumentAttribute(
'stats',
$id,
'value',
abs($value)
);
} else {
$dbForProject->increaseDocumentAttribute(
'stats',
$id,
'value',
$value
);
}
}
};
foreach ($this->periods as $period => $format) {
$time = 'inf' === $period ? null : date($format, time());
$id = \md5("{$time}_{$period}_{$key}");
$value = 0;
$previousValue = 0;
try {
$previousValue = ($dbForProject->getDocument('stats', $id))->getAttribute('value', 0);
} catch (\Exception $e) {
// No previous value
}
switch (count($data)) {
// Collection Level
case METRIC_COLLECTION_LEVEL_STORAGE:
Console::log('[' . DateTime::now() . '] Collection Level Storage Calculation [' . $key . ']');
$databaseInternalId = $data[0];
$collectionInternalId = $data[1];
if (!isset($collectionSizeCache[$collectionId])) {
try {
$collectionSizeCache[$collectionId] = $dbForProject->getSizeOfCollection($collectionId);
$value = $dbForProject->getSizeOfCollection('database_' . $databaseInternalId . '_collection_' . $collectionInternalId);
} catch (\Exception $e) {
if (!$e instanceof NotFound) {
// Collection not found
if ($e->getMessage() !== 'Collection not found') {
throw $e;
}
$collectionSizeCache[$collectionId] = 0;
}
}
$value = $collectionSizeCache[$collectionId];
// Compare with previous value
$diff = $value - $previousValue;
$diff = $value - $previousValue;
if ($diff === 0) {
if ($diff === 0) {
break;
}
// Update Collection
$updateMetric($dbForProject, $diff, $key, $period, $time);
// Update Database
$databaseKey = str_replace(['{databaseInternalId}'], [$data[0]], METRIC_DATABASE_ID_STORAGE);
$updateMetric($dbForProject, $diff, $databaseKey, $period, $time);
// Update Project
$projectKey = METRIC_DATABASES_STORAGE;
$updateMetric($dbForProject, $diff, $projectKey, $period, $time);
break;
}
// Database Level
case METRIC_DATABASE_LEVEL_STORAGE:
Console::log('[' . DateTime::now() . '] Database Level Storage Calculation [' . $key . ']');
$databaseInternalId = $data[0];
$keys = [
$key,
\str_replace(['{databaseInternalId}'], [$data[0]], METRIC_DATABASE_ID_STORAGE),
METRIC_DATABASES_STORAGE
];
foreach ($keys as $metric) {
$projectDocuments[] = $this->createStatsDocument($id, $period, $time, $metric, $diff);
}
break;
case METRIC_DATABASE_LEVEL_STORAGE:
$databaseInternalId = $data[0];
$databaseId = "database_{$databaseInternalId}";
if (!isset($databaseCache[$databaseId])) {
$collections = [];
try {
$databaseCache[$databaseId] = $dbForProject->find($databaseId);
$collections = $dbForProject->find('database_' . $databaseInternalId);
} catch (\Exception $e) {
if (!$e instanceof NotFound) {
// Database not found
if ($e->getMessage() !== 'Collection not found') {
throw $e;
}
$databaseCache[$databaseId] = [];
}
}
foreach ($databaseCache[$databaseId] as $collection) {
$collectionId = "{$databaseId}_collection_{$collection->getInternalId()}";
if (!isset($collectionSizeCache[$collectionId])) {
foreach ($collections as $collection) {
try {
$collectionSizeCache[$collectionId] = $dbForProject->getSizeOfCollection($collectionId);
$value += $dbForProject->getSizeOfCollection('database_' . $databaseInternalId . '_collection_' . $collection->getInternalId());
} catch (\Exception $e) {
if (!$e instanceof NotFound) {
// Collection not found
if ($e->getMessage() !== 'Collection not found') {
throw $e;
}
$collectionSizeCache[$collectionId] = 0;
}
}
$value += $collectionSizeCache[$collectionId];
}
$diff = $value - $previousValue;
if ($diff === 0) {
$diff = $value - $previousValue;
if ($diff === 0) {
break;
}
// Update Database
$databaseKey = str_replace(['{databaseInternalId}'], [$data[0]], METRIC_DATABASE_ID_STORAGE);
$updateMetric($dbForProject, $diff, $databaseKey, $period, $time);
// Update Project
$projectKey = METRIC_DATABASES_STORAGE;
$updateMetric($dbForProject, $diff, $projectKey, $period, $time);
break;
}
// Project Level
case METRIC_PROJECT_LEVEL_STORAGE:
Console::log('[' . DateTime::now() . '] Project Level Storage Calculation [' . $key . ']');
// Get all project databases
$databases = $dbForProject->find('database');
$keys = [
\str_replace(['{databaseInternalId}'], [$data[0]], METRIC_DATABASE_ID_STORAGE),
METRIC_DATABASES_STORAGE
];
// Recalculate all databases
foreach ($databases as $database) {
$collections = $dbForProject->find('database_' . $database->getInternalId());
foreach ($keys as $metric) {
$projectDocuments[] = $this->createStatsDocument($id, $period, $time, $metric, $diff);
}
break;
case METRIC_PROJECT_LEVEL_STORAGE:
if (!isset($databaseCache['*'])) {
try {
$databaseCache['*'] = $dbForProject->find('databases');
} catch (\Exception $e) {
if (!$e instanceof NotFound) {
throw $e;
}
$databaseCache['*'] = [];
}
}
foreach ($databaseCache['*'] as $database) {
$databaseId = "database_{$database->getInternalId()}";
if (!isset($databaseCache[$databaseId])) {
try {
$databaseCache[$databaseId] = $dbForProject->find($databaseId);
} catch (\Exception $e) {
if (!$e instanceof NotFound) {
throw $e;
}
$databaseCache[$databaseId] = [];
}
}
foreach ($databaseCache[$databaseId] as $collection) {
$collectionId = "{$databaseId}_collection_{$collection->getInternalId()}";
if (!isset($collectionSizeCache[$collectionId])) {
foreach ($collections as $collection) {
try {
$collectionSizeCache[$collectionId] = $dbForProject->getSizeOfCollection($collectionId);
$value += $dbForProject->getSizeOfCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId());
} catch (\Exception $e) {
if (!$e instanceof NotFound) {
// Collection not found
if ($e->getMessage() !== 'Collection not found') {
throw $e;
}
$collectionSizeCache[$collectionId] = 0;
}
}
$value += $collectionSizeCache[$collectionId];
}
}
$diff = $value - $previousValue;
if ($diff === 0) {
$diff = $value - $previousValue;
// Update Project
$projectKey = METRIC_DATABASES_STORAGE;
$updateMetric($dbForProject, $diff, $projectKey, $period, $time);
break;
}
$keys = [
METRIC_DATABASES_STORAGE
];
foreach ($keys as $metric) {
$projectDocuments[] = $this->createStatsDocument($id, $period, $time, $metric, $diff);
}
break;
}
}
}
private function createStatsDocument(
string $id,
string $period,
?string $time,
string $key,
int $diff,
): Document {
return new Document([
'$id' => $id,
'period' => $period,
'time' => $time,
'metric' => $key,
'value' => $diff,
'region' => System::getEnv('_APP_REGION', 'default'),
]);
$end = microtime(true);
console::log('[' . DateTime::now() . '] DB Storage Calculation [' . $key . '] took ' . (($end - $start) * 1000) . ' milliseconds');
}
}

View file

@ -70,14 +70,16 @@ class UsageDatabase extends Model
->addRule('databaseReads', [
'type' => Response::MODEL_METRIC,
'description' => 'An array of aggregated number of database reads.',
'default' => 0,
'example' => 0,
'default' => [],
'example' => [],
'array' => true
])
->addRule('databaseWrites', [
'type' => Response::MODEL_METRIC,
'description' => 'An array of aggregated number of database writes.',
'default' => 0,
'example' => 0,
'default' => [],
'example' => [],
'array' => true
])
;
}

View file

@ -83,14 +83,16 @@ class UsageDatabases extends Model
->addRule('databasesReads', [
'type' => Response::MODEL_METRIC,
'description' => 'An array of aggregated number of database reads.',
'default' => 0,
'example' => 0,
'default' => [],
'example' => [],
'array' => true
])
->addRule('databasesWrites', [
'type' => Response::MODEL_METRIC,
'description' => 'An array of aggregated number of database writes.',
'default' => 0,
'example' => 0,
'default' => [],
'example' => [],
'array' => true
])
;
}

View file

@ -186,14 +186,16 @@ class UsageProject extends Model
->addRule('databasesReads', [
'type' => Response::MODEL_METRIC,
'description' => 'An array of aggregated number of database reads.',
'default' => 0,
'example' => 0,
'default' => [],
'example' => [],
'array' => true
])
->addRule('databasesWrites', [
'type' => Response::MODEL_METRIC,
'description' => 'An array of aggregated number of database writes.',
'default' => 0,
'example' => 0,
'default' => [],
'example' => [],
'array' => true
])
;
}

View file

@ -651,6 +651,200 @@ class UsageTest extends Scope
];
}
// /** @depends testDatabaseStoragePrepare */
// #[Retry(count: 1)]
// public function testDatabaseStorageStatsCreateDocument(array $data): array
// {
// $databaseId = $data['databaseId'];
// $collectionId = $data['collectionId'];
// $originalProjectMetrics = $this->client->call(
// Client::METHOD_GET,
// '/project/usage',
// $this->getConsoleHeaders(),
// [
// 'period' => '1d',
// 'startDate' => self::getToday(),
// 'endDate' => self::getTomorrow(),
// ]
// );
// $this->assertEquals(200, $originalProjectMetrics['headers']['status-code']);
// $this->assertArrayHasKey('databasesStorageTotal', $originalProjectMetrics['body']);
// $originalProjectMetrics = $originalProjectMetrics['body'];
// $originalDatabaseMetrics = $this->client->call(
// Client::METHOD_GET,
// '/databases/' . $databaseId . '/usage?range=30d',
// $this->getConsoleHeaders()
// );
// $this->assertEquals(200, $originalDatabaseMetrics['headers']['status-code']);
// $this->assertArrayHasKey('storageTotal', $originalDatabaseMetrics['body']);
// $originalDatabaseMetrics = $originalDatabaseMetrics['body'];
// // Create documents
// for ($i = 0; $i < 100; $i++) {
// $response = $this->client->call(
// Client::METHOD_POST,
// '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents',
// array_merge([
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $this->getProject()['$id']
// ], $this->getHeaders()),
// [
// 'documentId' => 'unique()',
// 'data' => ['data' => str_repeat('a', 10000)],
// ]
// );
// $this->assertEquals(201, $response['headers']['status-code']);
// }
// sleep(self::WAIT);
// for ($i = 0; $i < 3; $i++) {
// try {
// $newProjectMetrics = $this->client->call(
// Client::METHOD_GET,
// '/project/usage',
// $this->getConsoleHeaders(),
// [
// 'period' => '1d',
// 'startDate' => self::getToday(),
// 'endDate' => self::getTomorrow(),
// ]
// );
// $this->assertEquals(200, $newProjectMetrics['headers']['status-code']);
// $this->assertArrayHasKey('databasesStorageTotal', $newProjectMetrics['body']);
// $this->assertGreaterThan($originalProjectMetrics['databasesStorageTotal'], $newProjectMetrics['body']['databasesStorageTotal']);
// $newProjectMetrics = $newProjectMetrics['body'];
// $newDatabaseMetrics = $this->client->call(
// Client::METHOD_GET,
// '/databases/' . $databaseId . '/usage?range=30d',
// $this->getConsoleHeaders()
// );
// $this->assertEquals(200, $newDatabaseMetrics['headers']['status-code']);
// $this->assertArrayHasKey('storageTotal', $newDatabaseMetrics['body']);
// $this->assertGreaterThan($originalDatabaseMetrics['storageTotal'], $newDatabaseMetrics['body']['storageTotal']);
// $newDatabaseMetrics = $newDatabaseMetrics['body'];
// return [
// 'databaseId' => $databaseId,
// 'collectionId' => $collectionId,
// 'currentProjectMetrics' => $newProjectMetrics,
// 'currentDatabaseMetrics' => $newDatabaseMetrics,
// ];
// } catch (ExpectationFailedException $e) {
// if ($i === 2) {
// throw $e;
// }
// sleep(self::WAIT);
// continue;
// }
// }
// }
// /** @depends testDatabaseStorageStatsCreateDocument */
// #[Retry(count: 1)]
// public function testDatabaseStorageStatsDeleteDocument(array $data): array
// {
// $databaseId = $data['databaseId'];
// $collectionId = $data['collectionId'];
// $currentProjectMetrics = $data['currentProjectMetrics'];
// $currentDatabaseMetrics = $data['currentDatabaseMetrics'];
// $documents = $this->client->call(
// Client::METHOD_GET,
// '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents',
// array_merge([
// 'x-appwrite-project' => $this->getProject()['$id']
// ], $this->getHeaders()),
// [
// 'queries' => [
// Query::limit(50)->toString()
// ]
// ]
// );
// foreach ($documents['body']['documents'] as $document) {
// $response = $this->client->call(
// Client::METHOD_DELETE,
// '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $document['$id'],
// array_merge([
// 'x-appwrite-project' => $this->getProject()['$id']
// ], $this->getHeaders())
// );
// $this->assertEquals(204, $response['headers']['status-code']);
// }
// sleep(self::WAIT);
// for ($i = 0; $i < 3; $i++) {
// try {
// $newProjectMetrics = $this->client->call(
// Client::METHOD_GET,
// '/project/usage',
// $this->getConsoleHeaders(),
// [
// 'period' => '1d',
// 'startDate' => self::getToday(),
// 'endDate' => self::getTomorrow(),
// ]
// );
// $this->assertEquals(200, $newProjectMetrics['headers']['status-code']);
// $this->assertArrayHasKey('databasesStorageTotal', $newProjectMetrics['body']);
// $this->assertLessThan($currentProjectMetrics['databasesStorageTotal'], $newProjectMetrics['body']['databasesStorageTotal']);
// $newProjectMetrics = $newProjectMetrics['body'];
// $newDatabaseMetrics = $this->client->call(
// Client::METHOD_GET,
// '/databases/' . $databaseId . '/usage?range=30d',
// $this->getConsoleHeaders()
// );
// $this->assertEquals(200, $newDatabaseMetrics['headers']['status-code']);
// $this->assertArrayHasKey('storageTotal', $newDatabaseMetrics['body']);
// $this->assertLessThan($currentDatabaseMetrics['storageTotal'], $newDatabaseMetrics['body']['storageTotal']);
// $newDatabaseMetrics = $newDatabaseMetrics['body'];
// return [
// 'databaseId' => $databaseId,
// 'collectionId' => $collectionId,
// 'currentProjectMetrics' => $newProjectMetrics,
// 'currentDatabaseMetrics' => $newDatabaseMetrics,
// ];
// } catch (ExpectationFailedException $e) {
// if ($i === 2) {
// throw $e;
// }
// sleep(self::WAIT);
// continue;
// }
// }
// $newProjectMetrics = $this->client->call(
// Client::METHOD_GET,
// '/project/usage',
// $this->getConsoleHeaders(),
// [
// 'period' => '1d',
// 'startDate' => self::getToday(),
// 'endDate' => self::getTomorrow(),
// ]
// );
// }
/** @depends testDatabaseStats */
public function testPrepareFunctionsStats(array $data): array
{

View file

@ -4,6 +4,7 @@ namespace Tests\E2E\Services\Projects;
use Appwrite\Auth\Auth;
use Appwrite\Extend\Exception;
use Appwrite\Tests\Async;
use Tests\E2E\Client;
use Tests\E2E\General\UsageTest;
use Tests\E2E\Scopes\ProjectConsole;
@ -19,6 +20,7 @@ class ProjectsConsoleClientTest extends Scope
use ProjectsBase;
use ProjectConsole;
use SideClient;
use Async;
/**
* @group smtpAndTemplates
@ -1411,18 +1413,20 @@ class ProjectsConsoleClientTest extends Scope
/**
* List sessions
*/
$response = $this->client->call(Client::METHOD_GET, '/account/sessions', [
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $id,
'Cookie' => $sessionCookie,
]);
$this->assertEventually(function () use ($id, $sessionCookie, $sessionId2) {
$response = $this->client->call(Client::METHOD_GET, '/account/sessions', [
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $id,
'Cookie' => $sessionCookie,
]);
$this->assertEquals(200, $response['headers']['status-code']);
$sessions = $response['body']['sessions'];
$this->assertEquals(200, $response['headers']['status-code']);
$sessions = $response['body']['sessions'];
$this->assertEquals(1, count($sessions));
$this->assertEquals($sessionId2, $sessions[0]['$id']);
$this->assertEquals(1, count($sessions));
$this->assertEquals($sessionId2, $sessions[0]['$id']);
});
/**
* Reset Limit