diff --git a/README-CN.md b/README-CN.md
index cdc5d90bfc..5c4ce54433 100644
--- a/README-CN.md
+++ b/README-CN.md
@@ -1,6 +1,3 @@
-
- 🌍 其他语言
-
@@ -19,6 +16,8 @@
[](docs/tutorials/add-translations.md)
[](https://store.appwrite.io)
+[English](README.md) | 简体中文
+
Appwrite是一个基于dcoker的端到端开发者平台,其容器化的微服务库可应用于网页端,移动端,以及后端。Appwrite 通过视觉化界面极简了从零编写 API 的繁琐过程,在保证软件安全的前提下为开发者创造了一个高效的开发环境。
Appwrite 可以提供给开发者用户验证,外部授权,用户数据读写检索,文件储存, 图像处理,云函数计算,[等多种服务](https:/ /appwrite.io/docs)。
@@ -169,8 +168,4 @@ Appwrite API 界面层利用后台缓存和任务委派来提供极速的响应
## 版权说明
-版权详情,访问 [BSD 3-Clause License](./LICENSE)。
-
-## 其他语言
-- [English](README.md)
-- [简体中文](README-CN.md)
\ No newline at end of file
+版权详情,访问 [BSD 3-Clause License](./LICENSE)。
\ No newline at end of file
diff --git a/README.md b/README.md
index 71196afdc2..3d1a0db74f 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,3 @@
-
- 🌍 Translations
-
@@ -19,6 +16,8 @@
[](docs/tutorials/add-translations.md)
[](https://store.appwrite.io)
+English | [简体中文](README-CN.md)
+
[**Appwrite 0.12 has been released! Learn what's new!**](https://dev.to/appwrite/its-here-announcing-the-release-of-appwrite-012-5c8b)
Appwrite is an end-to-end backend server for Web, Mobile, Native, or Backend apps packaged as a set of Docker microservices. Appwrite abstracts the complexity and repetitiveness required to build a modern backend API from scratch and allows you to build secure apps faster.
@@ -172,8 +171,4 @@ Join our growing community around the world! See our official [Blog](https://med
## License
-This repository is available under the [BSD 3-Clause License](./LICENSE).
-
-## Translations
-- [English](README.md)
-- [简体中文](README-CN.md)
+This repository is available under the [BSD 3-Clause License](./LICENSE).
\ No newline at end of file
diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php
index 9d5ac716b3..da3cfc68b0 100644
--- a/app/controllers/api/database.php
+++ b/app/controllers/api/database.php
@@ -166,8 +166,6 @@ App::post('/v1/database/collections')
$collectionId = $collectionId == 'unique()' ? $dbForProject->getId() : $collectionId;
try {
- $dbForProject->createCollection('collection_' . $collectionId);
-
$collection = $dbForProject->createDocument('collections', new Document([
'$id' => $collectionId,
'$read' => $read ?? [], // Collection permissions for collection documents (based on permission model)
@@ -179,8 +177,12 @@ App::post('/v1/database/collections')
'name' => $name,
'search' => implode(' ', [$collectionId, $name]),
]));
+
+ $dbForProject->createCollection('collection_' . $collectionId);
} catch (DuplicateException $th) {
throw new Exception('Collection already exists', 409);
+ } catch (LimitException $th) {
+ throw new Exception('Collection limit exceeded', 400);
}
$audits
diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php
index d9809bf305..0a5133d6b9 100644
--- a/app/controllers/api/teams.php
+++ b/app/controllers/api/teams.php
@@ -16,6 +16,7 @@ use Utopia\Validator\ArrayList;
use Utopia\Validator\WhiteList;
use Utopia\Database\Database;
use Utopia\Database\Document;
+use Utopia\Database\Exception\Authorization as AuthorizationException;
use Utopia\Database\Exception\Duplicate;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
@@ -761,7 +762,11 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
throw new Exception('Team not found', 404);
}
- if (!$dbForProject->deleteDocument('memberships', $membership->getId())) {
+ try {
+ $dbForProject->deleteDocument('memberships', $membership->getId());
+ } catch (AuthorizationException $exception) {
+ throw new Exception('Unauthorized permissions', 401);
+ } catch (\Exception $exception) {
throw new Exception('Failed to remove membership from DB', 500);
}
@@ -782,7 +787,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
if ($membership->getAttribute('confirm')) { // Count only confirmed members
$team->setAttribute('sum', \max($team->getAttribute('sum', 0) - 1, 0));
- $team = $dbForProject->updateDocument('teams', $team->getId(), $team);
+ Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team));
}
$audits
diff --git a/composer.lock b/composer.lock
index bf92c77845..2ae45c3928 100644
--- a/composer.lock
+++ b/composer.lock
@@ -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": "368924595cfbf7dc32394c09481df6c3",
+ "content-hash": "d9d66a3e700bc3936fe9a09f3c1b38f9",
"packages": [
{
"name": "adhocore/jwt",
@@ -2141,16 +2141,16 @@
},
{
"name": "utopia-php/database",
- "version": "0.14.0",
+ "version": "0.14.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
- "reference": "2f2527bb080cf578fba327ea2ec637064561d403"
+ "reference": "ecc143f2cfe16b23675407035c6b5375ba263285"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/database/zipball/2f2527bb080cf578fba327ea2ec637064561d403",
- "reference": "2f2527bb080cf578fba327ea2ec637064561d403",
+ "url": "https://api.github.com/repos/utopia-php/database/zipball/ecc143f2cfe16b23675407035c6b5375ba263285",
+ "reference": "ecc143f2cfe16b23675407035c6b5375ba263285",
"shasum": ""
},
"require": {
@@ -2198,9 +2198,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
- "source": "https://github.com/utopia-php/database/tree/0.14.0"
+ "source": "https://github.com/utopia-php/database/tree/0.14.1"
},
- "time": "2022-01-21T16:34:34+00:00"
+ "time": "2022-01-25T13:01:20+00:00"
},
{
"name": "utopia-php/domains",
@@ -3126,23 +3126,23 @@
},
{
"name": "composer/pcre",
- "version": "1.0.0",
+ "version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
- "reference": "3d322d715c43a1ac36c7fe215fa59336265500f2"
+ "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/pcre/zipball/3d322d715c43a1ac36c7fe215fa59336265500f2",
- "reference": "3d322d715c43a1ac36c7fe215fa59336265500f2",
+ "url": "https://api.github.com/repos/composer/pcre/zipball/67a32d7d6f9f560b726ab25a061b38ff3a80c560",
+ "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0"
},
"require-dev": {
- "phpstan/phpstan": "^1",
+ "phpstan/phpstan": "^1.3",
"phpstan/phpstan-strict-rules": "^1.1",
"symfony/phpunit-bridge": "^4.2 || ^5"
},
@@ -3177,7 +3177,7 @@
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
- "source": "https://github.com/composer/pcre/tree/1.0.0"
+ "source": "https://github.com/composer/pcre/tree/1.0.1"
},
"funding": [
{
@@ -3193,7 +3193,7 @@
"type": "tidelift"
}
],
- "time": "2021-12-06T15:17:27+00:00"
+ "time": "2022-01-21T20:24:37+00:00"
},
{
"name": "composer/semver",
@@ -3697,6 +3697,9 @@
"require": {
"php": "^7.1 || ^8.0"
},
+ "replace": {
+ "myclabs/deep-copy": "self.version"
+ },
"require-dev": {
"doctrine/collections": "^1.0",
"doctrine/common": "^2.6",
@@ -6662,5 +6665,5 @@
"platform-overrides": {
"php": "8.0"
},
- "plugin-api-version": "2.2.0"
+ "plugin-api-version": "2.1.0"
}
diff --git a/tests/e2e/Services/Database/DatabaseCustomServerTest.php b/tests/e2e/Services/Database/DatabaseCustomServerTest.php
index b770b2b6c3..18542961db 100644
--- a/tests/e2e/Services/Database/DatabaseCustomServerTest.php
+++ b/tests/e2e/Services/Database/DatabaseCustomServerTest.php
@@ -169,6 +169,21 @@ class DatabaseCustomServerTest extends Scope
]);
$this->assertEquals($response['headers']['status-code'], 400);
+
+ // This collection already exists
+ $response = $this->client->call(Client::METHOD_POST, '/database/collections', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ 'x-appwrite-key' => $this->getProject()['apiKey']
+ ]), [
+ 'name' => 'Test 1',
+ 'collectionId' => 'first',
+ 'read' => ['role:all'],
+ 'write' => ['role:all'],
+ 'permission' => 'document'
+ ]);
+
+ $this->assertEquals($response['headers']['status-code'], 409);
}
public function testDeleteAttribute(): array
diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php
index 89ac02da74..e03ce89a9c 100644
--- a/tests/e2e/Services/Teams/TeamsBaseClient.php
+++ b/tests/e2e/Services/Teams/TeamsBaseClient.php
@@ -391,11 +391,75 @@ trait TeamsBaseClient
{
$teamUid = $data['teamUid'] ?? '';
$membershipUid = $data['membershipUid'] ?? '';
+ $session = $data['session'] ?? '';
+
+ $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()));
+
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals(2, $response['body']['sum']);
+ $ownerMembershipUid = $response['body']['memberships'][0]['$id'];
+
+ /**
+ * Test for FAILURE
+ */
+
+ /**
+ * Test deleting a membership that does not exists
+ */
+ $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/dne', [
+ 'origin' => 'http://localhost',
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session,
+ ]);
+
+ $this->assertEquals(404, $response['headers']['status-code']);
+
+ /**
+ * Test deleting another user's membership
+ */
+ $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/'.$ownerMembershipUid, [
+ 'origin' => 'http://localhost',
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session,
+ ]);
+
+ $this->assertEquals(401, $response['headers']['status-code']);
+
/**
* Test for SUCCESS
*/
- $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/'.$membershipUid, array_merge([
+
+ /**
+ * Test for when a user other than the owner tries to delete their membership
+ */
+ $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/'.$membershipUid, [
+ 'origin' => 'http://localhost',
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ 'cookie' => 'a_session_'.$this->getProject()['$id'].'='.$session,
+ ]);
+
+ $this->assertEquals(204, $response['headers']['status-code']);
+ $this->assertEmpty($response['body']);
+
+ $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()));
+
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals(1, $response['body']['sum']);
+
+ /**
+ * Test for when the owner tries to delete their membership
+ */
+ $response = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/'.$ownerMembershipUid, array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -404,10 +468,7 @@ trait TeamsBaseClient
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEmpty($response['body']);
- /**
- * Test for FAILURE
- */
- $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$membershipUid, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamUid.'/memberships/'.$ownerMembershipUid, array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],