diff --git a/app/views/console/users/index.phtml b/app/views/console/users/index.phtml
index b55917eb5..e0a0306f0 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 6ccefc419..de6782351 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 fc21da1de..98cb51335 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 9aecea62b..817e1d75f 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 6907bc2fd..3d61607b6 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 684885be8..ae37b84eb 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 79e3f2f17..7dd9f9477 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 c90b38fc5..1ac7e1b0b 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 e0ca6d29a..cd1f22f62 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 ef6718574..e056d338d 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 4d6acc54b..8f1340f9b 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 9b0ba21e1..2a95fbed2 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 000000000..a8694653c
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 000000000..748e7958e
--- /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 1444c9066..b9ed5af27 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 5ccb0e692..3b6f98f99 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 f911f9ab7..3b3629965 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 b5b5e0e77..079777be4 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 0a7780b6f..8f89afb7d 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 659839deb..18542961d 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 264fae073..8a55a0ded 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 277537d40..4357bec38 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 89ac02da7..e03ce89a9 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'],