diff --git a/app/workers/certificates.php b/app/workers/certificates.php
index 42ead45a26..f932ba4bc3 100644
--- a/app/workers/certificates.php
+++ b/app/workers/certificates.php
@@ -8,6 +8,7 @@ use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\DateTime;
+use Utopia\Database\ID;
use Utopia\Database\Query;
use Utopia\Domains\Domain;
@@ -100,8 +101,11 @@ class CertificatesV1 extends Worker
throw new Exception('Renew isn\'t required.');
}
+ // Prepare folder name for certbot. Using this helps prevent miss-match in LetsEncrypt configuration when renewing certificate
+ $folder = ID::unique();
+
// Generate certificate files using Let's Encrypt
- $letsEncryptData = $this->issueCertificate($domain->get(), $email);
+ $letsEncryptData = $this->issueCertificate($folder, $domain->get(), $email);
// Command succeeded, store all data into document
// We store stderr too, because it may include warnings
@@ -111,7 +115,7 @@ class CertificatesV1 extends Worker
]));
// Give certificates to Traefik
- $this->applyCertificateFiles($domain->get(), $letsEncryptData);
+ $this->applyCertificateFiles($folder, $domain->get(), $letsEncryptData);
// Update certificate info stored in database
$certificate->setAttribute('renewDate', $this->getRenewDate($domain->get()));
@@ -125,6 +129,9 @@ class CertificatesV1 extends Worker
$attempts = $certificate->getAttribute('attempts', 0) + 1;
$certificate->setAttribute('attempts', $attempts);
+ // Store cuttent time as renew date to ensure another attempt in next maintenance cycle
+ $certificate->setAttribute('renewDate', DateTime::now());
+
// Send email to security email
$this->notifyError($domain->get(), $e->getMessage(), $attempts);
} finally {
@@ -259,11 +266,12 @@ class CertificatesV1 extends Worker
/**
* LetsEncrypt communication to issue certificate (using certbot CLI)
*
+ * @param string $folder Folder into which certificates should be generated
* @param string $domain Domain to generate certificate for
*
* @return array Named array with keys 'stdout' and 'stderr', both string
*/
- private function issueCertificate(string $domain, string $email): array
+ private function issueCertificate(string $folder, string $domain, string $email): array
{
$stdout = '';
$stderr = '';
@@ -271,6 +279,7 @@ class CertificatesV1 extends Worker
$staging = (App::isProduction()) ? '' : ' --dry-run';
$exit = Console::execute("certbot certonly --webroot --noninteractive --agree-tos{$staging}"
. " --email " . $email
+ . " --cert-name " . $folder
. " -w " . APP_STORAGE_CERTIFICATES
. " -d {$domain}", '', $stdout, $stderr);
@@ -290,9 +299,9 @@ class CertificatesV1 extends Worker
*
* @param string $domain Domain which certificate was generated for
*
- * @return int
+ * @return string
*/
- private function getRenewDate(string $domain): int
+ private function getRenewDate(string $domain): string
{
$certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem';
$certData = openssl_x509_parse(file_get_contents($certPath));
@@ -305,11 +314,12 @@ class CertificatesV1 extends Worker
* Method to take files from Let's Encrypt, and put it into Traefik.
*
* @param string $domain Domain which certificate was generated for
+ * @param string $folder Folder in which certificates were generated
* @param array $letsEncryptData Let's Encrypt logs to use for additional info when throwing error
*
* @return void
*/
- private function applyCertificateFiles(string $domain, array $letsEncryptData): void
+ private function applyCertificateFiles(string $folder, string $domain, array $letsEncryptData): void
{
// Prepare folder in storage for domain
$path = APP_STORAGE_CERTIFICATES . '/' . $domain;
@@ -319,20 +329,20 @@ class CertificatesV1 extends Worker
}
}
- // Move generated files from certbot into our storage
- if (!@\rename('/etc/letsencrypt/live/' . $domain . '/cert.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem')) {
+ // Move generated files
+ if (!@\rename('/etc/letsencrypt/live/' . $folder . '/cert.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem')) {
throw new Exception('Failed to rename certificate cert.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
}
- if (!@\rename('/etc/letsencrypt/live/' . $domain . '/chain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/chain.pem')) {
+ if (!@\rename('/etc/letsencrypt/live/' . $folder . '/chain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/chain.pem')) {
throw new Exception('Failed to rename certificate chain.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
}
- if (!@\rename('/etc/letsencrypt/live/' . $domain . '/fullchain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/fullchain.pem')) {
+ if (!@\rename('/etc/letsencrypt/live/' . $folder . '/fullchain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/fullchain.pem')) {
throw new Exception('Failed to rename certificate fullchain.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
}
- if (!@\rename('/etc/letsencrypt/live/' . $domain . '/privkey.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/privkey.pem')) {
+ if (!@\rename('/etc/letsencrypt/live/' . $folder . '/privkey.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/privkey.pem')) {
throw new Exception('Failed to rename certificate privkey.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
}
diff --git a/app/workers/functions.php b/app/workers/functions.php
index bcc8cb8dd3..b7ef80a40b 100644
--- a/app/workers/functions.php
+++ b/app/workers/functions.php
@@ -248,7 +248,7 @@ class FunctionsV1 extends Worker
'statusCode' => 0,
'response' => '',
'stderr' => '',
- 'time' => 0.0,
+ 'duration' => 0.0,
'search' => implode(' ', [$functionId, $executionId]),
]));
@@ -301,11 +301,11 @@ class FunctionsV1 extends Worker
->setAttribute('response', $executionResponse['response'])
->setAttribute('stdout', $executionResponse['stdout'])
->setAttribute('stderr', $executionResponse['stderr'])
- ->setAttribute('time', $executionResponse['time']);
+ ->setAttribute('duration', $executionResponse['duration']);
} catch (\Throwable $th) {
$interval = (new \DateTime())->diff(new \DateTime($execution->getCreatedAt()));
$execution
- ->setAttribute('time', (float)$interval->format('%s.%f'))
+ ->setAttribute('duration', (float)$interval->format('%s.%f'))
->setAttribute('status', 'failed')
->setAttribute('statusCode', $th->getCode())
->setAttribute('stderr', $th->getMessage());
@@ -367,7 +367,7 @@ class FunctionsV1 extends Worker
->setParam('functionId', $function->getId())
->setParam('executions.{scope}.compute', 1)
->setParam('executionStatus', $execution->getAttribute('status', ''))
- ->setParam('executionTime', $execution->getAttribute('time'))
+ ->setParam('executionTime', $execution->getAttribute('duration'))
->setParam('networkRequestSize', 0)
->setParam('networkResponseSize', 0)
->submit();
diff --git a/composer.lock b/composer.lock
index 8245baac5f..1f61b8aef6 100644
--- a/composer.lock
+++ b/composer.lock
@@ -2060,16 +2060,16 @@
},
{
"name": "utopia-php/database",
- "version": "0.25.1",
+ "version": "0.25.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
- "reference": "9d013ce3c111d1477d7986483f1003dcab2b9d14"
+ "reference": "140bbedf1c4d622990fb94d26681fcca235cd5b9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/database/zipball/9d013ce3c111d1477d7986483f1003dcab2b9d14",
- "reference": "9d013ce3c111d1477d7986483f1003dcab2b9d14",
+ "url": "https://api.github.com/repos/utopia-php/database/zipball/140bbedf1c4d622990fb94d26681fcca235cd5b9",
+ "reference": "140bbedf1c4d622990fb94d26681fcca235cd5b9",
"shasum": ""
},
"require": {
@@ -2118,9 +2118,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
- "source": "https://github.com/utopia-php/database/tree/0.25.1"
+ "source": "https://github.com/utopia-php/database/tree/0.25.2"
},
- "time": "2022-09-07T14:47:52+00:00"
+ "time": "2022-09-09T03:58:01+00:00"
},
{
"name": "utopia-php/domains",
@@ -5384,5 +5384,5 @@
"platform-overrides": {
"php": "8.0"
},
- "plugin-api-version": "2.2.0"
+ "plugin-api-version": "2.3.0"
}
diff --git a/docs/sdks/dart/CHANGELOG.md b/docs/sdks/dart/CHANGELOG.md
index a04b25270b..39f44c1d91 100644
--- a/docs/sdks/dart/CHANGELOG.md
+++ b/docs/sdks/dart/CHANGELOG.md
@@ -1,3 +1,33 @@
+## 7.0.0-dev.2
+### NEW
+* Support for Appwrite 1.0.0-RC1
+* More verbose headers have been included in the Clients - `x-sdk-name`, `x-sdk-platform`, `x-sdk-language`, `x-sdk-version`
+* Helper classes and methods for Permissions, Roles and IDs
+* Helper methods to suport new queries
+* All Dates and times are now returned in the ISO 8601 format
+* Execution Model now has an additional `stdout` attribute
+* Endpoint for creating DateTime attribute
+* User imports API with support for multiple hashing algorithms
+* CRUD API for functions environment variables
+* `createBucket` now supports different compression algorithms
+
+### BREAKING CHANGES
+
+* `databaseId` is no longer part of the `Database` Service constructor. `databaseId` will be part of the respective methods of the database service.
+* The `Users.create()` method signature has now been updated to include a `phone` parameter
+* `color` attribute is no longer supported in the Avatars Service
+* The `number` argument in phone endpoints have been renamed to `phone`
+* List endpoints no longer support `limit`, `offset`, `cursor`, `cursorDirection`, `orderAttributes`, `orderTypes` as they have been moved to the `queries` array
+* `read` and `write` permission have been deprecated and they are now included in the `permissions` array
+* Parameter `permission` for collections and buckets are now renamed to `documentSecurity` & `fileSecurity` respectively
+* Renamed methods of the Query helper
+ 1. `lesser` renamed to `lessThan`
+ 2. `lesserEqual` renamed to `lessThanEqual`
+ 3. `greater` renamed to `greaterThan`
+ 4. `greaterEqual` renamed to `greaterThanEqual`
+
+**Full Changelog for Appwrite 1.0.0-RC1 can be found here**: https://github.com/appwrite/appwrite/blob/master/CHANGES.md
+
## 6.0.1
* Dependency upgrades
* Doc comments updates
diff --git a/docs/sdks/flutter/CHANGELOG.md b/docs/sdks/flutter/CHANGELOG.md
index ae0022f7b2..3424e8d19f 100644
--- a/docs/sdks/flutter/CHANGELOG.md
+++ b/docs/sdks/flutter/CHANGELOG.md
@@ -1,3 +1,29 @@
+## 8.0.0-dev.2 Latest
+
+### NEW
+* Support for Appwrite 1.0.0-RC1
+* More verbose headers have been included in the Clients - `x-sdk-name`, `x-sdk-platform`, `x-sdk-language`, `x-sdk-version`
+* Helper classes and methods for Permissions, Roles and IDs
+* Helper methods to suport new queries
+* All Dates and times are now returned in the ISO 8601 format
+
+### BREAKING CHANGES
+
+* `databaseId` is no longer part of the `Database` Service constructor. `databaseId` will be part of the respective methods of the database service.
+* `color` attribute is no longer supported in the Avatars Service
+* The `number` argument in phone endpoints have been renamed to `phone`
+* List endpoints no longer support `limit`, `offset`, `cursor`, `cursorDirection`, `orderAttributes`, `orderTypes` as they have been moved to the `queries` array
+* `read` and `write` permission have been deprecated and they are now included in the `permissions` array
+* Renamed methods of the Query helper
+ 1. `lesser` renamed to `lessThan`
+ 2. `lesserEqual` renamed to `lessThanEqual`
+ 3. `greater` renamed to `greaterThan`
+ 4. `greaterEqual` renamed to `greaterThanEqual`
+* `User` response model is now renamed to `Account`
+
+**Full Changelog for Appwrite 1.0.0-RC1 can be found here**:
+https://github.com/appwrite/appwrite/blob/master/CHANGES.md
+
## 7.0.0
* **BREAKING** Switched to using [flutter_web_auth_2](https://pub.dev/packages/flutter_web_auth_2), check Getting Started section in Readme for changes (Android and Web will require adjustments for OAuth to work properly)
* Fixes Concurrent modification issue
diff --git a/docs/tutorials/add-route.md b/docs/tutorials/add-route.md
new file mode 100644
index 0000000000..6b1bf7e7cf
--- /dev/null
+++ b/docs/tutorials/add-route.md
@@ -0,0 +1,167 @@
+# Adding Route 🛡
+
+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).
+
+### 1. Alias
+Setting an alias allows the route to be also accessible from the alias URL.
+The first parameter specifies the alias URL, the second parameter specifies default values for route parameters.
+```php
+App::post('/v1/storage/buckets/:bucketId/files')
+ ->alias('/v1/storage/files', ['bucketId' => 'default'])
+```
+
+### 2. Description
+Used as an abstract description of the route.
+```php
+App::post('/v1/storage/buckets/:bucketId/files')
+ ->desc('Create File')
+```
+
+### 3. Groups
+Groups array is used to group one or more routes with one or more hooks functionality.
+```php
+App::post('/v1/storage/buckets/:bucketId/files')
+ ->groups(['api'])
+```
+In the above example groups() is used to define the current route as part of the routes that shares a common init middleware hook.
+```php
+App::init()
+ ->groups(['api'])
+ ->action(
+ some code.....
+);
+```
+
+
+### 4. The Labels Mechanism
+Labels are very strait forward and easy to use and understand, but in the same time are very robust.
+Labels are passed from the controllers route and used to pick up key-value pairs to be handled in a centralized place
+along the road.
+Labels can be used to pass a pattern in order to be replaced in the other end.
+Appwrite uses different labels to achieve different things, for example:
+
+#### Scope
+* scope - Defines the route permissions scope.
+
+```php
+App::post('/v1/storage/buckets/:bucketId/files')
+ ->label('scope', 'files.write')
+```
+
+#### Audit
+* audits.event - Identify the log in human-readable text.
+* audits.userId - Signals the extraction of $userId in places that it's not available natively.
+* audits.resource - Signals the extraction part of the resource.
+
+
+```php
+App::post('/v1/account/create')
+ ->label('audits.event', 'account.create')
+ ->label('audits.resource', 'user/{response.$id}')
+ ->label('audits.userId', '{response.$id}')
+```
+
+#### SDK
+* sdk.auth - Array of authentication types is passed in order to impose different authentication methods in different situations.
+* sdk.namespace - Refers to the route namespace.
+* sdk.method - Refers to the sdk method that needs to called.
+* sdk.description - Description of the route,using markdown format.
+* sdk.sdk.response.code - Refers to the route http response status code expected.
+* sdk.auth.response.model - Refers the route http response expected.
+
+```php
+App::post('/v1/account/jwt')
+ ->label('sdk.auth', [APP_AUTH_TYPE_SESSION])
+ ->label('sdk.namespace', 'account')
+ ->label('sdk.method', 'createJWT')
+ ->label('sdk.description', '/docs/references/account/create-jwt.md')
+ ->label('sdk.response.code', Response::STATUS_CODE_CREATED)
+ ->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
+ ->label('sdk.response.model', Response::MODEL_JWT)
+```
+
+#### Cache
+* cache - When set to true, signal the use of file cache.
+* cache.resource - Identifies the cached resource.
+
+```php
+App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
+ ->label('cache', true)
+ ->label('cache.resource', 'file/{request.fileId}')
+```
+
+#### Abuse
+* abuse-key - Specifies routes unique abuse key.
+* abuse-limit - Specifies the number of times the route can be requested in a time frame, per route.
+* abuse-time - Specifies the time frame (in seconds) relevancy of the all other abuse definitions, per route.
+
+When using the example below, we configure the abuse mechanism to allow this key combination
+constructed from the combination of the ip, http method, url, userId to hit the route maximum 60 times in 1 hour (60 seconds * 60 minutes).
+
+```php
+App::post('/v1/storage/buckets/:bucketId/files')
+ ->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
+ ->label('abuse-limit', 60)
+ ->label('abuse-time', 3600)
+```
+
+#### Events
+* event - A pattern that is associated with the route in behalf of realtime messaging.
+ Placeholders marked as `[]` are parsed and replaced with their real values.
+
+```php
+App::post('/v1/storage/buckets/:bucketId/files')
+ ->label('event', 'buckets.[bucketId].files.[fileId].create')
+```
+
+#### Usage
+* usage.metric - The metric the route generates.
+* usage.params - Additional parameters the metrics can have.
+```php
+App::post('/v1/storage/buckets/:bucketId/files')
+ ->label('usage.metric', 'files.{scope}.requests.create')
+ ->label('usage.params', ['bucketId:{request.bucketId}'])
+```
+
+### 5. Param
+As the name implies, `param()` is used to define a request parameter.
+
+`param()` accepts 6 parameters :
+* A key (name)
+* A default value
+* An instance of a validator class,This can also accept a callback that returns a validator instance. Dependency injection is supported for the callback.
+* Description of the parameter
+* Is the route optional
+* An array of injections
+
+```php
+App::get('/v1/account/logs')
+ ->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset', true)
+```
+
+
+### 6. inject
+inject is used to inject dependencies pre-bounded to the app.
+
+```php
+App::post('/v1/storage/buckets/:bucketId/files')
+ ->inject('user')
+```
+
+In the example above, the user object is injected into the route pre-bounded using `App::setResource()`.
+
+```php
+App::setResource('user', function() {
+some code...
+});
+```
+
+### 6. Action
+Action populates the actual routes code and has to be very clear and understandable. A good route stay simple and doesn't contain complex logic. An action is where we describe our business need in code, and combine different libraries to work together and tell our story.
+
+```php
+App::post('/v1/account/sessions/anonymous')
+ ->action(function (Request $request) {
+ some code...
+});
+```
diff --git a/public/dist/scripts/app-all.js b/public/dist/scripts/app-all.js
index f463538519..52f329f1e7 100644
--- a/public/dist/scripts/app-all.js
+++ b/public/dist/scripts/app-all.js
@@ -3967,7 +3967,7 @@ return false;};return{isRTL:isRTL,};},true);})(window);(function(window){"use st
let size=element.dataset["size"]||80;let name=$value.name||$value||"";name=(typeof name!=='string')?'--':name;return def="/v1/avatars/initials?project=console"+"&name="+
encodeURIComponent(name)+"&width="+
size+"&height="+
-size;}).add("selectedCollection",function($value,router){return $value===router.params.collectionId?"selected":"";}).add("selectedDocument",function($value,router){return $value===router.params.documentId?"selected":"";}).add("localeString",function($value){$value=parseInt($value);return!Number.isNaN($value)?$value.toLocaleString():"";}).add("dateTime",function($value,date){return $value?date.format({year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'},$value):"";}).add("date",function($value,date){return $value?date.format({year:'numeric',month:'short',day:'2-digit',},$value):"";}).add("timeSince",function($value){$value=new Date($value).getTime();let now=new Date();now.setMinutes(now.getMinutes()+now.getTimezoneOffset());let timestamp=new Date(now.toISOString()).getTime();let seconds=Math.floor((timestamp-$value)/1000);let unit="second";let direction="ago";if(seconds<0){seconds=-seconds;direction="from now";}
+size;}).add("selectedCollection",function($value,router){return $value===router.params.collectionId?"selected":"";}).add("selectedDocument",function($value,router){return $value===router.params.documentId?"selected":"";}).add("localeString",function($value){$value=parseInt($value);return!Number.isNaN($value)?$value.toLocaleString():"";}).add("dateTime",function($value,date){return $value?date.format({year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'},$value):"";}).add("date",function($value,date){return $value?date.format({year:'numeric',month:'short',day:'2-digit',},$value):"";}).add("timeSince",function($value){$value=new Date($value).getTime();let timestamp=new Date().getTime();let seconds=Math.floor((timestamp-$value)/1000);let unit="second";let direction="ago";if(seconds<0){seconds=-seconds;direction="from now";}
let value=seconds;if(seconds>=31536000){value=Math.floor(seconds/31536000);unit="year";}
else if(seconds>=86400){value=Math.floor(seconds/86400);unit="day";}
else if(seconds>=3600){value=Math.floor(seconds/3600);unit="hour";}
diff --git a/public/dist/scripts/app.js b/public/dist/scripts/app.js
index 0c79e5ba70..ed3fc41d53 100644
--- a/public/dist/scripts/app.js
+++ b/public/dist/scripts/app.js
@@ -555,7 +555,7 @@ return false;};return{isRTL:isRTL,};},true);})(window);(function(window){"use st
let size=element.dataset["size"]||80;let name=$value.name||$value||"";name=(typeof name!=='string')?'--':name;return def="/v1/avatars/initials?project=console"+"&name="+
encodeURIComponent(name)+"&width="+
size+"&height="+
-size;}).add("selectedCollection",function($value,router){return $value===router.params.collectionId?"selected":"";}).add("selectedDocument",function($value,router){return $value===router.params.documentId?"selected":"";}).add("localeString",function($value){$value=parseInt($value);return!Number.isNaN($value)?$value.toLocaleString():"";}).add("dateTime",function($value,date){return $value?date.format({year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'},$value):"";}).add("date",function($value,date){return $value?date.format({year:'numeric',month:'short',day:'2-digit',},$value):"";}).add("timeSince",function($value){$value=new Date($value).getTime();let now=new Date();now.setMinutes(now.getMinutes()+now.getTimezoneOffset());let timestamp=new Date(now.toISOString()).getTime();let seconds=Math.floor((timestamp-$value)/1000);let unit="second";let direction="ago";if(seconds<0){seconds=-seconds;direction="from now";}
+size;}).add("selectedCollection",function($value,router){return $value===router.params.collectionId?"selected":"";}).add("selectedDocument",function($value,router){return $value===router.params.documentId?"selected":"";}).add("localeString",function($value){$value=parseInt($value);return!Number.isNaN($value)?$value.toLocaleString():"";}).add("dateTime",function($value,date){return $value?date.format({year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'},$value):"";}).add("date",function($value,date){return $value?date.format({year:'numeric',month:'short',day:'2-digit',},$value):"";}).add("timeSince",function($value){$value=new Date($value).getTime();let timestamp=new Date().getTime();let seconds=Math.floor((timestamp-$value)/1000);let unit="second";let direction="ago";if(seconds<0){seconds=-seconds;direction="from now";}
let value=seconds;if(seconds>=31536000){value=Math.floor(seconds/31536000);unit="year";}
else if(seconds>=86400){value=Math.floor(seconds/86400);unit="day";}
else if(seconds>=3600){value=Math.floor(seconds/3600);unit="hour";}
diff --git a/public/scripts/filters.js b/public/scripts/filters.js
index b913a5648f..3e6679285f 100644
--- a/public/scripts/filters.js
+++ b/public/scripts/filters.js
@@ -47,13 +47,7 @@ window.ls.filter
.add("timeSince", function ($value) {
$value = new Date($value).getTime();
- /**
- * Adapt to timezone UTC.
- */
- let now = new Date();
- now.setMinutes(now.getMinutes() + now.getTimezoneOffset());
-
- let timestamp = new Date(now.toISOString()).getTime();
+ let timestamp = new Date().getTime();
let seconds = Math.floor((timestamp - $value) / 1000);
let unit = "second";
let direction = "ago";
diff --git a/src/Appwrite/Auth/Auth.php b/src/Appwrite/Auth/Auth.php
index 37a2ea8d39..c290d19862 100644
--- a/src/Appwrite/Auth/Auth.php
+++ b/src/Appwrite/Auth/Auth.php
@@ -431,11 +431,14 @@ class Auth
continue;
}
- if (isset($node['teamId']) && isset($node['roles'])) {
+ if (isset($node['$id']) && isset($node['teamId'])) {
$roles[] = Role::team($node['teamId'])->toString();
+ $roles[] = Role::member($node['$id'])->toString();
- foreach ($node['roles'] as $nodeRole) { // Set all team roles
- $roles[] = Role::team($node['teamId'], $nodeRole)->toString();
+ if (isset($node['roles'])) {
+ foreach ($node['roles'] as $nodeRole) { // Set all team roles
+ $roles[] = Role::team($node['teamId'], $nodeRole)->toString();
+ }
}
}
}
diff --git a/src/Appwrite/Usage/Calculators/TimeSeries.php b/src/Appwrite/Usage/Calculators/TimeSeries.php
index c2a6b4a141..01c8661206 100644
--- a/src/Appwrite/Usage/Calculators/TimeSeries.php
+++ b/src/Appwrite/Usage/Calculators/TimeSeries.php
@@ -323,7 +323,6 @@ class TimeSeries extends Calculator
$document->setAttribute('value', $value)
);
}
- $this->latestTime[$metric][$period] = $time;
} catch (\Exception $e) { // if projects are deleted this might fail
if (is_callable($this->errorHandler)) {
call_user_func($this->errorHandler, $e, "sync_project_{$projectId}_metric_{$metric}");
@@ -397,6 +396,7 @@ class TimeSeries extends Calculator
$value,
0
);
+ $this->latestTime[$metric][$period['key']] = $point['time'];
}
}
} catch (\Exception $e) { // if projects are deleted this might fail
diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php b/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php
index 74996936b9..2bfe46e28d 100644
--- a/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php
+++ b/src/Appwrite/Utopia/Database/Validator/Queries/Executions.php
@@ -8,7 +8,7 @@ class Executions extends Base
'trigger',
'status',
'statusCode',
- 'time'
+ 'duration'
];
/**
diff --git a/src/Appwrite/Utopia/Response/Model/Build.php b/src/Appwrite/Utopia/Response/Model/Build.php
index 0a28cbffa3..b76f0ee083 100644
--- a/src/Appwrite/Utopia/Response/Model/Build.php
+++ b/src/Appwrite/Utopia/Response/Model/Build.php
@@ -59,7 +59,7 @@ class Build extends Model
])
->addRule('duration', [
'type' => self::TYPE_INTEGER,
- 'description' => 'The build time in seconds.',
+ 'description' => 'The build duration in seconds.',
'default' => 0,
'example' => 0,
])
diff --git a/src/Appwrite/Utopia/Response/Model/Execution.php b/src/Appwrite/Utopia/Response/Model/Execution.php
index 74497cf935..13011a24b7 100644
--- a/src/Appwrite/Utopia/Response/Model/Execution.php
+++ b/src/Appwrite/Utopia/Response/Model/Execution.php
@@ -78,9 +78,9 @@ class Execution extends Model
'default' => '',
'example' => '',
])
- ->addRule('time', [
+ ->addRule('duration', [
'type' => self::TYPE_FLOAT,
- 'description' => 'The script execution time in seconds.',
+ 'description' => 'The script execution duration in seconds.',
'default' => 0,
'example' => 0.400,
])
diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php
index cde5dd3e29..5126b8eb8d 100644
--- a/tests/e2e/General/UsageTest.php
+++ b/tests/e2e/General/UsageTest.php
@@ -26,8 +26,7 @@ class UsageTest extends Scope
parent::setUp();
}
- #[Retry(count: 1)]
- public function testUsersStats(): array
+ public function testPrepareUsersStats(): array
{
$project = $this->getProject(true);
$projectId = $project['$id'];
@@ -63,8 +62,27 @@ class UsageTest extends Scope
}
}
+ return [
+ 'projectId' => $projectId,
+ 'headers' => $headers,
+ 'usersCount' => $usersCount,
+ 'requestsCount' => $requestsCount
+ ];
+ }
+
+ /**
+ * @depends testPrepareUsersStats
+ */
+ #[Retry(count: 1)]
+ public function testUsersStats(array $data): array
+ {
sleep(35);
+ $projectId = $data['projectId'];
+ $headers = $data['headers'];
+ $usersCount = $data['usersCount'];
+ $requestsCount = $data['requestsCount'];
+
// console request
$cheaders = [
'origin' => 'http://localhost',
@@ -94,8 +112,7 @@ class UsageTest extends Scope
}
/** @depends testUsersStats */
- #[Retry(count: 1)]
- public function testStorageStats(array $data): array
+ public function testPrepareStorageStats(array $data): array
{
$projectId = $data['projectId'];
$headers = $data['headers'];
@@ -190,6 +207,40 @@ class UsageTest extends Scope
}
}
+ return array_merge($data, [
+ 'bucketId' => $bucketId,
+ 'bucketsCount' => $bucketsCount,
+ 'requestsCount' => $requestsCount,
+ 'storageTotal' => $storageTotal,
+ 'bucketsCreate' => $bucketsCreate,
+ 'bucketsDelete' => $bucketsDelete,
+ 'bucketsRead' => $bucketsRead,
+ 'filesCount' => $filesCount,
+ 'filesRead' => $filesRead,
+ 'filesCreate' => $filesCreate,
+ 'filesDelete' => $filesDelete,
+ ]);
+ }
+
+ /**
+ * @depends testPrepareStorageStats
+ */
+ #[Retry(count: 1)]
+ public function testStorageStats(array $data): array
+ {
+ $projectId = $data['projectId'];
+ $bucketId = $data['bucketId'];
+ $bucketsCount = $data['bucketsCount'];
+ $requestsCount = $data['requestsCount'];
+ $storageTotal = $data['storageTotal'];
+ $bucketsCreate = $data['bucketsCreate'];
+ $bucketsDelete = $data['bucketsDelete'];
+ $bucketsRead = $data['bucketsRead'];
+ $filesCount = $data['filesCount'];
+ $filesRead = $data['filesRead'];
+ $filesCreate = $data['filesCreate'];
+ $filesDelete = $data['filesDelete'];
+
sleep(35);
// console request
@@ -239,8 +290,7 @@ class UsageTest extends Scope
}
/** @depends testStorageStats */
- #[Retry(count: 1)]
- public function testDatabaseStats(array $data): array
+ public function testPrepareDatabaseStats(array $data): array
{
$headers = $data['headers'];
$projectId = $data['projectId'];
@@ -366,6 +416,58 @@ class UsageTest extends Scope
}
}
+ $data = array_merge($data, [
+ 'databaseId' => $databaseId,
+ 'collectionId' => $collectionId,
+
+ 'requestsCount' => $requestsCount,
+ 'databasesCount' => $databasesCount,
+ 'databasesCreate' => $databasesCreate,
+ 'databasesRead' => $databasesRead,
+ 'databasesDelete' => $databasesDelete,
+
+ 'collectionsCount' => $collectionsCount,
+ 'collectionsCreate' => $collectionsCreate,
+ 'collectionsRead' => $collectionsRead,
+ 'collectionsUpdate' => $collectionsUpdate,
+ 'collectionsDelete' => $collectionsDelete,
+
+ 'documentsCount' => $documentsCount,
+ 'documentsCreate' => $documentsCreate,
+ 'documentsRead' => $documentsRead,
+ 'documentsDelete' => $documentsDelete,
+ ]);
+
+ return $data;
+ }
+
+ /** @depends testPrepareDatabaseStats */
+ #[Retry(count: 1)]
+ public function testDatabaseStats(array $data): array
+ {
+ $headers = $data['headers'];
+ $projectId = $data['projectId'];
+
+ $databaseId = $data['databaseId'];
+ $collectionId = $data['collectionId'];
+
+ $requestsCount = $data['requestsCount'];
+ $databasesCount = $data['databasesCount'];
+ $databasesCreate = $data['databasesCreate'];
+ $databasesRead = $data['databasesRead'];
+ $databasesDelete = $data['databasesDelete'];
+
+ $collectionsCount = $data['collectionsCount'];
+ $collectionsCreate = $data['collectionsCreate'];
+ $collectionsRead = $data['collectionsRead'];
+ $collectionsUpdate = $data['collectionsUpdate'];
+ $collectionsDelete = $data['collectionsDelete'];
+
+ $documentsCount = $data['documentsCount'];
+ $documentsCreate = $data['documentsCreate'];
+ $documentsRead = $data['documentsRead'];
+ $documentsDelete = $data['documentsDelete'];
+
sleep(35);
// check datbase stats
@@ -440,8 +542,7 @@ class UsageTest extends Scope
/** @depends testDatabaseStats */
- #[Retry(count: 1)]
- public function testFunctionsStats(array $data): void
+ public function testPrepareFunctionsStats(array $data): array
{
$headers = $data['headers'];
$functionId = '';
@@ -505,7 +606,7 @@ class UsageTest extends Scope
$this->assertEquals(201, $execution['headers']['status-code']);
$this->assertNotEmpty($execution['body']['$id']);
$this->assertEquals($functionId, $execution['body']['functionId']);
- $executionTime += (int) ($execution['body']['time'] * 1000);
+ $executionTime += (int) ($execution['body']['duration'] * 1000);
if ($execution['body']['status'] == 'failed') {
$failures++;
} elseif ($execution['body']['status'] == 'completed') {
@@ -524,7 +625,27 @@ class UsageTest extends Scope
} elseif ($execution['body']['status'] == 'completed') {
$executions++;
}
- $executionTime += (int) ($execution['body']['time'] * 1000);
+ $executionTime += (int) ($execution['body']['duration'] * 1000);
+
+ $data = array_merge($data, [
+ 'functionId' => $functionId,
+ 'executionTime' => $executionTime,
+ 'executions' => $executions,
+ 'failures' => $failures,
+ ]);
+
+ return $data;
+ }
+
+ /** @depends testPrepareFunctionsStats */
+ #[Retry(count: 1)]
+ public function testFunctionsStats(array $data): void
+ {
+ $headers = $data['headers'];
+ $functionId = $data['functionId'];
+ $executionTime = $data['executionTime'];
+ $executions = $data['executions'];
+ $failures = $data['failures'];
sleep(25);
diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
index 8e3fd47b38..f974c6006e 100644
--- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
+++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
@@ -608,7 +608,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(0, $execution['body']['statusCode']);
$this->assertEquals('', $execution['body']['response']);
$this->assertEquals('', $execution['body']['stderr']);
- $this->assertEquals(0, $execution['body']['time']);
+ $this->assertEquals(0, $execution['body']['duration']);
sleep(5);
@@ -631,7 +631,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertStringContainsString('8.0', $execution['body']['response']);
$this->assertStringContainsString('êä', $execution['body']['response']); // tests unknown utf-8 chars
$this->assertEquals('', $execution['body']['stderr']);
- $this->assertLessThan(0.500, $execution['body']['time']);
+ $this->assertLessThan(0.500, $execution['body']['duration']);
/**
* Test for FAILURE
@@ -750,7 +750,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertStringContainsString('PHP', $execution['body']['response']);
$this->assertStringContainsString('8.0', $execution['body']['response']);
$this->assertStringContainsString('êä', $execution['body']['response']); // tests unknown utf-8 chars
- $this->assertLessThan(0.500, $execution['body']['time']);
+ $this->assertLessThan(0.500, $execution['body']['duration']);
return $data;
}
@@ -909,9 +909,9 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
$this->assertEquals($executions['body']['executions'][0]['status'], 'failed');
$this->assertEquals($executions['body']['executions'][0]['statusCode'], 500);
- $this->assertGreaterThan(2, $executions['body']['executions'][0]['time']);
- $this->assertLessThan(6, $executions['body']['executions'][0]['time']);
- $this->assertGreaterThan(4, $executions['body']['executions'][0]['time']);
+ $this->assertGreaterThan(2, $executions['body']['executions'][0]['duration']);
+ $this->assertLessThan(6, $executions['body']['executions'][0]['duration']);
+ $this->assertGreaterThan(4, $executions['body']['executions'][0]['duration']);
$this->assertEquals($executions['body']['executions'][0]['response'], '');
$this->assertEquals($executions['body']['executions'][0]['stderr'], 'An internal curl error has occurred within the executor! Error Msg: Operation timed out');
diff --git a/tests/resources/functions/dart/main.dart b/tests/resources/functions/dart/main.dart
index 93463e9321..0a6cabdac7 100644
--- a/tests/resources/functions/dart/main.dart
+++ b/tests/resources/functions/dart/main.dart
@@ -2,7 +2,7 @@
'req' variable has:
'headers' - object with request headers
'payload' - object with request body data
- 'env' - object with environment variables
+ 'variables' - object with function variables
'res' variable has:
'send(text, status)' - function to return text response. Status code defaults to 200
'json(obj, status)' - function to return JSON response. Status code defaults to 200
@@ -12,18 +12,18 @@
Future start(final request, final response) async {
response.json({
- 'APPWRITE_FUNCTION_ID' : request.env['APPWRITE_FUNCTION_ID'],
- 'APPWRITE_FUNCTION_NAME' : request.env['APPWRITE_FUNCTION_NAME'],
- 'APPWRITE_FUNCTION_DEPLOYMENT' : request.env['APPWRITE_FUNCTION_DEPLOYMENT'],
- 'APPWRITE_FUNCTION_TRIGGER' : request.env['APPWRITE_FUNCTION_TRIGGER'],
- 'APPWRITE_FUNCTION_RUNTIME_NAME' : request.env['APPWRITE_FUNCTION_RUNTIME_NAME'],
- 'APPWRITE_FUNCTION_RUNTIME_VERSION' : request.env['APPWRITE_FUNCTION_RUNTIME_VERSION'],
- 'APPWRITE_FUNCTION_EVENT' : request.env['APPWRITE_FUNCTION_EVENT'],
- 'APPWRITE_FUNCTION_EVENT_DATA' : request.env['APPWRITE_FUNCTION_EVENT_DATA'],
- 'APPWRITE_FUNCTION_DATA' : request.env['APPWRITE_FUNCTION_DATA'],
- 'APPWRITE_FUNCTION_USER_ID' : request.env['APPWRITE_FUNCTION_USER_ID'],
- 'APPWRITE_FUNCTION_JWT' : request.env['APPWRITE_FUNCTION_JWT'],
- 'APPWRITE_FUNCTION_PROJECT_ID' : request.env['APPWRITE_FUNCTION_PROJECT_ID'],
- 'CUSTOM_VARIABLE' : request.env['CUSTOM_VARIABLE']
+ 'APPWRITE_FUNCTION_ID' : request.variables['APPWRITE_FUNCTION_ID'],
+ 'APPWRITE_FUNCTION_NAME' : request.variables['APPWRITE_FUNCTION_NAME'],
+ 'APPWRITE_FUNCTION_DEPLOYMENT' : request.variables['APPWRITE_FUNCTION_DEPLOYMENT'],
+ 'APPWRITE_FUNCTION_TRIGGER' : request.variables['APPWRITE_FUNCTION_TRIGGER'],
+ 'APPWRITE_FUNCTION_RUNTIME_NAME' : request.variables['APPWRITE_FUNCTION_RUNTIME_NAME'],
+ 'APPWRITE_FUNCTION_RUNTIME_VERSION' : request.variables['APPWRITE_FUNCTION_RUNTIME_VERSION'],
+ 'APPWRITE_FUNCTION_EVENT' : request.variables['APPWRITE_FUNCTION_EVENT'],
+ 'APPWRITE_FUNCTION_EVENT_DATA' : request.variables['APPWRITE_FUNCTION_EVENT_DATA'],
+ 'APPWRITE_FUNCTION_DATA' : request.variables['APPWRITE_FUNCTION_DATA'],
+ 'APPWRITE_FUNCTION_USER_ID' : request.variables['APPWRITE_FUNCTION_USER_ID'],
+ 'APPWRITE_FUNCTION_JWT' : request.variables['APPWRITE_FUNCTION_JWT'],
+ 'APPWRITE_FUNCTION_PROJECT_ID' : request.variables['APPWRITE_FUNCTION_PROJECT_ID'],
+ 'CUSTOM_VARIABLE' : request.variables['CUSTOM_VARIABLE']
});
}
\ No newline at end of file
diff --git a/tests/resources/functions/node/index.js b/tests/resources/functions/node/index.js
index 67e011e77e..7f190bcaf5 100644
--- a/tests/resources/functions/node/index.js
+++ b/tests/resources/functions/node/index.js
@@ -2,7 +2,7 @@
'req' variable has:
'headers' - object with request headers
'payload' - object with request body data
- 'env' - object with environment variables
+ 'variables' - object with function variables
'res' variable has:
'send(text, status)' - function to return text response. Status code defaults to 200
'json(obj, status)' - function to return JSON response. Status code defaults to 200
@@ -12,18 +12,18 @@
module.exports = async(req, res) => {
res.json({
- 'APPWRITE_FUNCTION_ID' : req.env.APPWRITE_FUNCTION_ID,
- 'APPWRITE_FUNCTION_NAME' : req.env.APPWRITE_FUNCTION_NAME,
- 'APPWRITE_FUNCTION_DEPLOYMENT' : req.env.APPWRITE_FUNCTION_DEPLOYMENT,
- 'APPWRITE_FUNCTION_TRIGGER' : req.env.APPWRITE_FUNCTION_TRIGGER,
- 'APPWRITE_FUNCTION_RUNTIME_NAME' : req.env.APPWRITE_FUNCTION_RUNTIME_NAME,
- 'APPWRITE_FUNCTION_RUNTIME_VERSION' : req.env.APPWRITE_FUNCTION_RUNTIME_VERSION,
- 'APPWRITE_FUNCTION_EVENT' : req.env.APPWRITE_FUNCTION_EVENT,
- 'APPWRITE_FUNCTION_EVENT_DATA' : req.env.APPWRITE_FUNCTION_EVENT_DATA,
- 'APPWRITE_FUNCTION_DATA' : req.env.APPWRITE_FUNCTION_DATA,
- 'APPWRITE_FUNCTION_USER_ID' : req.env.APPWRITE_FUNCTION_USER_ID,
- 'APPWRITE_FUNCTION_JWT' : req.env.APPWRITE_FUNCTION_JWT,
- 'APPWRITE_FUNCTION_PROJECT_ID' : req.env.APPWRITE_FUNCTION_PROJECT_ID,
- 'CUSTOM_VARIABLE' : req.env.CUSTOM_VARIABLE
+ 'APPWRITE_FUNCTION_ID' : req.variables.APPWRITE_FUNCTION_ID,
+ 'APPWRITE_FUNCTION_NAME' : req.variables.APPWRITE_FUNCTION_NAME,
+ 'APPWRITE_FUNCTION_DEPLOYMENT' : req.variables.APPWRITE_FUNCTION_DEPLOYMENT,
+ 'APPWRITE_FUNCTION_TRIGGER' : req.variables.APPWRITE_FUNCTION_TRIGGER,
+ 'APPWRITE_FUNCTION_RUNTIME_NAME' : req.variables.APPWRITE_FUNCTION_RUNTIME_NAME,
+ 'APPWRITE_FUNCTION_RUNTIME_VERSION' : req.variables.APPWRITE_FUNCTION_RUNTIME_VERSION,
+ 'APPWRITE_FUNCTION_EVENT' : req.variables.APPWRITE_FUNCTION_EVENT,
+ 'APPWRITE_FUNCTION_EVENT_DATA' : req.variables.APPWRITE_FUNCTION_EVENT_DATA,
+ 'APPWRITE_FUNCTION_DATA' : req.variables.APPWRITE_FUNCTION_DATA,
+ 'APPWRITE_FUNCTION_USER_ID' : req.variables.APPWRITE_FUNCTION_USER_ID,
+ 'APPWRITE_FUNCTION_JWT' : req.variables.APPWRITE_FUNCTION_JWT,
+ 'APPWRITE_FUNCTION_PROJECT_ID' : req.variables.APPWRITE_FUNCTION_PROJECT_ID,
+ 'CUSTOM_VARIABLE' : req.variables.CUSTOM_VARIABLE
});
}
\ No newline at end of file
diff --git a/tests/resources/functions/php-fn/index.php b/tests/resources/functions/php-fn/index.php
index e3ce05829c..7947c4a6a6 100644
--- a/tests/resources/functions/php-fn/index.php
+++ b/tests/resources/functions/php-fn/index.php
@@ -4,17 +4,17 @@ return function ($request, $response) {
\var_dump("Amazing Function Log"); // We test logs (stdout) visibility with this
$response->json([
- 'APPWRITE_FUNCTION_ID' => $request['env']['APPWRITE_FUNCTION_ID'],
- 'APPWRITE_FUNCTION_NAME' => $request['env']['APPWRITE_FUNCTION_NAME'],
- 'APPWRITE_FUNCTION_DEPLOYMENT' => $request['env']['APPWRITE_FUNCTION_DEPLOYMENT'],
- 'APPWRITE_FUNCTION_TRIGGER' => $request['env']['APPWRITE_FUNCTION_TRIGGER'],
- 'APPWRITE_FUNCTION_RUNTIME_NAME' => $request['env']['APPWRITE_FUNCTION_RUNTIME_NAME'],
- 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $request['env']['APPWRITE_FUNCTION_RUNTIME_VERSION'],
- 'APPWRITE_FUNCTION_EVENT' => $request['env']['APPWRITE_FUNCTION_EVENT'],
- 'APPWRITE_FUNCTION_EVENT_DATA' => $request['env']['APPWRITE_FUNCTION_EVENT_DATA'],
- 'APPWRITE_FUNCTION_DATA' => $request['env']['APPWRITE_FUNCTION_DATA'],
- 'APPWRITE_FUNCTION_USER_ID' => $request['env']['APPWRITE_FUNCTION_USER_ID'],
- 'APPWRITE_FUNCTION_JWT' => $request['env']['APPWRITE_FUNCTION_JWT'],
- 'APPWRITE_FUNCTION_PROJECT_ID' => $request['env']['APPWRITE_FUNCTION_PROJECT_ID'],
+ 'APPWRITE_FUNCTION_ID' => $request['variables']['APPWRITE_FUNCTION_ID'],
+ 'APPWRITE_FUNCTION_NAME' => $request['variables']['APPWRITE_FUNCTION_NAME'],
+ 'APPWRITE_FUNCTION_DEPLOYMENT' => $request['variables']['APPWRITE_FUNCTION_DEPLOYMENT'],
+ 'APPWRITE_FUNCTION_TRIGGER' => $request['variables']['APPWRITE_FUNCTION_TRIGGER'],
+ 'APPWRITE_FUNCTION_RUNTIME_NAME' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_NAME'],
+ 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_VERSION'],
+ 'APPWRITE_FUNCTION_EVENT' => $request['variables']['APPWRITE_FUNCTION_EVENT'],
+ 'APPWRITE_FUNCTION_EVENT_DATA' => $request['variables']['APPWRITE_FUNCTION_EVENT_DATA'],
+ 'APPWRITE_FUNCTION_DATA' => $request['variables']['APPWRITE_FUNCTION_DATA'],
+ 'APPWRITE_FUNCTION_USER_ID' => $request['variables']['APPWRITE_FUNCTION_USER_ID'],
+ 'APPWRITE_FUNCTION_JWT' => $request['variables']['APPWRITE_FUNCTION_JWT'],
+ 'APPWRITE_FUNCTION_PROJECT_ID' => $request['variables']['APPWRITE_FUNCTION_PROJECT_ID'],
]);
};
diff --git a/tests/resources/functions/php-large/index.php b/tests/resources/functions/php-large/index.php
index 8bd0de5e60..84b6a991fe 100644
--- a/tests/resources/functions/php-large/index.php
+++ b/tests/resources/functions/php-large/index.php
@@ -2,14 +2,14 @@
return function ($request, $response) {
return $response->json([
- 'APPWRITE_FUNCTION_ID' => $request['env']['APPWRITE_FUNCTION_ID'],
- 'APPWRITE_FUNCTION_NAME' => $request['env']['APPWRITE_FUNCTION_NAME'],
- 'APPWRITE_FUNCTION_DEPLOYMENT' => $request['env']['APPWRITE_FUNCTION_DEPLOYMENT'],
- 'APPWRITE_FUNCTION_TRIGGER' => $request['env']['APPWRITE_FUNCTION_TRIGGER'],
- 'APPWRITE_FUNCTION_RUNTIME_NAME' => $request['env']['APPWRITE_FUNCTION_RUNTIME_NAME'],
- 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $request['env']['APPWRITE_FUNCTION_RUNTIME_VERSION'],
- 'APPWRITE_FUNCTION_EVENT' => $request['env']['APPWRITE_FUNCTION_EVENT'],
- 'APPWRITE_FUNCTION_EVENT_DATA' => $request['env']['APPWRITE_FUNCTION_EVENT_DATA'],
+ 'APPWRITE_FUNCTION_ID' => $request['variables']['APPWRITE_FUNCTION_ID'],
+ 'APPWRITE_FUNCTION_NAME' => $request['variables']['APPWRITE_FUNCTION_NAME'],
+ 'APPWRITE_FUNCTION_DEPLOYMENT' => $request['variables']['APPWRITE_FUNCTION_DEPLOYMENT'],
+ 'APPWRITE_FUNCTION_TRIGGER' => $request['variables']['APPWRITE_FUNCTION_TRIGGER'],
+ 'APPWRITE_FUNCTION_RUNTIME_NAME' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_NAME'],
+ 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_VERSION'],
+ 'APPWRITE_FUNCTION_EVENT' => $request['variables']['APPWRITE_FUNCTION_EVENT'],
+ 'APPWRITE_FUNCTION_EVENT_DATA' => $request['variables']['APPWRITE_FUNCTION_EVENT_DATA'],
'UNICODE_TEST' => "êä"
]);
};
diff --git a/tests/resources/functions/php/index.php b/tests/resources/functions/php/index.php
index 8bd0de5e60..84b6a991fe 100644
--- a/tests/resources/functions/php/index.php
+++ b/tests/resources/functions/php/index.php
@@ -2,14 +2,14 @@
return function ($request, $response) {
return $response->json([
- 'APPWRITE_FUNCTION_ID' => $request['env']['APPWRITE_FUNCTION_ID'],
- 'APPWRITE_FUNCTION_NAME' => $request['env']['APPWRITE_FUNCTION_NAME'],
- 'APPWRITE_FUNCTION_DEPLOYMENT' => $request['env']['APPWRITE_FUNCTION_DEPLOYMENT'],
- 'APPWRITE_FUNCTION_TRIGGER' => $request['env']['APPWRITE_FUNCTION_TRIGGER'],
- 'APPWRITE_FUNCTION_RUNTIME_NAME' => $request['env']['APPWRITE_FUNCTION_RUNTIME_NAME'],
- 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $request['env']['APPWRITE_FUNCTION_RUNTIME_VERSION'],
- 'APPWRITE_FUNCTION_EVENT' => $request['env']['APPWRITE_FUNCTION_EVENT'],
- 'APPWRITE_FUNCTION_EVENT_DATA' => $request['env']['APPWRITE_FUNCTION_EVENT_DATA'],
+ 'APPWRITE_FUNCTION_ID' => $request['variables']['APPWRITE_FUNCTION_ID'],
+ 'APPWRITE_FUNCTION_NAME' => $request['variables']['APPWRITE_FUNCTION_NAME'],
+ 'APPWRITE_FUNCTION_DEPLOYMENT' => $request['variables']['APPWRITE_FUNCTION_DEPLOYMENT'],
+ 'APPWRITE_FUNCTION_TRIGGER' => $request['variables']['APPWRITE_FUNCTION_TRIGGER'],
+ 'APPWRITE_FUNCTION_RUNTIME_NAME' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_NAME'],
+ 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $request['variables']['APPWRITE_FUNCTION_RUNTIME_VERSION'],
+ 'APPWRITE_FUNCTION_EVENT' => $request['variables']['APPWRITE_FUNCTION_EVENT'],
+ 'APPWRITE_FUNCTION_EVENT_DATA' => $request['variables']['APPWRITE_FUNCTION_EVENT_DATA'],
'UNICODE_TEST' => "êä"
]);
};
diff --git a/tests/resources/functions/python/main.py b/tests/resources/functions/python/main.py
index af7d79ab23..ff78d6d336 100644
--- a/tests/resources/functions/python/main.py
+++ b/tests/resources/functions/python/main.py
@@ -3,7 +3,7 @@ import json
# 'req' variable has:
# 'headers' - object with request headers
# 'payload' - object with request body data
-# 'env' - object with environment variables
+# 'variables' - object with function variables
# 'res' variable has:
# 'send(text, status)' - function to return text response. Status code defaults to 200
# 'json(obj, status)' - function to return JSON response. Status code defaults to 200
@@ -12,17 +12,17 @@ import json
def main(request, response):
return response.json({
- 'APPWRITE_FUNCTION_ID' : request.env['APPWRITE_FUNCTION_ID'],
- 'APPWRITE_FUNCTION_NAME' : request.env['APPWRITE_FUNCTION_NAME'],
- 'APPWRITE_FUNCTION_DEPLOYMENT' : request.env['APPWRITE_FUNCTION_DEPLOYMENT'],
- 'APPWRITE_FUNCTION_TRIGGER' : request.env['APPWRITE_FUNCTION_TRIGGER'],
- 'APPWRITE_FUNCTION_RUNTIME_NAME' : request.env['APPWRITE_FUNCTION_RUNTIME_NAME'],
- 'APPWRITE_FUNCTION_RUNTIME_VERSION' : request.env['APPWRITE_FUNCTION_RUNTIME_VERSION'],
- 'APPWRITE_FUNCTION_EVENT' : request.env['APPWRITE_FUNCTION_EVENT'],
- 'APPWRITE_FUNCTION_EVENT_DATA' : request.env['APPWRITE_FUNCTION_EVENT_DATA'],
- 'APPWRITE_FUNCTION_DATA' : request.env['APPWRITE_FUNCTION_DATA'],
- 'APPWRITE_FUNCTION_USER_ID' : request.env['APPWRITE_FUNCTION_USER_ID'],
- 'APPWRITE_FUNCTION_JWT' : request.env['APPWRITE_FUNCTION_JWT'],
- 'APPWRITE_FUNCTION_PROJECT_ID' : request.env['APPWRITE_FUNCTION_PROJECT_ID'],
- 'CUSTOM_VARIABLE' : request.env['CUSTOM_VARIABLE'],
+ 'APPWRITE_FUNCTION_ID' : request.variables['APPWRITE_FUNCTION_ID'],
+ 'APPWRITE_FUNCTION_NAME' : request.variables['APPWRITE_FUNCTION_NAME'],
+ 'APPWRITE_FUNCTION_DEPLOYMENT' : request.variables['APPWRITE_FUNCTION_DEPLOYMENT'],
+ 'APPWRITE_FUNCTION_TRIGGER' : request.variables['APPWRITE_FUNCTION_TRIGGER'],
+ 'APPWRITE_FUNCTION_RUNTIME_NAME' : request.variables['APPWRITE_FUNCTION_RUNTIME_NAME'],
+ 'APPWRITE_FUNCTION_RUNTIME_VERSION' : request.variables['APPWRITE_FUNCTION_RUNTIME_VERSION'],
+ 'APPWRITE_FUNCTION_EVENT' : request.variables['APPWRITE_FUNCTION_EVENT'],
+ 'APPWRITE_FUNCTION_EVENT_DATA' : request.variables['APPWRITE_FUNCTION_EVENT_DATA'],
+ 'APPWRITE_FUNCTION_DATA' : request.variables['APPWRITE_FUNCTION_DATA'],
+ 'APPWRITE_FUNCTION_USER_ID' : request.variables['APPWRITE_FUNCTION_USER_ID'],
+ 'APPWRITE_FUNCTION_JWT' : request.variables['APPWRITE_FUNCTION_JWT'],
+ 'APPWRITE_FUNCTION_PROJECT_ID' : request.variables['APPWRITE_FUNCTION_PROJECT_ID'],
+ 'CUSTOM_VARIABLE' : request.variables['CUSTOM_VARIABLE'],
})
\ No newline at end of file
diff --git a/tests/resources/functions/ruby/main.rb b/tests/resources/functions/ruby/main.rb
index 41b9b0fc52..d6ccdfb073 100644
--- a/tests/resources/functions/ruby/main.rb
+++ b/tests/resources/functions/ruby/main.rb
@@ -2,7 +2,7 @@
'req' variable has:
'headers' - object with request headers
'payload' - object with request body data
- 'env' - object with environment variables
+ 'variables' - object with function variables
'res' variable has:
'send(text, status)' - function to return text response. Status code defaults to 200
'json(obj, status)' - function to return JSON response. Status code defaults to 200
@@ -12,18 +12,18 @@
def main(request, response)
return response.json({
- 'APPWRITE_FUNCTION_ID' => request.env['APPWRITE_FUNCTION_ID'],
- 'APPWRITE_FUNCTION_NAME' => request.env['APPWRITE_FUNCTION_NAME'],
- 'APPWRITE_FUNCTION_DEPLOYMENT' => request.env['APPWRITE_FUNCTION_DEPLOYMENT'],
- 'APPWRITE_FUNCTION_TRIGGER' => request.env['APPWRITE_FUNCTION_TRIGGER'],
- 'APPWRITE_FUNCTION_RUNTIME_NAME' => request.env['APPWRITE_FUNCTION_RUNTIME_NAME'],
- 'APPWRITE_FUNCTION_RUNTIME_VERSION' => request.env['APPWRITE_FUNCTION_RUNTIME_VERSION'],
- 'APPWRITE_FUNCTION_EVENT' => request.env['APPWRITE_FUNCTION_EVENT'],
- 'APPWRITE_FUNCTION_EVENT_DATA' => request.env['APPWRITE_FUNCTION_EVENT_DATA'],
- 'APPWRITE_FUNCTION_DATA' => request.env['APPWRITE_FUNCTION_DATA'],
- 'APPWRITE_FUNCTION_USER_ID' => request.env['APPWRITE_FUNCTION_USER_ID'],
- 'APPWRITE_FUNCTION_JWT' => request.env['APPWRITE_FUNCTION_JWT'],
- 'APPWRITE_FUNCTION_PROJECT_ID' => request.env['APPWRITE_FUNCTION_PROJECT_ID'],
- 'CUSTOM_VARIABLE' => request.env['CUSTOM_VARIABLE']
+ 'APPWRITE_FUNCTION_ID' => request.variables['APPWRITE_FUNCTION_ID'],
+ 'APPWRITE_FUNCTION_NAME' => request.variables['APPWRITE_FUNCTION_NAME'],
+ 'APPWRITE_FUNCTION_DEPLOYMENT' => request.variables['APPWRITE_FUNCTION_DEPLOYMENT'],
+ 'APPWRITE_FUNCTION_TRIGGER' => request.variables['APPWRITE_FUNCTION_TRIGGER'],
+ 'APPWRITE_FUNCTION_RUNTIME_NAME' => request.variables['APPWRITE_FUNCTION_RUNTIME_NAME'],
+ 'APPWRITE_FUNCTION_RUNTIME_VERSION' => request.variables['APPWRITE_FUNCTION_RUNTIME_VERSION'],
+ 'APPWRITE_FUNCTION_EVENT' => request.variables['APPWRITE_FUNCTION_EVENT'],
+ 'APPWRITE_FUNCTION_EVENT_DATA' => request.variables['APPWRITE_FUNCTION_EVENT_DATA'],
+ 'APPWRITE_FUNCTION_DATA' => request.variables['APPWRITE_FUNCTION_DATA'],
+ 'APPWRITE_FUNCTION_USER_ID' => request.variables['APPWRITE_FUNCTION_USER_ID'],
+ 'APPWRITE_FUNCTION_JWT' => request.variables['APPWRITE_FUNCTION_JWT'],
+ 'APPWRITE_FUNCTION_PROJECT_ID' => request.variables['APPWRITE_FUNCTION_PROJECT_ID'],
+ 'CUSTOM_VARIABLE' => request.variables['CUSTOM_VARIABLE']
})
end
\ No newline at end of file
diff --git a/tests/resources/functions/swift/index.swift b/tests/resources/functions/swift/index.swift
index 67b0f35bec..b3dcdbc91a 100644
--- a/tests/resources/functions/swift/index.swift
+++ b/tests/resources/functions/swift/index.swift
@@ -1,17 +1,17 @@
func main(req: RequestValue, res: RequestResponse) throws -> RequestResponse {
return res.json(data: [
- "APPWRITE_FUNCTION_ID": req.env["APPWRITE_FUNCTION_ID"],
- "APPWRITE_FUNCTION_NAME": req.env["APPWRITE_FUNCTION_NAME"],
- "APPWRITE_FUNCTION_DEPLOYMENT": req.env["APPWRITE_FUNCTION_DEPLOYMENT"],
- "APPWRITE_FUNCTION_TRIGGER": req.env["APPWRITE_FUNCTION_TRIGGER"],
- "APPWRITE_FUNCTION_RUNTIME_NAME": req.env["APPWRITE_FUNCTION_RUNTIME_NAME"],
- "APPWRITE_FUNCTION_RUNTIME_VERSION": req.env["APPWRITE_FUNCTION_RUNTIME_VERSION"],
- "APPWRITE_FUNCTION_EVENT": req.env["APPWRITE_FUNCTION_EVENT"],
- "APPWRITE_FUNCTION_EVENT_DATA": req.env["APPWRITE_FUNCTION_EVENT_DATA"],
- "APPWRITE_FUNCTION_DATA": req.env["APPWRITE_FUNCTION_DATA"],
- "APPWRITE_FUNCTION_USER_ID": req.env["APPWRITE_FUNCTION_USER_ID"],
- "APPWRITE_FUNCTION_JWT": req.env["APPWRITE_FUNCTION_JWT"],
- "APPWRITE_FUNCTION_PROJECT_ID": req.env["APPWRITE_FUNCTION_PROJECT_ID"],
- "CUSTOM_VARIABLE": req.env["CUSTOM_VARIABLE"]
+ "APPWRITE_FUNCTION_ID": req.variables["APPWRITE_FUNCTION_ID"],
+ "APPWRITE_FUNCTION_NAME": req.variables["APPWRITE_FUNCTION_NAME"],
+ "APPWRITE_FUNCTION_DEPLOYMENT": req.variables["APPWRITE_FUNCTION_DEPLOYMENT"],
+ "APPWRITE_FUNCTION_TRIGGER": req.variables["APPWRITE_FUNCTION_TRIGGER"],
+ "APPWRITE_FUNCTION_RUNTIME_NAME": req.variables["APPWRITE_FUNCTION_RUNTIME_NAME"],
+ "APPWRITE_FUNCTION_RUNTIME_VERSION": req.variables["APPWRITE_FUNCTION_RUNTIME_VERSION"],
+ "APPWRITE_FUNCTION_EVENT": req.variables["APPWRITE_FUNCTION_EVENT"],
+ "APPWRITE_FUNCTION_EVENT_DATA": req.variables["APPWRITE_FUNCTION_EVENT_DATA"],
+ "APPWRITE_FUNCTION_DATA": req.variables["APPWRITE_FUNCTION_DATA"],
+ "APPWRITE_FUNCTION_USER_ID": req.variables["APPWRITE_FUNCTION_USER_ID"],
+ "APPWRITE_FUNCTION_JWT": req.variables["APPWRITE_FUNCTION_JWT"],
+ "APPWRITE_FUNCTION_PROJECT_ID": req.variables["APPWRITE_FUNCTION_PROJECT_ID"],
+ "CUSTOM_VARIABLE": req.variables["CUSTOM_VARIABLE"]
])
}
\ No newline at end of file
diff --git a/tests/unit/Auth/AuthTest.php b/tests/unit/Auth/AuthTest.php
index 4cd180b956..1480fbb23f 100644
--- a/tests/unit/Auth/AuthTest.php
+++ b/tests/unit/Auth/AuthTest.php
@@ -353,16 +353,58 @@ class AuthTest extends TestCase
'$id' => ID::custom('123'),
'memberships' => [
[
- 'confirm' => true,
+ '$id' => ID::custom('456'),
'teamId' => ID::custom('abc'),
+ 'confirm' => true,
'roles' => [
'administrator',
'moderator'
]
],
[
- 'confirm' => true,
+ '$id' => ID::custom('abc'),
'teamId' => ID::custom('def'),
+ 'confirm' => true,
+ 'roles' => [
+ 'guest'
+ ]
+ ]
+ ]
+ ]);
+
+ $roles = Auth::getRoles($user);
+
+ $this->assertCount(9, $roles);
+ $this->assertContains(Role::users()->toString(), $roles);
+ $this->assertContains(Role::user(ID::custom('123'))->toString(), $roles);
+ $this->assertContains(Role::team(ID::custom('abc'))->toString(), $roles);
+ $this->assertContains(Role::team(ID::custom('abc'), 'administrator')->toString(), $roles);
+ $this->assertContains(Role::team(ID::custom('abc'), 'moderator')->toString(), $roles);
+ $this->assertContains(Role::team(ID::custom('def'))->toString(), $roles);
+ $this->assertContains(Role::team(ID::custom('def'), 'guest')->toString(), $roles);
+ $this->assertContains(Role::member(ID::custom('456'))->toString(), $roles);
+ $this->assertContains(Role::member(ID::custom('abc'))->toString(), $roles);
+ }
+
+ public function testPrivilegedUserRoles(): void
+ {
+ Authorization::setRole(Auth::USER_ROLE_OWNER);
+ $user = new Document([
+ '$id' => ID::custom('123'),
+ 'memberships' => [
+ [
+ '$id' => ID::custom('def'),
+ 'teamId' => ID::custom('abc'),
+ 'confirm' => true,
+ 'roles' => [
+ 'administrator',
+ 'moderator'
+ ]
+ ],
+ [
+ '$id' => ID::custom('abc'),
+ 'teamId' => ID::custom('def'),
+ 'confirm' => true,
'roles' => [
'guest'
]
@@ -373,42 +415,6 @@ class AuthTest extends TestCase
$roles = Auth::getRoles($user);
$this->assertCount(7, $roles);
- $this->assertContains(Role::users()->toString(), $roles);
- $this->assertContains(Role::user(ID::custom('123'))->toString(), $roles);
- $this->assertContains(Role::team(ID::custom('abc'))->toString(), $roles);
- $this->assertContains(Role::team(ID::custom('abc'), 'administrator')->toString(), $roles);
- $this->assertContains(Role::team(ID::custom('abc'), 'moderator')->toString(), $roles);
- $this->assertContains(Role::team(ID::custom('def'))->toString(), $roles);
- $this->assertContains(Role::team(ID::custom('def'), 'guest')->toString(), $roles);
- }
-
- public function testPrivilegedUserRoles(): void
- {
- Authorization::setRole(Auth::USER_ROLE_OWNER);
- $user = new Document([
- '$id' => ID::custom('123'),
- 'memberships' => [
- [
- 'confirm' => true,
- 'teamId' => ID::custom('abc'),
- 'roles' => [
- 'administrator',
- 'moderator'
- ]
- ],
- [
- 'confirm' => true,
- 'teamId' => ID::custom('def'),
- 'roles' => [
- 'guest'
- ]
- ]
- ]
- ]);
-
- $roles = Auth::getRoles($user);
-
- $this->assertCount(5, $roles);
$this->assertNotContains(Role::users()->toString(), $roles);
$this->assertNotContains(Role::user(ID::custom('123'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('abc'))->toString(), $roles);
@@ -416,6 +422,8 @@ class AuthTest extends TestCase
$this->assertContains(Role::team(ID::custom('abc'), 'moderator')->toString(), $roles);
$this->assertContains(Role::team(ID::custom('def'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('def'), 'guest')->toString(), $roles);
+ $this->assertContains(Role::member(ID::custom('def'))->toString(), $roles);
+ $this->assertContains(Role::member(ID::custom('abc'))->toString(), $roles);
}
public function testAppUserRoles(): void
@@ -425,16 +433,18 @@ class AuthTest extends TestCase
'$id' => ID::custom('123'),
'memberships' => [
[
- 'confirm' => true,
+ '$id' => ID::custom('def'),
'teamId' => ID::custom('abc'),
+ 'confirm' => true,
'roles' => [
'administrator',
'moderator'
]
],
[
- 'confirm' => true,
+ '$id' => ID::custom('abc'),
'teamId' => ID::custom('def'),
+ 'confirm' => true,
'roles' => [
'guest'
]
@@ -444,7 +454,7 @@ class AuthTest extends TestCase
$roles = Auth::getRoles($user);
- $this->assertCount(5, $roles);
+ $this->assertCount(7, $roles);
$this->assertNotContains(Role::users()->toString(), $roles);
$this->assertNotContains(Role::user(ID::custom('123'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('abc'))->toString(), $roles);
@@ -452,5 +462,7 @@ class AuthTest extends TestCase
$this->assertContains(Role::team(ID::custom('abc'), 'moderator')->toString(), $roles);
$this->assertContains(Role::team(ID::custom('def'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('def'), 'guest')->toString(), $roles);
+ $this->assertContains(Role::member(ID::custom('def'))->toString(), $roles);
+ $this->assertContains(Role::member(ID::custom('abc'))->toString(), $roles);
}
}
diff --git a/tests/unit/Messaging/MessagingChannelsTest.php b/tests/unit/Messaging/MessagingChannelsTest.php
index 26a1106688..dd2ec04401 100644
--- a/tests/unit/Messaging/MessagingChannelsTest.php
+++ b/tests/unit/Messaging/MessagingChannelsTest.php
@@ -54,8 +54,9 @@ class MessagingChannelsTest extends TestCase
'$id' => ID::custom('user' . $this->connectionsCount),
'memberships' => [
[
- 'confirm' => true,
+ '$id' => ID::custom('member' . $i),
'teamId' => ID::custom('team' . $i),
+ 'confirm' => true,
'roles' => [
empty($index % 2)
? Auth::USER_ROLE_ADMIN
@@ -122,11 +123,11 @@ class MessagingChannelsTest extends TestCase
* Check for correct amount of subscriptions:
* - XXX users
* - XXX teams
- * - XXX team roles (2 roles per team)
+ * - XXX team roles (3 roles per team)
* - 1 guests
* - 1 users
*/
- $this->assertCount(($this->connectionsAuthenticated + (3 * $this->connectionsPerChannel) + 2), $this->realtime->subscriptions['1']);
+ $this->assertCount(($this->connectionsAuthenticated + (4 * $this->connectionsPerChannel) + 2), $this->realtime->subscriptions['1']);
/**
* Check for connections
@@ -138,7 +139,7 @@ class MessagingChannelsTest extends TestCase
$this->realtime->unsubscribe(-1);
$this->assertCount($this->connectionsTotal, $this->realtime->connections);
- $this->assertCount(($this->connectionsAuthenticated + (3 * $this->connectionsPerChannel) + 2), $this->realtime->subscriptions['1']);
+ $this->assertCount(($this->connectionsAuthenticated + (4 * $this->connectionsPerChannel) + 2), $this->realtime->subscriptions['1']);
for ($i = 0; $i < $this->connectionsCount; $i++) {
$this->realtime->unsubscribe($i);
@@ -259,6 +260,7 @@ class MessagingChannelsTest extends TestCase
for ($i = 0; $i < $this->connectionsPerChannel; $i++) {
$permissions[] = Role::team(ID::custom('team' . $i))->toString();
+ $permissions[] = Role::member(ID::custom('member' . $i))->toString();
}
$event = [
'project' => '1',
@@ -284,13 +286,13 @@ class MessagingChannelsTest extends TestCase
$this->assertStringEndsWith($index, $receiver);
}
+ $role = empty($index % 2)
+ ? Auth::USER_ROLE_ADMIN
+ : 'member';
+
$permissions = [
- Role::team(
- ID::custom('team' . $index),
- (empty($index % 2)
- ? Auth::USER_ROLE_ADMIN
- : 'member')
- )->toString()
+ Role::team(ID::custom('team' . $index), $role)->toString(),
+ Role::member(ID::custom('member' . $index))->toString()
];
$event = [