diff --git a/app/config/errors.php b/app/config/errors.php
index b1e418e517..8420ddbb74 100644
--- a/app/config/errors.php
+++ b/app/config/errors.php
@@ -48,6 +48,11 @@ return [
'description' => 'SMTP is disabled on your Appwrite instance. You can learn more about setting up SMTP in our docs.',
'code' => 503,
],
+ Exception::GENERAL_PHONE_DISABLED => [
+ 'name' => Exception::GENERAL_PHONE_DISABLED,
+ 'description' => 'Phone provider is not configured. Please check the _APP_PHONE_PROVIDER environment variable of your Appwrite server.',
+ 'code' => 503,
+ ],
Exception::GENERAL_ARGUMENT_INVALID => [
'name' => Exception::GENERAL_ARGUMENT_INVALID,
'description' => 'The request contains one or more invalid arguments. Please refer to the endpoint documentation.',
@@ -170,6 +175,16 @@ return [
'description' => 'The requested authentication method is either disabled or unsupported. Please check the supported authentication methods in the Appwrite console.',
'code' => 501,
],
+ Exception::USER_PHONE_ALREADY_EXISTS => [
+ 'name' => Exception::USER_PHONE_ALREADY_EXISTS,
+ 'description' => 'A user with the same phone number already exists in the current project.',
+ 'code' => 409,
+ ],
+ Exception::USER_PHONE_NOT_FOUND => [
+ 'name' => Exception::USER_PHONE_NOT_FOUND,
+ 'description' => 'The current user does not have a phone number associated with their account.',
+ 'code' => 400,
+ ],
/** Teams */
Exception::TEAM_NOT_FOUND => [
diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php
index 0d5613beac..f61490b116 100644
--- a/app/controllers/api/account.php
+++ b/app/controllers/api/account.php
@@ -859,7 +859,7 @@ App::post('/v1/account/sessions/phone')
->inject('phone')
->action(function (string $userId, string $number, Request $request, Response $response, Document $project, Database $dbForProject, Audit $audits, Event $events, EventPhone $messaging, Phone $phone) {
if (empty(App::getEnv('_APP_PHONE_PROVIDER'))) {
- throw new Exception('Phone Disabled', 503, Exception::GENERAL_SMTP_DISABLED);
+ throw new Exception('Phone provider not configured', 503, Exception::GENERAL_PHONE_DISABLED);
}
$roles = Authorization::getRoles();
@@ -1596,7 +1596,7 @@ App::patch('/v1/account/phone')
try {
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
} catch (Duplicate $th) {
- throw new Exception('Phone number already exists', 409, Exception::USER_EMAIL_ALREADY_EXISTS);
+ throw new Exception('Phone number already exists', 409, Exception::USER_PHONE_ALREADY_EXISTS);
}
$audits
@@ -2263,12 +2263,12 @@ App::post('/v1/account/verification/phone')
->inject('messaging')
->action(function (Request $request, Response $response, Phone $phone, Document $user, Database $dbForProject, Audit $audits, Event $events, Stats $usage, EventPhone $messaging) {
- if (empty(App::getEnv('_APP_SMTP_HOST'))) {
- throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED);
+ if (empty(App::getEnv('_APP_PHONE_PROVIDER'))) {
+ throw new Exception('Phone provider not configured', 503, Exception::GENERAL_PHONE_DISABLED);
}
if (empty($user->getAttribute('phone'))) {
- throw new Exception('User has no phone number.', 400);
+ throw new Exception('User has no phone number.', 400, Exception::USER_PHONE_NOT_FOUND);
}
$roles = Authorization::getRoles();
diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php
index f288ac5391..1f98cbfc29 100644
--- a/app/controllers/api/databases.php
+++ b/app/controllers/api/databases.php
@@ -240,7 +240,7 @@ App::get('/v1/databases')
->label('sdk.description', '/docs/references/databases/list.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
- ->label('sdk.response.model', Response::MODEL_COLLECTION_LIST)
+ ->label('sdk.response.model', Response::MODEL_DATABASE_LIST)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->param('limit', 25, new Range(0, 100), 'Maximum number of collection to return in response. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, new Range(0, APP_LIMIT_COUNT), 'Offset value. The default value is 0. Use this param to manage pagination. [learn more about pagination](https://appwrite.io/docs/pagination)', true)
@@ -482,6 +482,7 @@ App::delete('/v1/databases/:databaseId')
});
App::post('/v1/databases/:databaseId/collections')
+ ->alias('/v1/database/collections', ['databaseId' => 'default'])
->desc('Create Collection')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].create')
@@ -554,6 +555,7 @@ App::post('/v1/databases/:databaseId/collections')
});
App::get('/v1/databases/:databaseId/collections')
+ ->alias('/v1/database/collections', ['databaseId' => 'default'])
->desc('List Collections')
->groups(['api', 'database'])
->label('scope', 'collections.read')
@@ -607,6 +609,7 @@ App::get('/v1/databases/:databaseId/collections')
});
App::get('/v1/databases/:databaseId/collections/:collectionId')
+ ->alias('/v1/database/collections/:collectionId', ['databaseId' => 'default'])
->desc('Get Collection')
->groups(['api', 'database'])
->label('scope', 'collections.read')
@@ -643,6 +646,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId')
});
App::get('/v1/databases/:databaseId/collections/:collectionId/logs')
+ ->alias('/v1/database/collections/:collectionId/logs', ['databaseId' => 'default'])
->desc('List Collection Logs')
->groups(['api', 'database'])
->label('scope', 'collections.read')
@@ -732,6 +736,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs')
App::put('/v1/databases/:databaseId/collections/:collectionId')
+ ->alias('/v1/database/collections/:collectionId', ['databaseId' => 'default'])
->desc('Update Collection')
->groups(['api', 'database'])
->label('scope', 'collections.write')
@@ -804,6 +809,7 @@ App::put('/v1/databases/:databaseId/collections/:collectionId')
});
App::delete('/v1/databases/:databaseId/collections/:collectionId')
+ ->alias('/v1/database/collections/:collectionId', ['databaseId' => 'default'])
->desc('Delete Collection')
->groups(['api', 'database'])
->label('scope', 'collections.write')
@@ -867,6 +873,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId')
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string')
+ ->alias('/v1/database/collections/:collectionId/attributes/string', ['databaseId' => 'default'])
->desc('Create String Attribute')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
@@ -912,6 +919,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email')
+ ->alias('/v1/database/collections/:collectionId/attributes/email', ['databaseId' => 'default'])
->desc('Create Email Attribute')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
@@ -951,6 +959,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email'
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum')
+ ->alias('/v1/database/collections/:collectionId/attributes/enum', ['databaseId' => 'default'])
->desc('Create Enum Attribute')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
@@ -1006,6 +1015,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum')
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip')
+ ->alias('/v1/database/collections/:collectionId/attributes/ip', ['databaseId' => 'default'])
->desc('Create IP Address Attribute')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
@@ -1045,6 +1055,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip')
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url')
+ ->alias('/v1/database/collections/:collectionId/attributes/url', ['databaseId' => 'default'])
->desc('Create URL Attribute')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
@@ -1084,6 +1095,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url')
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/integer')
+ ->alias('/v1/database/collections/:collectionId/attributes/integer', ['databaseId' => 'default'])
->desc('Create Integer Attribute')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
@@ -1152,6 +1164,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float')
+ ->alias('/v1/database/collections/:collectionId/attributes/float', ['databaseId' => 'default'])
->desc('Create Float Attribute')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
@@ -1223,6 +1236,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float'
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolean')
+ ->alias('/v1/database/collections/:collectionId/attributes/boolean', ['databaseId' => 'default'])
->desc('Create Boolean Attribute')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create')
@@ -1261,6 +1275,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea
});
App::get('/v1/databases/:databaseId/collections/:collectionId/attributes')
+ ->alias('/v1/database/collections/:collectionId/attributes', ['databaseId' => 'default'])
->desc('List Attributes')
->groups(['api', 'database'])
->label('scope', 'collections.read')
@@ -1302,6 +1317,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes')
});
App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key')
+ ->alias('/v1/database/collections/:collectionId/attributes/:key', ['databaseId' => 'default'])
->desc('Get Attribute')
->groups(['api', 'database'])
->label('scope', 'collections.read')
@@ -1372,6 +1388,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key')
});
App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key')
+ ->alias('/v1/database/collections/:collectionId/attributes/:key', ['databaseId' => 'default'])
->desc('Delete Attribute')
->groups(['api', 'database'])
->label('scope', 'collections.write')
@@ -1465,6 +1482,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
});
App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
+ ->alias('/v1/database/collections/:collectionId/indexes', ['databaseId' => 'default'])
->desc('Create Index')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].create')
@@ -1588,6 +1606,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
});
App::get('/v1/databases/:databaseId/collections/:collectionId/indexes')
+ ->alias('/v1/database/collections/:collectionId/indexes', ['databaseId' => 'default'])
->desc('List Indexes')
->groups(['api', 'database'])
->label('scope', 'collections.read')
@@ -1629,6 +1648,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes')
});
App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
+ ->alias('/v1/database/collections/:collectionId/indexes/:key', ['databaseId' => 'default'])
->desc('Get Index')
->groups(['api', 'database'])
->label('scope', 'collections.read')
@@ -1679,6 +1699,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
});
App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
+ ->alias('/v1/database/collections/:collectionId/indexes/:key', ['databaseId' => 'default'])
->desc('Delete Index')
->groups(['api', 'database'])
->label('scope', 'collections.write')
@@ -1753,6 +1774,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
});
App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
+ ->alias('/v1/database/collections/:collectionId/documents', ['databaseId' => 'default'])
->desc('Create Document')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].create')
@@ -1875,6 +1897,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
});
App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
+ ->alias('/v1/database/collections/:collectionId/documents', ['databaseId' => 'default'])
->desc('List Documents')
->groups(['api', 'database'])
->label('scope', 'documents.read')
@@ -1988,6 +2011,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
});
App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documentId')
+ ->alias('/v1/database/collections/:collectionId/documents/:documentId', ['databaseId' => 'default'])
->desc('Get Document')
->groups(['api', 'database'])
->label('scope', 'documents.read')
@@ -2057,6 +2081,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
});
App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documentId/logs')
+ ->alias('/v1/database/collections/:collectionId/documents/:documentId/logs', ['databaseId' => 'default'])
->desc('List Document Logs')
->groups(['api', 'database'])
->label('scope', 'documents.read')
@@ -2150,6 +2175,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
});
App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:documentId')
+ ->alias('/v1/database/collections/:collectionId/documents/:documentId', ['databaseId' => 'default'])
->desc('Update Document')
->groups(['api', 'database'])
->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].update')
@@ -2164,7 +2190,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
->param('databaseId', '', new UID(), 'Database ID.')
->param('collectionId', null, new UID(), 'Collection ID.')
->param('documentId', null, new UID(), 'Document ID.')
- ->param('data', [], new JSON(), 'Document data as JSON object. Include only attribute and value pairs to be updated.')
+ ->param('data', [], new JSON(), 'Document data as JSON object. Include only attribute and value pairs to be updated.', true)
->param('read', null, new Permissions(), 'An array of strings with read permissions. By default inherits the existing read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
->param('write', null, new Permissions(), 'An array of strings with write permissions. By default inherits the existing write permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
->inject('response')
@@ -2210,8 +2236,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
- if (empty($data)) {
- throw new Exception('Missing payload', 400, Exception::DOCUMENT_MISSING_PAYLOAD);
+ if (empty($data) && empty($read) && empty($write)) {
+ throw new Exception('Missing payload or read/write permissions', 400, Exception::DOCUMENT_MISSING_PAYLOAD);
}
if (!\is_array($data)) {
@@ -2221,6 +2247,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$data = \array_merge($document->getArrayCopy(), $data);
$data['$collection'] = $collection->getId(); // Make sure user don't switch collectionID
+ $data['$createdAt'] = $collection->getCreatedAt(); // Make sure user don't switch createdAt
$data['$id'] = $document->getId(); // Make sure user don't switch document unique ID
$data['$read'] = (is_null($read)) ? ($document->getRead() ?? []) : $read; // By default inherit read permissions
$data['$write'] = (is_null($write)) ? ($document->getWrite() ?? []) : $write; // By default inherit write permissions
@@ -2287,6 +2314,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
});
App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:documentId')
+ ->alias('/v1/database/collections/:collectionId/documents/:documentId', ['databaseId' => 'default'])
->desc('Delete Document')
->groups(['api', 'database'])
->label('scope', 'documents.write')
@@ -2386,330 +2414,331 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
});
App::get('/v1/databases/usage')
-->desc('Get usage stats for the database')
-->groups(['api', 'database'])
-->label('scope', 'collections.read')
-->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
-->label('sdk.namespace', 'databases')
-->label('sdk.method', 'getUsage')
-->label('sdk.response.code', Response::STATUS_CODE_OK)
-->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
-->label('sdk.response.model', Response::MODEL_USAGE_DATABASES)
-->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), '`Date range.', true)
-->inject('response')
-->inject('dbForProject')
-->action(function (string $range, Response $response, Database $dbForProject) {
+ ->desc('Get usage stats for the database')
+ ->groups(['api', 'database'])
+ ->label('scope', 'collections.read')
+ ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
+ ->label('sdk.namespace', 'databases')
+ ->label('sdk.method', 'getUsage')
+ ->label('sdk.response.code', Response::STATUS_CODE_OK)
+ ->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
+ ->label('sdk.response.model', Response::MODEL_USAGE_DATABASES)
+ ->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), '`Date range.', true)
+ ->inject('response')
+ ->inject('dbForProject')
+ ->action(function (string $range, Response $response, Database $dbForProject) {
- $usage = [];
- if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
- $periods = [
- '24h' => [
- 'period' => '30m',
- 'limit' => 48,
- ],
- '7d' => [
- 'period' => '1d',
- 'limit' => 7,
- ],
- '30d' => [
- 'period' => '1d',
- 'limit' => 30,
- ],
- '90d' => [
- 'period' => '1d',
- 'limit' => 90,
- ],
- ];
+ $usage = [];
+ if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
+ $periods = [
+ '24h' => [
+ 'period' => '30m',
+ 'limit' => 48,
+ ],
+ '7d' => [
+ 'period' => '1d',
+ 'limit' => 7,
+ ],
+ '30d' => [
+ 'period' => '1d',
+ 'limit' => 30,
+ ],
+ '90d' => [
+ 'period' => '1d',
+ 'limit' => 90,
+ ],
+ ];
- $metrics = [
- 'databases.count',
- 'databases.documents.count',
- 'databases.collections.count',
- 'databases.create',
- 'databases.read',
- 'databases.update',
- 'databases.delete',
- 'databases.collections.create',
- 'databases.collections.read',
- 'databases.collections.update',
- 'databases.collections.delete',
- 'databases.documents.create',
- 'databases.documents.read',
- 'databases.documents.update',
- 'databases.documents.delete'
- ];
+ $metrics = [
+ 'databases.count',
+ 'databases.documents.count',
+ 'databases.collections.count',
+ 'databases.create',
+ 'databases.read',
+ 'databases.update',
+ 'databases.delete',
+ 'databases.collections.create',
+ 'databases.collections.read',
+ 'databases.collections.update',
+ 'databases.collections.delete',
+ 'databases.documents.create',
+ 'databases.documents.read',
+ 'databases.documents.update',
+ 'databases.documents.delete'
+ ];
- $stats = [];
+ $stats = [];
- Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) {
- foreach ($metrics as $metric) {
- $limit = $periods[$range]['limit'];
- $period = $periods[$range]['period'];
+ Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) {
+ foreach ($metrics as $metric) {
+ $limit = $periods[$range]['limit'];
+ $period = $periods[$range]['period'];
- $requestDocs = $dbForProject->find('stats', [
- new Query('period', Query::TYPE_EQUAL, [$period]),
- new Query('metric', Query::TYPE_EQUAL, [$metric]),
- ], $limit, 0, ['time'], [Database::ORDER_DESC]);
+ $requestDocs = $dbForProject->find('stats', [
+ new Query('period', Query::TYPE_EQUAL, [$period]),
+ new Query('metric', Query::TYPE_EQUAL, [$metric]),
+ ], $limit, 0, ['time'], [Database::ORDER_DESC]);
- $stats[$metric] = [];
- foreach ($requestDocs as $requestDoc) {
- $stats[$metric][] = [
- 'value' => $requestDoc->getAttribute('value'),
- 'date' => $requestDoc->getAttribute('time'),
- ];
+ $stats[$metric] = [];
+ foreach ($requestDocs as $requestDoc) {
+ $stats[$metric][] = [
+ 'value' => $requestDoc->getAttribute('value'),
+ 'date' => $requestDoc->getAttribute('time'),
+ ];
+ }
+
+ // backfill metrics with empty values for graphs
+ $backfill = $limit - \count($requestDocs);
+ while ($backfill > 0) {
+ $last = $limit - $backfill - 1; // array index of last added metric
+ $diff = match ($period) { // convert period to seconds for unix timestamp math
+ '30m' => 1800,
+ '1d' => 86400,
+ };
+ $stats[$metric][] = [
+ 'value' => 0,
+ 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period
+ ];
+ $backfill--;
+ }
+ // TODO@kodumbeats explore performance if query is ordered by time ASC
+ $stats[$metric] = array_reverse($stats[$metric]);
}
+ });
- // backfill metrics with empty values for graphs
- $backfill = $limit - \count($requestDocs);
- while ($backfill > 0) {
- $last = $limit - $backfill - 1; // array index of last added metric
- $diff = match ($period) { // convert period to seconds for unix timestamp math
- '30m' => 1800,
- '1d' => 86400,
- };
- $stats[$metric][] = [
- 'value' => 0,
- 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period
- ];
- $backfill--;
- }
- // TODO@kodumbeats explore performance if query is ordered by time ASC
- $stats[$metric] = array_reverse($stats[$metric]);
- }
- });
+ $usage = new Document([
+ 'range' => $range,
+ 'databasesCount' => $stats["databases.count"],
+ 'documentsCount' => $stats["databases.documents.count"],
+ 'collectionsCount' => $stats["databases.collections.count"],
+ 'documentsCreate' => $stats["databases.documents.create"],
+ 'documentsRead' => $stats["databases.documents.read"],
+ 'documentsUpdate' => $stats["databases.documents.update"],
+ 'documentsDelete' => $stats["databases.documents.delete"],
+ 'collectionsCreate' => $stats["databases.collections.create"],
+ 'collectionsRead' => $stats["databases.collections.read"],
+ 'collectionsUpdate' => $stats["databases.collections.update"],
+ 'collectionsDelete' => $stats["databases.collections.delete"],
+ 'databasesCreate' => $stats["databases.create"],
+ 'databasesRead' => $stats["databases.read"],
+ 'databasesUpdate' => $stats["databases.update"],
+ 'databasesDelete' => $stats["databases.delete"],
+ ]);
+ }
- $usage = new Document([
- 'range' => $range,
- 'databasesCount' => $stats["databases.count"],
- 'documentsCount' => $stats["databases.documents.count"],
- 'collectionsCount' => $stats["databases.collections.count"],
- 'documentsCreate' => $stats["databases.documents.create"],
- 'documentsRead' => $stats["databases.documents.read"],
- 'documentsUpdate' => $stats["databases.documents.update"],
- 'documentsDelete' => $stats["databases.documents.delete"],
- 'collectionsCreate' => $stats["databases.collections.create"],
- 'collectionsRead' => $stats["databases.collections.read"],
- 'collectionsUpdate' => $stats["databases.collections.update"],
- 'collectionsDelete' => $stats["databases.collections.delete"],
- 'databasesCreate' => $stats["databases.create"],
- 'databasesRead' => $stats["databases.read"],
- 'databasesUpdate' => $stats["databases.update"],
- 'databasesDelete' => $stats["databases.delete"],
- ]);
- }
-
- $response->dynamic($usage, Response::MODEL_USAGE_DATABASES);
-});
+ $response->dynamic($usage, Response::MODEL_USAGE_DATABASES);
+ });
App::get('/v1/databases/:databaseId/usage')
-->desc('Get usage stats for the database')
-->groups(['api', 'database'])
-->label('scope', 'collections.read')
-->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
-->label('sdk.namespace', 'databases')
-->label('sdk.method', 'getDatabaseUsage')
-->label('sdk.response.code', Response::STATUS_CODE_OK)
-->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
-->label('sdk.response.model', Response::MODEL_USAGE_DATABASE)
-->param('databaseId', '', new UID(), 'Database ID.')
-->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), '`Date range.', true)
-->inject('response')
-->inject('dbForProject')
-->action(function (string $databaseId, string $range, Response $response, Database $dbForProject) {
+ ->desc('Get usage stats for the database')
+ ->groups(['api', 'database'])
+ ->label('scope', 'collections.read')
+ ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
+ ->label('sdk.namespace', 'databases')
+ ->label('sdk.method', 'getDatabaseUsage')
+ ->label('sdk.response.code', Response::STATUS_CODE_OK)
+ ->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
+ ->label('sdk.response.model', Response::MODEL_USAGE_DATABASE)
+ ->param('databaseId', '', new UID(), 'Database ID.')
+ ->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), '`Date range.', true)
+ ->inject('response')
+ ->inject('dbForProject')
+ ->action(function (string $databaseId, string $range, Response $response, Database $dbForProject) {
- $usage = [];
- if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
- $periods = [
- '24h' => [
- 'period' => '30m',
- 'limit' => 48,
- ],
- '7d' => [
- 'period' => '1d',
- 'limit' => 7,
- ],
- '30d' => [
- 'period' => '1d',
- 'limit' => 30,
- ],
- '90d' => [
- 'period' => '1d',
- 'limit' => 90,
- ],
- ];
+ $usage = [];
+ if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
+ $periods = [
+ '24h' => [
+ 'period' => '30m',
+ 'limit' => 48,
+ ],
+ '7d' => [
+ 'period' => '1d',
+ 'limit' => 7,
+ ],
+ '30d' => [
+ 'period' => '1d',
+ 'limit' => 30,
+ ],
+ '90d' => [
+ 'period' => '1d',
+ 'limit' => 90,
+ ],
+ ];
- $metrics = [
- 'databases.' . $databaseId . '.documents.count',
- 'databases.' . $databaseId . '.collections.count',
- 'databases.' . $databaseId . '.collections.create',
- 'databases.' . $databaseId . '.collections.read',
- 'databases.' . $databaseId . '.collections.update',
- 'databases.' . $databaseId . '.collections.delete',
- 'databases.' . $databaseId . '.documents.create',
- 'databases.' . $databaseId . '.documents.read',
- 'databases.' . $databaseId . '.documents.update',
- 'databases.' . $databaseId . '.documents.delete'
- ];
+ $metrics = [
+ 'databases.' . $databaseId . '.documents.count',
+ 'databases.' . $databaseId . '.collections.count',
+ 'databases.' . $databaseId . '.collections.create',
+ 'databases.' . $databaseId . '.collections.read',
+ 'databases.' . $databaseId . '.collections.update',
+ 'databases.' . $databaseId . '.collections.delete',
+ 'databases.' . $databaseId . '.documents.create',
+ 'databases.' . $databaseId . '.documents.read',
+ 'databases.' . $databaseId . '.documents.update',
+ 'databases.' . $databaseId . '.documents.delete'
+ ];
- $stats = [];
+ $stats = [];
- Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) {
- foreach ($metrics as $metric) {
- $limit = $periods[$range]['limit'];
- $period = $periods[$range]['period'];
+ Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) {
+ foreach ($metrics as $metric) {
+ $limit = $periods[$range]['limit'];
+ $period = $periods[$range]['period'];
- $requestDocs = $dbForProject->find('stats', [
- new Query('period', Query::TYPE_EQUAL, [$period]),
- new Query('metric', Query::TYPE_EQUAL, [$metric]),
- ], $limit, 0, ['time'], [Database::ORDER_DESC]);
+ $requestDocs = $dbForProject->find('stats', [
+ new Query('period', Query::TYPE_EQUAL, [$period]),
+ new Query('metric', Query::TYPE_EQUAL, [$metric]),
+ ], $limit, 0, ['time'], [Database::ORDER_DESC]);
- $stats[$metric] = [];
- foreach ($requestDocs as $requestDoc) {
- $stats[$metric][] = [
- 'value' => $requestDoc->getAttribute('value'),
- 'date' => $requestDoc->getAttribute('time'),
- ];
+ $stats[$metric] = [];
+ foreach ($requestDocs as $requestDoc) {
+ $stats[$metric][] = [
+ 'value' => $requestDoc->getAttribute('value'),
+ 'date' => $requestDoc->getAttribute('time'),
+ ];
+ }
+
+ // backfill metrics with empty values for graphs
+ $backfill = $limit - \count($requestDocs);
+ while ($backfill > 0) {
+ $last = $limit - $backfill - 1; // array index of last added metric
+ $diff = match ($period) { // convert period to seconds for unix timestamp math
+ '30m' => 1800,
+ '1d' => 86400,
+ };
+ $stats[$metric][] = [
+ 'value' => 0,
+ 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period
+ ];
+ $backfill--;
+ }
+ // TODO@kodumbeats explore performance if query is ordered by time ASC
+ $stats[$metric] = array_reverse($stats[$metric]);
}
+ });
- // backfill metrics with empty values for graphs
- $backfill = $limit - \count($requestDocs);
- while ($backfill > 0) {
- $last = $limit - $backfill - 1; // array index of last added metric
- $diff = match ($period) { // convert period to seconds for unix timestamp math
- '30m' => 1800,
- '1d' => 86400,
- };
- $stats[$metric][] = [
- 'value' => 0,
- 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period
- ];
- $backfill--;
- }
- // TODO@kodumbeats explore performance if query is ordered by time ASC
- $stats[$metric] = array_reverse($stats[$metric]);
- }
- });
+ $usage = new Document([
+ 'range' => $range,
+ 'documentsCount' => $stats["databases.{$databaseId}.documents.count"],
+ 'collectionsCount' => $stats["databases.{$databaseId}.collections.count"],
+ 'documentsCreate' => $stats["databases.{$databaseId}.documents.create"],
+ 'documentsRead' => $stats["databases.{$databaseId}.documents.read"],
+ 'documentsUpdate' => $stats["databases.{$databaseId}.documents.update"],
+ 'documentsDelete' => $stats["databases.{$databaseId}.documents.delete"],
+ 'collectionsCreate' => $stats["databases.{$databaseId}.collections.create"],
+ 'collectionsRead' => $stats["databases.{$databaseId}.collections.read"],
+ 'collectionsUpdate' => $stats["databases.{$databaseId}.collections.update"],
+ 'collectionsDelete' => $stats["databases.{$databaseId}.collections.delete"],
+ ]);
+ }
- $usage = new Document([
- 'range' => $range,
- 'documentsCount' => $stats["databases.{$databaseId}.documents.count"],
- 'collectionsCount' => $stats["databases.{$databaseId}.collections.count"],
- 'documentsCreate' => $stats["databases.{$databaseId}.documents.create"],
- 'documentsRead' => $stats["databases.{$databaseId}.documents.read"],
- 'documentsUpdate' => $stats["databases.{$databaseId}.documents.update"],
- 'documentsDelete' => $stats["databases.{$databaseId}.documents.delete"],
- 'collectionsCreate' => $stats["databases.{$databaseId}.collections.create"],
- 'collectionsRead' => $stats["databases.{$databaseId}.collections.read"],
- 'collectionsUpdate' => $stats["databases.{$databaseId}.collections.update"],
- 'collectionsDelete' => $stats["databases.{$databaseId}.collections.delete"],
- ]);
- }
-
- $response->dynamic($usage, Response::MODEL_USAGE_DATABASE);
-});
+ $response->dynamic($usage, Response::MODEL_USAGE_DATABASE);
+ });
App::get('/v1/databases/:databaseId/collections/:collectionId/usage')
-->desc('Get usage stats for a collection')
-->groups(['api', 'database'])
-->label('scope', 'collections.read')
-->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
-->label('sdk.namespace', 'databases')
-->label('sdk.method', 'getCollectionUsage')
-->label('sdk.response.code', Response::STATUS_CODE_OK)
-->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
-->label('sdk.response.model', Response::MODEL_USAGE_COLLECTION)
-->param('databaseId', '', new UID(), 'Database ID.')
-->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true)
-->param('collectionId', '', new UID(), 'Collection ID.')
-->inject('response')
-->inject('dbForProject')
-->action(function (string $databaseId, string $range, string $collectionId, Response $response, Database $dbForProject) {
+ ->alias('/v1/database/collections/:collectionId/documents', ['databaseId' => 'default'])
+ ->desc('Get usage stats for a collection')
+ ->groups(['api', 'database'])
+ ->label('scope', 'collections.read')
+ ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
+ ->label('sdk.namespace', 'databases')
+ ->label('sdk.method', 'getCollectionUsage')
+ ->label('sdk.response.code', Response::STATUS_CODE_OK)
+ ->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
+ ->label('sdk.response.model', Response::MODEL_USAGE_COLLECTION)
+ ->param('databaseId', '', new UID(), 'Database ID.')
+ ->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true)
+ ->param('collectionId', '', new UID(), 'Collection ID.')
+ ->inject('response')
+ ->inject('dbForProject')
+ ->action(function (string $databaseId, string $range, string $collectionId, Response $response, Database $dbForProject) {
- $database = $dbForProject->getDocument('databases', $databaseId);
+ $database = $dbForProject->getDocument('databases', $databaseId);
- $collectionDocument = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId);
- $collection = $dbForProject->getCollection('database_' . $database->getInternalId() . '_collection_' . $collectionDocument->getInternalId());
+ $collectionDocument = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId);
+ $collection = $dbForProject->getCollection('database_' . $database->getInternalId() . '_collection_' . $collectionDocument->getInternalId());
- if ($collection->isEmpty()) {
- throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND);
- }
+ if ($collection->isEmpty()) {
+ throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND);
+ }
- $usage = [];
- if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
- $periods = [
- '24h' => [
- 'period' => '30m',
- 'limit' => 48,
- ],
- '7d' => [
- 'period' => '1d',
- 'limit' => 7,
- ],
- '30d' => [
- 'period' => '1d',
- 'limit' => 30,
- ],
- '90d' => [
- 'period' => '1d',
- 'limit' => 90,
- ],
- ];
+ $usage = [];
+ if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
+ $periods = [
+ '24h' => [
+ 'period' => '30m',
+ 'limit' => 48,
+ ],
+ '7d' => [
+ 'period' => '1d',
+ 'limit' => 7,
+ ],
+ '30d' => [
+ 'period' => '1d',
+ 'limit' => 30,
+ ],
+ '90d' => [
+ 'period' => '1d',
+ 'limit' => 90,
+ ],
+ ];
- $metrics = [
- "databases.{$databaseId}.collections.{$collectionId}.documents.count",
- "databases.{$databaseId}.collections.{$collectionId}.documents.create",
- "databases.{$databaseId}.collections.{$collectionId}.documents.read",
- "databases.{$databaseId}.collections.{$collectionId}.documents.update",
- "databases.{$databaseId}.collections.{$collectionId}.documents.delete",
- ];
+ $metrics = [
+ "databases.{$databaseId}.collections.{$collectionId}.documents.count",
+ "databases.{$databaseId}.collections.{$collectionId}.documents.create",
+ "databases.{$databaseId}.collections.{$collectionId}.documents.read",
+ "databases.{$databaseId}.collections.{$collectionId}.documents.update",
+ "databases.{$databaseId}.collections.{$collectionId}.documents.delete",
+ ];
- $stats = [];
+ $stats = [];
- Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) {
- foreach ($metrics as $metric) {
- $limit = $periods[$range]['limit'];
- $period = $periods[$range]['period'];
+ Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) {
+ foreach ($metrics as $metric) {
+ $limit = $periods[$range]['limit'];
+ $period = $periods[$range]['period'];
- $requestDocs = $dbForProject->find('stats', [
- new Query('period', Query::TYPE_EQUAL, [$period]),
- new Query('metric', Query::TYPE_EQUAL, [$metric]),
- ], $limit, 0, ['time'], [Database::ORDER_DESC]);
+ $requestDocs = $dbForProject->find('stats', [
+ new Query('period', Query::TYPE_EQUAL, [$period]),
+ new Query('metric', Query::TYPE_EQUAL, [$metric]),
+ ], $limit, 0, ['time'], [Database::ORDER_DESC]);
- $stats[$metric] = [];
- foreach ($requestDocs as $requestDoc) {
- $stats[$metric][] = [
- 'value' => $requestDoc->getAttribute('value'),
- 'date' => $requestDoc->getAttribute('time'),
- ];
+ $stats[$metric] = [];
+ foreach ($requestDocs as $requestDoc) {
+ $stats[$metric][] = [
+ 'value' => $requestDoc->getAttribute('value'),
+ 'date' => $requestDoc->getAttribute('time'),
+ ];
+ }
+
+ // backfill metrics with empty values for graphs
+ $backfill = $limit - \count($requestDocs);
+ while ($backfill > 0) {
+ $last = $limit - $backfill - 1; // array index of last added metric
+ $diff = match ($period) { // convert period to seconds for unix timestamp math
+ '30m' => 1800,
+ '1d' => 86400,
+ };
+ $stats[$metric][] = [
+ 'value' => 0,
+ 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period
+ ];
+ $backfill--;
+ }
+ $stats[$metric] = array_reverse($stats[$metric]);
}
+ });
- // backfill metrics with empty values for graphs
- $backfill = $limit - \count($requestDocs);
- while ($backfill > 0) {
- $last = $limit - $backfill - 1; // array index of last added metric
- $diff = match ($period) { // convert period to seconds for unix timestamp math
- '30m' => 1800,
- '1d' => 86400,
- };
- $stats[$metric][] = [
- 'value' => 0,
- 'date' => ($stats[$metric][$last]['date'] ?? \time()) - $diff, // time of last metric minus period
- ];
- $backfill--;
- }
- $stats[$metric] = array_reverse($stats[$metric]);
- }
- });
+ $usage = new Document([
+ 'range' => $range,
+ 'documentsCount' => $stats["databases.{$databaseId}.collections.{$collectionId}.documents.count"],
+ 'documentsCreate' => $stats["databases.{$databaseId}.collections.{$collectionId}.documents.create"],
+ 'documentsRead' => $stats["databases.{$databaseId}.collections.{$collectionId}.documents.read"],
+ 'documentsUpdate' => $stats["databases.{$databaseId}.collections.{$collectionId}.documents.update"],
+ 'documentsDelete' => $stats["databases.{$databaseId}.collections.{$collectionId}.documents.delete"]
+ ]);
+ }
- $usage = new Document([
- 'range' => $range,
- 'documentsCount' => $stats["databases.{$databaseId}.collections.{$collectionId}.documents.count"],
- 'documentsCreate' => $stats["databases.{$databaseId}.collections.{$collectionId}.documents.create"],
- 'documentsRead' => $stats["databases.{$databaseId}.collections.{$collectionId}.documents.read"],
- 'documentsUpdate' => $stats["databases.{$databaseId}.collections.{$collectionId}.documents.update"],
- 'documentsDelete' => $stats["databases.{$databaseId}.collections.{$collectionId}.documents.delete"]
- ]);
- }
-
- $response->dynamic($usage, Response::MODEL_USAGE_COLLECTION);
-});
+ $response->dynamic($usage, Response::MODEL_USAGE_COLLECTION);
+ });
diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php
index 9fcd4998ce..d68a9b132f 100644
--- a/app/controllers/api/functions.php
+++ b/app/controllers/api/functions.php
@@ -467,7 +467,7 @@ App::post('/v1/functions/:functionId/deployments')
->inject('project')
->inject('deviceFunctions')
->inject('deviceLocal')
- ->action(function (string $functionId, string $entrypoint, array $file, bool $activate, Request $request, Response $response, Database $dbForProject, Stats $usage, Event $events, Document $project, Device $deviceFunctions, Device $deviceLocal) {
+ ->action(function (string $functionId, string $entrypoint, mixed $code, bool $activate, Request $request, Response $response, Database $dbForProject, Stats $usage, Event $events, Document $project, Device $deviceFunctions, Device $deviceLocal) {
$function = $dbForProject->getDocument('functions', $functionId);
diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php
index 429ebeb52f..12122e1f7b 100644
--- a/app/controllers/api/projects.php
+++ b/app/controllers/api/projects.php
@@ -278,8 +278,8 @@ App::get('/v1/projects/:projectId/usage')
'network',
'executions',
'users.count',
- 'database.documents.count',
- 'database.collections.count',
+ 'databases.documents.count',
+ 'databases.collections.count',
'storage.total'
];
@@ -326,8 +326,8 @@ App::get('/v1/projects/:projectId/usage')
'requests' => $stats['requests'],
'network' => $stats['network'],
'functions' => $stats['executions'],
- 'documents' => $stats['database.documents.count'],
- 'collections' => $stats['database.collections.count'],
+ 'documents' => $stats['databases.documents.count'],
+ 'collections' => $stats['databases.collections.count'],
'users' => $stats['users.count'],
'storage' => $stats['storage.total']
]);
diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php
index 9a0ee380b5..aeec82302b 100644
--- a/app/controllers/api/storage.php
+++ b/app/controllers/api/storage.php
@@ -354,7 +354,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
->inject('mode')
->inject('deviceFiles')
->inject('deviceLocal')
- ->action(function (string $bucketId, string $fileId, array $file, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, Document $user, Audit $audits, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) {
+ ->action(function (string $bucketId, string $fileId, mixed $file, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, Document $user, Audit $audits, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) {
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
if (
diff --git a/app/controllers/mock.php b/app/controllers/mock.php
index fb3369efc7..f681cb2482 100644
--- a/app/controllers/mock.php
+++ b/app/controllers/mock.php
@@ -237,7 +237,7 @@ App::post('/v1/mock/tests/general/upload')
->param('file', [], new File(), 'Sample file param', false)
->inject('request')
->inject('response')
- ->action(function (string $x, int $y, array $z, array $file, Request $request, Response $response) {
+ ->action(function (string $x, int $y, array $z, mixed $file, Request $request, Response $response) {
$file = $request->getFiles('file');
diff --git a/app/init.php b/app/init.php
index 941b7d8cbf..08eac912e8 100644
--- a/app/init.php
+++ b/app/init.php
@@ -437,7 +437,7 @@ Structure::addFormat(APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, function ($attribute) {
* Registry
*/
$register->set('logger', function () {
- // Register error logger
+ // Register error logger
$providerName = App::getEnv('_APP_LOGGING_PROVIDER', '');
$providerConfig = App::getEnv('_APP_LOGGING_CONFIG', '');
diff --git a/app/views/console/databases/collection.phtml b/app/views/console/databases/collection.phtml
index 00425c7bd5..096454d0bc 100644
--- a/app/views/console/databases/collection.phtml
+++ b/app/views/console/databases/collection.phtml
@@ -584,7 +584,16 @@ $logs = $this->getParam('logs', null);
- -
+ -
+
+
- Last Updated:
- Created:
diff --git a/app/views/console/databases/document.phtml b/app/views/console/databases/document.phtml
index f485a25eeb..de74726be6 100644
--- a/app/views/console/databases/document.phtml
+++ b/app/views/console/databases/document.phtml
@@ -24,7 +24,7 @@ $logs = $this->getParam('logs', null);
-
+
@@ -349,7 +349,16 @@ $logs = $this->getParam('logs', null);
- -
+ -
+
+
- Last Updated:
- Created:
diff --git a/app/views/console/functions/function.phtml b/app/views/console/functions/function.phtml
index 6f2b1cdf84..0a66b43448 100644
--- a/app/views/console/functions/function.phtml
+++ b/app/views/console/functions/function.phtml
@@ -245,7 +245,16 @@ sort($patterns);
- -
+ -
+
+
- Last Updated:
- Created:
@@ -595,7 +604,16 @@ sort($patterns);
- -
+ -
+
+
- Last Updated:
- Created:
diff --git a/app/views/console/storage/bucket.phtml b/app/views/console/storage/bucket.phtml
index d7dfaba300..97b7ffab6d 100644
--- a/app/views/console/storage/bucket.phtml
+++ b/app/views/console/storage/bucket.phtml
@@ -471,7 +471,16 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
- -
+ -
+
+
- Last Updated:
- Created:
diff --git a/app/views/console/users/index.phtml b/app/views/console/users/index.phtml
index 7641560892..d21ac95af7 100644
--- a/app/views/console/users/index.phtml
+++ b/app/views/console/users/index.phtml
@@ -453,7 +453,7 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
data-analytics-activity
data-analytics-event="submit"
data-analytics-category="console"
- data-analytics-label="Update Project OAuth2"
+ data-analytics-label="Update Project OAuth2 (escape($name); ?>)"
data-service="projects.updateOAuth2"
data-scope="console"
data-event="submit"
diff --git a/app/views/console/users/team.phtml b/app/views/console/users/team.phtml
index 058bdc94b4..d6da7f4d66 100644
--- a/app/views/console/users/team.phtml
+++ b/app/views/console/users/team.phtml
@@ -206,7 +206,16 @@
- -
+ -
+
+
- Created:
diff --git a/app/views/console/users/user.phtml b/app/views/console/users/user.phtml
index 17edd0ffb2..c1236c92e2 100644
--- a/app/views/console/users/user.phtml
+++ b/app/views/console/users/user.phtml
@@ -286,7 +286,16 @@
-
+
+
+
diff --git a/docs/examples/0.15.x/client-android/java/database/create-document.md b/docs/examples/0.15.x/client-android/java/database/create-document.md
deleted file mode 100644
index 059a42ed66..0000000000
--- a/docs/examples/0.15.x/client-android/java/database/create-document.md
+++ /dev/null
@@ -1,50 +0,0 @@
-import androidx.appcompat.app.AppCompatActivity
-import android.os.Bundle
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
-import io.appwrite.Client
-import io.appwrite.services.Database
-
-public class MainActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- Client client = new Client(getApplicationContext())
- .setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
- .setProject("5df5acd0d48c2"); // Your project ID
-
- Database database = new Database(client);
-
- database.createDocument(
- "[COLLECTION_ID]",
- "[DOCUMENT_ID]",
- mapOf( "a" to "b" ),
- new Continuation