1
0
Fork 0
mirror of synced 2024-06-30 04:00:34 +12:00

Merge branch '0.13.x' of github.com:appwrite/appwrite into feat-update-request-filters

This commit is contained in:
Christy Jacob 2022-03-01 18:55:59 +04:00
commit 0e18469000
87 changed files with 1063 additions and 473 deletions

1
.env
View file

@ -1,6 +1,7 @@
_APP_ENV=production
_APP_ENV=development
_APP_LOCALE=en
_APP_WORKER_PER_CORE=6
_APP_CONSOLE_WHITELIST_ROOT=disabled
_APP_CONSOLE_WHITELIST_EMAILS=
_APP_CONSOLE_WHITELIST_IPS=

View file

@ -134,6 +134,7 @@ ENV DEBUG=$DEBUG
ENV _APP_SERVER=swoole \
_APP_ENV=production \
_APP_LOCALE=en \
_APP_WORKER_PER_CORE= \
_APP_DOMAIN=localhost \
_APP_DOMAIN_TARGET=localhost \
_APP_HOME=https://appwrite.io \

View file

@ -1426,7 +1426,7 @@ $collections = [
'filters' => [],
],
[
'$id' => 'sum',
'$id' => 'total',
'type' => Database::VAR_INTEGER,
'format' => '',
'size' => 0,

View file

@ -180,7 +180,7 @@ return [
[
'key' => 'cli',
'name' => 'Command Line',
'version' => '0.14.0',
'version' => '0.15.0',
'url' => 'https://github.com/appwrite/sdk-for-cli',
'package' => 'https://www.npmjs.com/package/appwrite-cli',
'enabled' => true,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -176,6 +176,15 @@ return [
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_WORKER_PER_CORE',
'description' => 'Internal Worker per core for the API, Realtime and Executor containers. Can be configured to optimize performance.',
'introduction' => '0.13.0',
'default' => 6,
'required' => false,
'question' => '',
'filter' => ''
]
],
],

View file

@ -80,11 +80,11 @@ App::post('/v1/account')
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
if ($limit !== 0) {
$sum = $dbForProject->count('users', [
$total = $dbForProject->count('users', [
new Query('deleted', Query::TYPE_EQUAL, [false]),
], APP_LIMIT_USERS);
if ($sum >= $limit) {
if ($total >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
}
}
@ -483,9 +483,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
if ($limit !== 0) {
$sum = $dbForProject->count('users', [ new Query('deleted', Query::TYPE_EQUAL, [false]),], APP_LIMIT_USERS);
$total = $dbForProject->count('users', [ new Query('deleted', Query::TYPE_EQUAL, [false]),], APP_LIMIT_USERS);
if ($sum >= $limit) {
if ($total >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
}
}
@ -656,11 +656,11 @@ App::post('/v1/account/sessions/magic-url')
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
if ($limit !== 0) {
$sum = $dbForProject->count('users', [
$total = $dbForProject->count('users', [
new Query('deleted', Query::TYPE_EQUAL, [false]),
], APP_LIMIT_USERS);
if ($sum >= $limit) {
if ($total >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
}
}
@ -928,11 +928,11 @@ App::post('/v1/account/sessions/anonymous')
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
if ($limit !== 0) {
$sum = $dbForProject->count('users', [
$total = $dbForProject->count('users', [
new Query('deleted', Query::TYPE_EQUAL, [false]),
], APP_LIMIT_USERS);
if ($sum >= $limit) {
if ($total >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
}
}
@ -1163,7 +1163,7 @@ App::get('/v1/account/sessions')
;
$response->dynamic(new Document([
'sessions' => $sessions,
'sum' => count($sessions),
'total' => count($sessions),
]), Response::MODEL_SESSION_LIST);
});
@ -1249,7 +1249,7 @@ App::get('/v1/account/logs')
;
$response->dynamic(new Document([
'sum' => $audit->countLogsByUserAndEvents($user->getId(), $auditEvents),
'total' => $audit->countLogsByUserAndEvents($user->getId(), $auditEvents),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@ -1825,7 +1825,7 @@ App::delete('/v1/account/sessions')
$events
->setParam('eventData', $response->output(new Document([
'sessions' => $sessions,
'sum' => $numOfSessions,
'total' => $numOfSessions,
]), Response::MODEL_SESSION_LIST))
;

View file

@ -111,7 +111,7 @@ function createAttribute(string $collectionId, Document $attribute, Response $re
}
$dbForProject->deleteCachedDocument('collections', $collectionId);
$dbForProject->deleteCachedCollection('collection_' . $collectionId);
$dbForProject->deleteCachedCollection('collection_' . $collection->getInternalId());
// Pass clone of $attribute object to workers
// so we can later modify Document to fit response model
@ -166,7 +166,7 @@ App::post('/v1/database/collections')
$collectionId = $collectionId == 'unique()' ? $dbForProject->getId() : $collectionId;
try {
$collection = $dbForProject->createDocument('collections', new Document([
$dbForProject->createDocument('collections', new Document([
'$id' => $collectionId,
'$read' => $read ?? [], // Collection permissions for collection documents (based on permission model)
'$write' => $write ?? [], // Collection permissions for collection documents (based on permission model)
@ -177,8 +177,9 @@ App::post('/v1/database/collections')
'name' => $name,
'search' => implode(' ', [$collectionId, $name]),
]));
$collection = $dbForProject->getDocument('collections', $collectionId);
$dbForProject->createCollection('collection_' . $collectionId);
$dbForProject->createCollection('collection_' . $collection->getInternalId());
} catch (DuplicateException $th) {
throw new Exception('Collection already exists', 409, Exception::COLLECTION_ALREADY_EXISTS);
} catch (LimitException $th) {
@ -239,7 +240,7 @@ App::get('/v1/database/collections')
$response->dynamic(new Document([
'collections' => $dbForProject->find('collections', $queries, $limit, $offset, [], [$orderType], $cursorCollection ?? null, $cursorDirection),
'sum' => $dbForProject->count('collections', $queries, APP_LIMIT_COUNT),
'total' => $dbForProject->count('collections', $queries, APP_LIMIT_COUNT),
]), Response::MODEL_COLLECTION_LIST);
});
@ -402,7 +403,8 @@ App::get('/v1/database/:collectionId/usage')
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Registry\Registry $register */
$collection = $dbForProject->getCollection('collection_' . $collectionId);
$collectionDocument = $dbForProject->getDocument('collections', $collectionId);
$collection = $dbForProject->getCollection('collection_' . $collectionDocument->getInternalId());
if ($collection->isEmpty()) {
throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND);
@ -513,7 +515,8 @@ App::get('/v1/database/collections/:collectionId/logs')
/** @var Utopia\Locale\Locale $locale */
/** @var MaxMind\Db\Reader $geodb */
$collection = $dbForProject->getCollection('collection_' . $collectionId);
$collectionDocument = $dbForProject->getDocument('collections', $collectionId);
$collection = $dbForProject->getCollection('collection_' . $collectionDocument->getInternalId());
if ($collection->isEmpty()) {
throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND);
@ -569,7 +572,7 @@ App::get('/v1/database/collections/:collectionId/logs')
}
$response->dynamic(new Document([
'sum' => $audit->countLogsByResource($resource),
'total' => $audit->countLogsByResource($resource),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@ -676,7 +679,7 @@ App::delete('/v1/database/collections/:collectionId')
throw new Exception('Failed to remove collection from DB', 500, Exception::GENERAL_SERVER_ERROR);
}
$dbForProject->deleteCachedCollection('collection_' . $collectionId);
$dbForProject->deleteCachedCollection('collection_' . $collection->getInternalId());
$deletes
->setParam('type', DELETE_TYPE_DOCUMENT)
@ -1146,7 +1149,7 @@ App::get('/v1/database/collections/:collectionId/attributes')
$usage->setParam('database.collections.read', 1);
$response->dynamic(new Document([
'sum' => \count($attributes),
'total' => \count($attributes),
'attributes' => $attributes
]), Response::MODEL_ATTRIBUTE_LIST);
});
@ -1259,7 +1262,7 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key')
}
$dbForProject->deleteCachedDocument('collections', $collectionId);
$dbForProject->deleteCachedCollection('collection_' . $collectionId);
$dbForProject->deleteCachedCollection('collection_' . $collection->getInternalId());
$database
->setParam('type', DATABASE_TYPE_DELETE_ATTRIBUTE)
@ -1437,7 +1440,7 @@ App::get('/v1/database/collections/:collectionId/indexes')
$usage->setParam('database.collections.read', 1);
$response->dynamic(new Document([
'sum' => \count($indexes),
'total' => \count($indexes),
'indexes' => $indexes,
]), Response::MODEL_INDEX_LIST);
});
@ -1642,9 +1645,9 @@ App::post('/v1/database/collections/:collectionId/documents')
try {
if ($collection->getAttribute('permission') === 'collection') {
/** @var Document $document */
$document = Authorization::skip(fn() => $dbForProject->createDocument('collection_' . $collectionId, new Document($data)));
$document = Authorization::skip(fn() => $dbForProject->createDocument('collection_' . $collection->getInternalId(), new Document($data)));
} else {
$document = $dbForProject->createDocument('collection_' . $collectionId, new Document($data));
$document = $dbForProject->createDocument('collection_' . $collection->getInternalId(), new Document($data));
}
$document->setAttribute('$collection', $collectionId);
}
@ -1742,8 +1745,8 @@ App::get('/v1/database/collections/:collectionId/documents')
$cursorDocument = null;
if (!empty($cursor)) {
$cursorDocument = $collection->getAttribute('permission') === 'collection'
? Authorization::skip(fn () => $dbForProject->getDocument('collection_' . $collectionId, $cursor))
: $dbForProject->getDocument('collection_' . $collectionId, $cursor);
? Authorization::skip(fn () => $dbForProject->getDocument('collection_' . $collection->getInternalId(), $cursor))
: $dbForProject->getDocument('collection_' . $collection->getInternalId(), $cursor);
if ($cursorDocument->isEmpty()) {
throw new Exception("Document '{$cursor}' for the 'cursor' value not found.", 400, Exception::GENERAL_CURSOR_NOT_FOUND);
@ -1752,11 +1755,11 @@ App::get('/v1/database/collections/:collectionId/documents')
if ($collection->getAttribute('permission') === 'collection') {
/** @var Document[] $documents */
$documents = Authorization::skip(fn() => $dbForProject->find('collection_' . $collectionId, $queries, $limit, $offset, $orderAttributes, $orderTypes, $cursorDocument ?? null, $cursorDirection));
$sum = Authorization::skip(fn() => $dbForProject->count('collection_' . $collectionId, $queries, APP_LIMIT_COUNT));
$documents = Authorization::skip(fn() => $dbForProject->find('collection_' . $collection->getInternalId(), $queries, $limit, $offset, $orderAttributes, $orderTypes, $cursorDocument ?? null, $cursorDirection));
$total = Authorization::skip(fn() => $dbForProject->count('collection_' . $collection->getInternalId(), $queries, APP_LIMIT_COUNT));
} else {
$documents = $dbForProject->find('collection_' . $collectionId, $queries, $limit, $offset, $orderAttributes, $orderTypes, $cursorDocument ?? null, $cursorDirection);
$sum = $dbForProject->count('collection_' . $collectionId, $queries, APP_LIMIT_COUNT);
$documents = $dbForProject->find('collection_' . $collection->getInternalId(), $queries, $limit, $offset, $orderAttributes, $orderTypes, $cursorDocument ?? null, $cursorDirection);
$total = $dbForProject->count('collection_' . $collection->getInternalId(), $queries, APP_LIMIT_COUNT);
}
/**
@ -1770,7 +1773,7 @@ App::get('/v1/database/collections/:collectionId/documents')
;
$response->dynamic(new Document([
'sum' => $sum,
'total' => $total,
'documents' => $documents,
]), Response::MODEL_DOCUMENT_LIST);
});
@ -1818,9 +1821,9 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId')
if ($collection->getAttribute('permission') === 'collection') {
/** @var Document $document */
$document = Authorization::skip(fn() => $dbForProject->getDocument('collection_' . $collectionId, $documentId));
$document = Authorization::skip(fn() => $dbForProject->getDocument('collection_' . $collection->getInternalId(), $documentId));
} else {
$document = $dbForProject->getDocument('collection_' . $collectionId, $documentId);
$document = $dbForProject->getDocument('collection_' . $collection->getInternalId(), $documentId);
}
/**
@ -1872,7 +1875,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId/logs')
throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND);
}
$document = $dbForProject->getDocument('collection_' . $collectionId, $documentId);
$document = $dbForProject->getDocument('collection_' . $collection->getInternalId(), $documentId);
if ($document->isEmpty()) {
throw new Exception('No document found', 404, Exception::DOCUMENT_NOT_FOUND);
@ -1927,7 +1930,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId/logs')
}
}
$response->dynamic(new Document([
'sum' => $audit->countLogsByResource($resource),
'total' => $audit->countLogsByResource($resource),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@ -1981,9 +1984,9 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED);
}
$document = Authorization::skip(fn() => $dbForProject->getDocument('collection_' . $collectionId, $documentId));
$document = Authorization::skip(fn() => $dbForProject->getDocument('collection_' . $collection->getInternalId(), $documentId));
} else {
$document = $dbForProject->getDocument('collection_' . $collectionId, $documentId);
$document = $dbForProject->getDocument('collection_' . $collection->getInternalId(), $documentId);
}
@ -2031,9 +2034,9 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
try {
if ($collection->getAttribute('permission') === 'collection') {
/** @var Document $document */
$document = Authorization::skip(fn() => $dbForProject->updateDocument('collection_' . $collection->getId(), $document->getId(), new Document($data)));
$document = Authorization::skip(fn() => $dbForProject->updateDocument('collection_' . $collection->getInternalId(), $document->getId(), new Document($data)));
} else {
$document = $dbForProject->updateDocument('collection_' . $collection->getId(), $document->getId(), new Document($data));
$document = $dbForProject->updateDocument('collection_' . $collection->getInternalId(), $document->getId(), new Document($data));
}
/**
* Reset $collection attribute to remove prefix.
@ -2116,9 +2119,9 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
if ($collection->getAttribute('permission') === 'collection') {
/** @var Document $document */
$document = Authorization::skip(fn() => $dbForProject->getDocument('collection_' . $collectionId, $documentId));
$document = Authorization::skip(fn() => $dbForProject->getDocument('collection_' . $collection->getInternalId(), $documentId));
} else {
$document = $dbForProject->getDocument('collection_' . $collectionId, $documentId);
$document = $dbForProject->getDocument('collection_' . $collection->getInternalId(), $documentId);
}
if ($document->isEmpty()) {
@ -2126,12 +2129,12 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
}
if ($collection->getAttribute('permission') === 'collection') {
Authorization::skip(fn() => $dbForProject->deleteDocument('collection_' . $collectionId, $documentId));
Authorization::skip(fn() => $dbForProject->deleteDocument('collection_' . $collection->getInternalId(), $documentId));
} else {
$dbForProject->deleteDocument('collection_' . $collectionId, $documentId);
$dbForProject->deleteDocument('collection_' . $collection->getInternalId(), $documentId);
}
$dbForProject->deleteCachedDocument('collection_' . $collectionId, $documentId);
$dbForProject->deleteCachedDocument('collection_' . $collection->getInternalId(), $documentId);
/**
* Reset $collection attribute to remove prefix.

View file

@ -118,7 +118,7 @@ App::get('/v1/functions')
$response->dynamic(new Document([
'functions' => $dbForProject->find('functions', $queries, $limit, $offset, [], [$orderType], $cursorFunction ?? null, $cursorDirection),
'sum' => $dbForProject->count('functions', $queries, APP_LIMIT_COUNT),
'total' => $dbForProject->count('functions', $queries, APP_LIMIT_COUNT),
]), Response::MODEL_FUNCTION_LIST);
});
@ -145,7 +145,7 @@ App::get('/v1/functions/runtimes')
}, array_keys($runtimes));
$response->dynamic(new Document([
'sum' => count($runtimes),
'total' => count($runtimes),
'runtimes' => $runtimes
]), Response::MODEL_RUNTIME_LIST);
});
@ -686,7 +686,7 @@ App::get('/v1/functions/:functionId/deployments')
$queries[] = new Query('resourceType', Query::TYPE_EQUAL, ['functions']);
$results = $dbForProject->find('deployments', $queries, $limit, $offset, [], [$orderType], $cursorDeployment ?? null, $cursorDirection);
$sum = $dbForProject->count('deployments', $queries, APP_LIMIT_COUNT);
$total = $dbForProject->count('deployments', $queries, APP_LIMIT_COUNT);
foreach ($results as $result) {
$build = $dbForProject->getDocument('builds', $result->getAttribute('buildId', ''));
@ -697,7 +697,7 @@ App::get('/v1/functions/:functionId/deployments')
$response->dynamic(new Document([
'deployments' => $results,
'sum' => $sum,
'total' => $total,
]), Response::MODEL_DEPLOYMENT_LIST);
});
@ -999,6 +999,7 @@ App::get('/v1/functions/:functionId/executions')
$function = Authorization::skip(fn() => $dbForProject->getDocument('functions', $functionId));
throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND);
if ($function->isEmpty()) {
throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND);
}
@ -1020,11 +1021,11 @@ App::get('/v1/functions/:functionId/executions')
}
$results = $dbForProject->find('executions', $queries, $limit, $offset, [], [Database::ORDER_DESC], $cursorExecution ?? null, $cursorDirection);
$sum = $dbForProject->count('executions', $queries, APP_LIMIT_COUNT);
$total = $dbForProject->count('executions', $queries, APP_LIMIT_COUNT);
$response->dynamic(new Document([
'executions' => $results,
'sum' => $sum,
'total' => $total,
]), Response::MODEL_EXECUTION_LIST);
});

View file

@ -100,7 +100,7 @@ App::get('/v1/locale/countries')
return strcmp($a->getAttribute('name'), $b->getAttribute('name'));
});
$response->dynamic(new Document(['countries' => $output, 'sum' => \count($output)]), Response::MODEL_COUNTRY_LIST);
$response->dynamic(new Document(['countries' => $output, 'total' => \count($output)]), Response::MODEL_COUNTRY_LIST);
});
App::get('/v1/locale/countries/eu')
@ -136,7 +136,7 @@ App::get('/v1/locale/countries/eu')
return strcmp($a->getAttribute('name'), $b->getAttribute('name'));
});
$response->dynamic(new Document(['countries' => $output, 'sum' => \count($output)]), Response::MODEL_COUNTRY_LIST);
$response->dynamic(new Document(['countries' => $output, 'total' => \count($output)]), Response::MODEL_COUNTRY_LIST);
});
App::get('/v1/locale/countries/phones')
@ -171,7 +171,7 @@ App::get('/v1/locale/countries/phones')
}
}
$response->dynamic(new Document(['phones' => $output, 'sum' => \count($output)]), Response::MODEL_PHONE_LIST);
$response->dynamic(new Document(['phones' => $output, 'total' => \count($output)]), Response::MODEL_PHONE_LIST);
});
App::get('/v1/locale/continents')
@ -204,7 +204,7 @@ App::get('/v1/locale/continents')
return strcmp($a->getAttribute('name'), $b->getAttribute('name'));
});
$response->dynamic(new Document(['continents' => $output, 'sum' => \count($output)]), Response::MODEL_CONTINENT_LIST);
$response->dynamic(new Document(['continents' => $output, 'total' => \count($output)]), Response::MODEL_CONTINENT_LIST);
});
App::get('/v1/locale/currencies')
@ -226,7 +226,7 @@ App::get('/v1/locale/currencies')
$list = array_map(fn($node) => new Document($node), $list);
$response->dynamic(new Document(['currencies' => $list, 'sum' => \count($list)]), Response::MODEL_CURRENCY_LIST);
$response->dynamic(new Document(['currencies' => $list, 'total' => \count($list)]), Response::MODEL_CURRENCY_LIST);
});
@ -249,5 +249,5 @@ App::get('/v1/locale/languages')
$list = array_map(fn ($node) => new Document($node), $list);
$response->dynamic(new Document(['languages' => $list, 'sum' => \count($list)]), Response::MODEL_LANGUAGE_LIST);
$response->dynamic(new Document(['languages' => $list, 'total' => \count($list)]), Response::MODEL_LANGUAGE_LIST);
});

View file

@ -101,10 +101,10 @@ App::post('/v1/projects')
'auths' => $auths,
'search' => implode(' ', [$projectId, $name]),
]));
/** @var array $collections */
$collections = Config::getParam('collections', []);
$collections = Config::getParam('collections', []); /** @var array $collections */
$dbForProject->setNamespace('_project_' . $project->getId());
$dbForProject->setNamespace("_{$project->getId()}");
$dbForProject->create('appwrite');
$audit = new Audit($dbForProject);
@ -186,11 +186,11 @@ App::get('/v1/projects')
}
$results = $dbForConsole->find('projects', $queries, $limit, $offset, [], [$orderType], $cursorProject ?? null, $cursorDirection);
$sum = $dbForConsole->count('projects', $queries, APP_LIMIT_COUNT);
$total = $dbForConsole->count('projects', $queries, APP_LIMIT_COUNT);
$response->dynamic(new Document([
'projects' => $results,
'sum' => $sum,
'total' => $total,
]), Response::MODEL_PROJECT_LIST);
});
@ -269,7 +269,7 @@ App::get('/v1/projects/:projectId/usage')
],
];
$dbForProject->setNamespace('_project_' . $projectId);
$dbForProject->setNamespace("_{$projectId}");
$metrics = [
'requests',
@ -649,11 +649,11 @@ App::get('/v1/projects/:projectId/webhooks')
$webhooks = $dbForConsole->find('webhooks', [
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
]);
], 5000);
$response->dynamic(new Document([
'webhooks' => $webhooks,
'sum' => count($webhooks),
'total' => count($webhooks),
]), Response::MODEL_WEBHOOK_LIST);
});
@ -863,7 +863,7 @@ App::get('/v1/projects/:projectId/keys')
$response->dynamic(new Document([
'keys' => $keys,
'sum' => count($keys),
'total' => count($keys),
]), Response::MODEL_KEY_LIST);
});
@ -1070,7 +1070,7 @@ App::get('/v1/projects/:projectId/platforms')
$response->dynamic(new Document([
'platforms' => $platforms,
'sum' => count($platforms),
'total' => count($platforms),
]), Response::MODEL_PLATFORM_LIST);
});
@ -1294,7 +1294,7 @@ App::get('/v1/projects/:projectId/domains')
$response->dynamic(new Document([
'domains' => $domains,
'sum' => count($domains),
'total' => count($domains),
]), Response::MODEL_DOMAIN_LIST);
});

View file

@ -174,7 +174,7 @@ App::get('/v1/storage/buckets')
$response->dynamic(new Document([
'buckets' => $dbForProject->find('buckets', $queries, $limit, $offset, [], [$orderType], $cursorBucket ?? null, $cursorDirection),
'sum' => $dbForProject->count('buckets', $queries, APP_LIMIT_COUNT),
'total' => $dbForProject->count('buckets', $queries, APP_LIMIT_COUNT),
]), Response::MODEL_BUCKET_LIST);
});
@ -771,7 +771,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
$response->dynamic(new Document([
'files' => $files,
'sum' => $dbForProject->count('bucket_' . $bucket->getInternalId(), $queries, APP_LIMIT_COUNT),
'total' => $dbForProject->count('bucket_' . $bucket->getInternalId(), $queries, APP_LIMIT_COUNT),
]), Response::MODEL_FILE_LIST);
});
@ -864,13 +864,15 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
->inject('usage')
->inject('mode')
->inject('deviceFiles')
->action(function ($bucketId, $fileId, $width, $height, $gravity, $quality, $borderWidth, $borderColor, $borderRadius, $opacity, $rotation, $background, $output, $request, $response, $project, $dbForProject, $usage, $mode, $deviceFiles) {
->inject('deviceLocal')
->action(function ($bucketId, $fileId, $width, $height, $gravity, $quality, $borderWidth, $borderColor, $borderRadius, $opacity, $rotation, $background, $output, $request, $response, $project, $dbForProject, $usage, $mode, $deviceFiles, $deviceLocal) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Database $dbForProject */
/** @var Appwrite\Stats\Stats $usage */
/** @var Utopia\Storage\Device $deviceFiles */
/** @var Utopia\Storage\Device $deviceLocal */
/** @var string $mode */
if (!\extension_loaded('imagick')) {
@ -935,6 +937,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
$background = (empty($background)) ? 'eceff1' : $background;
$type = \strtolower(\pathinfo($path, PATHINFO_EXTENSION));
$key = \md5($path . $width . $height . $gravity . $quality . $borderWidth . $borderColor . $borderRadius . $opacity . $rotation . $background . $output);
$deviceFiles = $deviceLocal;
}

View file

@ -57,7 +57,7 @@ App::post('/v1/teams')
'$read' => ['team:'.$teamId],
'$write' => ['team:'.$teamId .'/owner'],
'name' => $name,
'sum' => ($isPrivilegedUser || $isAppUser) ? 0 : 1,
'total' => ($isPrivilegedUser || $isAppUser) ? 0 : 1,
'dateCreated' => \time(),
'search' => implode(' ', [$teamId, $name]),
])));
@ -131,11 +131,11 @@ App::get('/v1/teams')
}
$results = $dbForProject->find('teams', $queries, $limit, $offset, [], [$orderType], $cursorTeam ?? null, $cursorDirection);
$sum = $dbForProject->count('teams', $queries, APP_LIMIT_COUNT);
$total = $dbForProject->count('teams', $queries, APP_LIMIT_COUNT);
$response->dynamic(new Document([
'teams' => $results,
'sum' => $sum,
'total' => $total,
]), Response::MODEL_TEAM_LIST);
});
@ -311,9 +311,9 @@ App::post('/v1/teams/:teamId/memberships')
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
if ($limit !== 0 && $project->getId() !== 'console') { // check users limit, console invites are allways allowed.
$sum = $dbForProject->count('users', [], APP_LIMIT_USERS);
$total = $dbForProject->count('users', [], APP_LIMIT_USERS);
if($sum >= $limit) {
if($total >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
}
}
@ -377,7 +377,7 @@ App::post('/v1/teams/:teamId/memberships')
} catch (Duplicate $th) {
throw new Exception('User has already been invited or is already a member of this team', 409, Exception::TEAM_INVITE_ALREADY_EXISTS);
}
$team->setAttribute('sum', $team->getAttribute('sum', 0) + 1);
$team->setAttribute('total', $team->getAttribute('total', 0) + 1);
$team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team));
// Attach user to team
@ -479,7 +479,7 @@ App::get('/v1/teams/:teamId/memberships')
cursorDirection: $cursorDirection
);
$sum = $dbForProject->count(
$total = $dbForProject->count(
collection:'memberships',
queries: $queries,
max: APP_LIMIT_COUNT
@ -500,7 +500,7 @@ App::get('/v1/teams/:teamId/memberships')
$response->dynamic(new Document([
'memberships' => $memberships,
'sum' => $sum,
'total' => $total,
]), Response::MODEL_MEMBERSHIP_LIST);
});
@ -731,7 +731,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
$membership = $dbForProject->updateDocument('memberships', $membership->getId(), $membership);
$team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('sum', $team->getAttribute('sum', 0) + 1)));
$team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1)));
$audits
->setParam('userId', $user->getId())
@ -825,7 +825,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
Authorization::skip(fn() => $dbForProject->updateDocument('users', $user->getId(), $user));
if ($membership->getAttribute('confirm')) { // Count only confirmed members
$team->setAttribute('sum', \max($team->getAttribute('sum', 0) - 1, 0));
$team->setAttribute('total', \max($team->getAttribute('total', 0) - 1, 0));
Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team));
}

View file

@ -128,7 +128,7 @@ App::get('/v1/users')
$response->dynamic(new Document([
'users' => $dbForProject->find('users', $queries, $limit, $offset, [], [$orderType], $cursorUser ?? null, $cursorDirection),
'sum' => $dbForProject->count('users', $queries, APP_LIMIT_COUNT),
'total' => $dbForProject->count('users', $queries, APP_LIMIT_COUNT),
]), Response::MODEL_USER_LIST);
});
@ -243,7 +243,7 @@ App::get('/v1/users/:userId/sessions')
;
$response->dynamic(new Document([
'sessions' => $sessions,
'sum' => count($sessions),
'total' => count($sessions),
]), Response::MODEL_SESSION_LIST);
});
@ -348,7 +348,7 @@ App::get('/v1/users/:userId/logs')
;
$response->dynamic(new Document([
'sum' => $audit->countLogsByUserAndEvents($user->getId(), $auditEvents),
'total' => $audit->countLogsByUserAndEvents($user->getId(), $auditEvents),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});

View file

@ -14,6 +14,7 @@ use Utopia\Domains\Domain;
use Appwrite\Auth\Auth;
use Appwrite\Network\Validator\Origin;
use Appwrite\Utopia\Response\Filters\V11 as ResponseV11;
use Appwrite\Utopia\Response\Filters\V12 as ResponseV12;
use Utopia\CLI\Console;
use Utopia\Database\Document;
use Utopia\Database\Query;
@ -132,16 +133,6 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
$selfDomain = new Domain($request->getHostname());
$endDomain = new Domain((string)$origin);
// var_dump('referer', $referrer);
// var_dump('origin', $origin);
// var_dump('port', $request->getPort());
// var_dump('hostname', $request->getHostname());
// var_dump('protocol', $request->getProtocol());
// var_dump('method', $request->getMethod());
// var_dump('ip', $request->getIP());
// var_dump('-----------------');
// var_dump($request->debug());
Config::setParam('domainVerification',
($selfDomain->getRegisterable() === $endDomain->getRegisterable()) &&
$endDomain->getRegisterable() !== '');
@ -161,9 +152,12 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
$responseFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', ''));
if ($responseFormat) {
switch($responseFormat) {
case version_compare ($responseFormat , '0.11.0', '<=') :
case version_compare ($responseFormat , '0.11.2', '<=') :
Response::setFilter(new ResponseV11());
break;
case version_compare ($responseFormat , '0.12.4', '<='):
Response::setFilter(new ResponseV12());
break;
default:
Response::setFilter(null);
}
@ -380,7 +374,20 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l
throw $error;
}
if (php_sapi_name() === 'cli') {
Console::error('[Error] Timestamp: '.date('c', time()));
if($route) {
Console::error('[Error] Method: '.$route->getMethod());
Console::error('[Error] URL: '.$route->getPath());
}
Console::error('[Error] Type: '.get_class($error));
Console::error('[Error] Message: '.$error->getMessage());
Console::error('[Error] File: '.$error->getFile());
Console::error('[Error] Line: '.$error->getLine());
}
/** Handle Utopia Errors */
if ($error instanceof Utopia\Exception) {
$code = $error->getCode();
@ -400,22 +407,6 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l
$error = new Exception($error->getMessage(), $error->getCode(), Exception::GENERAL_UNKNOWN, $error);
}
$template = ($route) ? $route->getLabel('error', null) : null;
if (php_sapi_name() === 'cli') {
Console::error('[Error] Timestamp: '.date('c', time()));
if($route) {
Console::error('[Error] Method: '.$route->getMethod());
Console::error('[Error] URL: '.$route->getPath());
}
Console::error('[Error] Type: '.get_class($error));
Console::error('[Error] Message: '.$error->getMessage());
Console::error('[Error] File: '.$error->getFile());
Console::error('[Error] Line: '.$error->getLine());
}
switch ($error->getCode()) { // Don't show 500 errors!
case 400: // Error allowed publicly
case 401: // Error allowed publicly
@ -460,6 +451,8 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l
->setStatusCode($code)
;
$template = ($route) ? $route->getLabel('error', null) : null;
if ($template) {
$comp = new View($template);

View file

@ -244,6 +244,9 @@ App::post('/v1/mock/tests/general/upload')
$file = $request->getFiles('file');
$contentRange = $request->getHeader('content-range');
$chunkSize = 5*1024*1024; // 5MB
if(!empty($contentRange)) {
$start = $request->getContentRangeStart();
$end = $request->getContentRangeEnd();
@ -267,21 +270,25 @@ App::post('/v1/mock/tests/general/upload')
throw new Exception('All chunked request must have id header (except first)', 400, Exception::GENERAL_MOCK);
}
if($end !== $size && $end-$start+1 !== 5*1024*1024) {
if($end !== $size && $end-$start+1 !== $chunkSize) {
throw new Exception('Chunk size must be 5MB (except last chunk)', 400, Exception::GENERAL_MOCK);
}
foreach ($file['size'] as $i => $sz) {
if ($end !== $size && $sz !== 5*1024*1024) {
if ($end !== $size && $sz !== $chunkSize) {
throw new Exception('Wrong chunk size', 400, Exception::GENERAL_MOCK);
}
if($sz > 5*1024*1024) {
if($sz > $chunkSize) {
throw new Exception('Chunk size must be 5MB or less', 400, Exception::GENERAL_MOCK);
}
}
if($end !== $size) {
$response->json(['$id'=> 'newfileid']);
$response->json([
'$id'=> 'newfileid',
'chunksTotal' => $file['size'] / $chunkSize,
'chunksUploaded' => $start / $chunkSize
]);
}
} else {
$file['tmp_name'] = (\is_array($file['tmp_name'])) ? $file['tmp_name'] : [$file['tmp_name']];

View file

@ -160,13 +160,14 @@ App::post('/v1/runtimes')
$stderr = '';
$startTime = \time();
$endTime = 0;
$orchestration = $orchestrationPool->get();
try {
Console::info('Building container : ' . $runtimeId);
/**
* Temporary file paths in the executor
*/
$tmpSource = "/tmp/$runtimeId/src/code.tar.gz";
$tmpBuild = "/tmp/$runtimeId/builds/code.tar.gz";
@ -192,7 +193,6 @@ App::post('/v1/runtimes')
/**
* Create container
*/
$orchestration = $orchestrationPool->get();
$secret = \bin2hex(\random_bytes(16));
$vars = \array_merge($vars, [
'INTERNAL_RUNTIME_KEY' => $secret,

View file

@ -23,9 +23,11 @@ use Utopia\Logger\Log\User;
$http = new Server("0.0.0.0", App::getEnv('PORT', 80));
$payloadSize = 6 * (1024 * 1024); // 6MB
$workerNumber = swoole_cpu_num() * intval(App::getEnv('_APP_WORKER_PER_CORE', 6));
$http
->set([
'worker_num' => $workerNumber,
'open_http2_protocol' => true,
// 'document_root' => __DIR__.'/../public',
// 'enable_static_handler' => true,

View file

@ -786,7 +786,7 @@ App::setResource('dbForProject', function($db, $cache, $project) {
$database = new Database(new MariaDB($db), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace('_project_'.$project->getId());
$database->setNamespace("_{$project->getId()}");
return $database;
}, ['db', 'cache', 'project']);
@ -796,7 +796,7 @@ App::setResource('dbForConsole', function($db, $cache) {
$database = new Database(new MariaDB($db), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace('_project_console');
$database->setNamespace('_console');
return $database;
}, ['db', 'cache']);

View file

@ -46,9 +46,12 @@ $stats->create();
$containerId = uniqid();
$statsDocument = null;
$workerNumber = swoole_cpu_num() * intval(App::getEnv('_APP_WORKER_PER_CORE', 6));
$adapter = new Adapter\Swoole(port: App::getEnv('PORT', 80));
$adapter->setPackageMaxLength(64000); // Default maximum Package Size (64kb)
$adapter
->setPackageMaxLength(64000) // Default maximum Package Size (64kb)
->setWorkerNumber($workerNumber);
$server = new Server($adapter);
@ -137,7 +140,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
*/
go(function () use ($register, $containerId, &$statsDocument, $logError) {
try {
[$database, $returnDatabase] = getDatabase($register, '_project_console');
[$database, $returnDatabase] = getDatabase($register, '_console');
$document = new Document([
'$id' => $database->getId(),
'$collection' => 'realtime',
@ -190,7 +193,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
}
try {
[$database, $returnDatabase] = getDatabase($register, '_project_console');
[$database, $returnDatabase] = getDatabase($register, '_console');
$statsDocument
->setAttribute('timestamp', time())
@ -217,7 +220,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
*/
if ($realtime->hasSubscriber('console', 'role:member', 'project')) {
[$database, $returnDatabase] = getDatabase($register, '_project_console');
[$database, $returnDatabase] = getDatabase($register, '_console');
$payload = [];
@ -321,7 +324,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
return;
}
[$database, $returnDatabase] = getDatabase($register, '_project_' . $projectId);
[$database, $returnDatabase] = getDatabase($register, "_{$projectId}");
$user = $database->getDocument('users', $userId);
@ -397,7 +400,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
$cache = new Cache(new RedisCache($redis));
$database = new Database(new MariaDB($db), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace('_project_' . $project->getId());
$database->setNamespace("_{$project->getId()}");
/*
* Project Check
@ -504,7 +507,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
$cache = new Cache(new RedisCache($redis));
$database = new Database(new MariaDB($db), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace('_project_' . $realtime->connections[$connection]['projectId']);
$database->setNamespace("_{$realtime->connections[$connection]['projectId']}");
/*
* Abuse Check

View file

@ -46,7 +46,13 @@ $cli
$offset = 0;
$projects = [$console];
$count = 0;
$totalProjects = $consoleDB->count('projects') + 1;
try {
$totalProjects = $consoleDB->count('projects') + 1;
} catch (\Throwable $th) {
$consoleDB->setNamespace('_console');
$totalProjects = $consoleDB->count('projects') + 1;
}
$class = 'Appwrite\\Migration\\Version\\' . Migration::$versions[$version];
$migration = new $class();

View file

@ -259,7 +259,7 @@ $cli
$dbForConsole = new Database(new MariaDB($db), $cacheAdapter);
$dbForProject->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$dbForConsole->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$dbForConsole->setNamespace('_project_console');
$dbForConsole->setNamespace('_console');
$latestTime = [];
@ -325,7 +325,7 @@ $cli
$projectId = $point['projectId'];
if (!empty($projectId) && $projectId !== 'console') {
$dbForProject->setNamespace('_project_' . $projectId);
$dbForProject->setNamespace('_' . $projectId);
$metricUpdated = $metric;
if (!empty($groupBy)) {
@ -417,8 +417,8 @@ $cli
$projectId = $project->getId();
// Get total storage
$dbForProject->setNamespace('_project_' . $projectId);
$storageTotal = (int) $dbForProject->sum('deployments', 'size');
$dbForProject->setNamespace('_' . $projectId);
$storageTotal = $dbForProject->sum('tags', 'size');
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
$id = \md5($time . '_30m_storage.deployments.total'); //Construct unique id for each metric using time, period and metric
@ -487,7 +487,7 @@ $cli
'files' => [
'namespace' => '',
'collectionPrefix' => 'bucket_',
'sum' => [
'total' => [
'field' => 'sizeOriginal'
]
],
@ -497,7 +497,7 @@ $cli
foreach ($collections as $collection => $options) {
try {
$dbForProject->setNamespace("_project_{$projectId}");
$dbForProject->setNamespace("_{$projectId}");
$count = $dbForProject->count($collection);
$metricPrefix = $options['metricPrefix'] ?? '';
$metric = empty($metricPrefix) ? "{$collection}.count" : "{$metricPrefix}.{$collection}.count";
@ -553,7 +553,7 @@ $cli
$subCollectionTotals = []; //total project level sum of sub collections
do { // Loop over all the parent collection document for each sub collection
$dbForProject->setNamespace("_project_{$projectId}");
$dbForProject->setNamespace("_{$projectId}");
$parents = $dbForProject->find($collection, [], 100, cursor: $latestParent); // Get all the parents for the sub collections for example for documents, this will get all the collections
if (empty($parents)) {
@ -564,12 +564,12 @@ $cli
foreach ($parents as $parent) {
foreach ($subCollections as $subCollection => $subOptions) { // Sub collection counts, like database.collections.collectionId.documents.count
$dbForProject->setNamespace("_project_{$projectId}");
$dbForProject->setNamespace("_{$projectId}");
$count = $dbForProject->count(($subOptions['collectionPrefix'] ?? '') . $parent->getId());
$subCollectionCounts[$subCollection] = ($subCollectionCounts[$subCollection] ?? 0) + $count; // Project level counts for sub collections like database.documents.count
$dbForProject->setNamespace("_project_{$projectId}");
$dbForProject->setNamespace("_{$projectId}");
$metric = empty($metricPrefix) ? "{$collection}.{$parent->getId()}.{$subCollection}.count" : "{$metricPrefix}.{$collection}.{$parent->getId()}.{$subCollection}.count";
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
@ -613,17 +613,17 @@ $cli
}
// check if sum calculation is required
$sum = $subOptions['sum'] ?? [];
if(empty($sum)) {
$total = $subOptions['total'] ?? [];
if(empty($total)) {
continue;
}
$dbForProject->setNamespace("_project_{$projectId}");
$total = (int) $dbForProject->sum(($subOptions['collectionPrefix'] ?? '') . $parent->getId(), $sum['field']);
$dbForProject->setNamespace("_{$projectId}");
$total = (int) $dbForProject->sum(($subOptions['collectionPrefix'] ?? '') . $parent->getId(), $total['field']);
$subCollectionTotals[$subCollection] = ($ssubCollectionTotals[$subCollection] ?? 0) + $total; // Project level sum for sub collections like storage.total
$dbForProject->setNamespace("_project_{$projectId}");
$dbForProject->setNamespace("_{$projectId}");
$metric = empty($metricPrefix) ? "{$collection}.{$parent->getId()}.{$subCollection}.total" : "{$metricPrefix}.{$collection}.{$parent->getId()}.{$subCollection}.total";
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
@ -668,7 +668,7 @@ $cli
* Inserting project level counts for sub collections like database.documents.count
*/
foreach ($subCollectionCounts as $subCollection => $count) {
$dbForProject->setNamespace("_project_{$projectId}");
$dbForProject->setNamespace("_{$projectId}");
$metric = empty($metricPrefix) ? "{$subCollection}.count" : "{$metricPrefix}.{$subCollection}.count";
@ -717,7 +717,7 @@ $cli
* Inserting project level sums for sub collections like storage.total
*/
foreach ($subCollectionTotals as $subCollection => $count) {
$dbForProject->setNamespace("_project_{$projectId}");
$dbForProject->setNamespace("_{$projectId}");
$metric = empty($metricPrefix) ? "{$subCollection}.total" : "{$metricPrefix}.{$subCollection}.total";
@ -769,4 +769,4 @@ $cli
Console::info("[{$now}] Aggregation took {$loopTook} seconds");
}, $interval);
});
});

View file

@ -345,10 +345,10 @@
data-name="securityLogs"
data-success="state"
data-success-param-state-keys="offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{securityLogs.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{securityLogs.total}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{securityLogs.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{securityLogs.total|pageTotal}}"></span>
<form
data-service="account.getLogs"
@ -359,7 +359,7 @@
data-name="securityLogs"
data-success="state"
data-success-param-state-keys="offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{securityLogs.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{securityLogs.total}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>
</div>

View file

@ -20,7 +20,7 @@ $params = $this->getParam('params', []);
</div>
</div>
<div data-ls-if="0 != {{logs.sum}}">
<div data-ls-if="0 != {{logs.total}}">
<div class="margin-bottom-small margin-top-negative text-align-end text-size-small text-fade">Showing logs from the last <?php echo $this->escape($interval); ?> days</div>
<div class="box margin-bottom">
@ -71,10 +71,10 @@ $params = $this->getParam('params', []);
data-name="logs"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{logs.sum}}" class="margin-end-small round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{logs.total}}" class="margin-end-small round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{logs.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{logs.total|pageTotal}}"></span>
<form
data-service="<?php echo $method; ?>"
@ -89,7 +89,7 @@ $params = $this->getParam('params', []);
data-name="logs"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{logs.sum}}" class="margin-start-small round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{logs.total}}" class="margin-start-small round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>
</div>

View file

@ -49,14 +49,14 @@ $logs = $this->getParam('logs', null);
data-name="project-documents"
x-data="{ project: new URLSearchParams(location.search).get('project') }">
<div data-ls-if="0 == {{project-documents.sum}}" class="box margin-bottom">
<div data-ls-if="0 == {{project-documents.total}}" class="box margin-bottom">
<h3 class="margin-bottom-small text-bold">No Documents Found</h3>
<p class="margin-bottom-no">Add your first document to get started</p>
</div>
<div data-ls-if="({{project-documents.sum}})" class="margin-top-negative">
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-documents.sum}}"></span><span data-ls-if="{{project-documents.sum}} == <?php echo APP_LIMIT_COUNT; ?>">+</span> documents found</div>
<div data-ls-if="({{project-documents.total}})" class="margin-top-negative">
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-documents.total}}"></span><span data-ls-if="{{project-documents.total}} == <?php echo APP_LIMIT_COUNT; ?>">+</span> documents found</div>
<div class="box margin-bottom y-scroll text-size-small">
<!-- Alpine.js Start -->
<table
@ -108,10 +108,10 @@ $logs = $this->getParam('logs', null);
data-name="project-documents"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-documents.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{project-documents.total}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-documents.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-documents.total|pageTotal}}"></span>
<form
data-service="database.listDocuments"
@ -124,7 +124,7 @@ $logs = $this->getParam('logs', null);
data-name="project-documents"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-documents.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{project-documents.total}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>

View file

@ -22,7 +22,7 @@
data-scope="sdk"
data-name="project-collections">
<div data-ls-if="(!{{project-collections.sum}})" class="box dashboard margin-bottom">
<div data-ls-if="(!{{project-collections.total}})" class="box dashboard margin-bottom">
<div class="margin-bottom-small margin-top-small margin-end margin-start">
<h3 class="margin-bottom-small text-bold">No Collections Found</h3>
@ -30,7 +30,7 @@
</div>
</div>
<div data-ls-if="0 != {{project-collections.sum}}">
<div data-ls-if="0 != {{project-collections.total}}">
<ul data-ls-loop="project-collections.collections" data-ls-as="collection" data-ls-append="" class="tiles cell-3 margin-bottom-small">
<li class="margin-bottom">
<a data-ls-attrs="href=/console/database/collection?id={{collection.$id}}&project={{router.params.project}}" class="box">
@ -53,10 +53,10 @@
data-name="project-collections"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-collections.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{project-collections.total}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-collections.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-collections.total|pageTotal}}"></span>
<form
data-service="database.listCollections"
@ -68,7 +68,7 @@
data-name="project-collections"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-collections.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{project-collections.total}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>

View file

@ -36,13 +36,13 @@ $rules = $collection->getAttribute('rules', []);
data-scope="sdk"
data-name="project-documents">
<div data-ls-if="0 == {{project-documents.sum}}" class="margin-bottom">
<div data-ls-if="0 == {{project-documents.total}}" class="margin-bottom">
<h3 class="margin-bottom-small text-bold">No Documents Found</h3>
<p class="margin-bottom-no">Try a different search term.</p>
</div>
<div data-ls-if="({{project-documents.sum}})">
<div data-ls-if="({{project-documents.total}})">
<form class="scroll">
<table class="margin-top-no margin-bottom-no">
<thead>
@ -107,10 +107,10 @@ $rules = $collection->getAttribute('rules', []);
data-name="project-documents"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-documents.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{project-documents.total}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-documents.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-documents.total|pageTotal}}"></span>
<form
data-service="database.listDocuments"
@ -123,7 +123,7 @@ $rules = $collection->getAttribute('rules', []);
data-name="project-documents"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-documents.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{project-documents.total}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>

View file

@ -28,13 +28,13 @@
data-success="state"
data-success-param-state-keys="search,offset">
<div data-ls-if="0 == {{project-files.sum}}" class="margin-bottom">
<div data-ls-if="0 == {{project-files.total}}" class="margin-bottom">
<h3 class="margin-bottom-small text-bold">No Files Found</h3>
<p class="margin-bottom-no">Try a different search term.</p>
</div>
<div data-ls-if="0 != {{project-files.sum}}">
<div data-ls-if="0 != {{project-files.total}}">
<div class="scroll">
<table class="margin-top-no margin-bottom-no">
<thead>
@ -91,10 +91,10 @@
data-name="project-files"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-files.sum}}" class="margin-end-small round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{project-files.total}}" class="margin-end-small round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-files.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-files.total|pageTotal}}"></span>
<form
data-service="storage.listFiles"
@ -106,7 +106,7 @@
data-name="project-files"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-files.sum}}" class="margin-start-small round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{project-files.total}}" class="margin-start-small round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>

View file

@ -68,7 +68,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
data-success="trigger"
data-success-param-trigger-events="functions.listDeployments">
<h3>Deployments <span class="text-fade text-size-small pull-end margin-top-small" data-ls-bind="{{project-function-deployments.sum}} deployments found"></span></h3>
<h3>Deployments <span class="text-fade text-size-small pull-end margin-top-small" data-ls-bind="{{project-function-deployments.total}} deployments found"></span></h3>
<div data-ls-if="0 == {{project-function-deployments.deployments.length}} || undefined == {{project-function-deployments.deployments.length}}" class="box margin-top margin-bottom">
<h3 class="margin-bottom-small text-bold">No Deployments Found</h3>
@ -179,7 +179,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
</div>
<div class="pull-start">
<button data-ls-ui-trigger="deploy-deployment">Create Deployment</button>
<button data-ls-ui-trigger="create-deployment">Create Deployment</button>
</div>
<div class="pull-end paging">
@ -194,10 +194,10 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
data-name="project-function-deployments"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-function-deployments.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{project-function-deployments.total}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-function-deployments.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-function-deployments.total|pageTotal}}"></span>
<form
data-service="functions.listDeployments"
@ -210,7 +210,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
data-name="project-function-deployments"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-function-deployments.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{project-function-deployments.total}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>
</div>
@ -331,7 +331,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
<?php endif;?>
<li data-state="/console/functions/function/logs?id={{router.params.id}}&project={{router.params.project}}">
<div class="text-fade text-size-small pull-end margin-top" data-ls-bind="{{project-function-executions.sum}} executions found"></div>
<div class="text-fade text-size-small pull-end margin-top" data-ls-bind="{{project-function-executions.total}} executions found"></div>
<h2>Logs</h2>
@ -439,10 +439,10 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
data-name="project-function-executions"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-function-executions.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{project-function-executions.total}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-function-executions.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-function-executions.total|pageTotal}}"></span>
<form
data-service="functions.listExecutions"
@ -455,7 +455,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
data-name="project-function-executions"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-function-executions.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{project-function-executions.total}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>
</div>
@ -631,7 +631,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
<button type="submit" style="vertical-align: top;">Execute Now</button>
</form>
</div>
<div data-ui-modal class="modal close box sticky-footer" data-button-hide="on" data-open-event="deploy-deployment">
<div data-ui-modal class="modal close box sticky-footer" data-button-hide="on" data-open-event="create-deployment">
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
<h1 class="margin-bottom-xl">Create a New Deployment</h1>
@ -645,6 +645,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
<div class="margin-bottom">
<textarea type="hidden" data-ls-bind="appwrite functions createDeployment \
--functionId={{project-function.$id}} \
--activate=true \
--entrypoint='scriptFile' \
--code='/myrepo/myfunction'" data-forms-code="bash" data-lang="bash" data-lang-label="Bash"></textarea>
</div>
@ -654,6 +655,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
<div class="margin-bottom">
<textarea type="hidden" data-ls-bind="appwrite functions createDeployment `
--functionId={{project-function.$id}} `
--activate=true `
--entrypoint='scriptFile' `
--code='/myrepo/myfunction'" data-forms-code="powershell" data-lang="powershell" data-lang-label="PowerShell"></textarea>
</div>

View file

@ -34,7 +34,7 @@ $runtimes = $this->getParam('runtimes', []);
</div>
<div data-ls-if="0 != {{project-functions.functions.length}}">
<div class="margin-bottom-small text-align-end text-size-small margin-top-negative text-fade"><span data-ls-bind="{{project-functions.sum}}"></span> functions found</div>
<div class="margin-bottom-small text-align-end text-size-small margin-top-negative text-fade"><span data-ls-bind="{{project-functions.total}}"></span> functions found</div>
<div class="box margin-bottom">
<ul data-ls-loop="project-functions.functions" data-ls-as="function" class="list">
@ -64,10 +64,10 @@ $runtimes = $this->getParam('runtimes', []);
data-name="project-functions"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-users.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{project-users.total}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-functions.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-functions.total|pageTotal}}"></span>
<form
data-service="functions.list"
@ -79,7 +79,7 @@ $runtimes = $this->getParam('runtimes', []);
data-name="project-functions"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-functions.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{project-functions.total}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>

View file

@ -97,7 +97,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
</div>
<div class="chart-metric">
<div class="value margin-bottom-small"><span class="sum" data-ls-bind="{{usage.requests|statsGetSum|statsTotal}}">N/A</span></div>
<div class="value margin-bottom-small"><span class="sum" data-ls-bind="{{usage.requests|statsGetTotal|statsTotal}}">N/A</span></div>
<div class="unit margin-start-no margin-bottom-small">Requests</div>
</div>
</div>

View file

@ -62,10 +62,10 @@ $home = $this->getParam('home', '');
data-name="console-projects"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{console-projects.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{console-projects.total}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{console-projects.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{console-projects.total|pageTotal}}"></span>
<form
data-service="projects.list"
@ -78,7 +78,7 @@ $home = $this->getParam('home', '');
data-name="console-projects"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{console-projects.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{console-projects.total}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>

View file

@ -18,13 +18,13 @@ $scopes = $this->getParam('scopes', []);
data-success="trigger"
data-success-param-trigger-events="projects.listKeys">
<div data-ls-if="0 == {{console-keys.sum}} || undefined == {{console-keys.sum}}" class="box margin-top margin-bottom">
<div data-ls-if="0 == {{console-keys.total}} || undefined == {{console-keys.total}}" class="box margin-top margin-bottom">
<h3 class="margin-bottom-small text-bold">No API Keys Found</h3>
<p class="margin-bottom-no">You haven't created any API keys for your project yet.</p>
</div>
<div class="box margin-bottom" data-ls-if="0 != {{console-keys.sum}}">
<div class="box margin-bottom" data-ls-if="0 != {{console-keys.total}}">
<ul data-ls-loop="console-keys.keys" data-ls-as="key" class="list">
<li class="clear">
<div data-ui-modal class="modal box close" data-button-alias="none" data-open-event="key-update-{{key.$id}}">

View file

@ -273,13 +273,13 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
data-success="trigger"
data-success-param-trigger-events="projects.listDomains">
<div data-ls-if="0 == {{console-domains.sum}} || undefined == {{console-domains.sum}}" class="box margin-top margin-bottom">
<div data-ls-if="0 == {{console-domains.total}} || undefined == {{console-domains.total}}" class="box margin-top margin-bottom">
<h3 class="margin-bottom-small text-bold">No Custom Domains Added</h3>
<p class="margin-bottom-no">You haven't created any custom domains for your project yet.</p>
</div>
<div class="box margin-bottom" data-ls-if="0 != {{console-domains.sum}}">
<div class="box margin-bottom" data-ls-if="0 != {{console-domains.total}}">
<table class="vertical">
<thead>
<tr>

View file

@ -71,14 +71,14 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
data-scope="sdk"
data-name="project-files">
<div data-ls-if="0 == {{project-files.sum}}" class="box margin-bottom">
<div data-ls-if="0 == {{project-files.total}}" class="box margin-bottom">
<h3 class="margin-bottom-small text-bold">No Files Found</h3>
<p class="margin-bottom-no">Upload your first file to get started</p>
</div>
<div data-ls-if="0 != {{project-files.sum}}">
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-files.sum}}"></span> files found</div>
<div data-ls-if="0 != {{project-files.total}}">
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-files.total}}"></span> files found</div>
<div class="box margin-bottom">
<table class="vertical" style="overflow: visible">
@ -238,10 +238,10 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
data-name="project-files"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-files.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{project-files.total}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-files.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-files.total|pageTotal}}"></span>
<form
data-service="storage.listFiles"
@ -254,7 +254,7 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
data-name="project-files"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-files.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{project-files.total}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>

View file

@ -22,7 +22,7 @@
data-scope="sdk"
data-name="project-buckets">
<div data-ls-if="(!{{project-buckets.sum}})" class="box dashboard margin-bottom">
<div data-ls-if="(!{{project-buckets.total}})" class="box dashboard margin-bottom">
<div class="margin-bottom-small margin-top-small margin-end margin-start">
<h3 class="margin-bottom-small text-bold">No Buckets Found</h3>
@ -30,7 +30,7 @@
</div>
</div>
<div data-ls-if="0 != {{project-buckets.sum}}">
<div data-ls-if="0 != {{project-buckets.total}}">
<ul data-ls-loop="project-buckets.buckets" data-ls-as="bucket" data-ls-append="" class="tiles cell-3 margin-bottom-small">
<li class="margin-bottom">
<a data-ls-attrs="href=/console/storage/bucket?id={{bucket.$id}}&project={{router.params.project}}" class="box">
@ -52,10 +52,10 @@
data-name="project-buckets"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-buckets.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{project-buckets.total}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-buckets.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-buckets.total|pageTotal}}"></span>
<form
data-service="storage.listBuckets"
@ -67,7 +67,7 @@
data-name="project-buckets"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-buckets.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{project-buckets.total}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>

View file

@ -52,14 +52,14 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
data-scope="sdk"
data-name="project-users">
<div data-ls-if="0 == {{project-users.sum}}" class="box margin-bottom">
<div data-ls-if="0 == {{project-users.total}}" class="box margin-bottom">
<h3 class="margin-bottom-small text-bold">No Users Found</h3>
<p class="margin-bottom-no">Create your first user to get started</p>
</div>
<div data-ls-if="0 != {{project-users.sum}}">
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-users.sum}}"></span> users found</div>
<div data-ls-if="0 != {{project-users.total}}">
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-users.total}}"></span> users found</div>
<div class="box margin-bottom">
<table class="vertical">
@ -118,10 +118,10 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
data-name="project-users"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-users.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{project-users.total}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-users.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-users.total|pageTotal}}"></span>
<form
data-service="users.list"
@ -133,7 +133,7 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
data-name="project-users"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-users.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{project-users.total}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>
@ -220,14 +220,14 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
data-scope="sdk"
data-name="project-teams">
<div data-ls-if="0 == {{project-teams.sum}}" class="box margin-bottom">
<div data-ls-if="0 == {{project-teams.total}}" class="box margin-bottom">
<h3 class="margin-bottom-small text-bold">No Teams Found</h3>
<p class="margin-bottom-no">Create your first team to get started</p>
</div>
<div data-ls-if="0 != {{project-teams.sum}}">
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-teams.sum}}"></span> teams found</div>
<div data-ls-if="0 != {{project-teams.total}}">
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-teams.total}}"></span> teams found</div>
<div class="box margin-bottom">
<table class="vertical">
@ -247,7 +247,7 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
<td data-title="Name: ">
<a data-ls-attrs="href=/console/users/teams/team?id={{team.$id}}&project={{router.params.project}}" data-ls-bind="{{team.name}}" data-ls-attrs="title={{team.name}}"></a>
</td>
<td data-title="Members: "><span data-ls-bind="{{team.sum}} members"></span></td>
<td data-title="Members: "><span data-ls-bind="{{team.total}} members"></span></td>
<td data-title="Date Created: "><small data-ls-bind="{{team.dateCreated|dateText}}"></small></td>
</tr>
</tbody>
@ -266,10 +266,10 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
data-name="project-teams"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-teams.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{project-teams.total}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-teams.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-teams.total|pageTotal}}"></span>
<form
data-service="teams.list"
@ -281,7 +281,7 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
data-name="project-teams"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-teams.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{project-teams.total}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>

View file

@ -77,14 +77,14 @@
data-scope="sdk"
data-name="project-members">
<div data-ls-if="0 == {{project-members.sum}}" class="box margin-bottom">
<div data-ls-if="0 == {{project-members.total}}" class="box margin-bottom">
<h3 class="margin-bottom-small text-bold">No Memberships Found</h3>
<p class="margin-bottom-no">Add your first team member to get started</p>
</div>
<div data-ls-if="0 != {{project-members.sum}}">
<div class="margin-bottom-small margin-end-small text-align-end text-size-small margin-top-negative text-fade"><span data-ls-bind="{{project-members.sum}}"></span> memberships found</div>
<div data-ls-if="0 != {{project-members.total}}">
<div class="margin-bottom-small margin-end-small text-align-end text-size-small margin-top-negative text-fade"><span data-ls-bind="{{project-members.total}}"></span> memberships found</div>
<div class="box margin-bottom">
<ul data-ls-loop="project-members.memberships" data-ls-as="member" class="list">
@ -178,10 +178,10 @@
data-name="project-members"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-members.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-total="{{project-members.total}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-members.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-members.total|pageTotal}}"></span>
<form
data-service="teams.getMemberships"
@ -194,7 +194,7 @@
data-name="project-members"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-members.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-total="{{project-members.total}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>
</div>

View file

@ -21,13 +21,13 @@ $events = array_keys($this->getParam('events', []));
data-success="trigger"
data-success-param-trigger-events="projects.listWebhooks">
<div data-ls-if="0 == {{console-webhooks.sum}} || undefined == {{console-webhooks.sum}}" class="box margin-top margin-bottom">
<div data-ls-if="0 == {{console-webhooks.total}} || undefined == {{console-webhooks.total}}" class="box margin-top margin-bottom">
<h3 class="margin-bottom-small text-bold">No Webhooks Found</h3>
<p class="margin-bottom-no">You haven't created any webhooks for your project yet.</p>
</div>
<div class="box margin-bottom" data-ls-if="0 != {{console-webhooks.sum}}">
<div class="box margin-bottom" data-ls-if="0 != {{console-webhooks.total}}">
<ul data-ls-loop="console-webhooks.webhooks" data-ls-as="webhook" class="list">
<li class="clear">

View file

@ -66,6 +66,7 @@ services:
- influxdb
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_LOCALE
- _APP_CONSOLE_WHITELIST_ROOT
- _APP_CONSOLE_WHITELIST_EMAILS
@ -145,6 +146,7 @@ services:
- redis
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_OPTIONS_ABUSE
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
@ -155,6 +157,8 @@ services:
- _APP_DB_USER
- _APP_DB_PASS
- _APP_USAGE_STATS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG
appwrite-executor:
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>

View file

@ -1,5 +1,6 @@
<?php
use Appwrite\Messaging\Adapter\Realtime;
use Appwrite\Resque\Worker;
use Cron\CronExpression;
use Executor\Executor;
@ -58,6 +59,8 @@ class BuildsV1 extends Worker
protected function buildDeployment(string $projectId, string $functionId, string $deploymentId)
{
$dbForProject = $this->getProjectDB($projectId);
$dbForConsole = $this->getConsoleDB();
$project = $dbForConsole->getDocument('projects', $projectId);
$function = $dbForProject->getDocument('functions', $functionId);
if ($function->isEmpty()) {
@ -107,6 +110,16 @@ class BuildsV1 extends Worker
$build->setAttribute('status', 'building');
$build = $dbForProject->updateDocument('builds', $buildId, $build);
/** Send realtime event */
$target = Realtime::fromPayload('functions.deployments.update', $build, $project);
Realtime::send(
projectId: 'console',
payload: $build->getArrayCopy(),
event: 'functions.deployments.update',
channels: $target['channels'],
roles: $target['roles']
);
$source = $deployment->getAttribute('path');
$vars = $function->getAttribute('vars', []);
$baseImage = $runtime['image'];
@ -162,6 +175,18 @@ class BuildsV1 extends Worker
Console::error($th->getMessage());
} finally {
$build = $dbForProject->updateDocument('builds', $buildId, $build);
/**
* Send realtime Event
*/
$target = Realtime::fromPayload('functions.deployments.update', $build, $project);
Realtime::send(
projectId: 'console',
payload: $build->getArrayCopy(),
event: 'functions.deployments.update',
channels: $target['channels'],
roles: $target['roles']
);
}
}

View file

@ -86,7 +86,7 @@ class DatabaseV1 extends Worker
$project = $dbForConsole->getDocument('projects', $projectId);
try {
if(!$dbForProject->createAttribute('collection_' . $collectionId, $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
if(!$dbForProject->createAttribute('collection_' . $collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
throw new Exception('Failed to create Attribute');
}
$dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'available'));
@ -135,7 +135,7 @@ class DatabaseV1 extends Worker
// - failed: attribute was never created
// - stuck: attribute was available but cannot be removed
try {
if($status !== 'failed' && !$dbForProject->deleteAttribute('collection_' . $collectionId, $key)) {
if($status !== 'failed' && !$dbForProject->deleteAttribute('collection_' . $collection->getInternalId(), $key)) {
throw new Exception('Failed to delete Attribute');
}
$dbForProject->deleteDocument('attributes', $attribute->getId());
@ -210,7 +210,7 @@ class DatabaseV1 extends Worker
}
$dbForProject->deleteCachedDocument('collections', $collectionId);
$dbForProject->deleteCachedCollection('collection_' . $collectionId);
$dbForProject->deleteCachedCollection('collection_' . $collection->getInternalId());
}
/**
@ -233,7 +233,7 @@ class DatabaseV1 extends Worker
$project = $dbForConsole->getDocument('projects', $projectId);
try {
if(!$dbForProject->createIndex('collection_' . $collectionId, $key, $type, $attributes, $lengths, $orders)) {
if(!$dbForProject->createIndex('collection_' . $collection->getInternalId(), $key, $type, $attributes, $lengths, $orders)) {
throw new Exception('Failed to create Index');
}
$dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'available'));
@ -276,7 +276,7 @@ class DatabaseV1 extends Worker
$project = $dbForConsole->getDocument('projects', $projectId);
try {
if($status !== 'failed' && !$dbForProject->deleteIndex('collection_' . $collectionId, $key)) {
if($status !== 'failed' && !$dbForProject->deleteIndex('collection_' . $collection->getInternalId(), $key)) {
throw new Exception('Failed to delete index');
}
$dbForProject->deleteDocument('indexes', $index->getId());

View file

@ -129,7 +129,7 @@ class DeletesV1 extends Worker
$dbForProject = $this->getProjectDB($projectId);
$dbForProject->deleteCollection('collection_' . $collectionId);
$dbForProject->deleteCollection('collection_' . $document->getInternalId());
$this->deleteByGroup('attributes', [
new Query('collectionId', Query::TYPE_EQUAL, [$collectionId])
@ -227,7 +227,7 @@ class DeletesV1 extends Worker
$team = $this->getProjectDB($projectId)->getDocument('teams', $teamId);
if (!$team->isEmpty()) {
$team = $this->getProjectDB($projectId)->updateDocument('teams', $teamId, new Document(\array_merge($team->getArrayCopy(), [
'sum' => \max($team->getAttribute('sum', 0) - 1, 0), // Ensure that sum >= 0
'total' => \max($team->getAttribute('total', 0) - 1, 0), // Ensure that total >= 0
])));
}
}
@ -548,18 +548,18 @@ class DeletesV1 extends Worker
switch (App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL)) {
case Storage::DEVICE_S3:
$s3AccessKey = App::getEnv('_APP_STORAGE_DEVICE_S3_ACCESS_KEY', '');
$s3SecretKey = App::getEnv('_APP_STORAGE_DEVICE_S3_SECRET', '');
$s3Region = App::getEnv('_APP_STORAGE_DEVICE_S3_REGION', '');
$s3Bucket = App::getEnv('_APP_STORAGE_DEVICE_S3_BUCKET', '');
$s3AccessKey = App::getEnv('_APP_STORAGE_S3_ACCESS_KEY', '');
$s3SecretKey = App::getEnv('_APP_STORAGE_S3_SECRET', '');
$s3Region = App::getEnv('_APP_STORAGE_S3_REGION', '');
$s3Bucket = App::getEnv('_APP_STORAGE_S3_BUCKET', '');
$s3Acl = 'private';
$device = new S3(APP_STORAGE_UPLOADS . '/app-' . $projectId, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl);
break;
case Storage::DEVICE_DO_SPACES:
$doSpacesAccessKey = App::getEnv('_APP_STORAGE_DEVICE_DO_SPACES_ACCESS_KEY', '');
$doSpacesSecretKey = App::getEnv('_APP_STORAGE_DEVICE_DO_SPACES_SECRET', '');
$doSpacesRegion = App::getEnv('_APP_STORAGE_DEVICE_DO_SPACES_REGION', '');
$doSpacesBucket = App::getEnv('_APP_STORAGE_DEVICE_DO_SPACES_BUCKET', '');
$doSpacesAccessKey = App::getEnv('_APP_STORAGE_DO_SPACES_ACCESS_KEY', '');
$doSpacesSecretKey = App::getEnv('_APP_STORAGE_DO_SPACES_SECRET', '');
$doSpacesRegion = App::getEnv('_APP_STORAGE_DO_SPACES_REGION', '');
$doSpacesBucket = App::getEnv('_APP_STORAGE_DO_SPACES_BUCKET', '');
$doSpacesAcl = 'private';
$device = new DOSpaces(APP_STORAGE_UPLOADS . '/app-' . $projectId, $doSpacesAccessKey, $doSpacesSecretKey, $doSpacesBucket, $doSpacesRegion, $doSpacesAcl);
break;

View file

@ -328,6 +328,13 @@ class FunctionsV1 extends Worker
/** Trigger realtime event */
$target = Realtime::fromPayload('functions.executions.update', $execution);
Realtime::send(
projectId: 'console',
payload: $execution->getArrayCopy(),
event: 'functions.executions.update',
channels: $target['channels'],
roles: $target['roles']
);
Realtime::send(
projectId: $projectId,
payload: $execution->getArrayCopy(),

View file

@ -45,7 +45,7 @@
"utopia-php/cache": "0.4.*",
"utopia-php/cli": "0.12.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.14.*",
"utopia-php/database": "0.15.*",
"utopia-php/locale": "0.4.*",
"utopia-php/registry": "0.5.*",
"utopia-php/preloader": "0.2.*",

42
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": "deeea4a225c55fccc04729750dd8c5ec",
"content-hash": "b7919cd5b669605d051fadd3818523a7",
"packages": [
{
"name": "adhocore/jwt",
@ -2129,16 +2129,16 @@
},
{
"name": "utopia-php/database",
"version": "0.14.1",
"version": "0.15.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "ecc143f2cfe16b23675407035c6b5375ba263285"
"reference": "4ae9f1162d6640ccfe28afa0bbc60b907a7ad1c0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/ecc143f2cfe16b23675407035c6b5375ba263285",
"reference": "ecc143f2cfe16b23675407035c6b5375ba263285",
"url": "https://api.github.com/repos/utopia-php/database/zipball/4ae9f1162d6640ccfe28afa0bbc60b907a7ad1c0",
"reference": "4ae9f1162d6640ccfe28afa0bbc60b907a7ad1c0",
"shasum": ""
},
"require": {
@ -2186,9 +2186,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.14.1"
"source": "https://github.com/utopia-php/database/tree/0.15.2"
},
"time": "2022-01-25T13:01:20+00:00"
"time": "2022-02-28T15:53:37+00:00"
},
{
"name": "utopia-php/domains",
@ -3075,7 +3075,7 @@
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator",
"reference": "36e459dfd97a5693746e733ca9947a02ce12b0dc"
"reference": "3af54e71d0088b72b3223efc511b77e254fb7a1d"
},
"require": {
"ext-curl": "*",
@ -3110,7 +3110,7 @@
}
],
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"time": "2022-02-27T08:06:11+00:00"
"time": "2022-03-01T09:53:31+00:00"
},
{
"name": "composer/pcre",
@ -4223,16 +4223,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.13",
"version": "9.2.14",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "deac8540cb7bd40b2b8cfa679b76202834fd04e8"
"reference": "9f4d60b6afe5546421462b76cd4e633ebc364ab4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/deac8540cb7bd40b2b8cfa679b76202834fd04e8",
"reference": "deac8540cb7bd40b2b8cfa679b76202834fd04e8",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/9f4d60b6afe5546421462b76cd4e633ebc364ab4",
"reference": "9f4d60b6afe5546421462b76cd4e633ebc364ab4",
"shasum": ""
},
"require": {
@ -4288,7 +4288,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.13"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.14"
},
"funding": [
{
@ -4296,7 +4296,7 @@
"type": "github"
}
],
"time": "2022-02-23T17:02:38+00:00"
"time": "2022-02-28T12:38:02+00:00"
},
{
"name": "phpunit/php-file-iterator",
@ -5703,16 +5703,16 @@
},
{
"name": "symfony/console",
"version": "v6.0.3",
"version": "v6.0.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "22e8efd019c3270c4f79376234a3f8752cd25490"
"reference": "3bebf4108b9e07492a2a4057d207aa5a77d146b1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/22e8efd019c3270c4f79376234a3f8752cd25490",
"reference": "22e8efd019c3270c4f79376234a3f8752cd25490",
"url": "https://api.github.com/repos/symfony/console/zipball/3bebf4108b9e07492a2a4057d207aa5a77d146b1",
"reference": "3bebf4108b9e07492a2a4057d207aa5a77d146b1",
"shasum": ""
},
"require": {
@ -5778,7 +5778,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v6.0.3"
"source": "https://github.com/symfony/console/tree/v6.0.5"
},
"funding": [
{
@ -5794,7 +5794,7 @@
"type": "tidelift"
}
],
"time": "2022-01-26T17:23:29+00:00"
"time": "2022-02-25T10:48:52+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",

View file

@ -88,6 +88,7 @@ services:
environment:
- _APP_ENV
- _APP_LOCALE
- _APP_WORKER_PER_CORE
- _APP_CONSOLE_WHITELIST_ROOT
- _APP_CONSOLE_WHITELIST_EMAILS
- _APP_CONSOLE_WHITELIST_IPS
@ -174,6 +175,7 @@ services:
- redis
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_OPTIONS_ABUSE
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
@ -414,6 +416,8 @@ services:
- 9519:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
- appwrite-functions:/storage/functions:rw
- appwrite-builds:/storage/builds:rw
- /tmp:/tmp:rw
@ -431,6 +435,15 @@ services:
- _APP_EXECUTOR_RUNTIME_NETWORK
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG
- _APP_STORAGE_DEVICE
- _APP_STORAGE_S3_ACCESS_KEY
- _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION
- _APP_STORAGE_DO_SPACES_BUCKET
- DOCKERHUB_PULL_USERNAME
- DOCKERHUB_PULL_PASSWORD

View file

@ -513,7 +513,7 @@ if(typeof fileId==='undefined'){throw new AppwriteException('Missing required pa
let path='/storage/buckets/{bucketId}/files/{fileId}'.replace('{bucketId}',bucketId).replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getFileDownload:(bucketId,fileId)=>{if(typeof bucketId==='undefined'){throw new AppwriteException('Missing required parameter: "bucketId"');}
if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/buckets/{bucketId}/files/{fileId}/download'.replace('{bucketId}',bucketId).replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getFilePreview:(bucketId,fileId,width,height,gravity,quality,borderWidth,borderColor,borderRadius,opacity,rotation,background,output)=>__awaiter(this,void 0,void 0,function*(){if(typeof bucketId==='undefined'){throw new AppwriteException('Missing required parameter: "bucketId"');}
return uri;},getFilePreview:(bucketId,fileId,width,height,gravity,quality,borderWidth,borderColor,borderRadius,opacity,rotation,background,output)=>{if(typeof bucketId==='undefined'){throw new AppwriteException('Missing required parameter: "bucketId"');}
if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/buckets/{bucketId}/files/{fileId}/preview'.replace('{bucketId}',bucketId).replace('{fileId}',fileId);let payload={};if(typeof width!=='undefined'){payload['width']=width;}
if(typeof height!=='undefined'){payload['height']=height;}
@ -526,7 +526,8 @@ if(typeof opacity!=='undefined'){payload['opacity']=opacity;}
if(typeof rotation!=='undefined'){payload['rotation']=rotation;}
if(typeof background!=='undefined'){payload['background']=background;}
if(typeof output!=='undefined'){payload['output']=output;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getFileView:(bucketId,fileId)=>{if(typeof bucketId==='undefined'){throw new AppwriteException('Missing required parameter: "bucketId"');}
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getFileView:(bucketId,fileId)=>{if(typeof bucketId==='undefined'){throw new AppwriteException('Missing required parameter: "bucketId"');}
if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/buckets/{bucketId}/files/{fileId}/view'.replace('{bucketId}',bucketId).replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getUsage:(range)=>__awaiter(this,void 0,void 0,function*(){let path='/storage/usage';let payload={};if(typeof range!=='undefined'){payload['range']=range;}
@ -3541,7 +3542,7 @@ handler2.inline=(el,{expression},{cleanup:cleanup2})=>{let root=closestRoot(el);
root._x_refs={};root._x_refs[expression]=el;cleanup2(()=>delete root._x_refs[expression]);};directive("ref",handler2);directive("if",(el,{expression},{effect:effect3,cleanup:cleanup2})=>{let evaluate2=evaluateLater(el,expression);let show=()=>{if(el._x_currentIfEl)
return el._x_currentIfEl;let clone2=el.content.cloneNode(true).firstElementChild;addScopeToNode(clone2,{},el);mutateDom(()=>{el.after(clone2);initTree(clone2);});el._x_currentIfEl=clone2;el._x_undoIf=()=>{clone2.remove();delete el._x_currentIfEl;};return clone2;};let hide=()=>{if(!el._x_undoIf)
return;el._x_undoIf();delete el._x_undoIf;};effect3(()=>evaluate2((value)=>{value?show():hide();}));cleanup2(()=>el._x_undoIf&&el._x_undoIf());});mapAttributes(startingWith("@",into(prefix("on:"))));directive("on",skipDuringClone((el,{value,modifiers,expression},{cleanup:cleanup2})=>{let evaluate2=expression?evaluateLater(el,expression):()=>{};let removeListener=on(el,value,modifiers,(e)=>{evaluate2(()=>{},{scope:{$event:e},params:[e]});});cleanup2(()=>removeListener());}));alpine_default.setEvaluator(normalEvaluator);alpine_default.setReactivityEngine({reactive:reactive2,effect:effect2,release:stop,raw:toRaw});var src_default=alpine_default;window.Alpine=src_default;queueMicrotask(()=>{src_default.start();});})();window.ls.error=function(){return function(error){window.console.error(error);if(window.location.pathname!=='/console'){window.location='/console';}};};window.addEventListener("error",function(event){console.error("ERROR-EVENT:",event.error.message,event.error.stack);});document.addEventListener("account.deleteSession",function(){window.location="/auth/signin";});document.addEventListener("account.create",function(){let container=window.ls.container;let form=container.get('serviceForm');let sdk=container.get('console');let promise=sdk.account.createSession(form.email,form.password);container.set("serviceForm",{},true,true);promise.then(function(){var subscribe=document.getElementById('newsletter').checked;if(subscribe){let alerts=container.get('alerts');let loaderId=alerts.add({text:'Loading...',class:""},0);fetch('https://appwrite.io/v1/newsletter/subscribe',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name:form.name,email:form.email,}),}).finally(function(){alerts.remove(loaderId);window.location='/console';});}else{window.location='/console';}},function(error){window.location='/auth/signup?failure=1';});});window.addEventListener("load",async()=>{const bars=12;const realtime=window.ls.container.get('realtime');const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));let current={};window.ls.container.get('console').subscribe(['project','console'],response=>{switch(response.event){case'stats.connections':for(let project in response.payload){current[project]=response.payload[project]??0;}
break;case'database.attributes.create':case'database.attributes.update':case'database.attributes.delete':document.dispatchEvent(new CustomEvent('database.createAttribute'));break;case'database.indexes.create':case'database.indexes.update':case'database.indexes.delete':document.dispatchEvent(new CustomEvent('database.createIndex'));break;}});while(true){let newHistory={};let createdHistory=false;for(const project in current){let history=realtime?.history??{};if(!(project in history)){history[project]=new Array(bars).fill({percentage:0,value:0});}
break;case'database.attributes.create':case'database.attributes.update':case'database.attributes.delete':document.dispatchEvent(new CustomEvent('database.createAttribute'));break;case'database.indexes.create':case'database.indexes.update':case'database.indexes.delete':document.dispatchEvent(new CustomEvent('database.createIndex'));break;case'functions.deployments.create':case'functions.deployments.update':case'functions.deployments.delete':document.dispatchEvent(new CustomEvent('functions.createDeployment'));break;case'functions.executions.create':case'functions.executions.update':case'functions.executions.delete':document.dispatchEvent(new CustomEvent('functions.createExecution'));break;}});while(true){let newHistory={};let createdHistory=false;for(const project in current){let history=realtime?.history??{};if(!(project in history)){history[project]=new Array(bars).fill({percentage:0,value:0});}
history=history[project];history.push({percentage:0,value:current[project]});if(history.length>=bars){history.shift();}
const highest=history.reduce((prev,curr)=>{return(curr.value>prev)?curr.value:prev;},0);history=history.map(({percentage,value})=>{createdHistory=true;percentage=value===0?0:((Math.round((value/highest)*10)/10)*100);if(percentage>100)percentage=100;else if(percentage==0&&value!=0)percentage=5;return{percentage:percentage,value:value};})
newHistory[project]=history;}
@ -3715,7 +3716,7 @@ let units=["kB","MB","GB","TB","PB","EB","ZB","YB"];let u=-1;do{$value/=thresh;+
let thresh=1000;if(Math.abs($value)<thresh){return'B';}
let units=["kB","MB","GB","TB","PB","EB","ZB","YB"];let u=-1;do{$value/=thresh;++u;}while(Math.abs($value)>=thresh&&u<units.length-1);return units[u];}).add("statsTotal",function($value){if(!$value){return 0;}
$value=abbreviate($value,0,false,false);return $value??"N/A";}).add("statsGetLast",function($value){if(!$value||$value.length<1){return 0;}
return $value[$value.length-1].value;}).add("statsGetSum",function($value){if(!$value||$value.length<1){return 0;}
return $value[$value.length-1].value;}).add("statsGetTotal",function($value){if(!$value||$value.length<1){return 0;}
return $value.reduce(function(value,object){return value+object.value},0);}).add("isEmpty",function($value){return(!!$value);}).add("isEmptyObject",function($value){return((Object.keys($value).length===0&&$value.constructor===Object)||$value.length===0)}).add("activeDomainsCount",function($value){let result=[];if(Array.isArray($value)){result=$value.filter(function(node){return(node.verification&&node.certificateId);});}
return result.length;}).add("documentAction",function(container){let collection=container.get('project-collection');let document=container.get('project-document');if(collection&&document&&!document.$id){return'database.createDocument';}
return'database.updateDocument';}).add("documentSuccess",function(container){let document=container.get('project-document');if(document&&!document.$id){return',redirect';}
@ -3736,7 +3737,7 @@ if(forcePlaces!==false){rounded=Number(rounded).toFixed(forcePlaces);}
return rounded+abbr;}
window.ls.container.get("view").add({selector:"data-acl",controller:function(element,document,router,alerts){document.body.classList.remove("console");document.body.classList.remove("home");document.body.classList.add(router.getCurrent().view.scope);if(!router.getCurrent().view.project){document.body.classList.add("hide-nav");document.body.classList.remove("show-nav");}else{document.body.classList.add("show-nav");document.body.classList.remove("hide-nav");}
if("/console"===router.getCurrent().path){document.body.classList.add("index");}else{document.body.classList.remove("index");}}}).add({selector:"data-prism",controller:function(window,document,element,alerts){Prism.highlightElement(element);let copy=document.createElement("i");copy.className="icon-docs copy";copy.title="Copy to Clipboard";copy.textContent="Click Here to Copy";copy.addEventListener("click",function(){window.getSelection().removeAllRanges();let range=document.createRange();range.selectNode(element);window.getSelection().addRange(range);try{document.execCommand("copy");alerts.add({text:"Copied to clipboard",class:""},3000);}catch(err){alerts.add({text:"Failed to copy text ",class:"error"},3000);}
window.getSelection().removeAllRanges();});element.parentNode.parentNode.appendChild(copy);}});(function(window){document.addEventListener('alpine:init',()=>{Alpine.store('uploader',{_files:[],files(){return(this._files??[]).filter((file)=>!file.cancelled);},isOpen:true,init(){window.addEventListener('beforeunload',(event)=>{this._files.forEach((file)=>{if(!file.completed&&!file.failed){let confirmationMessage="There are incomplete uploads, are you sure you want to leave?";event.returnValue=confirmationMessage;return confirmationMessage;}});});},cancelAll(){if(confirm("Are you sure? This will cancel and remove any ungoing uploads?")){this._files.forEach(file=>{if(file.completed||file.failed){this.removeFile(file.id);}else{this.updateFile(file.id,{cancelled:true});}});}},toggle(){this.isOpen=!this.isOpen;},addFile(file){this._files.push(file);},updateFile(id,file){this._files=this._files.map((oldFile)=>id==oldFile.id?{...oldFile,...file}:oldFile);},removeFile(id){const file=this.getFile(id)??{};if(file.completed||file.failed){this._files=this._files.filter((file)=>file.id!==id);}else{if(confirm("Are you sure you want to cancel the upload?")){this.updateFile(id,{cancelled:true});}}},getFile(id){return this._files.find((file)=>file.id===id);},async uploadFile(target){const formData=new FormData(target);const sdk=window.ls.container.get('sdk');const bucketId=formData.get('bucketId');const file=formData.get('file');const fileId=formData.get('fileId');let id=fileId==='unique()'?performance.now():fileId;let read=formData.get('read');if(!file||!fileId){return;}
window.getSelection().removeAllRanges();});element.parentNode.parentNode.appendChild(copy);}});(function(window){document.addEventListener('alpine:init',()=>{Alpine.store('uploader',{_files:[],files(){return(this._files??[]).filter((file)=>!file.cancelled);},isOpen:true,init(){window.addEventListener('beforeunload',(event)=>{if(this.hasOngoingUploads()){let confirmationMessage="There are incomplete uploads, are you sure you want to leave?";event.returnValue=confirmationMessage;return confirmationMessage;}});},cancelAll(){if(this.hasOngoingUploads()?confirm("Are you sure? This will cancel and remove any ongoing uploads?"):true){this._files.forEach(file=>{if(file.completed||file.failed){this.removeFile(file.id);}else{this.updateFile(file.id,{cancelled:true});}});}},hasOngoingUploads(){let ongoing=false;this._files.some((file)=>{if(!file.completed&&!file.failed){ongoing=true;return;}});return ongoing;},toggle(){this.isOpen=!this.isOpen;},addFile(file){this._files.push(file);},updateFile(id,file){this._files=this._files.map((oldFile)=>id==oldFile.id?{...oldFile,...file}:oldFile);},removeFile(id){const file=this.getFile(id)??{};if(file.completed||file.failed){this._files=this._files.filter((file)=>file.id!==id);}else{if(confirm("Are you sure you want to cancel the upload?")){this.updateFile(id,{cancelled:true});}}},getFile(id){return this._files.find((file)=>file.id===id);},async uploadFile(target){const formData=new FormData(target);const sdk=window.ls.container.get('sdk');const bucketId=formData.get('bucketId');const file=formData.get('file');const fileId=formData.get('fileId');let id=fileId==='unique()'?performance.now():fileId;let read=formData.get('read');if(!file||!fileId){return;}
if(read){read=JSON.parse(read);}
let write=formData.get('write');if(write){write=JSON.parse(wirte);}
if(this.getFile(id)){this.updateFile(id,{name:file.name,completed:false,failed:false,cancelled:false,error:"",});}else{this.addFile({id:id,name:file.name,progress:0,completed:false,failed:false,cancelled:false,error:"",});}
@ -3876,7 +3877,7 @@ for(var i=0;i<newParts.length;i++){const a=parseInt(newParts[i])||0
const b=parseInt(oldParts[i])||0
if(a>b)return true
if(a<b)return false}
return false}}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-paging-back",controller:function(element,container,expression,env){let paths=[];let limit=env.PAGING_LIMIT;let check=function(){let offset=parseInt(expression.parse(element.dataset["offset"])||"0");paths=paths.concat(expression.getPaths());if(offset-limit<0){element.disabled=true;}else{element.disabled=false;element.value=offset-limit;}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split(".");while(path.length){container.bind(element,path.join("."),check);path.pop();}}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-paging-next",controller:function(element,container,expression,env){let paths=[];let limit=env.PAGING_LIMIT;let check=function(){let offset=parseInt(expression.parse(element.dataset["offset"])||"0");paths=paths.concat(expression.getPaths());let sum=parseInt(expression.parse(element.dataset["sum"])||"0");paths=paths.concat(expression.getPaths());if(offset+limit>=sum){element.disabled=true;}else{element.disabled=false;element.value=offset+limit;}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split(".");while(path.length){container.bind(element,path.join("."),check);path.pop();}}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-ui-highlight",controller:function(element,expression,document){let check=function(){let links=element.getElementsByTagName("a");let selected=null;let list=[];for(let i=0;i<links.length;i++){list.push(links[i]);}
return false}}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-paging-back",controller:function(element,container,expression,env){let paths=[];let limit=env.PAGING_LIMIT;let check=function(){let offset=parseInt(expression.parse(element.dataset["offset"])||"0");paths=paths.concat(expression.getPaths());if(offset-limit<0){element.disabled=true;}else{element.disabled=false;element.value=offset-limit;}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split(".");while(path.length){container.bind(element,path.join("."),check);path.pop();}}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-paging-next",controller:function(element,container,expression,env){let paths=[];let limit=env.PAGING_LIMIT;let check=function(){let offset=parseInt(expression.parse(element.dataset["offset"])||"0");paths=paths.concat(expression.getPaths());let total=parseInt(expression.parse(element.dataset["total"])||"0");paths=paths.concat(expression.getPaths());if(offset+limit>=total){element.disabled=true;}else{element.disabled=false;element.value=offset+limit;}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split(".");while(path.length){container.bind(element,path.join("."),check);path.pop();}}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-ui-highlight",controller:function(element,expression,document){let check=function(){let links=element.getElementsByTagName("a");let selected=null;let list=[];for(let i=0;i<links.length;i++){list.push(links[i]);}
list.sort(function(a,b){return a.pathname.length-b.pathname.length;});if(selected&&list[selected].dataset["selected"]){let parent=element.querySelector("a[href='"+list[selected].dataset["selected"]+"']");if(parent){parent.classList.remove("selected");}}
for(let i=0;i<list.length;i++){let path=list[i].pathname;if(path===window.location.pathname.substring(0,path.length)){list[i].classList.add("selected");if(selected!==null){list[selected].classList.remove("selected");}
selected=i;}else{list[i].classList.remove("selected");}}

View file

@ -513,7 +513,7 @@ if(typeof fileId==='undefined'){throw new AppwriteException('Missing required pa
let path='/storage/buckets/{bucketId}/files/{fileId}'.replace('{bucketId}',bucketId).replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('delete',uri,{'content-type':'application/json',},payload);}),getFileDownload:(bucketId,fileId)=>{if(typeof bucketId==='undefined'){throw new AppwriteException('Missing required parameter: "bucketId"');}
if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/buckets/{bucketId}/files/{fileId}/download'.replace('{bucketId}',bucketId).replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getFilePreview:(bucketId,fileId,width,height,gravity,quality,borderWidth,borderColor,borderRadius,opacity,rotation,background,output)=>__awaiter(this,void 0,void 0,function*(){if(typeof bucketId==='undefined'){throw new AppwriteException('Missing required parameter: "bucketId"');}
return uri;},getFilePreview:(bucketId,fileId,width,height,gravity,quality,borderWidth,borderColor,borderRadius,opacity,rotation,background,output)=>{if(typeof bucketId==='undefined'){throw new AppwriteException('Missing required parameter: "bucketId"');}
if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/buckets/{bucketId}/files/{fileId}/preview'.replace('{bucketId}',bucketId).replace('{fileId}',fileId);let payload={};if(typeof width!=='undefined'){payload['width']=width;}
if(typeof height!=='undefined'){payload['height']=height;}
@ -526,7 +526,8 @@ if(typeof opacity!=='undefined'){payload['opacity']=opacity;}
if(typeof rotation!=='undefined'){payload['rotation']=rotation;}
if(typeof background!=='undefined'){payload['background']=background;}
if(typeof output!=='undefined'){payload['output']=output;}
const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),getFileView:(bucketId,fileId)=>{if(typeof bucketId==='undefined'){throw new AppwriteException('Missing required parameter: "bucketId"');}
const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getFileView:(bucketId,fileId)=>{if(typeof bucketId==='undefined'){throw new AppwriteException('Missing required parameter: "bucketId"');}
if(typeof fileId==='undefined'){throw new AppwriteException('Missing required parameter: "fileId"');}
let path='/storage/buckets/{bucketId}/files/{fileId}/view'.replace('{bucketId}',bucketId).replace('{fileId}',fileId);let payload={};const uri=new URL(this.config.endpoint+path);payload['project']=this.config.project;for(const[key,value]of Object.entries(this.flatten(payload))){uri.searchParams.append(key,value);}
return uri;},getUsage:(range)=>__awaiter(this,void 0,void 0,function*(){let path='/storage/usage';let payload={};if(typeof range!=='undefined'){payload['range']=range;}

View file

@ -494,7 +494,7 @@ handler2.inline=(el,{expression},{cleanup:cleanup2})=>{let root=closestRoot(el);
root._x_refs={};root._x_refs[expression]=el;cleanup2(()=>delete root._x_refs[expression]);};directive("ref",handler2);directive("if",(el,{expression},{effect:effect3,cleanup:cleanup2})=>{let evaluate2=evaluateLater(el,expression);let show=()=>{if(el._x_currentIfEl)
return el._x_currentIfEl;let clone2=el.content.cloneNode(true).firstElementChild;addScopeToNode(clone2,{},el);mutateDom(()=>{el.after(clone2);initTree(clone2);});el._x_currentIfEl=clone2;el._x_undoIf=()=>{clone2.remove();delete el._x_currentIfEl;};return clone2;};let hide=()=>{if(!el._x_undoIf)
return;el._x_undoIf();delete el._x_undoIf;};effect3(()=>evaluate2((value)=>{value?show():hide();}));cleanup2(()=>el._x_undoIf&&el._x_undoIf());});mapAttributes(startingWith("@",into(prefix("on:"))));directive("on",skipDuringClone((el,{value,modifiers,expression},{cleanup:cleanup2})=>{let evaluate2=expression?evaluateLater(el,expression):()=>{};let removeListener=on(el,value,modifiers,(e)=>{evaluate2(()=>{},{scope:{$event:e},params:[e]});});cleanup2(()=>removeListener());}));alpine_default.setEvaluator(normalEvaluator);alpine_default.setReactivityEngine({reactive:reactive2,effect:effect2,release:stop,raw:toRaw});var src_default=alpine_default;window.Alpine=src_default;queueMicrotask(()=>{src_default.start();});})();window.ls.error=function(){return function(error){window.console.error(error);if(window.location.pathname!=='/console'){window.location='/console';}};};window.addEventListener("error",function(event){console.error("ERROR-EVENT:",event.error.message,event.error.stack);});document.addEventListener("account.deleteSession",function(){window.location="/auth/signin";});document.addEventListener("account.create",function(){let container=window.ls.container;let form=container.get('serviceForm');let sdk=container.get('console');let promise=sdk.account.createSession(form.email,form.password);container.set("serviceForm",{},true,true);promise.then(function(){var subscribe=document.getElementById('newsletter').checked;if(subscribe){let alerts=container.get('alerts');let loaderId=alerts.add({text:'Loading...',class:""},0);fetch('https://appwrite.io/v1/newsletter/subscribe',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name:form.name,email:form.email,}),}).finally(function(){alerts.remove(loaderId);window.location='/console';});}else{window.location='/console';}},function(error){window.location='/auth/signup?failure=1';});});window.addEventListener("load",async()=>{const bars=12;const realtime=window.ls.container.get('realtime');const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));let current={};window.ls.container.get('console').subscribe(['project','console'],response=>{switch(response.event){case'stats.connections':for(let project in response.payload){current[project]=response.payload[project]??0;}
break;case'database.attributes.create':case'database.attributes.update':case'database.attributes.delete':document.dispatchEvent(new CustomEvent('database.createAttribute'));break;case'database.indexes.create':case'database.indexes.update':case'database.indexes.delete':document.dispatchEvent(new CustomEvent('database.createIndex'));break;}});while(true){let newHistory={};let createdHistory=false;for(const project in current){let history=realtime?.history??{};if(!(project in history)){history[project]=new Array(bars).fill({percentage:0,value:0});}
break;case'database.attributes.create':case'database.attributes.update':case'database.attributes.delete':document.dispatchEvent(new CustomEvent('database.createAttribute'));break;case'database.indexes.create':case'database.indexes.update':case'database.indexes.delete':document.dispatchEvent(new CustomEvent('database.createIndex'));break;case'functions.deployments.create':case'functions.deployments.update':case'functions.deployments.delete':document.dispatchEvent(new CustomEvent('functions.createDeployment'));break;case'functions.executions.create':case'functions.executions.update':case'functions.executions.delete':document.dispatchEvent(new CustomEvent('functions.createExecution'));break;}});while(true){let newHistory={};let createdHistory=false;for(const project in current){let history=realtime?.history??{};if(!(project in history)){history[project]=new Array(bars).fill({percentage:0,value:0});}
history=history[project];history.push({percentage:0,value:current[project]});if(history.length>=bars){history.shift();}
const highest=history.reduce((prev,curr)=>{return(curr.value>prev)?curr.value:prev;},0);history=history.map(({percentage,value})=>{createdHistory=true;percentage=value===0?0:((Math.round((value/highest)*10)/10)*100);if(percentage>100)percentage=100;else if(percentage==0&&value!=0)percentage=5;return{percentage:percentage,value:value};})
newHistory[project]=history;}
@ -668,7 +668,7 @@ let units=["kB","MB","GB","TB","PB","EB","ZB","YB"];let u=-1;do{$value/=thresh;+
let thresh=1000;if(Math.abs($value)<thresh){return'B';}
let units=["kB","MB","GB","TB","PB","EB","ZB","YB"];let u=-1;do{$value/=thresh;++u;}while(Math.abs($value)>=thresh&&u<units.length-1);return units[u];}).add("statsTotal",function($value){if(!$value){return 0;}
$value=abbreviate($value,0,false,false);return $value??"N/A";}).add("statsGetLast",function($value){if(!$value||$value.length<1){return 0;}
return $value[$value.length-1].value;}).add("statsGetSum",function($value){if(!$value||$value.length<1){return 0;}
return $value[$value.length-1].value;}).add("statsGetTotal",function($value){if(!$value||$value.length<1){return 0;}
return $value.reduce(function(value,object){return value+object.value},0);}).add("isEmpty",function($value){return(!!$value);}).add("isEmptyObject",function($value){return((Object.keys($value).length===0&&$value.constructor===Object)||$value.length===0)}).add("activeDomainsCount",function($value){let result=[];if(Array.isArray($value)){result=$value.filter(function(node){return(node.verification&&node.certificateId);});}
return result.length;}).add("documentAction",function(container){let collection=container.get('project-collection');let document=container.get('project-document');if(collection&&document&&!document.$id){return'database.createDocument';}
return'database.updateDocument';}).add("documentSuccess",function(container){let document=container.get('project-document');if(document&&!document.$id){return',redirect';}
@ -689,7 +689,7 @@ if(forcePlaces!==false){rounded=Number(rounded).toFixed(forcePlaces);}
return rounded+abbr;}
window.ls.container.get("view").add({selector:"data-acl",controller:function(element,document,router,alerts){document.body.classList.remove("console");document.body.classList.remove("home");document.body.classList.add(router.getCurrent().view.scope);if(!router.getCurrent().view.project){document.body.classList.add("hide-nav");document.body.classList.remove("show-nav");}else{document.body.classList.add("show-nav");document.body.classList.remove("hide-nav");}
if("/console"===router.getCurrent().path){document.body.classList.add("index");}else{document.body.classList.remove("index");}}}).add({selector:"data-prism",controller:function(window,document,element,alerts){Prism.highlightElement(element);let copy=document.createElement("i");copy.className="icon-docs copy";copy.title="Copy to Clipboard";copy.textContent="Click Here to Copy";copy.addEventListener("click",function(){window.getSelection().removeAllRanges();let range=document.createRange();range.selectNode(element);window.getSelection().addRange(range);try{document.execCommand("copy");alerts.add({text:"Copied to clipboard",class:""},3000);}catch(err){alerts.add({text:"Failed to copy text ",class:"error"},3000);}
window.getSelection().removeAllRanges();});element.parentNode.parentNode.appendChild(copy);}});(function(window){document.addEventListener('alpine:init',()=>{Alpine.store('uploader',{_files:[],files(){return(this._files??[]).filter((file)=>!file.cancelled);},isOpen:true,init(){window.addEventListener('beforeunload',(event)=>{this._files.forEach((file)=>{if(!file.completed&&!file.failed){let confirmationMessage="There are incomplete uploads, are you sure you want to leave?";event.returnValue=confirmationMessage;return confirmationMessage;}});});},cancelAll(){if(confirm("Are you sure? This will cancel and remove any ungoing uploads?")){this._files.forEach(file=>{if(file.completed||file.failed){this.removeFile(file.id);}else{this.updateFile(file.id,{cancelled:true});}});}},toggle(){this.isOpen=!this.isOpen;},addFile(file){this._files.push(file);},updateFile(id,file){this._files=this._files.map((oldFile)=>id==oldFile.id?{...oldFile,...file}:oldFile);},removeFile(id){const file=this.getFile(id)??{};if(file.completed||file.failed){this._files=this._files.filter((file)=>file.id!==id);}else{if(confirm("Are you sure you want to cancel the upload?")){this.updateFile(id,{cancelled:true});}}},getFile(id){return this._files.find((file)=>file.id===id);},async uploadFile(target){const formData=new FormData(target);const sdk=window.ls.container.get('sdk');const bucketId=formData.get('bucketId');const file=formData.get('file');const fileId=formData.get('fileId');let id=fileId==='unique()'?performance.now():fileId;let read=formData.get('read');if(!file||!fileId){return;}
window.getSelection().removeAllRanges();});element.parentNode.parentNode.appendChild(copy);}});(function(window){document.addEventListener('alpine:init',()=>{Alpine.store('uploader',{_files:[],files(){return(this._files??[]).filter((file)=>!file.cancelled);},isOpen:true,init(){window.addEventListener('beforeunload',(event)=>{if(this.hasOngoingUploads()){let confirmationMessage="There are incomplete uploads, are you sure you want to leave?";event.returnValue=confirmationMessage;return confirmationMessage;}});},cancelAll(){if(this.hasOngoingUploads()?confirm("Are you sure? This will cancel and remove any ongoing uploads?"):true){this._files.forEach(file=>{if(file.completed||file.failed){this.removeFile(file.id);}else{this.updateFile(file.id,{cancelled:true});}});}},hasOngoingUploads(){let ongoing=false;this._files.some((file)=>{if(!file.completed&&!file.failed){ongoing=true;return;}});return ongoing;},toggle(){this.isOpen=!this.isOpen;},addFile(file){this._files.push(file);},updateFile(id,file){this._files=this._files.map((oldFile)=>id==oldFile.id?{...oldFile,...file}:oldFile);},removeFile(id){const file=this.getFile(id)??{};if(file.completed||file.failed){this._files=this._files.filter((file)=>file.id!==id);}else{if(confirm("Are you sure you want to cancel the upload?")){this.updateFile(id,{cancelled:true});}}},getFile(id){return this._files.find((file)=>file.id===id);},async uploadFile(target){const formData=new FormData(target);const sdk=window.ls.container.get('sdk');const bucketId=formData.get('bucketId');const file=formData.get('file');const fileId=formData.get('fileId');let id=fileId==='unique()'?performance.now():fileId;let read=formData.get('read');if(!file||!fileId){return;}
if(read){read=JSON.parse(read);}
let write=formData.get('write');if(write){write=JSON.parse(wirte);}
if(this.getFile(id)){this.updateFile(id,{name:file.name,completed:false,failed:false,cancelled:false,error:"",});}else{this.addFile({id:id,name:file.name,progress:0,completed:false,failed:false,cancelled:false,error:"",});}
@ -829,7 +829,7 @@ for(var i=0;i<newParts.length;i++){const a=parseInt(newParts[i])||0
const b=parseInt(oldParts[i])||0
if(a>b)return true
if(a<b)return false}
return false}}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-paging-back",controller:function(element,container,expression,env){let paths=[];let limit=env.PAGING_LIMIT;let check=function(){let offset=parseInt(expression.parse(element.dataset["offset"])||"0");paths=paths.concat(expression.getPaths());if(offset-limit<0){element.disabled=true;}else{element.disabled=false;element.value=offset-limit;}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split(".");while(path.length){container.bind(element,path.join("."),check);path.pop();}}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-paging-next",controller:function(element,container,expression,env){let paths=[];let limit=env.PAGING_LIMIT;let check=function(){let offset=parseInt(expression.parse(element.dataset["offset"])||"0");paths=paths.concat(expression.getPaths());let sum=parseInt(expression.parse(element.dataset["sum"])||"0");paths=paths.concat(expression.getPaths());if(offset+limit>=sum){element.disabled=true;}else{element.disabled=false;element.value=offset+limit;}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split(".");while(path.length){container.bind(element,path.join("."),check);path.pop();}}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-ui-highlight",controller:function(element,expression,document){let check=function(){let links=element.getElementsByTagName("a");let selected=null;let list=[];for(let i=0;i<links.length;i++){list.push(links[i]);}
return false}}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-paging-back",controller:function(element,container,expression,env){let paths=[];let limit=env.PAGING_LIMIT;let check=function(){let offset=parseInt(expression.parse(element.dataset["offset"])||"0");paths=paths.concat(expression.getPaths());if(offset-limit<0){element.disabled=true;}else{element.disabled=false;element.value=offset-limit;}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split(".");while(path.length){container.bind(element,path.join("."),check);path.pop();}}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-paging-next",controller:function(element,container,expression,env){let paths=[];let limit=env.PAGING_LIMIT;let check=function(){let offset=parseInt(expression.parse(element.dataset["offset"])||"0");paths=paths.concat(expression.getPaths());let total=parseInt(expression.parse(element.dataset["total"])||"0");paths=paths.concat(expression.getPaths());if(offset+limit>=total){element.disabled=true;}else{element.disabled=false;element.value=offset+limit;}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split(".");while(path.length){container.bind(element,path.join("."),check);path.pop();}}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-ui-highlight",controller:function(element,expression,document){let check=function(){let links=element.getElementsByTagName("a");let selected=null;let list=[];for(let i=0;i<links.length;i++){list.push(links[i]);}
list.sort(function(a,b){return a.pathname.length-b.pathname.length;});if(selected&&list[selected].dataset["selected"]){let parent=element.querySelector("a[href='"+list[selected].dataset["selected"]+"']");if(parent){parent.classList.remove("selected");}}
for(let i=0;i<list.length;i++){let path=list[i].pathname;if(path===window.location.pathname.substring(0,path.length)){list[i].classList.add("selected");if(selected!==null){list[selected].classList.remove("selected");}
selected=i;}else{list[i].classList.remove("selected");}}

View file

@ -4472,9 +4472,9 @@
* @param {string} background
* @param {string} output
* @throws {AppwriteException}
* @returns {Promise}
* @returns {URL}
*/
getFilePreview: (bucketId, fileId, width, height, gravity, quality, borderWidth, borderColor, borderRadius, opacity, rotation, background, output) => __awaiter(this, void 0, void 0, function* () {
getFilePreview: (bucketId, fileId, width, height, gravity, quality, borderWidth, borderColor, borderRadius, opacity, rotation, background, output) => {
if (typeof bucketId === 'undefined') {
throw new AppwriteException('Missing required parameter: "bucketId"');
}
@ -4517,10 +4517,12 @@
payload['output'] = output;
}
const uri = new URL(this.config.endpoint + path);
return yield this.call('get', uri, {
'content-type': 'application/json',
}, payload);
}),
payload['project'] = this.config.project;
for (const [key, value] of Object.entries(this.flatten(payload))) {
uri.searchParams.append(key, value);
}
return uri;
},
/**
* Get File for View
*

View file

@ -183,7 +183,7 @@ window.ls.filter
return $value[$value.length - 1].value;
})
.add("statsGetSum", function ($value) {
.add("statsGetTotal", function ($value) {
if (!$value || $value.length < 1) {
return 0;
}

View file

@ -76,6 +76,20 @@ window.addEventListener("load", async () => {
document.dispatchEvent(new CustomEvent('database.createIndex'));
break;
case 'functions.deployments.create':
case 'functions.deployments.update':
case 'functions.deployments.delete':
document.dispatchEvent(new CustomEvent('functions.createDeployment'));
break;
case 'functions.executions.create':
case 'functions.executions.update':
case 'functions.executions.delete':
document.dispatchEvent(new CustomEvent('functions.createExecution'));
break;
}
});

View file

@ -8,17 +8,15 @@
isOpen: true,
init() {
window.addEventListener('beforeunload', (event) => {
this._files.forEach((file) => {
if(!file.completed && !file.failed) {
let confirmationMessage = "There are incomplete uploads, are you sure you want to leave?";
event.returnValue = confirmationMessage;
return confirmationMessage;
}
});
if(this.hasOngoingUploads()) {
let confirmationMessage = "There are incomplete uploads, are you sure you want to leave?";
event.returnValue = confirmationMessage;
return confirmationMessage;
}
});
},
cancelAll() {
if(confirm("Are you sure? This will cancel and remove any ungoing uploads?")){
if(this.hasOngoingUploads() ? confirm("Are you sure? This will cancel and remove any ongoing uploads?") : true){
this._files.forEach(file => {
if(file.completed || file.failed) {
this.removeFile(file.id);
@ -28,6 +26,16 @@
});
}
},
hasOngoingUploads() {
let ongoing = false;
this._files.some((file) => {
if(!file.completed && !file.failed) {
ongoing = true;
return;
}
});
return ongoing;
},
toggle() {
this.isOpen = !this.isOpen;
},

View file

@ -12,11 +12,11 @@
paths = paths.concat(expression.getPaths());
let sum = parseInt(expression.parse(element.dataset["sum"]) || "0");
let total = parseInt(expression.parse(element.dataset["total"]) || "0");
paths = paths.concat(expression.getPaths());
if (offset + limit >= sum) {
if (offset + limit >= total) {
element.disabled = true;
} else {
element.disabled = false;

View file

@ -307,12 +307,17 @@ class Realtime extends Adapter
break;
case strpos($event, 'functions.executions.') === 0:
if (!empty($payload->getRead())) {
$channels[] = 'console';
$channels[] = 'executions';
$channels[] = 'executions.' . $payload->getId();
$channels[] = 'functions.' . $payload->getAttribute('functionId');
$roles = $payload->getRead();
}
break;
case strpos($event, 'functions.deployments.') === 0:
$channels[] = 'console';
$roles = ['team:' . $project->getAttribute('teamId')];
break;
}
return [

View file

@ -38,6 +38,26 @@ abstract class Migration
'0.13.0' => 'V12',
];
/**
* @var array
*/
protected array $collections;
public function __construct()
{
$this->collections = array_merge([
'_metadata' => [
'$id' => '_metadata'
],
'audit' => [
'$id' => 'audit'
],
'abuse' => [
'$id' => 'abuse'
]
], Config::getParam('collections', []));
}
/**
* Set project for migration.
*
@ -51,7 +71,7 @@ abstract class Migration
{
$this->project = $project;
$this->projectDB = $projectDB;
$this->projectDB->setNamespace('_project_' . $this->project->getId());
$this->projectDB->setNamespace('_' . $this->project->getId());
$this->consoleDB = $consoleDB;
@ -67,10 +87,7 @@ abstract class Migration
{
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
/** @var array $collections */
$collections = Config::getParam('collections', []);
foreach ($collections as $collection) {
foreach ($this->collections as $collection) {
$sum = 0;
$nextDocument = null;
$collectionCount = $this->projectDB->count($collection['$id']);

View file

@ -4,17 +4,178 @@ namespace Appwrite\Migration\Version;
use Appwrite\Migration\Migration;
use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\Document;
class V12 extends Migration
{
/**
* @var \PDO $pdo
*/
private $pdo;
public function execute(): void
{
global $register;
Console::log('Migrating project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')');
$this->pdo = $register->get('db');
Console::info('Migrating Project Schemas');
$this->migrateProjectSchema($this->project->getId());
/**
* Switch to migrated Console Project
*/
if ($this->project->getId() === 'console') {
$this->consoleDB->setNamespace('_console');
$this->projectDB->setNamespace('_console');
}
Console::info('Migrating Permissions');
$this->fixPermissions();
Console::info('Migrating Collections');
$this->fixCollections();
Console::info('Migrating Documents');
$this->forEachDocument([$this, 'fixDocument']);
}
/**
* Migrate Project Tables.
*
* @param string $projectId
* @return void
* @throws \Exception
* @throws \PDOException
*/
private function migrateProjectSchema(string $projectId): void
{
/**
* Remove empty generated Console Project.
*/
if ($this->consoleDB->getNamespace() === '_project_console' && $projectId === 'console') {
$all = [];
foreach ($this->collections as $collection) {
$all[] = "_{$projectId}_{$collection['$id']}";
$all[] = "_{$projectId}_{$collection['$id']}_perms";
}
$this->pdo->prepare('DROP TABLE IF EXISTS ' . implode(', ', $all) . ';')->execute();
} elseif ($this->projectDB->getNamespace() === '_console') {
return;
}
/**
* Rename Database Tables.
*/
foreach ($this->collections as $collection) {
$id = $collection['$id'];
$this->pdo->prepare("ALTER TABLE IF EXISTS _project_{$projectId}_{$id} RENAME TO _{$projectId}_{$id}")->execute();
$this->pdo->prepare("CREATE TABLE IF NOT EXISTS _{$projectId}_{$id}_perms (
`_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`_type` VARCHAR(12) NOT NULL,
`_permission` VARCHAR(255) NOT NULL,
`_document` VARCHAR(255) NOT NULL,
PRIMARY KEY (`_id`),
UNIQUE INDEX `_index1` (`_type`,`_document`,`_permission`),
INDEX `_index2` (`_permission`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;")->execute();
}
}
/**
* Migrate all Collection Structure.
*
* @return void
*/
protected function fixCollections(): void
{
foreach ($this->collections as $collection) {
$id = $collection['$id'];
Console::log("- {$id}");
switch ($id) {
case 'sessions':
try {
$this->projectDB->renameAttribute($id, 'providerToken', 'providerAccessToken');
} catch (\Throwable $th) {
Console::warning("'providerAccessToken' from {$id}: {$th->getMessage()}");
}
try {
$this->projectDB->createAttribute(collection: $id, id: 'providerRefreshToken', type: Database::VAR_STRING, size: 16384, signed: true, required: true, filters: ['encrypt']);
} catch (\Throwable $th) {
Console::warning("'providerRefreshToken' from {$id}: {$th->getMessage()}");
}
try {
$this->projectDB->createAttribute(collection: $id, id: 'providerAccessTokenExpiry', type: Database::VAR_INTEGER, size: 0, required: true);
} catch (\Throwable $th) {
Console::warning("'providerAccessTokenExpiry' from {$id}: {$th->getMessage()}");
}
break;
}
usleep(100000);
}
}
/**
* Migrate all Permission to new System with dedicated Table.
* @return void
* @throws \Exception
*/
protected function fixPermissions()
{
foreach ($this->collections as $collection) {
$id = $collection['$id'];
Console::log("- {$collection['$id']}");
$nextDocument = null;
do {
$documents = $this->projectDB->find($id, limit: $this->limit, cursor: $nextDocument);
$count = count($documents);
\Co\run(function (array $documents) {
foreach ($documents as $document) {
go(function (Document $document) {
$sql = "SELECT _read, _write FROM `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_{$document->getCollection()}` WHERE _uid = {$this->pdo->quote($document->getid())}";
$stmt = $this->pdo->prepare($sql);
$stmt->execute();
$permissions = $stmt->fetch();
$read = json_decode($permissions['_read'] ?? null) ?? [];
$write = json_decode($permissions['_write'] ?? null) ?? [];
$permissions = [];
foreach ($read as $permission) {
$permissions[] = "('read', '{$permission}', '{$document->getId()}')";
}
foreach ($write as $permission) {
$permissions[] = "('write', '{$permission}', '{$document->getId()}')";
}
if (!empty($permissions)) {
$queryPermissions = "INSERT IGNORE INTO `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_{$document->getCollection()}_perms` (_type, _permission, _document) VALUES " . implode(', ', $permissions);
$stmtPermissions = $this->pdo->prepare($queryPermissions);
$stmtPermissions->execute();
}
}, $document);
}
}, $documents);
if ($count !== $this->limit) {
$nextDocument = null;
} else {
$nextDocument = end($documents);
}
} while (!is_null($nextDocument));
}
/**
* Timeout to give MariaDB some room to breath
*/
usleep(100000);
}
protected function fixDocument(Document $document)
{
switch ($document->getCollection()) {
@ -92,6 +253,15 @@ class V12 extends Migration
}
break;
case 'sessions':
$document
->setAttribute('providerRefreshToken', '')
->setAttribute('providerAccessTokenExpiry', 0)
->setAttribute('providerAccessToken', $document->getAttribute('providerToken', ''))
->removeAttribute('providerToken');
break;
}
return $document;

View file

@ -184,10 +184,10 @@ abstract class Worker
if (!$projectId) {
throw new \Exception('ProjectID not provided - cannot get database');
}
$namespace = "_project_{$projectId}";
$namespace = "_{$projectId}";
break;
case self::DATABASE_CONSOLE:
$namespace = "_project_console";
$namespace = "_console";
$sleep = 5; // ConsoleDB needs extra sleep time to ensure tables are created
break;
default:

View file

@ -453,10 +453,14 @@ class OpenAPI3 extends Format
switch ($rule['type']) {
case 'string':
case 'json':
$type = 'string';
break;
case 'json':
$type = 'object';
$output['components']['schemas'][$model->getType()]['properties'][$name]['additionalProperties'] = true;
break;
case 'integer':
$type = 'integer';
$format = 'int32';
@ -516,9 +520,6 @@ class OpenAPI3 extends Format
$output['components']['schemas'][$model->getType()]['properties'][$name]['items']['format'] = $format;
}
if($items) {
$output['components']['schemas'][$model->getType()]['properties'][$name]['items'] = $items;
}
} else {
$output['components']['schemas'][$model->getType()]['properties'][$name] = [
'type' => $type,
@ -530,9 +531,9 @@ class OpenAPI3 extends Format
$output['components']['schemas'][$model->getType()]['properties'][$name]['format'] = $format;
}
if($items) {
$output['components']['schemas'][$model->getType()]['properties'][$name]['items'] = $items;
}
}
if($items) {
$output['components']['schemas'][$model->getType()]['properties'][$name]['items'] = $items;
}
if (!in_array($name, $required)) {
$output['components']['schemas'][$model->getType()]['properties'][$name]['nullable'] = true;

View file

@ -444,10 +444,14 @@ class Swagger2 extends Format
switch ($rule['type']) {
case 'string':
case 'json':
$type = 'string';
break;
case 'json':
$type = 'object';
$output['definitions'][$model->getType()]['properties'][$name]['additionalProperties'] = true;
break;
case 'integer':
$type = 'integer';
$format = 'int32';
@ -469,7 +473,7 @@ class Swagger2 extends Format
default:
$type = 'object';
$rule['type'] = ($rule['type']) ? $rule['type'] : 'none';
$rule['type'] = ($rule['type']) ?: 'none';
if(\is_array($rule['type'])) {
if($rule['array']) {
@ -508,14 +512,10 @@ class Swagger2 extends Format
$output['definitions'][$model->getType()]['properties'][$name]['items']['format'] = $format;
}
if($items) {
$output['definitions'][$model->getType()]['properties'][$name]['items'] = $items;
}
} else {
$output['definitions'][$model->getType()]['properties'][$name] = [
'type' => $type,
'description' => $rule['description'] ?? '',
//'default' => $rule['default'] ?? null,
'x-example' => $rule['example'] ?? null,
];
@ -523,9 +523,9 @@ class Swagger2 extends Format
$output['definitions'][$model->getType()]['properties'][$name]['format'] = $format;
}
if($items) {
$output['definitions'][$model->getType()]['properties'][$name]['items'] = $items;
}
}
if($items) {
$output['definitions'][$model->getType()]['properties'][$name]['items'] = $items;
}
if (!in_array($name, $required)) {
$output['definitions'][$model->getType()]['properties'][$name]['x-nullable'] = true;

View file

@ -157,7 +157,7 @@ class Response extends SwooleResponse
const MODEL_EXECUTION = 'execution';
const MODEL_EXECUTION_LIST = 'executionList';
const MODEL_BUILD = 'build';
const MODEL_BUILD_LIST = 'buildList';
const MODEL_BUILD_LIST = 'buildList'; // Not used anywhere yet
const MODEL_FUNC_PERMISSIONS = 'funcPermissions';
// Project
@ -225,7 +225,7 @@ class Response extends SwooleResponse
->setModel(new BaseList('Runtimes List', self::MODEL_RUNTIME_LIST, 'runtimes', self::MODEL_RUNTIME))
->setModel(new BaseList('Deployments List', self::MODEL_DEPLOYMENT_LIST, 'deployments', self::MODEL_DEPLOYMENT))
->setModel(new BaseList('Executions List', self::MODEL_EXECUTION_LIST, 'executions', self::MODEL_EXECUTION))
->setModel(new BaseList('Builds List', self::MODEL_BUILD_LIST, 'builds', self::MODEL_BUILD))
->setModel(new BaseList('Builds List', self::MODEL_BUILD_LIST, 'builds', self::MODEL_BUILD)) // Not used anywhere yet
->setModel(new BaseList('Projects List', self::MODEL_PROJECT_LIST, 'projects', self::MODEL_PROJECT, true, false))
->setModel(new BaseList('Webhooks List', self::MODEL_WEBHOOK_LIST, 'webhooks', self::MODEL_WEBHOOK, true, false))
->setModel(new BaseList('API Keys List', self::MODEL_KEY_LIST, 'keys', self::MODEL_KEY, true, false))

View file

@ -0,0 +1,262 @@
<?php
namespace Appwrite\Utopia\Response\Filters;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\Response\Filter;
use Exception;
class V12 extends Filter
{
// Convert 0.13 Data format to 0.12 format
public function parse(array $content, string $model): array
{
$parsedResponse = $content;
switch ($model) {
case Response::MODEL_ERROR_DEV:
case Response::MODEL_ERROR:
$parsedResponse = $this->parseError($content);
break;
case Response::MODEL_SESSION:
$parsedResponse = $this->parseSession($content);
break;
case Response::MODEL_SESSION_LIST:
$parsedResponse = $this->parseSessionList($content);
break;
case Response::MODEL_FILE:
$parsedResponse = $this->parseFile($content);
break;
case Response::MODEL_FILE_LIST:
$parsedResponse = $this->parseFileList($content);
break;
case Response::MODEL_FUNCTION:
$parsedResponse = $this->parseFunction($content);
break;
case Response::MODEL_FUNCTION_LIST:
$parsedResponse = $this->parseFunctionList($content);
break;
case Response::MODEL_DEPLOYMENT:
$parsedResponse = $this->parseDeployment($content);
break;
case Response::MODEL_DEPLOYMENT_LIST:
$parsedResponse = $this->parseDeploymentList($content);
break;
case Response::MODEL_EXECUTION:
$parsedResponse = $this->parseExecution($content);
break;
case Response::MODEL_EXECUTION_LIST:
$parsedResponse = $this->parseExecutionList($content);
break;
case Response::MODEL_USAGE_BUCKETS:
$parsedResponse = $this->parseUsageBuckets($content);
break;
case Response::MODEL_USAGE_STORAGE:
$parsedResponse = $this->parseUsageStorage($content);
break;
case Response::MODEL_TEAM:
$parsedResponse = $this->parseTeam($content);
break;
case Response::MODEL_TEAM_LIST:
$parsedResponse = $this->parseTeamList($content);
break;
case Response::MODEL_DOCUMENT_LIST:
case Response::MODEL_COLLECTION_LIST:
case Response::MODEL_INDEX_LIST:
case Response::MODEL_USER_LIST:
case Response::MODEL_LOG_LIST:
case Response::MODEL_BUCKET_LIST:
case Response::MODEL_MEMBERSHIP_LIST:
case Response::MODEL_RUNTIME_LIST:
case Response::MODEL_BUILD_LIST:
case Response::MODEL_PROJECT_LIST:
case Response::MODEL_WEBHOOK_LIST:
case Response::MODEL_KEY_LIST:
case Response::MODEL_PLATFORM_LIST:
case Response::MODEL_DOMAIN_LIST:
case Response::MODEL_COUNTRY_LIST:
case Response::MODEL_CONTINENT_LIST:
case Response::MODEL_LANGUAGE_LIST:
case Response::MODEL_CURRENCY_LIST:
case Response::MODEL_PHONE_LIST:
case Response::MODEL_METRIC_LIST:
case Response::MODEL_ATTRIBUTE_LIST:
$parsedResponse = $this->parseList($content);
break;
}
return $parsedResponse;
}
protected function parseError(array $content)
{
unset($content['type']);
return $content;
}
protected function parseSession(array $content)
{
$content['providerToken'] = $content['providerAccessToken'];
unset($content['providerAccessToken']);
unset($content['providerAccessTokenExpiry']);
unset($content['providerRefreshToken']);
return $content;
}
protected function parseSessionList(array $content)
{
$sessions = $content['sessions'];
$parsedResponse = [];
foreach ($sessions as $document) {
$parsedResponse[] = $this->parseSession($document);
}
$content['sessions'] = $parsedResponse;
$content['sum'] = $content['total'];
unset($content['total']);
return $content;
}
protected function parseFile(array $content)
{
unset($content['bucketId']);
unset($content['chunksTotal']);
unset($content['chunksUploaded']);
return $content;
}
protected function parseFileList(array $content)
{
$files = $content['files'];
$parsedResponse = [];
foreach ($files as $document) {
$parsedResponse[] = $this->parseFile($document);
}
$content['files'] = $parsedResponse;
$content['sum'] = $content['total'];
unset($content['total']);
return $content;
}
protected function parseFunction(array $content)
{
$content['tag'] = $content['deployment'];
unset($content['deployment']);
return $content;
}
protected function parseFunctionList(array $content)
{
$functions = $content['functions'];
$parsedResponse = [];
foreach ($functions as $document) {
$parsedResponse[] = $this->parseFunction($document);
}
$content['functions'] = $parsedResponse;
$content['sum'] = $content['total'];
unset($content['total']);
return $content;
}
protected function parseDeployment(array $content)
{
$content['functionId'] = $content['resourceId'];
$content['command'] = $content['entrypoint'];
return $content;
}
protected function parseDeploymentList(array $content)
{
$deployments = $content['deployments'];
$parsedResponse = [];
foreach ($deployments as $document) {
$parsedResponse[] = $this->parseDeployment($document);
}
$content['deployments'] = $parsedResponse;
$content['sum'] = $content['total'];
unset($content['total']);
return $content;
}
protected function parseUsageBuckets(array $content)
{
unset($content['filesStorage']);
}
protected function parseUsageStorage(array $content)
{
$content['storage'] = $content['filesStorage'];
unset($content['filesStorage']);
$content['files'] = $content['tagsStorage'];
unset($content['tagsStorage']);
unset($content['filesCount']);
unset($content['bucketsCount']);
unset($content['bucketsCreate']);
unset($content['bucketsRead']);
unset($content['bucketsUpdate']);
unset($content['bucketsDelete']);
unset($content['filesCount']);
unset($content['bucketsDelete']);
unset($content['filesCreate']);
unset($content['filesRead']);
unset($content['filesUpdate']);
unset($content['filesDelete']);
}
protected function parseExecution($content) {
$content['exitCode'] = $content['statusCode'];
unset($content['statusCode']);
return $content;
}
protected function parseExecutionList($content) {
$executions = $content['executions'];
$parsedResponse = [];
foreach ($executions as $document) {
$parsedResponse[] = $this->parseExecution($document);
}
$content['executions'] = $parsedResponse;
$content['sum'] = $content['total'];
unset($content['total']);
return $content;
}
protected function parseTeam($content) {
$content['sum'] = $content['total'];
unset($content['total']);
return $content;
}
protected function parseTeamList($content) {
$teams = $content['teams'];
$parsedResponse = [];
foreach ($teams as $document) {
$parsedResponse[] = $this->parseTeam($document);
}
$content['teams'] = $parsedResponse;
$content['sum'] = $content['total'];
unset($content['total']);
return $content;
}
protected function parseList($content) {
$content['sum'] = $content['total'];
unset($content['total']);
return $content;
}
}

View file

@ -11,9 +11,9 @@ class AttributeList extends Model
public function __construct()
{
$this
->addRule('sum', [
->addRule('total', [
'type' => self::TYPE_INTEGER,
'description' => 'Total sum of items in the list.',
'description' => 'Total number of attributes in the given collection.',
'default' => 0,
'example' => 5,
])

View file

@ -32,9 +32,21 @@ class BaseList extends Model
$this->public = $public;
if ($paging) {
$this->addRule('sum', [
$namesWithCap = [
'documents', 'collections', 'users', 'files', 'buckets', 'functions',
'deployments', 'executions', 'projects', 'webhooks', 'keys',
'platforms', 'domains', 'memberships', 'teams'
];
if (\in_array($name, $namesWithCap)) {
$description = 'Total number of ' . $key . ' documents that matched your query used as reference for offset pagination. When the `total` number of ' . $key . ' documents available is greater than 5000, total returned will be capped at 5000, and cursor pagination should be used. Read more about [pagination](https://appwrite.io/docs/pagination).';
} else {
$description = 'Total number of ' . $key . ' documents that matched your query.';
}
$this->addRule('total', [
'type' => self::TYPE_INTEGER,
'description' => 'Total number of items available on the server.',
'description' => $description,
'default' => 0,
'example' => 5,
]);

View file

@ -28,9 +28,9 @@ class Team extends Model
'default' => 0,
'example' => 1592981250,
])
->addRule('sum', [
->addRule('total', [
'type' => self::TYPE_INTEGER,
'description' => 'Total sum of team members.',
'description' => 'Total number of team members.',
'default' => 0,
'example' => 7,
])

View file

@ -267,7 +267,7 @@ trait AccountBase
$this->assertIsArray($response['body']);
$this->assertNotEmpty($response['body']);
$this->assertCount(2, $response['body']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertEquals(1, $response['body']['total']);
$this->assertEquals($sessionId, $response['body']['sessions'][0]['$id']);
$this->assertEquals('Windows', $response['body']['sessions'][0]['osName']);
@ -325,7 +325,7 @@ trait AccountBase
$this->assertIsArray($response['body']['logs']);
$this->assertNotEmpty($response['body']['logs']);
$this->assertCount(2, $response['body']['logs']);
$this->assertIsNumeric($response['body']['sum']);
$this->assertIsNumeric($response['body']['total']);
$this->assertContains($response['body']['logs'][0]['event'], ['account.create', 'account.sessions.create']);
$this->assertEquals($response['body']['logs'][0]['ip'], filter_var($response['body']['logs'][0]['ip'], FILTER_VALIDATE_IP));
@ -384,7 +384,7 @@ trait AccountBase
$this->assertIsArray($responseLimit['body']['logs']);
$this->assertNotEmpty($responseLimit['body']['logs']);
$this->assertCount(1, $responseLimit['body']['logs']);
$this->assertIsNumeric($responseLimit['body']['sum']);
$this->assertIsNumeric($responseLimit['body']['total']);
$this->assertEquals($response['body']['logs'][0], $responseLimit['body']['logs'][0]);
@ -401,7 +401,7 @@ trait AccountBase
$this->assertIsArray($responseOffset['body']['logs']);
$this->assertNotEmpty($responseOffset['body']['logs']);
$this->assertCount(1, $responseOffset['body']['logs']);
$this->assertIsNumeric($responseOffset['body']['sum']);
$this->assertIsNumeric($responseOffset['body']['total']);
$this->assertEquals($response['body']['logs'][1], $responseOffset['body']['logs'][0]);
@ -419,7 +419,7 @@ trait AccountBase
$this->assertIsArray($responseLimitOffset['body']['logs']);
$this->assertNotEmpty($responseLimitOffset['body']['logs']);
$this->assertCount(1, $responseLimitOffset['body']['logs']);
$this->assertIsNumeric($responseLimitOffset['body']['sum']);
$this->assertIsNumeric($responseLimitOffset['body']['total']);
$this->assertEquals($response['body']['logs'][1], $responseLimitOffset['body']['logs'][0]);
/**

View file

@ -472,7 +472,7 @@ trait DatabaseBase
]));
$this->assertEquals(200, $attributes['headers']['status-code']);
$this->assertEquals(8, $attributes['body']['sum']);
$this->assertEquals(8, $attributes['body']['total']);
$attributes = $attributes['body']['attributes'];
@ -2017,7 +2017,7 @@ trait DatabaseBase
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals(3, $documents['body']['sum']);
$this->assertEquals(3, $documents['body']['total']);
$this->assertCount(3, $documents['body']['documents']);
/*

View file

@ -138,7 +138,7 @@ class DatabaseConsoleClientTest extends Scope
$this->assertEquals($logs['headers']['status-code'], 200);
$this->assertIsArray($logs['body']['logs']);
$this->assertIsNumeric($logs['body']['sum']);
$this->assertIsNumeric($logs['body']['total']);
$logs = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/logs', array_merge([
'content-type' => 'application/json',
@ -150,7 +150,7 @@ class DatabaseConsoleClientTest extends Scope
$this->assertEquals($logs['headers']['status-code'], 200);
$this->assertIsArray($logs['body']['logs']);
$this->assertLessThanOrEqual(1, count($logs['body']['logs']));
$this->assertIsNumeric($logs['body']['sum']);
$this->assertIsNumeric($logs['body']['total']);
$logs = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/logs', array_merge([
'content-type' => 'application/json',
@ -161,7 +161,7 @@ class DatabaseConsoleClientTest extends Scope
$this->assertEquals($logs['headers']['status-code'], 200);
$this->assertIsArray($logs['body']['logs']);
$this->assertIsNumeric($logs['body']['sum']);
$this->assertIsNumeric($logs['body']['total']);
$logs = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/logs', array_merge([
'content-type' => 'application/json',
@ -174,6 +174,6 @@ class DatabaseConsoleClientTest extends Scope
$this->assertEquals($logs['headers']['status-code'], 200);
$this->assertIsArray($logs['body']['logs']);
$this->assertLessThanOrEqual(1, count($logs['body']['logs']));
$this->assertIsNumeric($logs['body']['sum']);
$this->assertIsNumeric($logs['body']['total']);
}
}

View file

@ -48,7 +48,7 @@ class DatabaseCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals(2, $collections['body']['sum']);
$this->assertEquals(2, $collections['body']['total']);
$this->assertEquals($test1['body']['$id'], $collections['body']['collections'][0]['$id']);
$this->assertEquals($test2['body']['$id'], $collections['body']['collections'][1]['$id']);
@ -63,7 +63,7 @@ class DatabaseCustomServerTest extends Scope
'orderType' => 'DESC'
]);
$this->assertEquals(2, $collections['body']['sum']);
$this->assertEquals(2, $collections['body']['total']);
$this->assertEquals($base[0]['$id'], $collections['body']['collections'][0]['$id']);
$this->assertEquals($base[1]['$id'], $collections['body']['collections'][1]['$id']);
@ -135,7 +135,7 @@ class DatabaseCustomServerTest extends Scope
'search' => 'first'
]);
$this->assertEquals(1, $collections['body']['sum']);
$this->assertEquals(1, $collections['body']['total']);
$this->assertEquals('first', $collections['body']['collections'][0]['$id']);
$collections = $this->client->call(Client::METHOD_GET, '/database/collections', array_merge([
@ -145,7 +145,7 @@ class DatabaseCustomServerTest extends Scope
'search' => 'Test'
]);
$this->assertEquals(2, $collections['body']['sum']);
$this->assertEquals(2, $collections['body']['total']);
$this->assertEquals('Test 1', $collections['body']['collections'][0]['name']);
$this->assertEquals('Test 2', $collections['body']['collections'][1]['name']);
@ -156,7 +156,7 @@ class DatabaseCustomServerTest extends Scope
'search' => 'Nonexistent'
]);
$this->assertEquals(0, $collections['body']['sum']);
$this->assertEquals(0, $collections['body']['total']);
/**
* Test for FAILURE

View file

@ -32,8 +32,8 @@ trait FunctionsBase
// $this->assertEquals(200, $response['headers']['status-code']);
// $this->assertNotEmpty($response['body']['$id']);
// $this->assertEquals('Arsenal', $response['body']['name']);
// $this->assertGreaterThan(-1, $response['body']['sum']);
// $this->assertIsInt($response['body']['sum']);
// $this->assertGreaterThan(-1, $response['body']['total']);
// $this->assertIsInt($response['body']['total']);
// $this->assertIsInt($response['body']['dateCreated']);
// /**
@ -57,8 +57,8 @@ trait FunctionsBase
// ], $this->getHeaders()));
// $this->assertEquals(200, $response['headers']['status-code']);
// $this->assertGreaterThan(0, $response['body']['sum']);
// $this->assertIsInt($response['body']['sum']);
// $this->assertGreaterThan(0, $response['body']['total']);
// $this->assertIsInt($response['body']['total']);
// $this->assertCount(3, $response['body']['teams']);
// $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
@ -69,8 +69,8 @@ trait FunctionsBase
// ]);
// $this->assertEquals(200, $response['headers']['status-code']);
// $this->assertGreaterThan(0, $response['body']['sum']);
// $this->assertIsInt($response['body']['sum']);
// $this->assertGreaterThan(0, $response['body']['total']);
// $this->assertIsInt($response['body']['total']);
// $this->assertCount(2, $response['body']['teams']);
// $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
@ -81,8 +81,8 @@ trait FunctionsBase
// ]);
// $this->assertEquals(200, $response['headers']['status-code']);
// $this->assertGreaterThan(0, $response['body']['sum']);
// $this->assertIsInt($response['body']['sum']);
// $this->assertGreaterThan(0, $response['body']['total']);
// $this->assertIsInt($response['body']['total']);
// $this->assertCount(2, $response['body']['teams']);
// $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
@ -93,8 +93,8 @@ trait FunctionsBase
// ]);
// $this->assertEquals(200, $response['headers']['status-code']);
// $this->assertGreaterThan(0, $response['body']['sum']);
// $this->assertIsInt($response['body']['sum']);
// $this->assertGreaterThan(0, $response['body']['total']);
// $this->assertIsInt($response['body']['total']);
// $this->assertCount(1, $response['body']['teams']);
// $this->assertEquals('Manchester United', $response['body']['teams'][0]['name']);
@ -106,8 +106,8 @@ trait FunctionsBase
// ]);
// $this->assertEquals(200, $response['headers']['status-code']);
// $this->assertGreaterThan(0, $response['body']['sum']);
// $this->assertIsInt($response['body']['sum']);
// $this->assertGreaterThan(0, $response['body']['total']);
// $this->assertIsInt($response['body']['total']);
// $this->assertCount(1, $response['body']['teams']);
// $this->assertEquals('Manchester United', $response['body']['teams'][0]['name']);
@ -133,8 +133,8 @@ trait FunctionsBase
// $this->assertEquals(201, $response['headers']['status-code']);
// $this->assertNotEmpty($response['body']['$id']);
// $this->assertEquals('Demo', $response['body']['name']);
// $this->assertGreaterThan(-1, $response['body']['sum']);
// $this->assertIsInt($response['body']['sum']);
// $this->assertGreaterThan(-1, $response['body']['total']);
// $this->assertIsInt($response['body']['total']);
// $this->assertIsInt($response['body']['dateCreated']);
// $response = $this->client->call(Client::METHOD_PUT, '/teams/'.$response['body']['$id'], array_merge([
@ -147,8 +147,8 @@ trait FunctionsBase
// $this->assertEquals(200, $response['headers']['status-code']);
// $this->assertNotEmpty($response['body']['$id']);
// $this->assertEquals('Demo New', $response['body']['name']);
// $this->assertGreaterThan(-1, $response['body']['sum']);
// $this->assertIsInt($response['body']['sum']);
// $this->assertGreaterThan(-1, $response['body']['total']);
// $this->assertIsInt($response['body']['total']);
// $this->assertIsInt($response['body']['dateCreated']);
// /**
@ -182,8 +182,8 @@ trait FunctionsBase
// $this->assertEquals(201, $response['headers']['status-code']);
// $this->assertNotEmpty($response['body']['$id']);
// $this->assertEquals('Demo', $response['body']['name']);
// $this->assertGreaterThan(-1, $response['body']['sum']);
// $this->assertIsInt($response['body']['sum']);
// $this->assertGreaterThan(-1, $response['body']['total']);
// $this->assertIsInt($response['body']['total']);
// $this->assertIsInt($response['body']['dateCreated']);
// $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid, array_merge([

View file

@ -146,7 +146,7 @@ class FunctionsCustomServerTest extends Scope
], $this->getHeaders()));
$this->assertEquals($functions['headers']['status-code'], 200);
$this->assertEquals($functions['body']['sum'], 2);
$this->assertEquals($functions['body']['total'], 2);
$this->assertIsArray($functions['body']['functions']);
$this->assertCount(2, $functions['body']['functions']);
$this->assertEquals($functions['body']['functions'][0]['name'], 'Test');
@ -205,7 +205,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals($function['headers']['status-code'], 200);
$this->assertEquals($function['body']['name'], 'Test');
/**
* Test for FAILURE
*/
@ -281,7 +281,7 @@ class FunctionsCustomServerTest extends Scope
$folder = 'php';
$code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz";
$this->packageCode($folder);
$deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/deployments', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
@ -298,7 +298,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals('index.php', $deployment['body']['entrypoint']);
// Wait for deployment to build.
sleep(15);
sleep(30);
return array_merge($data, ['deploymentId' => $deploymentId]);
}
@ -389,7 +389,7 @@ class FunctionsCustomServerTest extends Scope
], $this->getHeaders()));
$this->assertEquals($function['headers']['status-code'], 200);
$this->assertEquals($function['body']['sum'], 2);
$this->assertEquals($function['body']['total'], 2);
$this->assertIsArray($function['body']['deployments']);
$this->assertCount(2, $function['body']['deployments']);
@ -404,7 +404,7 @@ class FunctionsCustomServerTest extends Scope
]));
$this->assertEquals($function['headers']['status-code'], 200);
$this->assertEquals(2, $function['body']['sum']);
$this->assertEquals(2, $function['body']['total']);
$this->assertIsArray($function['body']['deployments']);
$this->assertCount(2, $function['body']['deployments']);
$this->assertEquals($function['body']['deployments'][0]['$id'], $data['deploymentId']);
@ -417,7 +417,7 @@ class FunctionsCustomServerTest extends Scope
]));
$this->assertEquals($function['headers']['status-code'], 200);
$this->assertEquals(2, $function['body']['sum']);
$this->assertEquals(2, $function['body']['total']);
$this->assertIsArray($function['body']['deployments']);
$this->assertCount(2, $function['body']['deployments']);
$this->assertEquals($function['body']['deployments'][0]['$id'], $data['deploymentId']);
@ -430,7 +430,7 @@ class FunctionsCustomServerTest extends Scope
]));
$this->assertEquals($function['headers']['status-code'], 200);
$this->assertEquals(2, $function['body']['sum']);
$this->assertEquals(2, $function['body']['total']);
$this->assertIsArray($function['body']['deployments']);
$this->assertCount(2, $function['body']['deployments']);
$this->assertEquals($function['body']['deployments'][0]['$id'], $data['deploymentId']);
@ -540,7 +540,7 @@ class FunctionsCustomServerTest extends Scope
], $this->getHeaders()));
$this->assertEquals($function['headers']['status-code'], 200);
$this->assertEquals($function['body']['sum'], 1);
$this->assertEquals($function['body']['total'], 1);
$this->assertIsArray($function['body']['executions']);
$this->assertCount(1, $function['body']['executions']);
$this->assertEquals($function['body']['executions'][0]['$id'], $data['executionId']);
@ -557,8 +557,8 @@ class FunctionsCustomServerTest extends Scope
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertEquals(1, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertCount(1, $response['body']['executions']);
$this->assertEquals($data['functionId'], $response['body']['executions'][0]['functionId']);
@ -570,8 +570,8 @@ class FunctionsCustomServerTest extends Scope
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertEquals(1, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertCount(1, $response['body']['executions']);
$this->assertEquals($data['executionId'], $response['body']['executions'][0]['$id']);
@ -734,7 +734,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $deployment['headers']['status-code']);
// Allow build step to run
sleep(5);
sleep(20);
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
'content-type' => 'application/json',
@ -755,7 +755,7 @@ class FunctionsCustomServerTest extends Scope
], $this->getHeaders()));
$this->assertEquals($executions['headers']['status-code'], 200);
$this->assertEquals($executions['body']['sum'], 1);
$this->assertEquals($executions['body']['total'], 1);
$this->assertIsArray($executions['body']['executions']);
$this->assertCount(1, $executions['body']['executions']);
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
@ -870,7 +870,7 @@ class FunctionsCustomServerTest extends Scope
], $this->getHeaders()));
$this->assertEquals($executions['headers']['status-code'], 200);
$this->assertEquals($executions['body']['sum'], 1);
$this->assertEquals($executions['body']['total'], 1);
$this->assertIsArray($executions['body']['executions']);
$this->assertCount(1, $executions['body']['executions']);
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
@ -976,7 +976,7 @@ class FunctionsCustomServerTest extends Scope
], $this->getHeaders()));
$this->assertEquals($executions['headers']['status-code'], 200);
$this->assertEquals($executions['body']['sum'], 1);
$this->assertEquals($executions['body']['total'], 1);
$this->assertIsArray($executions['body']['executions']);
$this->assertCount(1, $executions['body']['executions']);
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
@ -999,7 +999,7 @@ class FunctionsCustomServerTest extends Scope
$folder = 'python';
$code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz";
$this->packageCode($folder);
$entrypoint = 'main.py';
$timeout = 2;
@ -1035,7 +1035,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $deployment['headers']['status-code']);
// Allow build step to run
sleep(10);
sleep(30);
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
'content-type' => 'application/json',
@ -1050,7 +1050,7 @@ class FunctionsCustomServerTest extends Scope
$executionId = $execution['body']['$id'] ?? '';
sleep(10);
sleep(30);
$executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([
'content-type' => 'application/json',
@ -1081,7 +1081,7 @@ class FunctionsCustomServerTest extends Scope
], $this->getHeaders()));
$this->assertEquals($executions['headers']['status-code'], 200);
$this->assertEquals($executions['body']['sum'], 1);
$this->assertEquals($executions['body']['total'], 1);
$this->assertIsArray($executions['body']['executions']);
$this->assertCount(1, $executions['body']['executions']);
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
@ -1140,7 +1140,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $deployment['headers']['status-code']);
// Allow build step to run
sleep(20);
sleep(40);
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
'content-type' => 'application/json',
@ -1186,7 +1186,7 @@ class FunctionsCustomServerTest extends Scope
], $this->getHeaders()));
$this->assertEquals($executions['headers']['status-code'], 200);
$this->assertEquals($executions['body']['sum'], 1);
$this->assertEquals($executions['body']['total'], 1);
$this->assertIsArray($executions['body']['executions']);
$this->assertCount(1, $executions['body']['executions']);
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
@ -1291,7 +1291,7 @@ class FunctionsCustomServerTest extends Scope
], $this->getHeaders()));
$this->assertEquals($executions['headers']['status-code'], 200);
$this->assertEquals($executions['body']['sum'], 1);
$this->assertEquals($executions['body']['total'], 1);
$this->assertIsArray($executions['body']['executions']);
$this->assertCount(1, $executions['body']['executions']);
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
@ -1396,7 +1396,7 @@ class FunctionsCustomServerTest extends Scope
// ], $this->getHeaders()));
// $this->assertEquals($executions['headers']['status-code'], 200);
// $this->assertEquals($executions['body']['sum'], 1);
// $this->assertEquals($executions['body']['total'], 1);
// $this->assertIsArray($executions['body']['executions']);
// $this->assertCount(1, $executions['body']['executions']);
// $this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
@ -1421,7 +1421,7 @@ class FunctionsCustomServerTest extends Scope
], $this->getHeaders()));
$this->assertEquals(200, $runtimes['headers']['status-code']);
$this->assertGreaterThan(0, $runtimes['body']['sum']);
$this->assertGreaterThan(0, $runtimes['body']['total']);
$runtime = $runtimes['body']['runtimes'][0];

View file

@ -45,7 +45,7 @@ trait LocaleBase
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertIsArray($response['body']);
$this->assertEquals(194, $response['body']['sum']);
$this->assertEquals(194, $response['body']['total']);
$this->assertEquals($response['body']['countries'][0]['name'], 'Afghanistan');
$this->assertEquals($response['body']['countries'][0]['code'], 'AF');
@ -59,7 +59,7 @@ trait LocaleBase
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertIsArray($response['body']);
$this->assertEquals(194, $response['body']['sum']);
$this->assertEquals(194, $response['body']['total']);
$this->assertEquals($response['body']['countries'][0]['name'], 'Afganistán');
$this->assertEquals($response['body']['countries'][0]['code'], 'AF');
@ -81,7 +81,7 @@ trait LocaleBase
], $this->getHeaders()));
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals(27, $response['body']['sum']);
$this->assertEquals(27, $response['body']['total']);
$this->assertIsArray($response['body']['countries']);
$this->assertEquals($response['body']['countries'][0]['name'], 'Austria');
$this->assertEquals($response['body']['countries'][0]['code'], 'AT');
@ -95,7 +95,7 @@ trait LocaleBase
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals(27, $response['body']['sum']);
$this->assertEquals(27, $response['body']['total']);
$this->assertIsArray($response['body']['countries']);
$this->assertEquals($response['body']['countries'][0]['name'], 'Alemania');
$this->assertEquals($response['body']['countries'][0]['code'], 'DE');
@ -120,7 +120,7 @@ trait LocaleBase
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertIsArray($response['body']);
$this->assertEquals(194, $response['body']['sum']);
$this->assertEquals(194, $response['body']['total']);
$this->assertIsArray($response['body']['phones']);
$this->assertEquals($response['body']['phones'][0]['code'], '+1');
$this->assertEquals($response['body']['phones'][0]['countryName'], 'Canada');
@ -144,7 +144,7 @@ trait LocaleBase
], $this->getHeaders()));
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals(7, $response['body']['sum']);
$this->assertEquals(7, $response['body']['total']);
$this->assertIsArray($response['body']['continents']);
$this->assertEquals($response['body']['continents'][0]['code'], 'AF');
$this->assertEquals($response['body']['continents'][0]['name'], 'Africa');
@ -157,7 +157,7 @@ trait LocaleBase
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals(7, $response['body']['sum']);
$this->assertEquals(7, $response['body']['total']);
$this->assertIsArray($response['body']['continents']);
$this->assertEquals($response['body']['continents'][0]['code'], 'NA');
$this->assertEquals($response['body']['continents'][0]['name'], 'América del Norte');
@ -182,7 +182,7 @@ trait LocaleBase
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertIsArray($response['body']);
$this->assertEquals(117, $response['body']['sum']);
$this->assertEquals(117, $response['body']['total']);
$this->assertEquals($response['body']['currencies'][0]['symbol'], '$');
$this->assertEquals($response['body']['currencies'][0]['name'], 'US Dollar');
@ -205,7 +205,7 @@ trait LocaleBase
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertIsArray($response['body']);
$this->assertEquals(184, $response['body']['sum']);
$this->assertEquals(184, $response['body']['total']);
$this->assertEquals($response['body']['languages'][0]['code'], 'aa');
$this->assertEquals($response['body']['languages'][0]['name'], 'Afar');
@ -251,7 +251,7 @@ trait LocaleBase
// }
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals(194, $response['body']['sum']);
$this->assertEquals(194, $response['body']['total']);
$response = $this->client->call(Client::METHOD_GET, '/locale/continents', [
'content-type' => 'application/json',
@ -268,7 +268,7 @@ trait LocaleBase
// }
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals(7, $response['body']['sum']);
$this->assertEquals(7, $response['body']['total']);
}
/**

View file

@ -110,7 +110,7 @@ class ProjectsConsoleClientTest extends Scope
]));
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals($response['body']['sum'], 1);
$this->assertEquals($response['body']['total'], 1);
$this->assertIsArray($response['body']['projects']);
$this->assertCount(1, $response['body']['projects']);
$this->assertEquals($response['body']['projects'][0]['name'], 'Project Test');
@ -123,7 +123,7 @@ class ProjectsConsoleClientTest extends Scope
]));
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals($response['body']['sum'], 1);
$this->assertEquals($response['body']['total'], 1);
$this->assertIsArray($response['body']['projects']);
$this->assertCount(1, $response['body']['projects']);
$this->assertEquals($response['body']['projects'][0]['$id'], $data['projectId']);
@ -861,7 +861,7 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), []);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertEquals(1, $response['body']['total']);
/**
* Test for FAILURE
@ -1095,7 +1095,7 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), []);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertEquals(1, $response['body']['total']);
/**
* Test for FAILURE
@ -1420,7 +1420,7 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), []);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(7, $response['body']['sum']);
$this->assertEquals(7, $response['body']['total']);
/**
* Test for FAILURE
@ -1926,7 +1926,7 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), []);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertEquals(1, $response['body']['total']);
/**
* Test for FAILURE

View file

@ -1052,7 +1052,8 @@ class RealtimeCustomClientTest extends Scope
$this->assertEquals('event', $response['type']);
$this->assertNotEmpty($response['data']);
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(3, $response['data']['channels']);
$this->assertCount(4, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
$this->assertContains('executions', $response['data']['channels']);
$this->assertContains('executions.' . $execution['body']['$id'], $response['data']['channels']);
$this->assertContains('functions.' . $execution['body']['functionId'], $response['data']['channels']);
@ -1064,7 +1065,8 @@ class RealtimeCustomClientTest extends Scope
$this->assertEquals('event', $responseUpdate['type']);
$this->assertNotEmpty($responseUpdate['data']);
$this->assertArrayHasKey('timestamp', $responseUpdate['data']);
$this->assertCount(3, $responseUpdate['data']['channels']);
$this->assertCount(4, $responseUpdate['data']['channels']);
$this->assertContains('console', $responseUpdate['data']['channels']);
$this->assertContains('executions', $responseUpdate['data']['channels']);
$this->assertContains('executions.' . $execution['body']['$id'], $responseUpdate['data']['channels']);
$this->assertContains('functions.' . $execution['body']['functionId'], $responseUpdate['data']['channels']);

View file

@ -203,7 +203,7 @@ trait StorageBase
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals(200, $files['headers']['status-code']);
$this->assertGreaterThan(0, $files['body']['sum']);
$this->assertGreaterThan(0, $files['body']['total']);
$this->assertGreaterThan(0, count($files['body']['files']));
/**

View file

@ -23,8 +23,8 @@ trait TeamsBase
$this->assertEquals(201, $response1['headers']['status-code']);
$this->assertNotEmpty($response1['body']['$id']);
$this->assertEquals('Arsenal', $response1['body']['name']);
$this->assertGreaterThan(-1, $response1['body']['sum']);
$this->assertIsInt($response1['body']['sum']);
$this->assertGreaterThan(-1, $response1['body']['total']);
$this->assertIsInt($response1['body']['total']);
$this->assertIsInt($response1['body']['dateCreated']);
$teamUid = $response1['body']['$id'];
@ -43,8 +43,8 @@ trait TeamsBase
$this->assertNotEmpty($response2['body']['$id']);
$this->assertEquals($teamId, $response2['body']['$id']);
$this->assertEquals('Manchester United', $response2['body']['name']);
$this->assertGreaterThan(-1, $response2['body']['sum']);
$this->assertIsInt($response2['body']['sum']);
$this->assertGreaterThan(-1, $response2['body']['total']);
$this->assertIsInt($response2['body']['total']);
$this->assertIsInt($response2['body']['dateCreated']);
$response3 = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
@ -58,8 +58,8 @@ trait TeamsBase
$this->assertEquals(201, $response3['headers']['status-code']);
$this->assertNotEmpty($response3['body']['$id']);
$this->assertEquals('Newcastle', $response3['body']['name']);
$this->assertGreaterThan(-1, $response3['body']['sum']);
$this->assertIsInt($response3['body']['sum']);
$this->assertGreaterThan(-1, $response3['body']['total']);
$this->assertIsInt($response3['body']['total']);
$this->assertIsInt($response3['body']['dateCreated']);
/**
@ -94,8 +94,8 @@ trait TeamsBase
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals('Arsenal', $response['body']['name']);
$this->assertGreaterThan(-1, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertGreaterThan(-1, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertIsInt($response['body']['dateCreated']);
/**
@ -119,8 +119,8 @@ trait TeamsBase
], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertGreaterThan(0, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertGreaterThan(0, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertGreaterThan(2, count($response['body']['teams']));
$response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
@ -131,8 +131,8 @@ trait TeamsBase
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertGreaterThan(0, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertGreaterThan(0, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertCount(2, $response['body']['teams']);
$response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
@ -143,8 +143,8 @@ trait TeamsBase
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertGreaterThan(0, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertGreaterThan(0, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertGreaterThan(2, $response['body']['teams']);
$response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
@ -155,8 +155,8 @@ trait TeamsBase
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertGreaterThan(0, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertGreaterThan(0, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertCount(1, $response['body']['teams']);
$this->assertEquals('Manchester United', $response['body']['teams'][0]['name']);
@ -168,8 +168,8 @@ trait TeamsBase
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertGreaterThan(0, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertGreaterThan(0, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertCount(1, $response['body']['teams']);
$this->assertEquals('Manchester United', $response['body']['teams'][0]['name']);
@ -181,8 +181,8 @@ trait TeamsBase
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertGreaterThan(0, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertGreaterThan(0, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertCount(1, $response['body']['teams']);
$this->assertEquals('Arsenal', $response['body']['teams'][0]['name']);
@ -194,8 +194,8 @@ trait TeamsBase
]);
$this->assertEquals(200, $teams['headers']['status-code']);
$this->assertGreaterThan(0, $teams['body']['sum']);
$this->assertIsInt($teams['body']['sum']);
$this->assertGreaterThan(0, $teams['body']['total']);
$this->assertIsInt($teams['body']['total']);
$this->assertCount(2, $teams['body']['teams']);
$response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
@ -207,8 +207,8 @@ trait TeamsBase
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertGreaterThan(0, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertGreaterThan(0, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertCount(1, $response['body']['teams']);
$this->assertEquals($teams['body']['teams'][1]['$id'], $response['body']['teams'][0]['$id']);
@ -222,8 +222,8 @@ trait TeamsBase
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertGreaterThan(0, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertGreaterThan(0, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertCount(1, $response['body']['teams']);
$this->assertEquals($teams['body']['teams'][0]['$id'], $response['body']['teams'][0]['$id']);
@ -258,8 +258,8 @@ trait TeamsBase
$this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals('Demo', $response['body']['name']);
$this->assertGreaterThan(-1, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertGreaterThan(-1, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertIsInt($response['body']['dateCreated']);
$response = $this->client->call(Client::METHOD_PUT, '/teams/'.$response['body']['$id'], array_merge([
@ -273,8 +273,8 @@ trait TeamsBase
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals('Demo New', $response['body']['name']);
$this->assertGreaterThan(-1, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertGreaterThan(-1, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertIsInt($response['body']['dateCreated']);
/**
@ -309,8 +309,8 @@ trait TeamsBase
$this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals('Demo', $response['body']['name']);
$this->assertGreaterThan(-1, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertGreaterThan(-1, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertIsInt($response['body']['dateCreated']);
$response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid, array_merge([

View file

@ -22,7 +22,7 @@ trait TeamsBaseClient
], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertIsInt($response['body']['sum']);
$this->assertIsInt($response['body']['total']);
$this->assertNotEmpty($response['body']['memberships'][0]['$id']);
$this->assertEquals($this->getUser()['name'], $response['body']['memberships'][0]['name']);
$this->assertEquals($this->getUser()['email'], $response['body']['memberships'][0]['email']);
@ -38,7 +38,7 @@ trait TeamsBaseClient
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertIsInt($response['body']['sum']);
$this->assertIsInt($response['body']['total']);
$this->assertNotEmpty($response['body']['memberships'][0]);
$this->assertEquals($this->getUser()['name'], $response['body']['memberships'][0]['name']);
$this->assertEquals($this->getUser()['email'], $response['body']['memberships'][0]['email']);
@ -52,7 +52,7 @@ trait TeamsBaseClient
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertIsInt($response['body']['sum']);
$this->assertIsInt($response['body']['total']);
$this->assertNotEmpty($response['body']['memberships'][0]);
$this->assertEquals($this->getUser()['name'], $response['body']['memberships'][0]['name']);
$this->assertEquals($this->getUser()['email'], $response['body']['memberships'][0]['email']);
@ -66,9 +66,9 @@ trait TeamsBaseClient
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertIsInt($response['body']['sum']);
$this->assertIsInt($response['body']['total']);
$this->assertEmpty($response['body']['memberships']);
$this->assertEquals(0, $response['body']['sum']);
$this->assertEquals(0, $response['body']['total']);
/**
* Test for FAILURE
@ -191,7 +191,7 @@ trait TeamsBaseClient
], $this->getHeaders()));
$this->assertEquals(200, $memberships['headers']['status-code']);
$this->assertIsInt($memberships['body']['sum']);
$this->assertIsInt($memberships['body']['total']);
$this->assertNotEmpty($memberships['body']['memberships']);
$this->assertCount(2, $memberships['body']['memberships']);
@ -203,7 +203,7 @@ trait TeamsBaseClient
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertIsInt($response['body']['sum']);
$this->assertIsInt($response['body']['total']);
$this->assertNotEmpty($response['body']['memberships']);
$this->assertCount(1, $response['body']['memberships']);
$this->assertEquals($memberships['body']['memberships'][1]['$id'], $response['body']['memberships'][0]['$id']);
@ -441,7 +441,7 @@ trait TeamsBaseClient
], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(2, $response['body']['sum']);
$this->assertEquals(2, $response['body']['total']);
$ownerMembershipUid = $response['body']['memberships'][0]['$id'];
@ -496,7 +496,7 @@ trait TeamsBaseClient
], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertEquals(1, $response['body']['total']);
/**
* Test for when the owner tries to delete their membership

View file

@ -22,7 +22,7 @@ trait TeamsBaseServer
], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(0, $response['body']['sum']);
$this->assertEquals(0, $response['body']['total']);
/**
* Test for FAILURE
@ -201,8 +201,8 @@ trait TeamsBaseServer
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals('Arsenal', $response['body']['name']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertEquals(1, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertIsInt($response['body']['dateCreated']);
@ -227,8 +227,8 @@ trait TeamsBaseServer
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals('Arsenal', $response['body']['name']);
$this->assertEquals(0, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertEquals(0, $response['body']['total']);
$this->assertIsInt($response['body']['total']);
$this->assertIsInt($response['body']['dateCreated']);
}

View file

@ -149,14 +149,28 @@ trait UsersBase
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'manchester-united.co.uk'
'search' => 'united.co.uk'
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertIsArray($response['body']);
$this->assertIsArray($response['body']['users']);
$this->assertIsInt($response['body']['sum']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertIsInt($response['body']['total']);
$this->assertEquals(1, $response['body']['total']);
$this->assertCount(1, $response['body']['users']);
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'man'
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertIsArray($response['body']);
$this->assertIsArray($response['body']['users']);
$this->assertIsInt($response['body']['total']);
$this->assertEquals(1, $response['body']['total']);
$this->assertCount(1, $response['body']['users']);
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
@ -165,6 +179,7 @@ trait UsersBase
], $this->getHeaders()), [
'search' => $data['userId']
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertNotEmpty($response['body']);
$this->assertNotEmpty($response['body']['users']);
@ -219,8 +234,8 @@ trait UsersBase
$this->assertEquals($users['headers']['status-code'], 200);
$this->assertIsArray($users['body']);
$this->assertIsArray($users['body']['users']);
$this->assertIsInt($users['body']['sum']);
$this->assertGreaterThan(0, $users['body']['sum']);
$this->assertIsInt($users['body']['total']);
$this->assertGreaterThan(0, $users['body']['total']);
return $data;
}
@ -443,7 +458,7 @@ trait UsersBase
$this->assertEquals($logs['headers']['status-code'], 200);
$this->assertIsArray($logs['body']['logs']);
$this->assertIsNumeric($logs['body']['sum']);
$this->assertIsNumeric($logs['body']['total']);
$logs = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([
'content-type' => 'application/json',
@ -455,7 +470,7 @@ trait UsersBase
$this->assertEquals($logs['headers']['status-code'], 200);
$this->assertIsArray($logs['body']['logs']);
$this->assertLessThanOrEqual(1, count($logs['body']['logs']));
$this->assertIsNumeric($logs['body']['sum']);
$this->assertIsNumeric($logs['body']['total']);
$logs = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([
'content-type' => 'application/json',
@ -466,7 +481,7 @@ trait UsersBase
$this->assertEquals($logs['headers']['status-code'], 200);
$this->assertIsArray($logs['body']['logs']);
$this->assertIsNumeric($logs['body']['sum']);
$this->assertIsNumeric($logs['body']['total']);
$logs = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/logs', array_merge([
'content-type' => 'application/json',
@ -479,7 +494,7 @@ trait UsersBase
$this->assertEquals($logs['headers']['status-code'], 200);
$this->assertIsArray($logs['body']['logs']);
$this->assertLessThanOrEqual(1, count($logs['body']['logs']));
$this->assertIsNumeric($logs['body']['sum']);
$this->assertIsNumeric($logs['body']['total']);
}
/**

View file

@ -544,8 +544,8 @@ trait WebhooksBase
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
$this->assertNotEmpty($webhook['data']['$id']);
$this->assertEquals('Arsenal', $webhook['data']['name']);
$this->assertGreaterThan(-1, $webhook['data']['sum']);
$this->assertIsInt($webhook['data']['sum']);
$this->assertGreaterThan(-1, $webhook['data']['total']);
$this->assertIsInt($webhook['data']['total']);
$this->assertIsInt($webhook['data']['dateCreated']);
/**
@ -584,8 +584,8 @@ trait WebhooksBase
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
$this->assertNotEmpty($webhook['data']['$id']);
$this->assertEquals('Demo New', $webhook['data']['name']);
$this->assertGreaterThan(-1, $webhook['data']['sum']);
$this->assertIsInt($webhook['data']['sum']);
$this->assertGreaterThan(-1, $webhook['data']['total']);
$this->assertIsInt($webhook['data']['total']);
$this->assertIsInt($webhook['data']['dateCreated']);
/**
@ -627,8 +627,8 @@ trait WebhooksBase
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
$this->assertNotEmpty($webhook['data']['$id']);
$this->assertEquals('Chelsea', $webhook['data']['name']);
$this->assertGreaterThan(-1, $webhook['data']['sum']);
$this->assertIsInt($webhook['data']['sum']);
$this->assertGreaterThan(-1, $webhook['data']['total']);
$this->assertIsInt($webhook['data']['total']);
$this->assertIsInt($webhook['data']['dateCreated']);
/**

View file

@ -310,7 +310,7 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
$this->assertEquals($webhook['data']['sum'], 2);
$this->assertEquals($webhook['data']['total'], 2);
$this->assertNotEmpty($webhook['data']['sessions'][1]['$id']);
$this->assertNotEmpty($webhook['data']['sessions'][1]['userId']);
$this->assertIsInt($webhook['data']['sessions'][1]['expire']);