diff --git a/app/views/console/users/index.phtml b/app/views/console/users/index.phtml
index b55917eb5c..e0a0306f05 100644
--- a/app/views/console/users/index.phtml
+++ b/app/views/console/users/index.phtml
@@ -174,7 +174,7 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
diff --git a/app/views/home/auth/recovery/reset.phtml b/app/views/home/auth/recovery/reset.phtml
index 6ccefc419c..de67823513 100644
--- a/app/views/home/auth/recovery/reset.phtml
+++ b/app/views/home/auth/recovery/reset.phtml
@@ -28,10 +28,10 @@
diff --git a/app/views/home/auth/signin.phtml b/app/views/home/auth/signin.phtml
index fc21da1de8..98cb513358 100644
--- a/app/views/home/auth/signin.phtml
+++ b/app/views/home/auth/signin.phtml
@@ -37,7 +37,7 @@ $root = ($this->getParam('root') !== 'disabled');
diff --git a/app/views/home/auth/signup.phtml b/app/views/home/auth/signup.phtml
index 9aecea62b5..817e1d75f1 100644
--- a/app/views/home/auth/signup.phtml
+++ b/app/views/home/auth/signup.phtml
@@ -46,7 +46,7 @@ $root = ($this->getParam('root') !== 'disabled');
diff --git a/app/workers/deletes.php b/app/workers/deletes.php
index 6907bc2fdd..3d61607b6b 100644
--- a/app/workers/deletes.php
+++ b/app/workers/deletes.php
@@ -191,9 +191,22 @@ class DeletesV1 extends Worker
*/
protected function deleteUser(Document $document, string $projectId): void
{
+ /**
+ * DO NOT DELETE THE USER RECORD ITSELF.
+ * WE RETAIN THE USER RECORD TO RESERVE THE USER ID AND ENSURE THAT THE USER ID IS NOT REUSED.
+ */
+
$userId = $document->getId();
+ $user = $this->getProjectDB($projectId)->getDocument('users', $userId);
+
+ // Delete all sessions of this user from the sessions table and update the sessions field of the user record
+ $this->deleteByGroup('sessions', [
+ new Query('userId', Query::TYPE_EQUAL, [$userId])
+ ], $this->getProjectDB($projectId));
+
+ $user->setAttribute('sessions', []);
+ $updated = Authorization::skip(fn() => $this->getProjectDB($projectId)->updateDocument('users', $userId, $user));
- // Tokens and Sessions removed with user document
// Delete Memberships and decrement team membership counts
$this->deleteByGroup('memberships', [
new Query('userId', Query::TYPE_EQUAL, [$userId])
diff --git a/composer.json b/composer.json
index 684885be8c..ae37b84eba 100644
--- a/composer.json
+++ b/composer.json
@@ -46,7 +46,7 @@
"utopia-php/cache": "0.4.*",
"utopia-php/cli": "0.11.*",
"utopia-php/config": "0.2.*",
- "utopia-php/database": "0.13.*",
+ "utopia-php/database": "0.14.*",
"utopia-php/locale": "0.4.*",
"utopia-php/orchestration": "0.2.*",
"utopia-php/registry": "0.5.*",
diff --git a/composer.lock b/composer.lock
index 79e3f2f173..7dd9f94770 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": "ab493f0a7f01a1105f8bc5caaf9b928b",
"packages": [
{
"name": "adhocore/jwt",
@@ -355,16 +355,16 @@
},
{
"name": "composer/package-versions-deprecated",
- "version": "1.11.99.4",
+ "version": "1.11.99.5",
"source": {
"type": "git",
"url": "https://github.com/composer/package-versions-deprecated.git",
- "reference": "b174585d1fe49ceed21928a945138948cb394600"
+ "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b174585d1fe49ceed21928a945138948cb394600",
- "reference": "b174585d1fe49ceed21928a945138948cb394600",
+ "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b4f54f74ef3453349c24a845d22392cd31e65f1d",
+ "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d",
"shasum": ""
},
"require": {
@@ -408,7 +408,7 @@
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
"support": {
"issues": "https://github.com/composer/package-versions-deprecated/issues",
- "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.4"
+ "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.5"
},
"funding": [
{
@@ -424,7 +424,7 @@
"type": "tidelift"
}
],
- "time": "2021-09-13T08:41:34+00:00"
+ "time": "2022-01-17T14:14:24+00:00"
},
{
"name": "dragonmantank/cron-expression",
@@ -2141,16 +2141,16 @@
},
{
"name": "utopia-php/database",
- "version": "0.13.2",
+ "version": "0.14.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
- "reference": "bf92279b707b3a10ee5ec5df5c065023b2221357"
+ "reference": "2f2527bb080cf578fba327ea2ec637064561d403"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/database/zipball/bf92279b707b3a10ee5ec5df5c065023b2221357",
- "reference": "bf92279b707b3a10ee5ec5df5c065023b2221357",
+ "url": "https://api.github.com/repos/utopia-php/database/zipball/2f2527bb080cf578fba327ea2ec637064561d403",
+ "reference": "2f2527bb080cf578fba327ea2ec637064561d403",
"shasum": ""
},
"require": {
@@ -2198,9 +2198,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
- "source": "https://github.com/utopia-php/database/tree/0.13.2"
+ "source": "https://github.com/utopia-php/database/tree/0.14.0"
},
- "time": "2022-01-04T10:51:22+00:00"
+ "time": "2022-01-21T16:34:34+00:00"
},
{
"name": "utopia-php/domains",
@@ -3697,9 +3697,6 @@
"require": {
"php": "^7.1 || ^8.0"
},
- "replace": {
- "myclabs/deep-copy": "self.version"
- },
"require-dev": {
"doctrine/collections": "^1.0",
"doctrine/common": "^2.6",
@@ -6665,5 +6662,5 @@
"platform-overrides": {
"php": "8.0"
},
- "plugin-api-version": "2.1.0"
+ "plugin-api-version": "2.2.0"
}
diff --git a/docker-compose.yml b/docker-compose.yml
index c90b38fc5f..1ac7e1b0b0 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -412,11 +412,7 @@ services:
- _APP_MAINTENANCE_RETENTION_AUDIT
appwrite-usage:
- entrypoint:
- - php
- - -e
- - /usr/src/code/app/cli.php
- - usage
+ entrypoint: usage
container_name: appwrite-usage
build:
context: .
diff --git a/docs/references/account/delete-session.md b/docs/references/account/delete-session.md
index e0ca6d29ac..cd1f22f627 100644
--- a/docs/references/account/delete-session.md
+++ b/docs/references/account/delete-session.md
@@ -1 +1 @@
-Use this endpoint to log out the currently logged in user from all their account sessions across all of their different devices. When using the option id argument, only the session unique ID provider will be deleted.
\ No newline at end of file
+Use this endpoint to log out the currently logged in user from all their account sessions across all of their different devices. When using the Session ID argument, only the unique session ID provided is deleted.
diff --git a/docs/tutorials/add-environment-variable.md b/docs/tutorials/add-environment-variable.md
index ef67185747..e056d338d1 100644
--- a/docs/tutorials/add-environment-variable.md
+++ b/docs/tutorials/add-environment-variable.md
@@ -1,32 +1,32 @@
# Introducing new Environment Variable
-This document is part of the Appwrite contributors' guide. Before you continue reading this document make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md).
+This document is part of the Appwrite contributors' guide. Before you continue reading this document, make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md).
## Getting Started
### Agenda
-Adding new features may require various configurations options to be set by the users. And for such options we use environment variables in Appwrite.
+Adding new features may require various configurations options to be set by the users. And for such options, we use environment variables in Appwrite.
-This tutorial will cover, how to properly add a new environment variable in Appwrite.
+This tutorial will cover how to properly add a new environment variable in Appwrite.
### Naming environment variable
-The environment variables in Appwrite are prefixed with `_APP_`. If it belongs to a specific category, the category name is appended as `_APP_REDIS` for the redis category. The available categories are General, Redis, MariaDB, InfluxDB, StatsD, SMTP, Storage and Functions. Finally a properly describing name is given to the variable. For example `_APP_REDIS_HOST` is an environment variable for redis connection host. You can find more information on available categories and existing environment variables in the [environment variables doc](https://appwrite.io/docs/environment-variables).
+The environment variables in Appwrite are prefixed with `_APP_`. If it belongs to a specific category, the category name is appended as `_APP_REDIS` for the Redis category. The available categories are General, Redis, MariaDB, InfluxDB, StatsD, SMTP, Storage and Functions. Finally, a properly describing name is given to the variable. For example, `_APP_REDIS_HOST` is an environment variable for Redis connection host. You can find more information on available categories and existing environment variables in the [environment variables doc](https://appwrite.io/docs/environment-variables).
### Describe new environment variable
-First of all, we add the new environment variable to `app/config/variables.php` in the designated category. If none of the categories fit, add it to the General category. Copy the existing variables description to create a new one, so that you will not miss any required fields.
+First of all, we add the new environment variable to `app/config/variables.php` in the designated category. If none of the categories fit, add it to the General category. Copy the existing variable description to create a new one so that you will not miss any required fields.
This information is also used to generate the website documentation at https://appwrite.io/docs/environment-variables, so please use good descriptions that clearly define the purpose and other required info about the environment variable that you are adding.
### Add to .env and Dockerfile
-If newly introduced environment variable has a default value, add it to the `.env` and `Dockerfile` along with other environment variables. `.env` file uses settings for Appwrite development environment.
+If the newly introduced environment variable has a default value, add it to the `.env` and `Dockerfile` along with other environment variables. `.env` file uses settings for Appwrite development environment.
-### Add to docker compose file and template
-Add the new environment variables to the `docker-compose.yml` and `app/views/install/compose.phtml` for each docker services that require access to those environment variables.
+### Add to Docker Compose file and template
+Add the new environment variables to the `docker-compose.yml` and `app/views/install/compose.phtml` for each docker service that requires access to those environment variables.
-The `docker-compose.yml` file is used by the Appwrite maintainers during development where as `app/views/install/compose.phtml` file is used by the Appwrite setup script.
+The `docker-compose.yml` file is used by the Appwrite maintainers during development, whereas the `app/views/install/compose.phtml` file is used by the Appwrite setup script.
With these steps, your environment variable is properly added and can be accessed inside Appwrite code and any other containers where it is passed. You can access and use those variables to implement the features you are trying to achieve.
If everything went well, commit and initiate a PR and wait for the Appwrite team's approval.
-Whooho! you have successfully added new environment variable to Appwrite. 🎉
+Whooho! You have successfully added a new environment variable to Appwrite. 🎉
diff --git a/package-lock.json b/package-lock.json
index 4d6acc54bc..8f1340f9b7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,8 +9,8 @@
"version": "0.1.0",
"license": "BSD-3-Clause",
"dependencies": {
- "chart.js": "^3.6.2",
- "markdown-it": "^12.3.0",
+ "chart.js": "^3.7.0",
+ "markdown-it": "^12.3.2",
"pell": "^1.0.6",
"prismjs": "^1.25.0",
"turndown": "^7.1.1"
@@ -549,9 +549,9 @@
}
},
"node_modules/chart.js": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.6.2.tgz",
- "integrity": "sha512-Xz7f/fgtVltfQYWq0zL1Xbv7N2inpG+B54p3D5FSvpCdy3sM+oZhbqa42eNuYXltaVvajgX5UpKCU2GeeJIgxg=="
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz",
+ "integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg=="
},
"node_modules/chokidar": {
"version": "2.1.8",
@@ -2862,9 +2862,9 @@
}
},
"node_modules/markdown-it": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.0.tgz",
- "integrity": "sha512-T345UZZ6ejQWTjG6PSEHplzNy5m4kF6zvUpHVDv8Snl/pEU0OxIK0jGg8YLVNwJvT8E0YJC7/2UvssJDk/wQCQ==",
+ "version": "12.3.2",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+ "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
"dependencies": {
"argparse": "^2.0.1",
"entities": "~2.1.0",
@@ -5484,9 +5484,9 @@
"dev": true
},
"chart.js": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.6.2.tgz",
- "integrity": "sha512-Xz7f/fgtVltfQYWq0zL1Xbv7N2inpG+B54p3D5FSvpCdy3sM+oZhbqa42eNuYXltaVvajgX5UpKCU2GeeJIgxg=="
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz",
+ "integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg=="
},
"chokidar": {
"version": "2.1.8",
@@ -7413,9 +7413,9 @@
}
},
"markdown-it": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.0.tgz",
- "integrity": "sha512-T345UZZ6ejQWTjG6PSEHplzNy5m4kF6zvUpHVDv8Snl/pEU0OxIK0jGg8YLVNwJvT8E0YJC7/2UvssJDk/wQCQ==",
+ "version": "12.3.2",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+ "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
"requires": {
"argparse": "^2.0.1",
"entities": "~2.1.0",
diff --git a/package.json b/package.json
index 9b0ba21e17..2a95fbed23 100644
--- a/package.json
+++ b/package.json
@@ -17,8 +17,8 @@
"gulp-less": "^5.0.0"
},
"dependencies": {
- "chart.js": "^3.6.2",
- "markdown-it": "^12.3.0",
+ "chart.js": "^3.7.0",
+ "markdown-it": "^12.3.2",
"pell": "^1.0.6",
"prismjs": "^1.25.0",
"turndown": "^7.1.1"
diff --git a/public/images/users/notion.png b/public/images/users/notion.png
new file mode 100644
index 0000000000..a8694653ca
Binary files /dev/null and b/public/images/users/notion.png differ
diff --git a/src/Appwrite/Auth/OAuth2/Notion.php b/src/Appwrite/Auth/OAuth2/Notion.php
new file mode 100644
index 0000000000..748e7958ed
--- /dev/null
+++ b/src/Appwrite/Auth/OAuth2/Notion.php
@@ -0,0 +1,148 @@
+endpoint . '/oauth/authorize?'. \http_build_query([
+ 'client_id' => $this->appID,
+ 'redirect_uri' => $this->callback,
+ 'response_type' => 'code',
+ 'state' => \json_encode($this->state),
+ 'owner' => 'user'
+ ]);
+ }
+
+ /**
+ * @param string $code
+ *
+ * @return string
+ */
+ public function getAccessToken(string $code):string
+ {
+ $headers = [
+ "Authorization: Basic " . \base64_encode($this->appID . ":" . $this->appSecret),
+ ];
+
+ $response = $this->request(
+ 'POST',
+ $this->endpoint . '/oauth/token',
+ $headers,
+ \http_build_query([
+ 'grant_type' => 'authorization_code',
+ 'redirect_uri' => $this->callback,
+ 'code' => $code
+ ])
+ );
+
+ $response = \json_decode($response, true);
+
+ if (isset($response['access_token'])) {
+ return $response['access_token'];
+ }
+
+ return '';
+ }
+
+ /**
+ * @param $accessToken
+ *
+ * @return string
+ */
+ public function getUserID(string $accessToken):string
+ {
+ $response = $this->getUser($accessToken);
+
+ if (isset($response['bot']['owner']['user']['id'])) {
+ return $response['bot']['owner']['user']['id'];
+ }
+
+ return '';
+ }
+
+ /**
+ * @param $accessToken
+ *
+ * @return string
+ */
+ public function getUserEmail(string $accessToken):string
+ {
+ $response = $this->getUser($accessToken);
+
+ if(isset($response['bot']['owner']['user']['person']['email'])){
+ return $response['bot']['owner']['user']['person']['email'];
+ }
+
+ return '';
+ }
+
+ /**
+ * @param $accessToken
+ *
+ * @return string
+ */
+ public function getUserName(string $accessToken):string
+ {
+ $response = $this->getUser($accessToken);
+
+ if (isset($response['bot']['owner']['user']['name'])) {
+ return $response['bot']['owner']['user']['name'];
+ }
+
+ return '';
+ }
+
+ /**
+ * @param string $accessToken
+ *
+ * @return array
+ */
+ protected function getUser(string $accessToken)
+ {
+ $headers = [
+ 'Notion-Version: ' . $this->version,
+ 'Authorization: Bearer '.\urlencode($accessToken)
+ ];
+
+ if (empty($this->user)) {
+ $this->user = \json_decode($this->request('GET', $this->endpoint . '/users/me', $headers), true);
+ }
+
+ return $this->user;
+ }
+}
diff --git a/src/Appwrite/Resque/Worker.php b/src/Appwrite/Resque/Worker.php
index 1444c90663..b9ed5af275 100644
--- a/src/Appwrite/Resque/Worker.php
+++ b/src/Appwrite/Resque/Worker.php
@@ -70,9 +70,6 @@ abstract class Worker
throw new Exception("Please implement getName method in worker");
}
- const MAX_ATTEMPTS = 10;
- const SLEEP_TIME = 2;
-
const DATABASE_PROJECT = 'project';
const DATABASE_CONSOLE = 'console';
@@ -174,7 +171,7 @@ abstract class Worker
global $register;
$namespace = '';
- $sleep = self::SLEEP_TIME; // overwritten when necessary
+ $sleep = DATABASE_RECONNECT_SLEEP; // overwritten when necessary
switch ($type) {
case self::DATABASE_PROJECT:
@@ -201,18 +198,24 @@ abstract class Worker
$database = new Database(new MariaDB($register->get('db')), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace($namespace); // Main DB
+
if (!empty($projectId) && !$database->getDocument('projects', $projectId)->isEmpty()) {
throw new \Exception("Project does not exist: {$projectId}");
}
+
+ if ($type === self::DATABASE_CONSOLE && !$database->exists($database->getDefaultDatabase(), 'realtime')) {
+ throw new \Exception('Console project not ready');
+ }
+
break; // leave loop if successful
} catch(\Exception $e) {
Console::warning("Database not ready. Retrying connection ({$attempts})...");
- if ($attempts >= self::MAX_ATTEMPTS) {
+ if ($attempts >= DATABASE_RECONNECT_MAX_ATTEMPTS) {
throw new \Exception('Failed to connect to database: '. $e->getMessage());
}
sleep($sleep);
}
- } while ($attempts < self::MAX_ATTEMPTS);
+ } while ($attempts < DATABASE_RECONNECT_MAX_ATTEMPTS);
return $database;
}
diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php
index 5ccb0e6926..3b6f98f996 100644
--- a/src/Appwrite/Utopia/Response.php
+++ b/src/Appwrite/Utopia/Response.php
@@ -26,6 +26,7 @@ use Appwrite\Utopia\Response\Model\Continent;
use Appwrite\Utopia\Response\Model\Country;
use Appwrite\Utopia\Response\Model\Currency;
use Appwrite\Utopia\Response\Model\Document as ModelDocument;
+use Appwrite\Utopia\Response\Model\DocumentList;
use Appwrite\Utopia\Response\Model\Domain;
use Appwrite\Utopia\Response\Model\Error;
use Appwrite\Utopia\Response\Model\ErrorDev;
@@ -207,9 +208,9 @@ class Response extends SwooleResponse
->setModel(new Error())
->setModel(new ErrorDev())
// Lists
+ ->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT))
->setModel(new BaseList('Collections List', self::MODEL_COLLECTION_LIST, 'collections', self::MODEL_COLLECTION))
->setModel(new BaseList('Indexes List', self::MODEL_INDEX_LIST, 'indexes', self::MODEL_INDEX))
- ->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT))
->setModel(new BaseList('Users List', self::MODEL_USER_LIST, 'users', self::MODEL_USER))
->setModel(new BaseList('Sessions List', self::MODEL_SESSION_LIST, 'sessions', self::MODEL_SESSION))
->setModel(new BaseList('Logs List', self::MODEL_LOG_LIST, 'logs', self::MODEL_LOG))
@@ -374,13 +375,13 @@ class Response extends SwooleResponse
$model = $this->getModel($model);
$output = [];
+ $document = $model->filter($document);
+
if ($model->isAny()) {
$this->payload = $document->getArrayCopy();
return $this->payload;
}
- $document = $model->filter($document);
-
foreach ($model->getRules() as $key => $rule) {
if (!$document->isSet($key) && $rule['require']) { // do not set attribute in response if not required
if (!is_null($rule['default'])) {
diff --git a/src/Appwrite/Utopia/Response/Model/Document.php b/src/Appwrite/Utopia/Response/Model/Document.php
index f911f9ab71..3b3629965f 100644
--- a/src/Appwrite/Utopia/Response/Model/Document.php
+++ b/src/Appwrite/Utopia/Response/Model/Document.php
@@ -3,6 +3,7 @@
namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
+use Utopia\Database\Document as DatabaseDocument;
class Document extends Any
{
@@ -57,4 +58,11 @@ class Document extends Any
])
;
}
+
+ public function filter(DatabaseDocument $document): DatabaseDocument
+ {
+ $document->removeAttribute('$internalId');
+
+ return $document;
+ }
}
diff --git a/tests/e2e/Scopes/Scope.php b/tests/e2e/Scopes/Scope.php
index b5b5e0e775..079777be4c 100644
--- a/tests/e2e/Scopes/Scope.php
+++ b/tests/e2e/Scopes/Scope.php
@@ -33,7 +33,7 @@ abstract class Scope extends TestCase
protected function getLastEmail():array
{
- sleep(5);
+ sleep(3);
$emails = json_decode(file_get_contents('http://maildev:1080/email'), true);
@@ -46,7 +46,7 @@ abstract class Scope extends TestCase
protected function getLastRequest():array
{
- sleep(5);
+ sleep(2);
$resquest = json_decode(file_get_contents('http://request-catcher:5000/__last_request__'), true);
$resquest['data'] = json_decode($resquest['data'], true);
@@ -167,4 +167,4 @@ abstract class Scope extends TestCase
return self::$user[$this->getProject()['$id']];
}
-}
\ No newline at end of file
+}
diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php
index 0a7780b6fc..8f89afb7da 100644
--- a/tests/e2e/Services/Database/DatabaseBase.php
+++ b/tests/e2e/Services/Database/DatabaseBase.php
@@ -825,6 +825,9 @@ trait DatabaseBase
$this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']);
$this->assertEquals(2017, $documents['body']['documents'][1]['releaseYear']);
$this->assertEquals(2019, $documents['body']['documents'][2]['releaseYear']);
+ $this->assertFalse(array_key_exists('$internalId', $documents['body']['documents'][0]));
+ $this->assertFalse(array_key_exists('$internalId', $documents['body']['documents'][1]));
+ $this->assertFalse(array_key_exists('$internalId', $documents['body']['documents'][2]));
$this->assertCount(3, $documents['body']['documents']);
foreach ($documents['body']['documents'] as $document) {
@@ -866,6 +869,7 @@ trait DatabaseBase
$this->assertEquals($response['body']['releaseYear'], $document['releaseYear']);
$this->assertEquals($response['body']['$read'], $document['$read']);
$this->assertEquals($response['body']['$write'], $document['$write']);
+ $this->assertFalse(array_key_exists('$internalId', $response['body']));
}
}
diff --git a/tests/e2e/Services/Database/DatabaseCustomServerTest.php b/tests/e2e/Services/Database/DatabaseCustomServerTest.php
index 659839debe..18542961db 100644
--- a/tests/e2e/Services/Database/DatabaseCustomServerTest.php
+++ b/tests/e2e/Services/Database/DatabaseCustomServerTest.php
@@ -125,6 +125,39 @@ class DatabaseCustomServerTest extends Scope
$this->assertCount(0, $collections['body']['collections']);
$this->assertEmpty($collections['body']['collections']);
+ /**
+ * Test for Search
+ */
+ $collections = $this->client->call(Client::METHOD_GET, '/database/collections', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), [
+ 'search' => 'first'
+ ]);
+
+ $this->assertEquals(1, $collections['body']['sum']);
+ $this->assertEquals('first', $collections['body']['collections'][0]['$id']);
+
+ $collections = $this->client->call(Client::METHOD_GET, '/database/collections', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), [
+ 'search' => 'Test'
+ ]);
+
+ $this->assertEquals(2, $collections['body']['sum']);
+ $this->assertEquals('Test 1', $collections['body']['collections'][0]['name']);
+ $this->assertEquals('Test 2', $collections['body']['collections'][1]['name']);
+
+ $collections = $this->client->call(Client::METHOD_GET, '/database/collections', array_merge([
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], $this->getHeaders()), [
+ 'search' => 'Nonexistent'
+ ]);
+
+ $this->assertEquals(0, $collections['body']['sum']);
+
/**
* Test for FAILURE
*/
@@ -136,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/Functions/FunctionsCustomClientTest.php b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php
index 264fae0735..8a55a0ded4 100644
--- a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php
+++ b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php
@@ -218,6 +218,32 @@ class FunctionsCustomClientTest extends Scope
];
}
+ public function testCreateExecutionUnauthorized():array
+ {
+ $function = $this->client->call(Client::METHOD_POST, '/functions', [
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ 'x-appwrite-key' => $this->getProject()['apiKey'],
+ ], [
+ 'functionId' => 'unique()',
+ 'name' => 'Test',
+ 'execute' => [],
+ 'runtime' => 'php-8.0',
+ 'timeout' => 10,
+ ]);
+
+ $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/executions', [
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ], [
+ 'async' => 1,
+ ]);
+
+ $this->assertEquals(401, $execution['headers']['status-code']);
+
+ return [];
+ }
+
/**
* @depends testCreateCustomExecution
*/
diff --git a/tests/e2e/Services/Realtime/RealtimeBase.php b/tests/e2e/Services/Realtime/RealtimeBase.php
index 277537d407..4357bec383 100644
--- a/tests/e2e/Services/Realtime/RealtimeBase.php
+++ b/tests/e2e/Services/Realtime/RealtimeBase.php
@@ -66,6 +66,7 @@ trait RealtimeBase
$this->assertEquals('error', $payload['type']);
$this->assertEquals(1008, $payload['data']['code']);
$this->assertEquals('Missing or unknown project ID', $payload['data']['message']);
+ \usleep(250000); // 250ms
$this->expectException(ConnectionException::class); // Check if server disconnnected client
$client->close();
}
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'],