Compare commits

..
27 changed files with 196 additions and 317 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
[submodule "app/console"]
path = app/console
url = https://github.com/appwrite/console
branch = 2.3.4
branch = 2.3.3
-7
View File
@@ -1,10 +1,3 @@
# Version 1.3.2
## Bugs
- Fixed auto-setting custom ID on nested documents [#5363](https://github.com/appwrite/appwrite/pull/5363)
- Fixed listDocuments not returning all the documents [#5395](https://github.com/appwrite/appwrite/pull/5395)
- Fixed deleting keys, webhooks, platforms and domains after deleting project [#5395](https://github.com/appwrite/appwrite/pull/5395)
# Version 1.3.1
## Bugs
+1 -1
View File
@@ -321,7 +321,7 @@ The Runtimes for all supported cloud functions (multicore builds) can be found a
The following steps are used to generate a new console SDK:
1. Update the console spec file located at `app/config/specs/swagger2-<version-number>.console.json` using Appwrite Tasks. Run the `php app/cli.php specs version=<version-number> mode=normal` command in a running `appwrite/appwrite` container.
1. Update the console spec file located at `app/config/specs/swagger2-<version-number>.console.json` using Appwrite Tasks. Run the `php app/cli.php specs <version-number> normal` command in a running `appwrite/appwrite` container.
2. Generate a new SDK using the command `php app/cli.php sdks`.
3. Change your working dir using `cd app/sdks/console-web`.
4. Build the new SDK `npm run build`.
+3 -3
View File
@@ -67,7 +67,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:1.3.2
appwrite/appwrite:1.3.1
```
### Windows
@@ -79,7 +79,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^
appwrite/appwrite:1.3.2
appwrite/appwrite:1.3.1
```
#### PowerShell
@@ -89,7 +89,7 @@ docker run -it --rm `
--volume /var/run/docker.sock:/var/run/docker.sock `
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
--entrypoint="install" `
appwrite/appwrite:1.3.2
appwrite/appwrite:1.3.1
```
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
+3 -3
View File
@@ -76,7 +76,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:1.3.2
appwrite/appwrite:1.3.1
```
### Windows
@@ -88,7 +88,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^
appwrite/appwrite:1.3.2
appwrite/appwrite:1.3.1
```
#### PowerShell
@@ -98,7 +98,7 @@ docker run -it --rm `
--volume /var/run/docker.sock:/var/run/docker.sock `
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
--entrypoint="install" `
appwrite/appwrite:1.3.2
appwrite/appwrite:1.3.1
```
Once the Docker installation is complete, go to http://localhost to access the Appwrite console from your browser. Please note that on non-Linux native hosts, the server might take a few minutes to start after completing the installation.
+1 -1
View File
@@ -102,7 +102,7 @@ return [
],
Exception::USER_ALREADY_EXISTS => [
'name' => Exception::USER_ALREADY_EXISTS,
'description' => 'A user with the same id, email, or phone already exists in your project.',
'description' => 'A user with the same email already exists in your project.',
'code' => 409,
],
Exception::USER_BLOCKED => [
+19 -19
View File
@@ -28,7 +28,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-web.git',
'gitRepoName' => 'sdk-for-web',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'master',
'demos' => [
[
'icon' => 'react.svg',
@@ -76,7 +76,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-flutter.git',
'gitRepoName' => 'sdk-for-flutter',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'master',
],
[
'key' => 'apple',
@@ -94,7 +94,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-apple.git',
'gitRepoName' => 'sdk-for-apple',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'master',
],
[
'key' => 'objective-c',
@@ -111,7 +111,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-objective-c.git',
'gitRepoName' => 'sdk-for-objective-c',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'master',
],
[
'key' => 'android',
@@ -129,7 +129,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-android.git',
'gitRepoName' => 'sdk-for-android',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'main',
'docDirectories' => [
'Kotlin' => 'kotlin',
'Java' => 'java',
@@ -196,14 +196,14 @@ return [
'prism' => 'javascript',
'source' => \realpath(__DIR__ . '/../sdks/console-web'),
'gitUrl' => 'git@github.com:appwrite/sdk-for-console.git',
'gitBranch' => 'dev',
'gitBranch' => 'main',
'gitRepoName' => 'sdk-for-console',
'gitUserName' => 'appwrite',
],
[
'key' => 'cli',
'name' => 'Command Line',
'version' => '2.0.2',
'version' => '2.0.0',
'url' => 'https://github.com/appwrite/sdk-for-cli',
'package' => 'https://www.npmjs.com/package/appwrite-cli',
'enabled' => true,
@@ -216,7 +216,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-cli.git',
'gitRepoName' => 'sdk-for-cli',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'master',
],
],
],
@@ -244,7 +244,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-node.git',
'gitRepoName' => 'sdk-for-node',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'master',
],
[
'key' => 'deno',
@@ -262,7 +262,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-deno.git',
'gitRepoName' => 'sdk-for-deno',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'master',
],
[
'key' => 'php',
@@ -280,7 +280,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-php.git',
'gitRepoName' => 'sdk-for-php',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'master',
],
[
'key' => 'python',
@@ -298,7 +298,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-python.git',
'gitRepoName' => 'sdk-for-python',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'master',
],
[
'key' => 'ruby',
@@ -316,7 +316,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-ruby.git',
'gitRepoName' => 'sdk-for-ruby',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'master',
],
[
'key' => 'go',
@@ -334,7 +334,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-go.git',
'gitRepoName' => 'sdk-for-go',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'master',
],
[
'key' => 'java',
@@ -352,7 +352,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-java.git',
'gitRepoName' => 'sdk-for-java',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'master',
],
[
'key' => 'dotnet',
@@ -370,7 +370,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-dotnet.git',
'gitRepoName' => 'sdk-for-dotnet',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'main',
],
[
'key' => 'dart',
@@ -388,7 +388,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-dart.git',
'gitRepoName' => 'sdk-for-dart',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'master',
],
[
'key' => 'kotlin',
@@ -406,7 +406,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-kotlin.git',
'gitRepoName' => 'sdk-for-kotlin',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'main',
'docDirectories' => [
'Kotlin' => 'kotlin',
'Java' => 'java',
@@ -428,7 +428,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-swift.git',
'gitRepoName' => 'sdk-for-swift',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'gitBranch' => 'main',
],
[
'key' => 'graphql',
+60 -72
View File
@@ -743,7 +743,7 @@ App::post('/v1/databases/:databaseId/collections')
]));
$collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId);
$dbForProject->createCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), permissions: $permissions ?? [], documentSecurity: $documentSecurity);
$dbForProject->createCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId());
} catch (DuplicateException) {
throw new Exception(Exception::COLLECTION_ALREADY_EXISTS);
} catch (LimitException) {
@@ -1001,7 +1001,6 @@ App::put('/v1/databases/:databaseId/collections/:collectionId')
->setAttribute('documentSecurity', $documentSecurity)
->setAttribute('enabled', $enabled)
->setAttribute('search', implode(' ', [$collectionId, $name])));
$dbForProject->updateCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $permissions, $documentSecurity);
} catch (AuthorizationException) {
throw new Exception(Exception::USER_UNAUTHORIZED);
} catch (StructureException $exception) {
@@ -2400,7 +2399,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
$attributeIndex = \array_search($attribute, array_column($oldAttributes, 'key'));
if ($attributeIndex === false) {
throw new Exception(Exception::ATTRIBUTE_UNKNOWN, 'Unknown attribute: ' . $attribute);
throw new Exception(Exception::ATTRIBUTE_UNKNOWN, 'Unknown attribute: ' . $attribute . '. Verify the attribute name or create the attribute.");
}
$attributeStatus = $oldAttributes[$attributeIndex]['status'];
@@ -2744,13 +2743,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
if (empty($related)) {
continue;
}
$isList = \is_array($related) && \array_values($related) === $related;
if ($isList) {
$relations = $related;
} else {
$relations = [$related];
if (!\is_array($related)) {
$related = [$related];
}
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
@@ -2758,15 +2752,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId)
);
foreach ($relations as &$relation) {
if (
\is_array($relation)
&& \array_values($relation) !== $relation
&& !isset($relation['$id'])
) {
$relation['$id'] = ID::unique();
$relation = new Document($relation);
}
foreach ($related as $relation) {
if ($relation instanceof Document) {
$current = Authorization::skip(
fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), $relation->getId())
@@ -2775,7 +2761,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
if ($current->isEmpty()) {
$type = Database::PERMISSION_CREATE;
if (isset($relation['$id']) && $relation['$id'] === 'unique()') {
if (!isset($relation['$id']) || $relation['$id'] === 'unique()') {
$relation['$id'] = ID::unique();
}
} else {
@@ -2788,12 +2774,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
$checkPermissions($relatedCollection, $relation, $type);
}
}
if ($isList) {
$document->setAttribute($relationship->getAttribute('key'), \array_values($relations));
} else {
$document->setAttribute($relationship->getAttribute('key'), \reset($relations));
}
}
};
@@ -2886,17 +2866,10 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
$collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId));
if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
if (!$collection->getAttribute('documentSecurity', false)) {
$validator = new Authorization(Database::PERMISSION_READ);
if (!$validator->isValid($collection->getRead())) {
$collection = new Document();
}
}
}
if ($collection->isEmpty() || !$collection->getAttribute('enabled')) {
throw new Exception(Exception::COLLECTION_NOT_FOUND);
if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
throw new Exception(Exception::COLLECTION_NOT_FOUND);
}
}
// Validate queries
@@ -2925,16 +2898,34 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
$filterQueries = Query::groupByType($queries)['filters'];
$documents = $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries);
$total = $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT);
$documents = Authorization::skip(fn () => $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries));
$documentSecurity = $collection->getAttribute('documentSecurity', false);
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($collection->getRead());
if (!$valid) {
$total = $documentSecurity
? $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT)
: 0;
} else {
$total = Authorization::skip(fn() => $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT));
}
// Add $collectionId and $databaseId for all documents
$processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database): bool {
if ($document->isEmpty()) {
$documentSecurity = $collection->getAttribute('documentSecurity', false);
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($collection->getRead());
if (!$documentSecurity && !$valid) {
return false;
}
$valid = $valid || $validator->isValid($document->getRead());
if ($documentSecurity && !$valid) {
return false;
}
$document->removeAttribute('$collection');
$document->setAttribute('$databaseId', $database->getId());
$document->setAttribute('$collectionId', $collection->getId());
@@ -2978,10 +2969,18 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
};
// The linter is forcing this indentation
foreach ($documents as $document) {
$processDocument($collection, $document);
foreach ($documents as $index => $document) {
if (!$processDocument($collection, $document)) {
unset($documents[$index]);
if ($valid) {
$total--;
}
}
}
$documents = \array_values($documents);
$response->dynamic(new Document([
'total' => $total,
'documents' => $documents,
@@ -3036,7 +3035,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
$queries = Query::parseQueries($queries);
$document = $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId, $queries);
$document = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId, $queries));
if ($document->isEmpty()) {
throw new Exception(Exception::DOCUMENT_NOT_FOUND);
@@ -3044,8 +3043,17 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
// Add $collectionId and $databaseId for all documents
$processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) {
if ($document->isEmpty()) {
return;
$documentSecurity = $collection->getAttribute('documentSecurity', false);
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($collection->getRead());
if (!$documentSecurity && !$valid) {
throw new Exception(Exception::DOCUMENT_NOT_FOUND);
}
$valid = $valid || $validator->isValid($document->getRead());
if ($documentSecurity && !$valid) {
throw new Exception(Exception::DOCUMENT_NOT_FOUND);
}
$document->setAttribute('$databaseId', $database->getId());
@@ -3279,6 +3287,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$permissions = $document->getPermissions() ?? [];
}
$data = \array_merge($document->getArrayCopy(), $data);
$data['$collection'] = $collection->getId(); // Make sure user doesn't switch collectionID
$data['$createdAt'] = $document->getCreatedAt(); // Make sure user doesn't switch createdAt
$data['$id'] = $document->getId(); // Make sure user doesn't switch document unique ID
@@ -3312,13 +3321,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
if (empty($related)) {
continue;
}
$isList = \is_array($related) && \array_values($related) === $related;
if ($isList) {
$relations = $related;
} else {
$relations = [$related];
if (!\is_array($related)) {
$related = [$related];
}
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
@@ -3326,15 +3330,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId)
);
foreach ($relations as &$relation) {
if (
\is_array($relation)
&& \array_values($relation) !== $relation
&& !isset($relation['$id'])
) {
$relation['$id'] = ID::unique();
$relation = new Document($relation);
}
foreach ($related as $relation) {
if ($relation instanceof Document) {
$oldDocument = Authorization::skip(fn() => $dbForProject->getDocument(
'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(),
@@ -3344,7 +3340,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
if ($oldDocument->isEmpty()) {
$type = Database::PERMISSION_CREATE;
if (isset($relation['$id']) && $relation['$id'] === 'unique()') {
if (!isset($relation['$id']) || $relation['$id'] === 'unique()') {
$relation['$id'] = ID::unique();
}
} else {
@@ -3357,28 +3353,20 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$checkPermissions($relatedCollection, $relation, $oldDocument, $type);
}
}
if ($isList) {
$document->setAttribute($relationship->getAttribute('key'), \array_values($relations));
} else {
$document->setAttribute($relationship->getAttribute('key'), \reset($relations));
}
}
};
$checkPermissions($collection, $newDocument, $document, Database::PERMISSION_UPDATE);
$newDocument = new Document(\array_merge($document->getArrayCopy(), $data));
try {
$document = $dbForProject->withRequestTimestamp(
$document = Authorization::skip(fn() => $dbForProject->withRequestTimestamp(
$requestTimestamp,
fn () => $dbForProject->updateDocument(
'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
$document->getId(),
$newDocument
)
);
));
} catch (AuthorizationException) {
throw new Exception(Exception::USER_UNAUTHORIZED);
} catch (DuplicateException) {
+1 -1
View File
@@ -1237,7 +1237,7 @@ App::get('/v1/projects/:projectId/platforms')
}
$platforms = $dbForConsole->find('platforms', [
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectId', [$project->getId()]),
Query::limit(5000),
]);
+6
View File
@@ -115,6 +115,12 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
if (!$dbForConsole->getCollection($key)->isEmpty()) {
continue;
}
/**
* Skip to prevent 0.16 migration issues.
*/
if (in_array($key, ['cache', 'variables']) && $dbForConsole->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), 'bucket_1')) {
continue;
}
Console::success('[Setup] - Creating collection: ' . $collection['$id'] . '...');
+1 -1
View File
@@ -101,7 +101,7 @@ const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return
const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
const APP_CACHE_BUSTER = 503;
const APP_VERSION_STABLE = '1.3.2';
const APP_VERSION_STABLE = '1.3.1';
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
+5 -5
View File
@@ -95,9 +95,9 @@ $cli
if (is_null($value)) {
continue;
}
foreach ($vars as $i => $var) {
foreach ($vars as &$var) {
if ($var['name'] === $key) {
$vars[$i]['default'] = $value;
$var['default'] = $value;
}
}
}
@@ -114,9 +114,9 @@ $cli
if (is_null($value)) {
continue;
}
foreach ($vars as $i => $var) {
foreach ($vars as &$var) {
if ($var['name'] === $key) {
$vars[$i]['default'] = $value;
$var['default'] = $value;
}
}
}
@@ -146,7 +146,7 @@ $cli
$input = [];
foreach ($vars as $var) {
foreach ($vars as $key => $var) {
if (!empty($var['filter']) && ($interactive !== 'Y' || !Console::isInteractive())) {
if ($data && $var['default'] !== null) {
$input[$var['name']] = $var['default'];
+2 -2
View File
@@ -239,8 +239,8 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
cd ' . $target . ' && \
git init --initial-branch=' . $gitBranch . ' && \
git remote add origin ' . $gitUrl . ' && \
git fetch origin ' . $gitBranch . ' && \
git pull origin ' . $gitBranch . ' && \
git fetch && \
git pull ' . $gitUrl . ' && \
rm -rf ' . $target . '/* && \
cp -r ' . $result . '/* ' . $target . '/ && \
git add . && \
+3 -23
View File
@@ -9,6 +9,7 @@ use Utopia\Database\Document;
use Utopia\Database\Query;
use Appwrite\Resque\Worker;
use Executor\Executor;
use Utopia\Storage\Device\Local;
use Utopia\Abuse\Abuse;
use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\CLI\Console;
@@ -290,13 +291,12 @@ class DeletesV1 extends Worker
protected function deleteProject(Document $document): void
{
$projectId = $document->getId();
$projectInternalId = $document->getInternalId();
// Delete project certificates
// Delete project domains and certificates
$dbForConsole = $this->getConsoleDB();
$domains = $dbForConsole->find('domains', [
Query::equal('projectInternalId', [$projectInternalId])
Query::equal('projectInternalId', [$document->getInternalId()])
]);
foreach ($domains as $domain) {
@@ -318,26 +318,6 @@ class DeletesV1 extends Worker
}
}
// Delete Platforms
$this->deleteByGroup('platforms', [
Query::equal('projectInternalId', [$projectInternalId])
], $dbForConsole);
// Delete Domains
$this->deleteByGroup('domains', [
Query::equal('projectInternalId', [$projectInternalId])
], $dbForConsole);
// Delete Keys
$this->deleteByGroup('keys', [
Query::equal('projectInternalId', [$projectInternalId])
], $dbForConsole);
// Delete Webhooks
$this->deleteByGroup('webhooks', [
Query::equal('projectInternalId', [$projectInternalId])
], $dbForConsole);
// Delete metadata tables
try {
$dbForProject->deleteCollection('_metadata');
+11 -15
View File
@@ -82,22 +82,18 @@ class FunctionsV1 extends Worker
Console::success('Iterating function: ' . $function->getAttribute('name'));
try {
$this->execute(
project: $project,
function: $function,
dbForProject: $database,
trigger: 'event',
// Pass first, most verbose event pattern
event: $events[0],
eventData: $payload,
user: $user
);
$this->execute(
project: $project,
function: $function,
dbForProject: $database,
trigger: 'event',
// Pass first, most verbose event pattern
event: $events[0],
eventData: $payload,
user: $user
);
Console::success('Triggered function: ' . $events[0]);
} catch (\Throwable $th) {
Console::error("Failed to execute " . $function->getId() . " with error: " . $th->getMessage());
}
Console::success('Triggered function: ' . $events[0]);
}
}
+3 -3
View File
@@ -43,13 +43,13 @@
"ext-sockets": "*",
"appwrite/php-clamav": "1.1.*",
"appwrite/php-runtimes": "0.11.*",
"utopia-php/abuse": "0.25.*",
"utopia-php/abuse": "0.24.*",
"utopia-php/analytics": "0.2.*",
"utopia-php/audit": "0.26.*",
"utopia-php/audit": "0.25.*",
"utopia-php/cache": "0.8.*",
"utopia-php/cli": "0.13.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.36.*",
"utopia-php/database": "0.35.*",
"utopia-php/domains": "1.1.*",
"utopia-php/framework": "0.28.*",
"utopia-php/image": "0.5.*",
Generated
+66 -63
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": "169ab6e7dd540e45309d3c5093506fad",
"content-hash": "87de4ea3130e576470a63b21628e30fb",
"packages": [
{
"name": "adhocore/jwt",
@@ -300,16 +300,16 @@
},
{
"name": "colinmollenhour/credis",
"version": "v1.15.0",
"version": "v1.14.0",
"source": {
"type": "git",
"url": "https://github.com/colinmollenhour/credis.git",
"reference": "28810439de1d9597b7ba11794ed9479fb6f3de7c"
"reference": "dccc8a46586475075fbb012d8bd523b8a938c2dc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/colinmollenhour/credis/zipball/28810439de1d9597b7ba11794ed9479fb6f3de7c",
"reference": "28810439de1d9597b7ba11794ed9479fb6f3de7c",
"url": "https://api.github.com/repos/colinmollenhour/credis/zipball/dccc8a46586475075fbb012d8bd523b8a938c2dc",
"reference": "dccc8a46586475075fbb012d8bd523b8a938c2dc",
"shasum": ""
},
"require": {
@@ -341,9 +341,9 @@
"homepage": "https://github.com/colinmollenhour/credis",
"support": {
"issues": "https://github.com/colinmollenhour/credis/issues",
"source": "https://github.com/colinmollenhour/credis/tree/v1.15.0"
"source": "https://github.com/colinmollenhour/credis/tree/v1.14.0"
},
"time": "2023-04-18T15:34:23+00:00"
"time": "2022-11-09T01:18:39+00:00"
},
{
"name": "composer/package-versions-deprecated",
@@ -481,22 +481,22 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "7.5.1",
"version": "7.5.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "b964ca597e86b752cd994f27293e9fa6b6a95ed9"
"reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b964ca597e86b752cd994f27293e9fa6b6a95ed9",
"reference": "b964ca597e86b752cd994f27293e9fa6b6a95ed9",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b50a2a1251152e43f6a37f0fa053e730a67d25ba",
"reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.5",
"guzzlehttp/psr7": "^1.9.1 || ^2.4.5",
"guzzlehttp/psr7": "^1.9 || ^2.4",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
@@ -589,7 +589,7 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.5.1"
"source": "https://github.com/guzzle/guzzle/tree/7.5.0"
},
"funding": [
{
@@ -605,7 +605,7 @@
"type": "tidelift"
}
],
"time": "2023-04-17T16:30:08+00:00"
"time": "2022-08-28T15:39:27+00:00"
},
{
"name": "guzzlehttp/promises",
@@ -693,22 +693,22 @@
},
{
"name": "guzzlehttp/psr7",
"version": "2.5.0",
"version": "2.4.4",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "b635f279edd83fc275f822a1188157ffea568ff6"
"reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6",
"reference": "b635f279edd83fc275f822a1188157ffea568ff6",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
"reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.1 || ^2.0",
"psr/http-message": "^1.0",
"ralouphie/getallheaders": "^3.0"
},
"provide": {
@@ -728,6 +728,9 @@
"bamarni-bin": {
"bin-links": true,
"forward-command": false
},
"branch-alias": {
"dev-master": "2.4-dev"
}
},
"autoload": {
@@ -789,7 +792,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.5.0"
"source": "https://github.com/guzzle/psr7/tree/2.4.4"
},
"funding": [
{
@@ -805,7 +808,7 @@
"type": "tidelift"
}
],
"time": "2023-04-17T16:11:26+00:00"
"time": "2023-03-09T13:19:02+00:00"
},
{
"name": "influxdb/influxdb-php",
@@ -1369,16 +1372,16 @@
},
{
"name": "psr/http-message",
"version": "2.0",
"version": "1.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"shasum": ""
},
"require": {
@@ -1387,7 +1390,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
"dev-master": "1.1.x-dev"
}
},
"autoload": {
@@ -1402,7 +1405,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
@@ -1416,9 +1419,9 @@
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/2.0"
"source": "https://github.com/php-fig/http-message/tree/1.1"
},
"time": "2023-04-04T09:54:51+00:00"
"time": "2023-04-04T09:50:52+00:00"
},
{
"name": "psr/log",
@@ -1805,26 +1808,26 @@
},
{
"name": "utopia-php/abuse",
"version": "0.25.0",
"version": "0.24.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "49a180cab5316cddec9676d900d5112d03e97ffc"
"reference": "403641f16a53b81ac40b91111a86e5672da49e8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/49a180cab5316cddec9676d900d5112d03e97ffc",
"reference": "49a180cab5316cddec9676d900d5112d03e97ffc",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/403641f16a53b81ac40b91111a86e5672da49e8c",
"reference": "403641f16a53b81ac40b91111a86e5672da49e8c",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-pdo": "*",
"php": ">=8.0",
"utopia-php/database": "0.36.*"
"utopia-php/database": "0.35.*"
},
"require-dev": {
"laravel/pint": "1.5.*",
"laravel/pint": "1.2.*",
"phpstan/phpstan": "^1.9",
"phpunit/phpunit": "^9.4"
},
@@ -1848,9 +1851,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.25.0"
"source": "https://github.com/utopia-php/abuse/tree/0.24.0"
},
"time": "2023-04-27T15:43:47+00:00"
"time": "2023-04-11T05:31:55+00:00"
},
{
"name": "utopia-php/analytics",
@@ -1909,24 +1912,24 @@
},
{
"name": "utopia-php/audit",
"version": "0.26.0",
"version": "0.25.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "e7228080f14df28737fbb050c180c26d86ac0403"
"reference": "adc209f2e16878e5468f0b9cfd9f7f7ab497db31"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/e7228080f14df28737fbb050c180c26d86ac0403",
"reference": "e7228080f14df28737fbb050c180c26d86ac0403",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/adc209f2e16878e5468f0b9cfd9f7f7ab497db31",
"reference": "adc209f2e16878e5468f0b9cfd9f7f7ab497db31",
"shasum": ""
},
"require": {
"php": ">=8.0",
"utopia-php/database": "0.36.*"
"utopia-php/database": "0.35.*"
},
"require-dev": {
"laravel/pint": "1.5.*",
"laravel/pint": "1.2.*",
"phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^9.3"
},
@@ -1950,9 +1953,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.26.0"
"source": "https://github.com/utopia-php/audit/tree/0.25.0"
},
"time": "2023-04-27T15:43:50+00:00"
"time": "2023-04-11T05:31:15+00:00"
},
{
"name": "utopia-php/cache",
@@ -2109,16 +2112,16 @@
},
{
"name": "utopia-php/database",
"version": "0.36.1",
"version": "0.35.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "f6ab65e59a199da5155c114564077b1ab8c4daef"
"reference": "f162c142fd61753c4b413b15c3c4041f3cd00bb2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/f6ab65e59a199da5155c114564077b1ab8c4daef",
"reference": "f6ab65e59a199da5155c114564077b1ab8c4daef",
"url": "https://api.github.com/repos/utopia-php/database/zipball/f162c142fd61753c4b413b15c3c4041f3cd00bb2",
"reference": "f162c142fd61753c4b413b15c3c4041f3cd00bb2",
"shasum": ""
},
"require": {
@@ -2161,9 +2164,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.36.1"
"source": "https://github.com/utopia-php/database/tree/0.35.0"
},
"time": "2023-04-27T08:39:55+00:00"
"time": "2023-04-11T04:02:22+00:00"
},
{
"name": "utopia-php/domains",
@@ -3034,16 +3037,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "0.32.2",
"version": "0.32.1",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "cdec289bcf38c99d0074414d2438e9967d0c9699"
"reference": "ba1d7afd57e3baef06c04ce6abc26f79310146df"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/cdec289bcf38c99d0074414d2438e9967d0c9699",
"reference": "cdec289bcf38c99d0074414d2438e9967d0c9699",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/ba1d7afd57e3baef06c04ce6abc26f79310146df",
"reference": "ba1d7afd57e3baef06c04ce6abc26f79310146df",
"shasum": ""
},
"require": {
@@ -3079,9 +3082,9 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
"source": "https://github.com/appwrite/sdk-generator/tree/0.32.2"
"source": "https://github.com/appwrite/sdk-generator/tree/0.32.1"
},
"time": "2023-04-12T21:06:57+00:00"
"time": "2023-04-12T04:43:07+00:00"
},
{
"name": "doctrine/deprecations",
@@ -3784,16 +3787,16 @@
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.20.3",
"version": "1.18.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "6c04009f6cae6eda2f040745b6b846080ef069c2"
"reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6c04009f6cae6eda2f040745b6b846080ef069c2",
"reference": "6c04009f6cae6eda2f040745b6b846080ef069c2",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/22dcdfd725ddf99583bfe398fc624ad6c5004a0f",
"reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f",
"shasum": ""
},
"require": {
@@ -3823,9 +3826,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.20.3"
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.18.1"
},
"time": "2023-04-25T09:01:03+00:00"
"time": "2023-04-07T11:51:11+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -1 +0,0 @@
appwrite console variables
+1 -1
View File
@@ -1 +1 @@
Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](/docs/server/databases#databasesCreateCollection) API or directly from your database console.
Create a new document. Before using this route, you should create a new collection and at least one attribute using either a [server integration](/docs/server/databases#databasesCreateCollection) API or directly from the Appwrite Console.
+1 -1
View File
@@ -33,7 +33,7 @@ Next we need to add a hook to save cookies when our app is opened by its callbac
> If you're using UIKit, you can skip this section.
In SwiftUI this is as simple as ensuring `.registerOAuthHandler()` is called on the `View` you want to invoke an OAuth request from.
In SwiftUI this is as simple as ensuring `.registerOAuthHanlder()` is called on the `View` you want to invoke an OAuth request from.
### Updating the SceneDelegate for UIKit
-10
View File
@@ -37,9 +37,6 @@ abstract class Migration
*/
protected Database $consoleDB;
/**
* @var \PDO
*/
protected \PDO $pdo;
/**
@@ -57,7 +54,6 @@ abstract class Migration
'1.2.1' => 'V17',
'1.3.0' => 'V18',
'1.3.1' => 'V18',
'1.3.2' => 'V18',
];
/**
@@ -106,12 +102,6 @@ abstract class Migration
return $this;
}
/**
* Set PDO for Migration.
*
* @param \PDO $pdo
* @return \Appwrite\Migration\Migration
*/
public function setPDO(\PDO $pdo): self
{
$this->pdo = $pdo;
-39
View File
@@ -6,8 +6,6 @@ use Appwrite\Migration\Migration;
use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
class V18 extends Migration
{
@@ -27,7 +25,6 @@ class V18 extends Migration
Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')');
$this->projectDB->setNamespace("_{$this->project->getInternalId()}");
$this->addDocumentSecurityToProject();
Console::info('Migrating Databases');
$this->migrateDatabases();
@@ -61,15 +58,6 @@ class V18 extends Migration
}
$this->changeAttributeInternalType($collectionTable, $attribute['key'], 'DOUBLE');
}
try {
$documentSecurity = $collection->getAttribute('documentSecurity', false);
$permissions = $collection->getPermissions();
$this->projectDB->updateCollection($collectionTable, $permissions, $documentSecurity);
} catch (\Throwable $th) {
Console::warning($th->getMessage());
}
}
}
}
@@ -93,12 +81,6 @@ class V18 extends Migration
$this->changeAttributeInternalType($id, $attribute['$id'], 'DOUBLE');
}
try {
$this->projectDB->updateCollection($id, [Permission::create(Role::any())], true);
} catch (\Throwable $th) {
Console::warning($th->getMessage());
}
switch ($id) {
case 'users':
try {
@@ -186,25 +168,4 @@ class V18 extends Migration
return $document;
}
protected function addDocumentSecurityToProject(): void
{
try {
/**
* Create 'documentSecurity' column
*/
$this->pdo->prepare("ALTER TABLE `{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}__metadata` ADD COLUMN IF NOT EXISTS documentSecurity TINYINT(1);")->execute();
} catch (\Throwable $th) {
Console::warning($th->getMessage());
}
try {
/**
* Set 'documentSecurity' column to 1 if NULL
*/
$this->pdo->prepare("UPDATE `{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}__metadata` SET documentSecurity = 1 WHERE documentSecurity IS NULL")->execute();
} catch (\Throwable $th) {
Console::warning($th->getMessage());
}
}
}
@@ -18,10 +18,10 @@ class AttributeDatetime extends Attribute
'example' => 'birthDay',
])
->addRule('type', [
'type' => self::TYPE_STRING,
'type' => self::TYPE_DATETIME,
'description' => 'Attribute type.',
'default' => '',
'example' => self::TYPE_DATETIME,
'example' => self::TYPE_DATETIME_EXAMPLE,
])
->addRule('format', [
'type' => self::TYPE_DATETIME,
@@ -4,7 +4,6 @@ namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\Response\Model;
use Utopia\Database\Document;
class Team extends Model
{
@@ -50,24 +49,6 @@ class Team extends Model
;
}
/**
* Process Document before returning it to the client
*
* @return Document
*/
public function filter(Document $document): Document
{
$prefs = $document->getAttribute('prefs');
if ($prefs instanceof Document) {
$prefs = $prefs->getArrayCopy();
}
if (is_array($prefs) && empty($prefs)) {
$document->setAttribute('prefs', new \stdClass());
}
return $document;
}
/**
* Get Name
*
+4 -22
View File
@@ -2853,7 +2853,9 @@ trait DatabasesBase
]);
// Current user has no collection permissions and document permissions are disabled
$this->assertEquals(404, $documentsUser2['headers']['status-code']);
$this->assertEquals(200, $documentsUser2['headers']['status-code']);
$this->assertEquals(0, $documentsUser2['body']['total']);
$this->assertEquals(true, empty($documentsUser2['body']['documents']));
// Enable document permissions
$collection = $this->client->call(CLient::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $collectionId, [
@@ -3337,26 +3339,6 @@ trait DatabasesBase
$this->assertEquals('Library 1', $person1['body']['library']['libraryName']);
// Create without nested ID
$person2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'documentId' => ID::unique(),
'data' => [
'library' => [
'libraryName' => 'Library 2',
],
],
'permissions' => [
Permission::read(Role::user($this->getUser()['$id'])),
Permission::update(Role::user($this->getUser()['$id'])),
Permission::delete(Role::user($this->getUser()['$id'])),
]
]);
$this->assertEquals('Library 2', $person2['body']['library']['libraryName']);
// Ensure IDs were set and internal IDs removed
$this->assertEquals($databaseId, $person1['body']['$databaseId']);
$this->assertEquals($databaseId, $person1['body']['library']['$databaseId']);
@@ -3919,7 +3901,7 @@ trait DatabasesBase
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(2, count($response['body']['documents']));
$this->assertEquals(1, count($response['body']['documents']));
$this->assertEquals(null, $response['body']['documents'][0]['fullName']);
$this->assertArrayNotHasKey("libraries", $response['body']['documents'][0]);
}
@@ -176,7 +176,7 @@ class DatabasesPermissionsTeamTest extends Scope
if ($success) {
$this->assertCount(1, $documents['body']['documents']);
} else {
$this->assertEquals(404, $documents['headers']['status-code']);
$this->assertCount(0, $documents['body']['documents']);
}
}