diff --git a/README-CN.md b/README-CN.md
index cc8457fd5..826163ee2 100644
--- a/README-CN.md
+++ b/README-CN.md
@@ -59,7 +59,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
- appwrite/appwrite:0.13.4
+ appwrite/appwrite:0.14.0
```
### Windows
@@ -71,7 +71,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^
- appwrite/appwrite:0.13.4
+ appwrite/appwrite:0.14.0
```
#### PowerShell
@@ -81,7 +81,7 @@ docker run -it --rm ,
--volume /var/run/docker.sock:/var/run/docker.sock ,
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ,
--entrypoint="install" ,
- appwrite/appwrite:0.13.4
+ appwrite/appwrite:0.14.0
```
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
diff --git a/README.md b/README.md
index c74b33cc2..dea890c3a 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
- appwrite/appwrite:0.13.4
+ appwrite/appwrite:0.14.0
```
### Windows
@@ -74,7 +74,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^
- appwrite/appwrite:0.13.4
+ appwrite/appwrite:0.14.0
```
#### PowerShell
@@ -84,7 +84,7 @@ docker run -it --rm ,
--volume /var/run/docker.sock:/var/run/docker.sock ,
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ,
--entrypoint="install" ,
- appwrite/appwrite:0.13.4
+ appwrite/appwrite:0.14.0
```
Once the Docker installation completes, go to http://localhost to access the Appwrite console from your browser. Please note that on non-Linux native hosts, the server might take a few minutes to start after installation completes.
diff --git a/app/config/events.php b/app/config/events.php
index bfb70e218..2c2ded49d 100644
--- a/app/config/events.php
+++ b/app/config/events.php
@@ -7,279 +7,217 @@
use Appwrite\Utopia\Response;
return [
- 'account.create' => [
- 'description' => 'This event triggers when the account is created.',
- 'model' => Response::MODEL_USER,
- 'note' => '',
+ 'users' => [
+ '$model' => Response::MODEL_USER,
+ '$resource' => true,
+ '$description' => 'This event triggers on any user\'s event.',
+ 'sessions' => [
+ '$model' => Response::MODEL_SESSION,
+ '$resource' => true,
+ '$description' => 'This event triggers on any user\'s sessions event.',
+ 'create' => [
+ '$description' => 'This event triggers when a session for a user is created.',
+ ],
+ 'delete' => [
+ '$description' => 'This event triggers when a session for a user is deleted.'
+ ],
+ ],
+ 'recovery' => [
+ '$model' => Response::MODEL_TOKEN,
+ '$resource' => true,
+ '$description' => 'This event triggers on any user\'s recovery token event.',
+ 'create' => [
+ '$description' => 'This event triggers when a recovery token for a user is created.',
+ ],
+ 'update' => [
+ '$description' => 'This event triggers when a recovery token for a user is validated.'
+ ],
+ ],
+ 'verification' => [
+ '$model' => Response::MODEL_TOKEN,
+ '$resource' => true,
+ '$description' => 'This event triggers on any user\'s verification token event.',
+ 'create' => [
+ '$description' => 'This event triggers when a verification token for a user is created.',
+ ],
+ 'update' => [
+ '$description' => 'This event triggers when a verification token for a user is validated.'
+ ],
+ ],
+ 'create' => [
+ '$description' => 'This event triggers when a user is created.'
+ ],
+ 'delete' => [
+ '$description' => 'This event triggers when a user is deleted.',
+ ],
+ 'update' => [
+ '$description' => 'This event triggers when a user is updated.',
+ 'email' => [
+ '$description' => 'This event triggers when a user\'s email address is updated.',
+ ],
+ 'name' => [
+ '$description' => 'This event triggers when a user\'s name is updated.',
+ ],
+ 'password' => [
+ '$description' => 'This event triggers when a user\'s password is updated.',
+ ],
+ 'status' => [
+ '$description' => 'This event triggers when a user\'s status is updated.',
+ ],
+ 'prefs' => [
+ '$description' => 'This event triggers when a user\'s preferences is updated.',
+ ],
+ ]
],
- 'account.update.email' => [
- 'description' => 'This event triggers when the account email address is updated.',
- 'model' => Response::MODEL_USER,
- 'note' => '',
+ 'collections' => [
+ '$model' => Response::MODEL_COLLECTION,
+ '$resource' => true,
+ '$description' => 'This event triggers on any collection event.',
+ 'documents' => [
+ '$model' => Response::MODEL_DOCUMENT,
+ '$resource' => true,
+ '$description' => 'This event triggers on any documents event.',
+ 'create' => [
+ '$description' => 'This event triggers when a document is created.',
+ ],
+ 'delete' => [
+ '$description' => 'This event triggers when a document is deleted.'
+ ],
+ 'update' => [
+ '$description' => 'This event triggers when a document is updated.'
+ ],
+ ],
+ 'indexes' => [
+ '$model' => Response::MODEL_INDEX,
+ '$resource' => true,
+ '$description' => 'This event triggers on any indexes event.',
+ 'create' => [
+ '$description' => 'This event triggers when an index is created.',
+ ],
+ 'delete' => [
+ '$description' => 'This event triggers when an index is deleted.'
+ ]
+ ],
+ 'attributes' => [
+ '$model' => Response::MODEL_ATTRIBUTE,
+ '$resource' => true,
+ '$description' => 'This event triggers on any attributes event.',
+ 'create' => [
+ '$description' => 'This event triggers when an attribute is created.',
+ ],
+ 'delete' => [
+ '$description' => 'This event triggers when an attribute is deleted.'
+ ]
+ ],
+ 'create' => [
+ '$description' => 'This event triggers when a collection is created.'
+ ],
+ 'delete' => [
+ '$description' => 'This event triggers when a collection is deleted.',
+ ],
+ 'update' => [
+ '$description' => 'This event triggers when a collection is updated.',
+ ]
],
- 'account.update.name' => [
- 'description' => 'This event triggers when the account name is updated.',
- 'model' => Response::MODEL_USER,
- 'note' => '',
+ 'buckets' => [
+ '$model' => Response::MODEL_BUCKET,
+ '$resource' => true,
+ '$description' => 'This event triggers on any buckets event.',
+ 'files' => [
+ '$model' => Response::MODEL_FILE,
+ '$resource' => true,
+ '$description' => 'This event triggers on any files event.',
+ 'create' => [
+ '$description' => 'This event triggers when a file is created.',
+ ],
+ 'delete' => [
+ '$description' => 'This event triggers when a file is deleted.'
+ ],
+ 'update' => [
+ '$description' => 'This event triggers when a file is updated.'
+ ],
+ ],
+ 'create' => [
+ '$description' => 'This event triggers when a bucket is created.'
+ ],
+ 'delete' => [
+ '$description' => 'This event triggers when a bucket is deleted.',
+ ],
+ 'update' => [
+ '$description' => 'This event triggers when a bucket is updated.',
+ ]
],
- 'account.update.password' => [
- 'description' => 'This event triggers when the account password is updated.',
- 'model' => Response::MODEL_USER,
- 'note' => '',
- ],
- 'users.update.email' => [
- 'description' => 'This event triggers when the user email address is updated.',
- 'model' => Response::MODEL_USER,
- 'note' => '',
- ],
- 'users.update.name' => [
- 'description' => 'This event triggers when the user name is updated.',
- 'model' => Response::MODEL_USER,
- 'note' => '',
- ],
- 'users.update.password' => [
- 'description' => 'This event triggers when the user password is updated.',
- 'model' => Response::MODEL_USER,
- 'note' => '',
- ],
- 'account.update.prefs' => [
- 'description' => 'This event triggers when the account preferences are updated.',
- 'model' => Response::MODEL_USER,
- 'note' => '',
- ],
- 'account.recovery.create' => [
- 'description' => 'This event triggers when the account recovery token is created.',
- 'model' => Response::MODEL_TOKEN,
- 'note' => 'version >= 0.7',
- ],
- 'account.recovery.update' => [
- 'description' => 'This event triggers when the account recovery token is validated.',
- 'model' => Response::MODEL_TOKEN,
- 'note' => 'version >= 0.7',
- ],
- 'account.verification.create' => [
- 'description' => 'This event triggers when the account verification token is created.',
- 'model' => Response::MODEL_TOKEN,
- 'note' => 'version >= 0.7',
- ],
- 'account.verification.update' => [
- 'description' => 'This event triggers when the account verification token is validated.',
- 'model' => Response::MODEL_TOKEN,
- 'note' => 'version >= 0.7',
- ],
- 'account.delete' => [
- 'description' => 'This event triggers when the account is deleted.',
- 'model' => Response::MODEL_USER,
- 'note' => '',
- ],
- 'account.sessions.create' => [
- 'description' => 'This event triggers when the account session is created.',
- 'model' => Response::MODEL_SESSION,
- 'note' => '',
- ],
- 'account.sessions.delete' => [
- 'description' => 'This event triggers when the account session is deleted.',
- 'model' => Response::MODEL_SESSION,
- 'note' => '',
- ],
- 'account.sessions.update' => [
- 'description' => 'This event triggers when the account session is updated.',
- 'model' => Response::MODEL_SESSION,
- 'note' => '',
- ],
- 'database.collections.create' => [
- 'description' => 'This event triggers when a database collection is created.',
- 'model' => Response::MODEL_COLLECTION,
- 'note' => '',
- ],
- 'database.collections.update' => [
- 'description' => 'This event triggers when a database collection is updated.',
- 'model' => Response::MODEL_COLLECTION,
- 'note' => '',
- ],
- 'database.collections.delete' => [
- 'description' => 'This event triggers when a database collection is deleted.',
- 'model' => Response::MODEL_COLLECTION,
- 'note' => '',
- ],
- 'database.attributes.create' => [
- 'description' => 'This event triggers when a collection attribute is created.',
- 'model' => Response::MODEL_ATTRIBUTE,
- 'note' => '',
- ],
- 'database.attributes.delete' => [
- 'description' => 'This event triggers when a collection attribute is deleted.',
- 'model' => Response::MODEL_ATTRIBUTE,
- 'note' => '',
- ],
- 'database.indexes.create' => [
- 'description' => 'This event triggers when a collection index is created.',
- 'model' => Response::MODEL_INDEX,
- 'note' => '',
- ],
- 'database.indexes.delete' => [
- 'description' => 'This event triggers when a collection index is deleted.',
- 'model' => Response::MODEL_INDEX,
- 'note' => '',
- ],
- 'database.documents.create' => [
- 'description' => 'This event triggers when a database document is created.',
- 'model' => Response::MODEL_DOCUMENT,
- 'note' => '',
- ],
- 'database.documents.update' => [
- 'description' => 'This event triggers when a database document is updated.',
- 'model' => Response::MODEL_DOCUMENT,
- 'note' => '',
- ],
- 'database.documents.delete' => [
- 'description' => 'This event triggers when a database document is deleted.',
- 'model' => Response::MODEL_DOCUMENT,
- 'note' => '',
- ],
- 'functions.create' => [
- 'description' => 'This event triggers when a function is created.',
- 'model' => Response::MODEL_FUNCTION,
- 'note' => 'version >= 0.7',
- ],
- 'functions.update' => [
- 'description' => 'This event triggers when a function is updated.',
- 'model' => Response::MODEL_FUNCTION,
- 'note' => 'version >= 0.7',
- ],
- 'functions.delete' => [
- 'description' => 'This event triggers when a function is deleted.',
- 'model' => Response::MODEL_ANY,
- 'note' => 'version >= 0.7',
- ],
- 'functions.deployments.create' => [
- 'description' => 'This event triggers when a function delpoyment is created.',
- 'model' => Response::MODEL_DEPLOYMENT,
- 'note' => 'version >= 0.7',
- ],
- 'functions.deployments.update' => [
- 'description' => 'This event triggers when a function delpoyment is updated.',
- 'model' => Response::MODEL_FUNCTION,
- 'note' => 'version >= 0.7',
- ],
- 'functions.deployments.delete' => [
- 'description' => 'This event triggers when a function delpoyment is deleted.',
- 'model' => Response::MODEL_ANY,
- 'note' => 'version >= 0.7',
- ],
- 'functions.executions.create' => [
- 'description' => 'This event triggers when a function execution is created.',
- 'model' => Response::MODEL_EXECUTION,
- 'note' => 'version >= 0.7',
- ],
- 'functions.executions.update' => [
- 'description' => 'This event triggers when a function execution is updated.',
- 'model' => Response::MODEL_EXECUTION,
- 'note' => 'version >= 0.7',
- ],
- 'storage.files.create' => [
- 'description' => 'This event triggers when a storage file is created.',
- 'model' => Response::MODEL_FILE,
- 'note' => '',
- ],
- 'storage.files.update' => [
- 'description' => 'This event triggers when a storage file is updated.',
- 'model' => Response::MODEL_FILE,
- 'note' => '',
- ],
- 'storage.files.delete' => [
- 'description' => 'This event triggers when a storage file is deleted.',
- 'model' => Response::MODEL_FILE,
- 'note' => '',
- ],
- 'storage.buckets.create' => [
- 'description' => 'This event triggers when a storage bucket is created.',
- 'model' => Response::MODEL_BUCKET,
- 'note' => '',
- ],
- 'storage.buckets.update' => [
- 'description' => 'This event triggers when a storage bucket is updated.',
- 'model' => Response::MODEL_BUCKET,
- 'note' => '',
- ],
- 'storage.buckets.delete' => [
- 'description' => 'This event triggers when a storage bucket is deleted.',
- 'model' => Response::MODEL_BUCKET,
- 'note' => '',
- ],
- 'users.create' => [
- 'description' => 'This event triggers when a user is created from the users API.',
- 'model' => Response::MODEL_USER,
- 'note' => 'version >= 0.7',
- ],
- 'users.update.prefs' => [
- 'description' => 'This event triggers when a user preference is updated from the users API.',
- 'model' => Response::MODEL_ANY,
- 'note' => 'version >= 0.7',
- ],
- 'users.update.email' => [
- 'description' => 'This event triggers when the user email address is updated.',
- 'model' => Response::MODEL_USER,
- 'note' => 'version >= 0.10',
- ],
- 'users.update.name' => [
- 'description' => 'This event triggers when the user name is updated.',
- 'model' => Response::MODEL_USER,
- 'note' => 'version >= 0.10',
- ],
- 'users.update.password' => [
- 'description' => 'This event triggers when the user password is updated.',
- 'model' => Response::MODEL_USER,
- 'note' => 'version >= 0.10',
- ],
- 'users.update.status' => [
- 'description' => 'This event triggers when a user status is updated from the users API.',
- 'model' => Response::MODEL_USER,
- 'note' => 'version >= 0.7',
- ],
- 'users.delete' => [
- 'description' => 'This event triggers when a user is deleted from users API.',
- 'model' => Response::MODEL_USER,
- 'note' => 'version >= 0.7',
- ],
- 'users.sessions.delete' => [
- 'description' => 'This event triggers when a user session is deleted from users API.',
- 'model' => Response::MODEL_SESSION,
- 'note' => 'version >= 0.7',
- ],
- 'teams.create' => [
- 'description' => 'This event triggers when a team is created.',
- 'model' => Response::MODEL_TEAM,
- 'note' => 'version >= 0.7',
- ],
- 'teams.update' => [
- 'description' => 'This event triggers when a team is updated.',
- 'model' => Response::MODEL_TEAM,
- 'note' => 'version >= 0.7',
- ],
- 'teams.delete' => [
- 'description' => 'This event triggers when a team is deleted.',
- 'model' => Response::MODEL_TEAM,
- 'note' => 'version >= 0.7',
- ],
- 'teams.memberships.create' => [
- 'description' => 'This event triggers when a team memberships is created.',
- 'model' => Response::MODEL_MEMBERSHIP,
- 'note' => 'version >= 0.7',
- ],
- 'teams.memberships.update' => [
- 'description' => 'This event triggers when a team membership is updated.',
- 'model' => Response::MODEL_MEMBERSHIP,
- 'note' => 'version >= 0.8',
- ],
- 'teams.memberships.update.status' => [
- 'description' => 'This event triggers when a team memberships status is updated.',
- 'model' => Response::MODEL_MEMBERSHIP,
- 'note' => 'version >= 0.7',
- ],
- 'teams.memberships.delete' => [
- 'description' => 'This event triggers when a team memberships is deleted.',
- 'model' => Response::MODEL_MEMBERSHIP,
- 'note' => 'version >= 0.7',
+ 'teams' => [
+ '$model' => Response::MODEL_TEAM,
+ '$resource' => true,
+ '$description' => 'This event triggers on any teams event.',
+ 'memberships' => [
+ '$model' => Response::MODEL_MEMBERSHIP,
+ '$resource' => true,
+ '$description' => 'This event triggers on any team memberships event.',
+ 'create' => [
+ '$description' => 'This event triggers when a membership is created.',
+ ],
+ 'delete' => [
+ '$description' => 'This event triggers when a membership is deleted.'
+ ],
+ 'update' => [
+ '$description' => 'This event triggers when a membership is updated.',
+ 'status' => [
+ '$description' => 'This event triggers when a team memberships status is updated.'
+ ]
+ ],
+ ],
+ 'create' => [
+ '$description' => 'This event triggers when a bucket is created.'
+ ],
+ 'delete' => [
+ '$description' => 'This event triggers when a bucket is deleted.',
+ ],
+ 'update' => [
+ '$description' => 'This event triggers when a bucket is updated.',
+ ]
],
+ 'functions' => [
+ '$model' => Response::MODEL_FUNCTION,
+ '$resource' => true,
+ '$description' => 'This event triggers on any functions event.',
+ 'deployments' => [
+ '$model' => Response::MODEL_DEPLOYMENT,
+ '$resource' => true,
+ '$description' => 'This event triggers on any deployments event.',
+ 'create' => [
+ '$description' => 'This event triggers when a deployment is created.',
+ ],
+ 'delete' => [
+ '$description' => 'This event triggers when a deployment is deleted.'
+ ],
+ 'update' => [
+ '$description' => 'This event triggers when a deployment is updated.'
+ ],
+ ],
+ 'executions' => [
+ '$model' => Response::MODEL_EXECUTION,
+ '$resource' => true,
+ '$description' => 'This event triggers on any executions event.',
+ 'create' => [
+ '$description' => 'This event triggers when an execution is created.',
+ ],
+ 'delete' => [
+ '$description' => 'This event triggers when an execution is deleted.'
+ ],
+ 'update' => [
+ '$description' => 'This event triggers when an execution is updated.'
+ ],
+ ],
+ 'create' => [
+ '$description' => 'This event triggers when a function is created.'
+ ],
+ 'delete' => [
+ '$description' => 'This event triggers when a function is deleted.',
+ ],
+ 'update' => [
+ '$description' => 'This event triggers when a function is updated.',
+ ]
+ ]
];
diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php
index eedc8f6df..aaaf5eaa4 100644
--- a/app/controllers/api/account.php
+++ b/app/controllers/api/account.php
@@ -23,7 +23,6 @@ use Utopia\Database\Validator\UID;
use Appwrite\Extend\Exception;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Assoc;
-use Utopia\Validator\Boolean;
use Utopia\Validator\Range;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
@@ -34,7 +33,7 @@ $oauthDefaultFailure = '/v1/auth/oauth2/failure';
App::post('/v1/account')
->desc('Create Account')
->groups(['api', 'account', 'auth'])
- ->label('event', 'account.create')
+ ->label('event', 'users.[userId].create')
->label('scope', 'public')
->label('auth.type', 'emailPassword')
->label('sdk.auth', [])
@@ -55,13 +54,15 @@ App::post('/v1/account')
->inject('dbForProject')
->inject('audits')
->inject('usage')
- ->action(function ($userId, $email, $password, $name, $request, $response, $project, $dbForProject, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($userId, $email, $password, $name, $request, $response, $project, $dbForProject, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
$email = \strtolower($email);
if ('console' === $project->getId()) {
@@ -119,14 +120,13 @@ App::post('/v1/account')
Authorization::setRole('role:' . Auth::USER_ROLE_MEMBER);
$audits
- ->setParam('userId', $user->getId())
- ->setParam('event', 'account.create')
- ->setParam('resource', 'user/' . $user->getId())
+ ->setResource('user/'.$user->getId())
+ ->setUser($user)
;
- $usage
- ->setParam('users.create', 1)
- ;
+ $usage->setParam('users.create', 1);
+ $events->setParam('userId', $user->getId());
+
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($user, Response::MODEL_USER);
});
@@ -134,7 +134,7 @@ App::post('/v1/account')
App::post('/v1/account/sessions')
->desc('Create Account Session')
->groups(['api', 'account', 'auth'])
- ->label('event', 'account.sessions.create')
+ ->label('event', 'users.[userId].sessions.[sessionId].create')
->label('scope', 'public')
->label('auth.type', 'emailPassword')
->label('sdk.auth', [])
@@ -155,14 +155,16 @@ App::post('/v1/account/sessions')
->inject('geodb')
->inject('audits')
->inject('usage')
- ->action(function ($email, $password, $request, $response, $dbForProject, $locale, $geodb, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($email, $password, $request, $response, $dbForProject, $locale, $geodb, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Locale\Locale $locale */
/** @var MaxMind\Db\Reader $geodb */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
$email = \strtolower($email);
$protocol = $request->getProtocol();
@@ -173,12 +175,6 @@ App::post('/v1/account/sessions')
);
if (!$profile || !Auth::passwordVerify($password, $profile->getAttribute('password'))) {
- $audits
- //->setParam('userId', $profile->getId())
- ->setParam('event', 'account.sessions.failed')
- ->setParam('resource', 'user/'.($profile ? $profile->getId() : ''))
- ;
-
throw new Exception('Invalid credentials', 401, Exception::USER_INVALID_CREDENTIALS); // Wrong password or username
}
@@ -214,11 +210,8 @@ App::post('/v1/account/sessions')
$dbForProject->deleteCachedDocument('users', $profile->getId());
$audits
- ->setParam('userId', $profile->getId())
- ->setParam('event', 'account.sessions.create')
- ->setParam('resource', 'user/' . $profile->getId())
- ->setParam('userEmail', $profile->getAttribute('email', ''))
- ->setParam('userName', $profile->getAttribute('name', ''))
+ ->setResource('user/'.$profile->getId())
+ ->setUser($profile)
;
if (!Config::getParam('domainVerification')) {
@@ -245,6 +238,12 @@ App::post('/v1/account/sessions')
->setParam('users.sessions.create', 1)
->setParam('provider', 'email')
;
+
+ $events
+ ->setParam('userId', $profile->getId())
+ ->setParam('sessionId', $session->getId())
+ ;
+
$response->dynamic($session, Response::MODEL_SESSION);
});
@@ -367,7 +366,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
->desc('OAuth2 Redirect')
->groups(['api', 'account'])
->label('error', __DIR__ . '/../../views/general/error.phtml')
- ->label('event', 'account.sessions.create')
+ ->label('event', 'users.[userId].sessions.[sessionId].create')
->label('scope', 'public')
->label('abuse-limit', 50)
->label('abuse-key', 'ip:{ip}')
@@ -391,7 +390,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
/** @var MaxMind\Db\Reader $geodb */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
+ /** @var Appwrite\Event\Event $events */
/** @var Appwrite\Stats\Stats $usage */
$protocol = $request->getProtocol();
@@ -572,23 +572,24 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$dbForProject->deleteCachedDocument('users', $user->getId());
$audits
- ->setParam('userId', $user->getId())
- ->setParam('event', 'account.sessions.create')
- ->setParam('resource', 'user/' . $user->getId())
- ->setParam('data', ['provider' => $provider])
+ ->setResource('user/'.$user->getId())
+ ->setUser($user)
;
- $events->setParam('eventData', $response->output($session, Response::MODEL_SESSION));
-
$usage
->setParam('users.sessions.create', 1)
->setParam('projectId', $project->getId())
->setParam('provider', 'oauth2-'.$provider)
;
+
+ $events
+ ->setParam('userId', $user->getId())
+ ->setParam('sessionId', $session->getId())
+ ->setPayload($response->output($session, Response::MODEL_SESSION))
+ ;
+
if (!Config::getParam('domainVerification')) {
- $response
- ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)]))
- ;
+ $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)]));
}
// Add keys for non-web platforms - TODO - add verification phase to aviod session sniffing
@@ -644,9 +645,9 @@ App::post('/v1/account/sessions/magic-url')
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Locale\Locale $locale */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Event\Event $events */
- /** @var Appwrite\Event\Event $mails */
+ /** @var Appwrite\Event\Mail $mails */
if(empty(App::getEnv('_APP_SMTP_HOST'))) {
throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED);
@@ -691,9 +692,6 @@ App::post('/v1/account/sessions/magic-url')
'search' => implode(' ', [$userId, $email]),
'deleted' => false
])));
-
- $mails->setParam('event', 'users.create');
- $audits->setParam('event', 'users.create');
}
$loginSecret = Auth::tokenGenerator();
@@ -728,29 +726,26 @@ App::post('/v1/account/sessions/magic-url')
$url = Template::unParseURL($url);
$mails
- ->setParam('from', $project->getId())
- ->setParam('recipient', $user->getAttribute('email'))
- ->setParam('url', $url)
- ->setParam('locale', $locale->default)
- ->setParam('project', $project->getAttribute('name', ['[APP-NAME]']))
- ->setParam('type', MAIL_TYPE_MAGIC_SESSION)
+ ->setType(MAIL_TYPE_MAGIC_SESSION)
+ ->setRecipient($user->getAttribute('email'))
+ ->setUrl($url)
+ ->setLocale($locale->default)
->trigger()
;
- $events
- ->setParam('eventData',
- $response->output($token->setAttribute('secret', $loginSecret),
+ $events->setPayload(
+ $response->output(
+ $token->setAttribute('secret', $loginSecret),
Response::MODEL_TOKEN
- ))
- ;
+ )
+ );
- $token // Hide secret for clients
- ->setAttribute('secret',
- ($isPrivilegedUser || $isAppUser) ? $loginSecret : '');
+ // Hide secret for clients
+ $token->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $loginSecret : '');
$audits
- ->setParam('userId', $user->getId())
- ->setParam('resource', 'users/'.$user->getId())
+ ->setResource('user/'.$user->getId())
+ ->setUser($user)
;
$response
@@ -763,7 +758,7 @@ App::put('/v1/account/sessions/magic-url')
->desc('Create Magic URL session (confirmation)')
->groups(['api', 'account'])
->label('scope', 'public')
- ->label('event', 'account.sessions.create')
+ ->label('event', 'users.[userId].sessions.[sessionId].create')
->label('sdk.auth', [])
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateMagicURLSession')
@@ -781,7 +776,8 @@ App::put('/v1/account/sessions/magic-url')
->inject('locale')
->inject('geodb')
->inject('audits')
- ->action(function ($userId, $secret, $request, $response, $dbForProject, $locale, $geodb, $audits) {
+ ->inject('events')
+ ->action(function ($userId, $secret, $request, $response, $dbForProject, $locale, $geodb, $audits, $events) {
/** @var string $userId */
/** @var string $secret */
/** @var Appwrite\Utopia\Request $request */
@@ -789,7 +785,8 @@ App::put('/v1/account/sessions/magic-url')
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Locale\Locale $locale */
/** @var MaxMind\Db\Reader $geodb */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
+ /** @var Appwrite\Event\Event $events */
$user = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId));
@@ -841,8 +838,7 @@ App::put('/v1/account/sessions/magic-url')
$dbForProject->deleteDocument('tokens', $token);
$dbForProject->deleteCachedDocument('users', $user->getId());
- $user
- ->setAttribute('emailVerification', true);
+ $user->setAttribute('emailVerification', true);
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
@@ -850,16 +846,15 @@ App::put('/v1/account/sessions/magic-url')
throw new Exception('Failed saving user to DB', 500, Exception::GENERAL_SERVER_ERROR);
}
- $audits
+ $audits->setResource('user/'.$user->getId());
+
+ $events
->setParam('userId', $user->getId())
- ->setParam('event', 'account.sessions.create')
- ->setParam('resource', 'users/'.$user->getId())
+ ->setParam('sessionId', $session->getId())
;
if (!Config::getParam('domainVerification')) {
- $response
- ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)]))
- ;
+ $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)]));
}
$protocol = $request->getProtocol();
@@ -883,7 +878,7 @@ App::put('/v1/account/sessions/magic-url')
App::post('/v1/account/sessions/anonymous')
->desc('Create Anonymous Session')
->groups(['api', 'account', 'auth'])
- ->label('event', 'account.sessions.create')
+ ->label('event', 'users.[userId].sessions.[sessionId].create')
->label('scope', 'public')
->label('auth.type', 'anonymous')
->label('sdk.auth', [])
@@ -904,7 +899,8 @@ App::post('/v1/account/sessions/anonymous')
->inject('geodb')
->inject('audits')
->inject('usage')
- ->action(function ($request, $response, $locale, $user, $project, $dbForProject, $geodb, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($request, $response, $locale, $user, $project, $dbForProject, $geodb, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Locale\Locale $locale */
@@ -912,8 +908,9 @@ App::post('/v1/account/sessions/anonymous')
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Database $dbForProject */
/** @var MaxMind\Db\Reader $geodb */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Stats\Stats $events */
$protocol = $request->getProtocol();
@@ -989,21 +986,20 @@ App::post('/v1/account/sessions/anonymous')
$dbForProject->deleteCachedDocument('users', $user->getId());
- $audits
- ->setParam('userId', $user->getId())
- ->setParam('event', 'account.sessions.create')
- ->setParam('resource', 'user/' . $user->getId())
- ;
+ $audits->setResource('user/'.$user->getId());
$usage
->setParam('users.sessions.create', 1)
->setParam('provider', 'anonymous')
;
+ $events
+ ->setParam('userId', $user->getId())
+ ->setParam('sessionId', $session->getId())
+ ;
+
if (!Config::getParam('domainVerification')) {
- $response
- ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)]))
- ;
+ $response->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)]));
}
$response
@@ -1090,9 +1086,8 @@ App::get('/v1/account')
/** @var Utopia\Database\Document $user */
/** @var Appwrite\Stats\Stats $usage */
- $usage
- ->setParam('users.read', 1)
- ;
+ $usage->setParam('users.read', 1);
+
$response->dynamic($user, Response::MODEL_USER);
});
@@ -1117,9 +1112,8 @@ App::get('/v1/account/prefs')
$prefs = $user->getAttribute('prefs', new \stdClass());
- $usage
- ->setParam('users.read', 1)
- ;
+ $usage->setParam('users.read', 1);
+
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
@@ -1156,9 +1150,8 @@ App::get('/v1/account/sessions')
$sessions[$key] = $session;
}
- $usage
- ->setParam('users.read', 1)
- ;
+ $usage->setParam('users.read', 1);
+
$response->dynamic(new Document([
'sessions' => $sessions,
'total' => count($sessions),
@@ -1194,26 +1187,8 @@ App::get('/v1/account/logs')
/** @var Appwrite\Stats\Stats $usage */
$audit = new Audit($dbForProject);
- $auditEvents = [
- 'account.create',
- 'account.delete',
- 'account.update.name',
- 'account.update.email',
- 'account.update.password',
- 'account.update.prefs',
- 'account.sessions.create',
- 'account.sessions.update',
- 'account.sessions.delete',
- 'account.recovery.create',
- 'account.recovery.update',
- 'account.verification.create',
- 'account.verification.update',
- 'teams.membership.create',
- 'teams.membership.update',
- 'teams.membership.delete',
- ];
- $logs = $audit->getLogsByUserAndEvents($user->getId(), $auditEvents, $limit, $offset);
+ $logs = $audit->getLogsByUser($user->getId(), $limit, $offset);
$output = [];
@@ -1242,12 +1217,10 @@ App::get('/v1/account/logs')
}
- $usage
- ->setParam('users.read', 1)
- ;
+ $usage->setParam('users.read', 1);
$response->dynamic(new Document([
- 'total' => $audit->countLogsByUserAndEvents($user->getId(), $auditEvents),
+ 'total' => $audit->countLogsByUser($user->getId()),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@@ -1283,7 +1256,6 @@ App::get('/v1/account/sessions/:sessionId')
foreach ($sessions as $session) {/** @var Document $session */
if ($sessionId == $session->getId()) {
-
$countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
$session
@@ -1291,9 +1263,7 @@ App::get('/v1/account/sessions/:sessionId')
->setAttribute('countryName', $countryName)
;
- $usage
- ->setParam('users.read', 1)
- ;
+ $usage->setParam('users.read', 1);
return $response->dynamic($session, Response::MODEL_SESSION);
}
@@ -1305,7 +1275,7 @@ App::get('/v1/account/sessions/:sessionId')
App::patch('/v1/account/name')
->desc('Update Account Name')
->groups(['api', 'account'])
- ->label('event', 'account.update.name')
+ ->label('event', 'users.[userId].update.name')
->label('scope', 'account')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
@@ -1320,12 +1290,14 @@ App::patch('/v1/account/name')
->inject('dbForProject')
->inject('audits')
->inject('usage')
- ->action(function ($name, $response, $user, $dbForProject, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($name, $response, $user, $dbForProject, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Stats\Stats $events */
$user = $dbForProject->updateDocument('users', $user->getId(), $user
->setAttribute('name', $name)
@@ -1333,14 +1305,12 @@ App::patch('/v1/account/name')
);
$audits
- ->setParam('userId', $user->getId())
- ->setParam('event', 'account.update.name')
- ->setParam('resource', 'user/' . $user->getId())
+ ->setResource('user/'.$user->getId())
+ ->setUser($user)
;
- $usage
- ->setParam('users.update', 1)
- ;
+ $usage->setParam('users.update', 1);
+ $events->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_USER);
});
@@ -1348,7 +1318,7 @@ App::patch('/v1/account/name')
App::patch('/v1/account/password')
->desc('Update Account Password')
->groups(['api', 'account'])
- ->label('event', 'account.update.password')
+ ->label('event', 'users.[userId].update.password')
->label('scope', 'account')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
@@ -1364,39 +1334,43 @@ App::patch('/v1/account/password')
->inject('dbForProject')
->inject('audits')
->inject('usage')
- ->action(function ($password, $oldPassword, $response, $user, $dbForProject, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($password, $oldPassword, $response, $user, $dbForProject, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Stats\Stats $events */
// Check old password only if its an existing user.
if ($user->getAttribute('passwordUpdate') !== 0 && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'))) { // Double check user password
throw new Exception('Invalid credentials', 401, Exception::USER_INVALID_CREDENTIALS);
}
- $user = $dbForProject->updateDocument('users', $user->getId(), $user
+ $user = $dbForProject->updateDocument(
+ 'users',
+ $user->getId(),
+ $user
->setAttribute('password', Auth::passwordHash($password))
->setAttribute('passwordUpdate', \time())
);
$audits
- ->setParam('userId', $user->getId())
- ->setParam('event', 'account.update.password')
- ->setParam('resource', 'user/' . $user->getId())
+ ->setResource('user/'.$user->getId())
+ ->setUser($user)
;
- $usage
- ->setParam('users.update', 1)
- ;
+ $usage->setParam('users.update', 1);
+ $events->setParam('userId', $user->getId());
+
$response->dynamic($user, Response::MODEL_USER);
});
App::patch('/v1/account/email')
->desc('Update Account Email')
->groups(['api', 'account'])
- ->label('event', 'account.update.email')
+ ->label('event', 'users.[userId].update.email')
->label('scope', 'account')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
@@ -1412,12 +1386,14 @@ App::patch('/v1/account/email')
->inject('dbForProject')
->inject('audits')
->inject('usage')
- ->action(function ($email, $password, $response, $user, $dbForProject, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($email, $password, $response, $user, $dbForProject, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Stats\Stats $events */
$isAnonymousUser = is_null($user->getAttribute('email')) && is_null($user->getAttribute('password')); // Check if request is from an anonymous account for converting
@@ -1447,21 +1423,20 @@ App::patch('/v1/account/email')
}
$audits
- ->setParam('userId', $user->getId())
- ->setParam('event', 'account.update.email')
- ->setParam('resource', 'user/' . $user->getId())
+ ->setResource('user/'.$user->getId())
+ ->setUser($user)
;
- $usage
- ->setParam('users.update', 1)
- ;
+ $usage->setParam('users.update', 1);
+ $events->setParam('userId', $user->getId());
+
$response->dynamic($user, Response::MODEL_USER);
});
App::patch('/v1/account/prefs')
->desc('Update Account Preferences')
->groups(['api', 'account'])
- ->label('event', 'account.update.prefs')
+ ->label('event', 'users.[userId].update.prefs')
->label('scope', 'account')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
@@ -1476,30 +1451,28 @@ App::patch('/v1/account/prefs')
->inject('dbForProject')
->inject('audits')
->inject('usage')
- ->action(function ($prefs, $response, $user, $dbForProject, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($prefs, $response, $user, $dbForProject, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs));
- $audits
- ->setParam('event', 'account.update.prefs')
- ->setParam('resource', 'user/' . $user->getId())
- ;
+ $audits->setResource('user/'.$user->getId());
+ $usage->setParam('users.update', 1);
+ $events->setParam('userId', $user->getId());
- $usage
- ->setParam('users.update', 1)
- ;
$response->dynamic($user, Response::MODEL_USER);
});
App::delete('/v1/account')
->desc('Delete Account')
->groups(['api', 'account'])
- ->label('event', 'account.delete')
+ ->label('event', 'users.[userId].delete')
->label('scope', 'account')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
@@ -1519,7 +1492,7 @@ App::delete('/v1/account')
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Stats\Stats $usage */
@@ -1530,32 +1503,28 @@ App::delete('/v1/account')
// TODO delete all tokens or only current session?
// TODO delete all user data according to GDPR. Make sure everything is backed up and backups are deleted later
- /*
- * Data to delete
- * * Tokens
- * * Memberships
- */
+ /**
+ * Data to delete
+ * * Tokens
+ * * Memberships
+ */
$audits
- ->setParam('userId', $user->getId())
- ->setParam('event', 'account.delete')
- ->setParam('resource', 'user/' . $user->getId())
- ->setParam('data', $user->getArrayCopy())
+ ->setResource('user/' . $user->getId())
+ ->setPayload($response->output($user, Response::MODEL_USER))
;
$events
- ->setParam('eventData', $response->output($user, Response::MODEL_USER))
+ ->setParam('userId', $user->getId())
+ ->setPayload($response->output($user, Response::MODEL_USER))
;
if (!Config::getParam('domainVerification')) {
- $response
- ->addHeader('X-Fallback-Cookies', \json_encode([]))
- ;
+ $response->addHeader('X-Fallback-Cookies', \json_encode([]));
}
- $usage
- ->setParam('users.delete', 1)
- ;
+ $usage->setParam('users.delete', 1);
+
$response
->addCookie(Auth::$cookieName . '_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'))
@@ -1567,7 +1536,7 @@ App::delete('/v1/account/sessions/:sessionId')
->desc('Delete Account Session')
->groups(['api', 'account'])
->label('scope', 'account')
- ->label('event', 'account.sessions.delete')
+ ->label('event', 'users.[userId].sessions.[sessionId].delete')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'deleteSession')
@@ -1590,7 +1559,7 @@ App::delete('/v1/account/sessions/:sessionId')
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Locale\Locale $locale */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Stats\Stats $usage */
@@ -1607,11 +1576,7 @@ App::delete('/v1/account/sessions/:sessionId')
$dbForProject->deleteDocument('sessions', $session->getId());
- $audits
- ->setParam('userId', $user->getId())
- ->setParam('event', 'account.sessions.delete')
- ->setParam('resource', 'user/' . $user->getId())
- ;
+ $audits->setResource('user/' . $user->getId());
$session->setAttribute('current', false);
@@ -1636,7 +1601,9 @@ App::delete('/v1/account/sessions/:sessionId')
$dbForProject->deleteCachedDocument('users', $user->getId());
$events
- ->setParam('eventData', $response->output($session, Response::MODEL_SESSION))
+ ->setParam('userId', $user->getId())
+ ->setParam('sessionId', $session->getId())
+ ->setPayload($response->output($session, Response::MODEL_SESSION))
;
$usage
@@ -1654,7 +1621,7 @@ App::patch('/v1/account/sessions/:sessionId')
->desc('Update Session (Refresh Tokens)')
->groups(['api', 'account'])
->label('scope', 'account')
- ->label('event', 'account.sessions.update')
+ ->label('event', 'users.[userId].sessions.[sessionId].update')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateSession')
@@ -1681,7 +1648,7 @@ App::patch('/v1/account/sessions/:sessionId')
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Database\Document $project */
/** @var Utopia\Locale\Locale $locale */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Stats\Stats $usage */
@@ -1710,7 +1677,7 @@ App::patch('/v1/account/sessions/:sessionId')
$appSecret = $project->getAttribute('authProviders', [])[$provider.'Secret'] ?? '{}';
$className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider);
-
+
if (!\class_exists($className)) {
throw new Exception('Provider is not supported', 501, Exception::PROJECT_PROVIDER_UNSUPPORTED);
}
@@ -1729,14 +1696,12 @@ App::patch('/v1/account/sessions/:sessionId')
$dbForProject->deleteCachedDocument('users', $user->getId());
- $audits
- ->setParam('userId', $user->getId())
- ->setParam('event', 'account.sessions.update')
- ->setParam('resource', 'user/' . $user->getId())
- ;
+ $audits->setResource('user/' . $user->getId());
$events
- ->setParam('eventData', $response->output($session, Response::MODEL_SESSION))
+ ->setParam('userId', $user->getId())
+ ->setParam('sessionId', $session->getId())
+ ->setPayload($response->output($session, Response::MODEL_SESSION))
;
$usage
@@ -1755,7 +1720,7 @@ App::delete('/v1/account/sessions')
->desc('Delete All Account Sessions')
->groups(['api', 'account'])
->label('scope', 'account')
- ->label('event', 'account.sessions.delete')
+ ->label('event', 'users.[userId].sessions.[sessionId].delete')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'deleteSessions')
@@ -1777,7 +1742,7 @@ App::delete('/v1/account/sessions')
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Locale\Locale $locale */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Stats\Stats $usage */
@@ -1787,11 +1752,7 @@ App::delete('/v1/account/sessions')
foreach ($sessions as $session) {/** @var Document $session */
$dbForProject->deleteDocument('sessions', $session->getId());
- $audits
- ->setParam('userId', $user->getId())
- ->setParam('event', 'account.sessions.delete')
- ->setParam('resource', 'user/' . $user->getId())
- ;
+ $audits->setResource('user/' . $user->getId());
if (!Config::getParam('domainVerification')) {
$response
@@ -1818,7 +1779,9 @@ App::delete('/v1/account/sessions')
$numOfSessions = count($sessions);
$events
- ->setParam('eventData', $response->output(new Document([
+ ->setParam('userId', $user->getId())
+ ->setParam('sessionId', $session->getId())
+ ->setPayload($response->output(new Document([
'sessions' => $sessions,
'total' => $numOfSessions,
]), Response::MODEL_SESSION_LIST))
@@ -1828,6 +1791,7 @@ App::delete('/v1/account/sessions')
->setParam('users.sessions.delete', $numOfSessions)
->setParam('users.update', 1)
;
+
$response->noContent();
});
@@ -1835,7 +1799,7 @@ App::post('/v1/account/recovery')
->desc('Create Password Recovery')
->groups(['api', 'account'])
->label('scope', 'public')
- ->label('event', 'account.recovery.create')
+ ->label('event', 'users.[userId].recovery.[tokenId].create')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'createRecovery')
@@ -1862,8 +1826,8 @@ App::post('/v1/account/recovery')
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Database\Document $project */
/** @var Utopia\Locale\Locale $locale */
- /** @var Appwrite\Event\Event $mails */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Mail $mails */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Stats\Stats $usage */
@@ -1917,37 +1881,30 @@ App::post('/v1/account/recovery')
$url = Template::unParseURL($url);
$mails
- ->setParam('event', 'account.recovery.create')
- ->setParam('from', $project->getId())
- ->setParam('recipient', $profile->getAttribute('email', ''))
- ->setParam('name', $profile->getAttribute('name', ''))
- ->setParam('url', $url)
- ->setParam('locale', $locale->default)
- ->setParam('project', $project->getAttribute('name', ['[APP-NAME]']))
- ->setParam('type', MAIL_TYPE_RECOVERY)
+ ->setType(MAIL_TYPE_RECOVERY)
+ ->setRecipient($profile->getAttribute('email', ''))
+ ->setUrl($url)
+ ->setLocale($locale->default)
+ ->setName($profile->getAttribute('name'))
->trigger();
;
$events
- ->setParam('eventData',
- $response->output($recovery->setAttribute('secret', $secret),
- Response::MODEL_TOKEN
- ))
- ;
-
- $recovery // Hide secret for clients, sp
- ->setAttribute('secret',
- ($isPrivilegedUser || $isAppUser) ? $secret : '');
-
- $audits
->setParam('userId', $profile->getId())
- ->setParam('event', 'account.recovery.create')
- ->setParam('resource', 'user/' . $profile->getId())
+ ->setParam('tokenId', $recovery->getId())
+ ->setUser($profile)
+ ->setPayload($response->output(
+ $recovery->setAttribute('secret', $secret),
+ Response::MODEL_TOKEN
+ ))
;
- $usage
- ->setParam('users.update', 1)
- ;
+ // Hide secret for clients
+ $recovery->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $secret : '');
+
+ $audits->setResource('user/' . $profile->getId());
+ $usage->setParam('users.update', 1);
+
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($recovery, Response::MODEL_TOKEN);
});
@@ -1956,7 +1913,7 @@ App::put('/v1/account/recovery')
->desc('Create Password Recovery (confirmation)')
->groups(['api', 'account'])
->label('scope', 'public')
- ->label('event', 'account.recovery.update')
+ ->label('event', 'users.[userId].recovery.[tokenId].update')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateRecovery')
@@ -1974,11 +1931,13 @@ App::put('/v1/account/recovery')
->inject('dbForProject')
->inject('audits')
->inject('usage')
- ->action(function ($userId, $secret, $password, $passwordAgain, $response, $dbForProject, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($userId, $secret, $password, $passwordAgain, $response, $dbForProject, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
if ($password !== $passwordAgain) {
throw new Exception('Passwords must match', 400, Exception::USER_PASSWORD_MISMATCH);
@@ -2014,15 +1973,15 @@ App::put('/v1/account/recovery')
$dbForProject->deleteDocument('tokens', $recovery);
$dbForProject->deleteCachedDocument('users', $profile->getId());
- $audits
+ $audits->setResource('user/' . $profile->getId());
+
+ $usage->setParam('users.update', 1);
+
+ $events
->setParam('userId', $profile->getId())
- ->setParam('event', 'account.recovery.update')
- ->setParam('resource', 'user/' . $profile->getId())
+ ->setParam('tokenId', $recoveryDocument->getId())
;
- $usage
- ->setParam('users.update', 1)
- ;
$response->dynamic($recoveryDocument, Response::MODEL_TOKEN);
});
@@ -2030,7 +1989,7 @@ App::post('/v1/account/verification')
->desc('Create Email Verification')
->groups(['api', 'account'])
->label('scope', 'account')
- ->label('event', 'account.verification.create')
+ ->label('event', 'users.[userId].verification.[tokenId].create')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'createVerification')
@@ -2058,9 +2017,9 @@ App::post('/v1/account/verification')
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Locale\Locale $locale */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Event\Event $events */
- /** @var Appwrite\Event\Event $mails */
+ /** @var Appwrite\Event\Mail $mails */
/** @var Appwrite\Stats\Stats $usage */
if(empty(App::getEnv('_APP_SMTP_HOST'))) {
@@ -2099,37 +2058,29 @@ App::post('/v1/account/verification')
$url = Template::unParseURL($url);
$mails
- ->setParam('event', 'account.verification.create')
- ->setParam('from', $project->getId())
- ->setParam('recipient', $user->getAttribute('email'))
- ->setParam('name', $user->getAttribute('name'))
- ->setParam('url', $url)
- ->setParam('locale', $locale->default)
- ->setParam('project', $project->getAttribute('name', ['[APP-NAME]']))
- ->setParam('type', MAIL_TYPE_VERIFICATION)
+ ->setType(MAIL_TYPE_VERIFICATION)
+ ->setRecipient($user->getAttribute('email'))
+ ->setUrl($url)
+ ->setLocale($locale->default)
+ ->setName($user->getAttribute('name'))
->trigger()
;
$events
- ->setParam('eventData',
- $response->output($verification->setAttribute('secret', $verificationSecret),
- Response::MODEL_TOKEN
- ))
- ;
-
- $verification // Hide secret for clients, sp
- ->setAttribute('secret',
- ($isPrivilegedUser || $isAppUser) ? $verificationSecret : '');
-
- $audits
->setParam('userId', $user->getId())
- ->setParam('event', 'account.verification.create')
- ->setParam('resource', 'user/' . $user->getId())
+ ->setParam('tokenId', $verification->getId())
+ ->setPayload($response->output(
+ $verification->setAttribute('secret', $verificationSecret),
+ Response::MODEL_TOKEN
+ ))
;
- $usage
- ->setParam('users.update', 1)
- ;
+ // Hide secret for clients
+ $verification->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $verificationSecret : '');
+
+ $audits->setResource('user/' . $user->getId());
+ $usage->setParam('users.update', 1);
+
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($verification, Response::MODEL_TOKEN);
});
@@ -2138,7 +2089,7 @@ App::put('/v1/account/verification')
->desc('Create Email Verification (confirmation)')
->groups(['api', 'account'])
->label('scope', 'public')
- ->label('event', 'account.verification.update')
+ ->label('event', 'users.[userId].verification.[tokenId].update')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateVerification')
@@ -2155,12 +2106,14 @@ App::put('/v1/account/verification')
->inject('dbForProject')
->inject('audits')
->inject('usage')
- ->action(function ($userId, $secret, $response, $user, $dbForProject, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($userId, $secret, $response, $user, $dbForProject, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $user */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
$profile = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId));
@@ -2178,7 +2131,7 @@ App::put('/v1/account/verification')
Authorization::setRole('user:' . $profile->getId());
$profile = $dbForProject->updateDocument('users', $profile->getId(), $profile->setAttribute('emailVerification', true));
-
+
$verificationDocument = $dbForProject->getDocument('tokens', $verification);
/**
@@ -2188,14 +2141,14 @@ App::put('/v1/account/verification')
$dbForProject->deleteDocument('tokens', $verification);
$dbForProject->deleteCachedDocument('users', $profile->getId());
- $audits
- ->setParam('userId', $profile->getId())
- ->setParam('event', 'account.verification.update')
- ->setParam('resource', 'user/' . $user->getId())
+ $audits->setResource('user/' . $user->getId());
+
+ $usage->setParam('users.update', 1);
+
+ $events
+ ->setParam('userId', $user->getId())
+ ->setParam('tokenId', $verificationDocument->getId())
;
- $usage
- ->setParam('users.update', 1)
- ;
$response->dynamic($verificationDocument, Response::MODEL_TOKEN);
});
diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php
index 2e77e165a..7277044ae 100644
--- a/app/controllers/api/database.php
+++ b/app/controllers/api/database.php
@@ -34,6 +34,8 @@ use Appwrite\Utopia\Database\Validator\Queries as QueriesValidator;
use Appwrite\Utopia\Database\Validator\OrderAttributes as OrderAttributesValidator;
use Appwrite\Utopia\Response;
use Appwrite\Detector\Detector;
+use Appwrite\Event\Audit as EventAudit;
+use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Stats\Stats;
@@ -44,13 +46,13 @@ use Appwrite\Stats\Stats;
* @param Utopia\Database\Document $attribute
* @param Appwrite\Utopia\Response $response
* @param Utopia\Database\Database $dbForProject
- * @param Appwrite\Event\Event $database
- * @param Appwrite\Event\Event $audits
+ * @param Appwrite\Event\Database $database
+ * @param Appwrite\Event\Audit $audits
* @param Appwrite\Stats\Stats $usage
*
* @return Document Newly created attribute document
*/
-function createAttribute(string $collectionId, Document $attribute, Response $response, Database $dbForProject, Event $database, Event $audits, Stats $usage): Document
+function createAttribute(string $collectionId, Document $attribute, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Event $events, Stats $usage): Document
{
$key = $attribute->getAttribute('key');
$type = $attribute->getAttribute('type', '');
@@ -114,22 +116,23 @@ function createAttribute(string $collectionId, Document $attribute, Response $re
$dbForProject->deleteCachedDocument('collections', $collectionId);
$dbForProject->deleteCachedCollection('collection_' . $collection->getInternalId());
- // Pass clone of $attribute object to workers
- // so we can later modify Document to fit response model
- $clone = clone $attribute;
-
- $database
- ->setParam('type', DATABASE_TYPE_CREATE_ATTRIBUTE)
- ->setParam('collection', $collection)
- ->setParam('document', $clone)
- ;
-
$usage->setParam('database.collections.update', 1);
+ $database
+ ->setType(DATABASE_TYPE_CREATE_ATTRIBUTE)
+ ->setCollection($collection)
+ ->setDocument($attribute)
+ ;
+
+ $events
+ ->setContext($collection)
+ ->setParam('collectionId', $collection->getId())
+ ->setParam('attributeId', $attribute->getId())
+ ;
+
$audits
- ->setParam('event', 'database.attributes.create')
- ->setParam('resource', 'collection/'.$collectionId)
- ->setParam('data', $clone)
+ ->setResource('collection/'.$collectionId)
+ ->setPayload($attribute->getArrayCopy())
;
$response->setStatusCode(Response::STATUS_CODE_CREATED);
@@ -140,7 +143,7 @@ function createAttribute(string $collectionId, Document $attribute, Response $re
App::post('/v1/database/collections')
->desc('Create Collection')
->groups(['api', 'database'])
- ->label('event', 'database.collections.create')
+ ->label('event', 'collections.[collectionId].create')
->label('scope', 'collections.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
@@ -158,11 +161,13 @@ App::post('/v1/database/collections')
->inject('dbForProject')
->inject('audits')
->inject('usage')
- ->action(function ($collectionId, $name, $permission, $read, $write, $response, $dbForProject, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($collectionId, $name, $permission, $read, $write, $response, $dbForProject, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject*/
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
$collectionId = $collectionId == 'unique()' ? $dbForProject->getId() : $collectionId;
@@ -188,11 +193,11 @@ App::post('/v1/database/collections')
}
$audits
- ->setParam('event', 'database.collections.create')
- ->setParam('resource', 'collection/'.$collectionId)
- ->setParam('data', $collection->getArrayCopy())
+ ->setResource('collection/'.$collectionId)
+ ->setPayload($collection->getArrayCopy())
;
+ $events->setParam('collectionId', $collection->getId());
$usage->setParam('database.collections.create', 1);
$response->setStatusCode(Response::STATUS_CODE_CREATED);
@@ -582,7 +587,7 @@ App::put('/v1/database/collections/:collectionId')
->desc('Update Collection')
->groups(['api', 'database'])
->label('scope', 'collections.write')
- ->label('event', 'database.collections.update')
+ ->label('event', 'collections.[collectionId].update')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.method', 'updateCollection')
@@ -600,11 +605,13 @@ App::put('/v1/database/collections/:collectionId')
->inject('dbForProject')
->inject('audits')
->inject('usage')
- ->action(function ($collectionId, $name, $permission, $read, $write, $enabled, $response, $dbForProject, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($collectionId, $name, $permission, $read, $write, $enabled, $response, $dbForProject, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
$collection = $dbForProject->getDocument('collections', $collectionId);
@@ -634,14 +641,14 @@ App::put('/v1/database/collections/:collectionId')
throw new Exception('Bad structure. '.$exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE);
}
- $usage->setParam('database.collections.update', 1);
-
$audits
- ->setParam('event', 'database.collections.update')
- ->setParam('resource', 'collection/'.$collectionId)
- ->setParam('data', $collection->getArrayCopy())
+ ->setResource('collection/'.$collectionId)
+ ->setPayload($collection->getArrayCopy())
;
+ $usage->setParam('database.collections.update', 1);
+ $events->setParam('collectionId', $collection->getId());
+
$response->dynamic($collection, Response::MODEL_COLLECTION);
});
@@ -649,7 +656,7 @@ App::delete('/v1/database/collections/:collectionId')
->desc('Delete Collection')
->groups(['api', 'database'])
->label('scope', 'collections.write')
- ->label('event', 'database.collections.delete')
+ ->label('event', 'collections.[collectionId].delete')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.method', 'deleteCollection')
@@ -667,8 +674,9 @@ App::delete('/v1/database/collections/:collectionId')
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Appwrite\Event\Event $events */
- /** @var Appwrite\Event\Event $audits */
- /** @var Appwrite\Stats\Stats $audits */
+ /** @var Appwrite\Event\Audit $audits */
+ /** @var Appwrite\Event\Delete $deletes */
+ /** @var Appwrite\Stats\Stats $usage */
$collection = $dbForProject->getDocument('collections', $collectionId);
@@ -683,29 +691,29 @@ App::delete('/v1/database/collections/:collectionId')
$dbForProject->deleteCachedCollection('collection_' . $collection->getInternalId());
$deletes
- ->setParam('type', DELETE_TYPE_DOCUMENT)
- ->setParam('document', $collection)
+ ->setType(DELETE_TYPE_DOCUMENT)
+ ->setDocument($collection)
;
- $usage->setParam('database.collections.delete', 1);
-
$events
- ->setParam('eventData', $response->output($collection, Response::MODEL_COLLECTION))
+ ->setParam('collectionId', $collection->getId())
+ ->setPayload($response->output($collection, Response::MODEL_COLLECTION))
;
$audits
- ->setParam('event', 'database.collections.delete')
- ->setParam('resource', 'collection/'.$collectionId)
- ->setParam('data', $collection->getArrayCopy())
+ ->setResource('collection/'.$collectionId)
+ ->setPayload($collection->getArrayCopy())
;
+ $usage->setParam('database.collections.delete', 1);
+
$response->noContent();
});
App::post('/v1/database/collections/:collectionId/attributes/string')
->desc('Create String Attribute')
->groups(['api', 'database'])
- ->label('event', 'database.attributes.create')
+ ->label('event', 'collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
@@ -725,12 +733,14 @@ App::post('/v1/database/collections/:collectionId/attributes/string')
->inject('database')
->inject('audits')
->inject('usage')
- ->action(function ($collectionId, $key, $size, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($collectionId, $key, $size, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject*/
- /** @var Appwrite\Event\Event $database */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Database $database */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
// Ensure attribute default is within required size
$validator = new Text($size);
@@ -745,7 +755,7 @@ App::post('/v1/database/collections/:collectionId/attributes/string')
'required' => $required,
'default' => $default,
'array' => $array,
- ]), $response, $dbForProject, $database, $audits, $usage);
+ ]), $response, $dbForProject, $database, $audits, $events, $usage);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_STRING);
});
@@ -753,7 +763,7 @@ App::post('/v1/database/collections/:collectionId/attributes/string')
App::post('/v1/database/collections/:collectionId/attributes/email')
->desc('Create Email Attribute')
->groups(['api', 'database'])
- ->label('event', 'database.attributes.create')
+ ->label('event', 'collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -772,11 +782,12 @@ App::post('/v1/database/collections/:collectionId/attributes/email')
->inject('database')
->inject('audits')
->inject('usage')
- ->action(function ($collectionId, $key, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($collectionId, $key, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject*/
- /** @var Appwrite\Event\Event $database */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Database $database */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
$attribute = createAttribute($collectionId, new Document([
@@ -787,7 +798,7 @@ App::post('/v1/database/collections/:collectionId/attributes/email')
'default' => $default,
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_EMAIL,
- ]), $response, $dbForProject, $database, $audits, $usage);
+ ]), $response, $dbForProject, $database, $audits, $events, $usage);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_EMAIL);
});
@@ -795,7 +806,7 @@ App::post('/v1/database/collections/:collectionId/attributes/email')
App::post('/v1/database/collections/:collectionId/attributes/enum')
->desc('Create Enum Attribute')
->groups(['api', 'database'])
- ->label('event', 'database.attributes.create')
+ ->label('event', 'collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -815,12 +826,14 @@ App::post('/v1/database/collections/:collectionId/attributes/enum')
->inject('database')
->inject('audits')
->inject('usage')
- ->action(function ($collectionId, $key, $elements, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($collectionId, $key, $elements, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject*/
- /** @var Appwrite\Event\Event $database */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Database $database */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
// use length of longest string as attribute size
$size = 0;
@@ -846,7 +859,7 @@ App::post('/v1/database/collections/:collectionId/attributes/enum')
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_ENUM,
'formatOptions' => ['elements' => $elements],
- ]), $response, $dbForProject, $database, $audits, $usage);
+ ]), $response, $dbForProject, $database, $audits, $events, $usage);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_ENUM);
});
@@ -854,7 +867,7 @@ App::post('/v1/database/collections/:collectionId/attributes/enum')
App::post('/v1/database/collections/:collectionId/attributes/ip')
->desc('Create IP Address Attribute')
->groups(['api', 'database'])
- ->label('event', 'database.attributes.create')
+ ->label('event', 'collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -873,11 +886,12 @@ App::post('/v1/database/collections/:collectionId/attributes/ip')
->inject('database')
->inject('audits')
->inject('usage')
- ->action(function ($collectionId, $key, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($collectionId, $key, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject*/
- /** @var Appwrite\Event\Event $database */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Database $database */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
$attribute = createAttribute($collectionId, new Document([
@@ -888,7 +902,7 @@ App::post('/v1/database/collections/:collectionId/attributes/ip')
'default' => $default,
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_IP,
- ]), $response, $dbForProject, $database, $audits, $usage);
+ ]), $response, $dbForProject, $database, $audits, $events, $usage);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_IP);
});
@@ -896,7 +910,7 @@ App::post('/v1/database/collections/:collectionId/attributes/ip')
App::post('/v1/database/collections/:collectionId/attributes/url')
->desc('Create URL Attribute')
->groups(['api', 'database'])
- ->label('event', 'database.attributes.create')
+ ->label('event', 'collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -915,11 +929,13 @@ App::post('/v1/database/collections/:collectionId/attributes/url')
->inject('database')
->inject('audits')
->inject('usage')
- ->action(function ($collectionId, $key, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($collectionId, $key, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
- /** @var Appwrite\Event\Event $database */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Database $database */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
$attribute = createAttribute($collectionId, new Document([
'key' => $key,
@@ -929,7 +945,7 @@ App::post('/v1/database/collections/:collectionId/attributes/url')
'default' => $default,
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_URL,
- ]), $response, $dbForProject, $database, $audits, $usage);
+ ]), $response, $dbForProject, $database, $audits, $events, $usage);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_URL);
});
@@ -937,7 +953,7 @@ App::post('/v1/database/collections/:collectionId/attributes/url')
App::post('/v1/database/collections/:collectionId/attributes/integer')
->desc('Create Integer Attribute')
->groups(['api', 'database'])
- ->label('event', 'database.attributes.create')
+ ->label('event', 'collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -958,12 +974,14 @@ App::post('/v1/database/collections/:collectionId/attributes/integer')
->inject('database')
->inject('audits')
->inject('usage')
- ->action(function ($collectionId, $key, $required, $min, $max, $default, $array, $response, $dbForProject, $database, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($collectionId, $key, $required, $min, $max, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject*/
- /** @var Appwrite\Event\Event $database */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Database $database */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
// Ensure attribute default is within range
$min = (is_null($min)) ? PHP_INT_MIN : \intval($min);
@@ -993,7 +1011,7 @@ App::post('/v1/database/collections/:collectionId/attributes/integer')
'min' => $min,
'max' => $max,
],
- ]), $response, $dbForProject, $database, $audits, $usage);
+ ]), $response, $dbForProject, $database, $audits, $events, $usage);
$formatOptions = $attribute->getAttribute('formatOptions', []);
@@ -1008,7 +1026,7 @@ App::post('/v1/database/collections/:collectionId/attributes/integer')
App::post('/v1/database/collections/:collectionId/attributes/float')
->desc('Create Float Attribute')
->groups(['api', 'database'])
- ->label('event', 'database.attributes.create')
+ ->label('event', 'collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -1028,13 +1046,15 @@ App::post('/v1/database/collections/:collectionId/attributes/float')
->inject('dbForProject')
->inject('database')
->inject('audits')
+ ->inject('events')
->inject('usage')
- ->action(function ($collectionId, $key, $required, $min, $max, $default, $array, $response, $dbForProject, $database, $audits, $usage) {
+ ->action(function ($collectionId, $key, $required, $min, $max, $default, $array, $response, $dbForProject, $database, $audits, $events, $usage) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject*/
- /** @var Appwrite\Event\Event $database */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Database $database */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
// Ensure attribute default is within range
$min = (is_null($min)) ? -PHP_FLOAT_MAX : \floatval($min);
@@ -1067,7 +1087,7 @@ App::post('/v1/database/collections/:collectionId/attributes/float')
'min' => $min,
'max' => $max,
],
- ]), $response, $dbForProject, $database, $audits, $usage);
+ ]), $response, $dbForProject, $database, $audits, $events, $usage);
$formatOptions = $attribute->getAttribute('formatOptions', []);
@@ -1082,7 +1102,7 @@ App::post('/v1/database/collections/:collectionId/attributes/float')
App::post('/v1/database/collections/:collectionId/attributes/boolean')
->desc('Create Boolean Attribute')
->groups(['api', 'database'])
- ->label('event', 'database.attributes.create')
+ ->label('event', 'collections.[collectionId].attributes.[attributeId].create')
->label('scope', 'collections.write')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
@@ -1101,12 +1121,14 @@ App::post('/v1/database/collections/:collectionId/attributes/boolean')
->inject('database')
->inject('audits')
->inject('usage')
- ->action(function ($collectionId, $key, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($collectionId, $key, $required, $default, $array, $response, $dbForProject, $database, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject*/
- /** @var Appwrite\Event\Event $database */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Database $database */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
$attribute = createAttribute($collectionId, new Document([
'key' => $key,
@@ -1115,7 +1137,7 @@ App::post('/v1/database/collections/:collectionId/attributes/boolean')
'required' => $required,
'default' => $default,
'array' => $array,
- ]), $response, $dbForProject, $database, $audits, $usage);
+ ]), $response, $dbForProject, $database, $audits, $events, $usage);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_BOOLEAN);
});
@@ -1222,7 +1244,7 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key')
->desc('Delete Attribute')
->groups(['api', 'database'])
->label('scope', 'collections.write')
- ->label('event', 'database.attributes.delete')
+ ->label('event', 'collections.[collectionId].attributes.[attributeId].delete')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.method', 'deleteAttribute')
@@ -1240,9 +1262,9 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key')
->action(function ($collectionId, $key, $response, $dbForProject, $database, $events, $audits, $usage) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $database */
+ /** @var Appwrite\Event\Database $database */
/** @var Appwrite\Event\Event $events */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
$collection = $dbForProject->getDocument('collections', $collectionId);
@@ -1266,9 +1288,9 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key')
$dbForProject->deleteCachedCollection('collection_' . $collection->getInternalId());
$database
- ->setParam('type', DATABASE_TYPE_DELETE_ATTRIBUTE)
- ->setParam('collection', $collection)
- ->setParam('document', $attribute)
+ ->setType(DATABASE_TYPE_DELETE_ATTRIBUTE)
+ ->setCollection($collection)
+ ->setDocument($attribute)
;
$usage->setParam('database.collections.update', 1);
@@ -1292,13 +1314,15 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key')
};
$events
- ->setParam('payload', $response->output($attribute, $model))
+ ->setParam('collectionId', $collection->getId())
+ ->setParam('attributeId', $attribute->getId())
+ ->setContext($collection)
+ ->setPayload($response->output($attribute, $model))
;
$audits
- ->setParam('event', 'database.attributes.delete')
- ->setParam('resource', 'collection/'.$collectionId)
- ->setParam('data', $attribute->getArrayCopy())
+ ->setResource('collection/'.$collectionId)
+ ->setPayload($attribute->getArrayCopy())
;
$response->noContent();
@@ -1307,7 +1331,7 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key')
App::post('/v1/database/collections/:collectionId/indexes')
->desc('Create Index')
->groups(['api', 'database'])
- ->label('event', 'database.indexes.create')
+ ->label('event', 'collections.[collectionId].indexes.[indexId].create')
->label('scope', 'collections.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
@@ -1326,12 +1350,14 @@ App::post('/v1/database/collections/:collectionId/indexes')
->inject('database')
->inject('audits')
->inject('usage')
- ->action(function ($collectionId, $key, $type, $attributes, $orders, $response, $dbForProject, $database, $audits, $usage) {
+ ->inject('events')
+ ->action(function ($collectionId, $key, $type, $attributes, $orders, $response, $dbForProject, $database, $audits, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $database */
- /** @var Appwrite\Event\Event $audits */
- /** @var Appwrite\Stats\Stats $audits */
+ /** @var Appwrite\Event\Database $database */
+ /** @var Appwrite\Event\Audit $audits */
+ /** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
$collection = $dbForProject->getDocument('collections', $collectionId);
@@ -1394,17 +1420,22 @@ App::post('/v1/database/collections/:collectionId/indexes')
$dbForProject->deleteCachedDocument('collections', $collectionId);
$database
- ->setParam('type', DATABASE_TYPE_CREATE_INDEX)
- ->setParam('collection', $collection)
- ->setParam('document', $index)
+ ->setType(DATABASE_TYPE_CREATE_INDEX)
+ ->setCollection($collection)
+ ->setDocument($index)
;
$usage->setParam('database.collections.update', 1);
+ $events
+ ->setParam('collectionId', $collection->getId())
+ ->setParam('indexId', $index->getId())
+ ->setContext($collection)
+ ;
+
$audits
- ->setParam('event', 'database.indexes.create')
- ->setParam('resource', 'collection/'.$collectionId)
- ->setParam('data', $index->getArrayCopy())
+ ->setResource('collection/'.$collection->getId())
+ ->setPayload($index->getArrayCopy())
;
$response->setStatusCode(Response::STATUS_CODE_CREATED);
@@ -1494,7 +1525,7 @@ App::delete('/v1/database/collections/:collectionId/indexes/:key')
->desc('Delete Index')
->groups(['api', 'database'])
->label('scope', 'collections.write')
- ->label('event', 'database.indexes.delete')
+ ->label('event', 'collections.[collectionId].indexes.[indexId].delete')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.method', 'deleteIndex')
@@ -1512,9 +1543,9 @@ App::delete('/v1/database/collections/:collectionId/indexes/:key')
->action(function ($collectionId, $key, $response, $dbForProject, $database, $events, $audits, $usage) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $database */
+ /** @var Appwrite\Event\Database $database */
/** @var Appwrite\Event\Event $events */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
$collection = $dbForProject->getDocument('collections', $collectionId);
@@ -1537,21 +1568,23 @@ App::delete('/v1/database/collections/:collectionId/indexes/:key')
$dbForProject->deleteCachedDocument('collections', $collectionId);
$database
- ->setParam('type', DATABASE_TYPE_DELETE_INDEX)
- ->setParam('collection', $collection)
- ->setParam('document', $index)
+ ->setType(DATABASE_TYPE_DELETE_INDEX)
+ ->setCollection($collection)
+ ->setDocument($index)
;
$usage->setParam('database.collections.update', 1);
$events
- ->setParam('payload', $response->output($index, Response::MODEL_INDEX))
+ ->setParam('collectionId', $collection->getId())
+ ->setParam('indexId', $index->getId())
+ ->setContext($collection)
+ ->setPayload($response->output($index, Response::MODEL_INDEX))
;
$audits
- ->setParam('event', 'database.indexes.delete')
- ->setParam('resource', 'collection/'.$collectionId)
- ->setParam('data', $index->getArrayCopy())
+ ->setResource('collection/'.$collection->getId())
+ ->setPayload($index->getArrayCopy())
;
$response->noContent();
@@ -1560,7 +1593,7 @@ App::delete('/v1/database/collections/:collectionId/indexes/:key')
App::post('/v1/database/collections/:collectionId/documents')
->desc('Create Document')
->groups(['api', 'database'])
- ->label('event', 'database.documents.create')
+ ->label('event', 'collections.[collectionId].documents.[documentId].create')
->label('scope', 'documents.write')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'database')
@@ -1585,7 +1618,7 @@ App::post('/v1/database/collections/:collectionId/documents')
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Database\Document $user */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
/** @var Appwrite\Event\Event $events */
/** @var string $mode */
@@ -1659,7 +1692,11 @@ App::post('/v1/database/collections/:collectionId/documents')
throw new Exception('Document already exists', 409, Exception::DOCUMENT_ALREADY_EXISTS);
}
- $events->setParam('collection', $collection->getArrayCopy());
+ $events
+ ->setParam('collectionId', $collection->getId())
+ ->setParam('documentId', $document->getId())
+ ->setContext($collection)
+ ;
$usage
->setParam('database.documents.create', 1)
@@ -1667,9 +1704,8 @@ App::post('/v1/database/collections/:collectionId/documents')
;
$audits
- ->setParam('event', 'database.documents.create')
- ->setParam('resource', 'document/'.$document->getId())
- ->setParam('data', $document->getArrayCopy())
+ ->setResource('document/'.$document->getId())
+ ->setPayload($document->getArrayCopy())
;
$response->setStatusCode(Response::STATUS_CODE_CREATED);
@@ -1946,7 +1982,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId/logs')
App::patch('/v1/database/collections/:collectionId/documents/:documentId')
->desc('Update Document')
->groups(['api', 'database'])
- ->label('event', 'database.documents.update')
+ ->label('event', 'collections.[collectionId].documents.[documentId].update')
->label('scope', 'documents.write')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'database')
@@ -1969,7 +2005,7 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
->action(function ($collectionId, $documentId, $data, $read, $write, $response, $dbForProject, $audits, $usage, $events, $mode) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
/** @var Appwrite\Event\Event $events */
/** @var string $mode */
@@ -2007,7 +2043,7 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
if (empty($data)) {
throw new Exception('Missing payload', 400, Exception::DOCUMENT_MISSING_PAYLOAD);
}
-
+
if (!\is_array($data)) {
throw new Exception('Data param should be a valid JSON object', 400, Exception::DOCUMENT_INVALID_STRUCTURE);
}
@@ -2061,17 +2097,20 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
throw new Exception($exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE);
}
- $events->setParam('collection', $collection->getArrayCopy());
+ $events
+ ->setParam('collectionId', $collection->getId())
+ ->setParam('documentId', $document->getId())
+ ->setContext($collection)
+ ;
$usage
->setParam('database.documents.update', 1)
->setParam('collectionId', $collectionId)
- ;
+ ;
$audits
- ->setParam('event', 'database.documents.update')
- ->setParam('resource', 'document/'.$document->getId())
- ->setParam('data', $document->getArrayCopy())
+ ->setResource('document/'.$document->getId())
+ ->setPayload($document->getArrayCopy())
;
$response->dynamic($document, Response::MODEL_DOCUMENT);
@@ -2081,7 +2120,7 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
->desc('Delete Document')
->groups(['api', 'database'])
->label('scope', 'documents.write')
- ->label('event', 'database.documents.delete')
+ ->label('event', 'collections.[collectionId].documents.[documentId].delete')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'database')
->label('sdk.method', 'deleteDocument')
@@ -2101,8 +2140,8 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Appwrite\Event\Event $events */
- /** @var Appwrite\Event\Event $audits */
- /** @var Appwrite\Event\Event $deletes */
+ /** @var Appwrite\Event\Audit $audits */
+ /** @var Appwrite\Event\Delete $deletes */
/** @var Appwrite\Stats\Stats $usage */
/** @var string $mode */
@@ -2150,24 +2189,25 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
$document->setAttribute('$collection', $collectionId);
$deletes
- ->setParam('type', DELETE_TYPE_AUDIT)
- ->setParam('document', $document)
+ ->setType(DELETE_TYPE_AUDIT)
+ ->setDocument($document)
;
$usage
->setParam('database.documents.delete', 1)
->setParam('collectionId', $collectionId)
- ;
+ ;
$events
- ->setParam('eventData', $response->output($document, Response::MODEL_DOCUMENT))
- ->setParam('collection', $collection->getArrayCopy());
+ ->setParam('collectionId', $collection->getId())
+ ->setParam('documentId', $document->getId())
+ ->setContext($collection)
+ ->setPayload($response->output($document, Response::MODEL_DOCUMENT))
;
$audits
- ->setParam('event', 'database.documents.delete')
- ->setParam('resource', 'document/'.$document->getId())
- ->setParam('data', $document->getArrayCopy()) // Audit document in case of malicious or disastrous action
+ ->setResource('document/'.$document->getId())
+ ->setPayload($document->getArrayCopy())
;
$response->noContent();
diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php
index 2a80c9bb9..f7de8362a 100644
--- a/app/controllers/api/functions.php
+++ b/app/controllers/api/functions.php
@@ -2,7 +2,9 @@
use Ahc\Jwt\JWT;
use Appwrite\Auth\Auth;
-use Appwrite\Event\Event;
+use Appwrite\Event\Build;
+use Appwrite\Event\Func;
+use Appwrite\Event\Validator\Event as ValidatorEvent;
use Appwrite\Extend\Exception;
use Appwrite\Utopia\Database\Validator\CustomId;
use Utopia\Database\Validator\UID;
@@ -34,7 +36,7 @@ App::post('/v1/functions')
->groups(['api', 'functions'])
->desc('Create Function')
->label('scope', 'functions.write')
- ->label('event', 'functions.create')
+ ->label('event', 'functions.[functionId].create')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'create')
@@ -47,14 +49,16 @@ App::post('/v1/functions')
->param('execute', [], new ArrayList(new Text(64)), 'An array of strings with execution permissions. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.')
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.')
->param('vars', [], new Assoc(), 'Key-value JSON object that will be passed to the function as environment variables.', true)
- ->param('events', [], new ArrayList(new WhiteList(array_keys(Config::getParam('events')), true)), 'Events list.', true)
+ ->param('events', [], new ArrayList(new ValidatorEvent()), 'Events list.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Function maximum execution time in seconds.', true)
->inject('response')
->inject('dbForProject')
- ->action(function ($functionId, $name, $execute, $runtime, $vars, $events, $schedule, $timeout, $response, $dbForProject) {
+ ->inject('events')
+ ->action(function ($functionId, $name, $execute, $runtime, $vars, $events, $schedule, $timeout, $response, $dbForProject, $eventsInstance) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
+ /** @var Appwrite\Event\Event $eventsInstance */
$functionId = ($functionId == 'unique()') ? $dbForProject->getId() : $functionId;
$function = $dbForProject->createDocument('functions', new Document([
@@ -75,6 +79,8 @@ App::post('/v1/functions')
'search' => implode(' ', [$functionId, $name, $runtime]),
]));
+ $eventsInstance->setParam('functionId', $function->getId());
+
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($function, Response::MODEL_FUNCTION);
});
@@ -144,7 +150,7 @@ App::get('/v1/functions/runtimes')
return $runtimes[$key];
}, array_keys($runtimes));
- $response->dynamic(new Document([
+ $response->dynamic(new Document([
'total' => count($runtimes),
'runtimes' => $runtimes
]), Response::MODEL_RUNTIME_LIST);
@@ -202,9 +208,9 @@ App::get('/v1/functions/:functionId/usage')
if ($function->isEmpty()) {
throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND);
}
-
+
$usage = [];
- if(App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
+ if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
$periods = [
'24h' => [
'period' => '30m',
@@ -223,16 +229,16 @@ App::get('/v1/functions/:functionId/usage')
'limit' => 90,
],
];
-
+
$metrics = [
- "functions.$functionId.executions",
- "functions.$functionId.failures",
+ "functions.$functionId.executions",
+ "functions.$functionId.failures",
"functions.$functionId.compute"
];
$stats = [];
- Authorization::skip(function() use ($dbForProject, $periods, $range, $metrics, &$stats) {
+ Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) {
foreach ($metrics as $metric) {
$limit = $periods[$range]['limit'];
$period = $periods[$range]['period'];
@@ -241,7 +247,7 @@ App::get('/v1/functions/:functionId/usage')
new Query('period', Query::TYPE_EQUAL, [$period]),
new Query('metric', Query::TYPE_EQUAL, [$metric]),
], $limit, 0, ['time'], [Database::ORDER_DESC]);
-
+
$stats[$metric] = [];
foreach ($requestDocs as $requestDoc) {
$stats[$metric][] = [
@@ -254,7 +260,7 @@ App::get('/v1/functions/:functionId/usage')
$backfill = $limit - \count($requestDocs);
while ($backfill > 0) {
$last = $limit - $backfill - 1; // array index of last added metric
- $diff = match($period) { // convert period to seconds for unix timestamp math
+ $diff = match ($period) { // convert period to seconds for unix timestamp math
'30m' => 1800,
'1d' => 86400,
};
@@ -265,7 +271,7 @@ App::get('/v1/functions/:functionId/usage')
$backfill--;
}
$stats[$metric] = array_reverse($stats[$metric]);
- }
+ }
});
$usage = new Document([
@@ -283,7 +289,7 @@ App::put('/v1/functions/:functionId')
->groups(['api', 'functions'])
->desc('Update Function')
->label('scope', 'functions.write')
- ->label('event', 'functions.update')
+ ->label('event', 'functions.[functionId].update')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'update')
@@ -295,18 +301,20 @@ App::put('/v1/functions/:functionId')
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('execute', [], new ArrayList(new Text(64)), 'An array of strings with execution permissions. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.')
->param('vars', [], new Assoc(), 'Key-value JSON object that will be passed to the function as environment variables.', true)
- ->param('events', [], new ArrayList(new WhiteList(array_keys(Config::getParam('events')), true)), 'Events list.', true)
+ ->param('events', [], new ArrayList(new ValidatorEvent()), 'Events list.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Maximum execution time in seconds.', true)
->inject('response')
->inject('dbForProject')
->inject('project')
->inject('user')
- ->action(function ($functionId, $name, $execute, $vars, $events, $schedule, $timeout, $response, $dbForProject, $project, $user) {
+ ->inject('events')
+ ->action(function ($functionId, $name, $execute, $vars, $events, $schedule, $timeout, $response, $dbForProject, $project, $user, $eventsInstance) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Database\Document $project */
- /** @var Appwrite\Auth\User $user */
+ /** @var Utopia\Database\Document $user */
+ /** @var Appwrite\Event\Event $eventsInstance */
$function = $dbForProject->getDocument('functions', $functionId);
@@ -331,16 +339,19 @@ App::put('/v1/functions/:functionId')
])));
if ($next && $schedule !== $original) {
- ResqueScheduler::enqueueAt($next, Event::FUNCTIONS_QUEUE_NAME, Event::FUNCTIONS_CLASS_NAME, [
- 'projectId' => $project->getId(),
- 'webhooks' => $project->getAttribute('webhooks', []),
- 'functionId' => $function->getId(),
- 'userId' => $user->getId(),
- 'executionId' => null,
- 'trigger' => 'schedule',
- ]); // Async task rescheduale
+ // Async task reschedule
+ $functionEvent = new Func();
+ $functionEvent
+ ->setFunction($function)
+ ->setType('schedule')
+ ->setUser($user)
+ ->setProject($project);
+
+ $functionEvent->schedule($next);
}
+ $eventsInstance->setParam('functionId', $function->getId());
+
$response->dynamic($function, Response::MODEL_FUNCTION);
});
@@ -348,7 +359,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId')
->groups(['api', 'functions'])
->desc('Update Function Deployment')
->label('scope', 'functions.write')
- ->label('event', 'functions.deployments.update')
+ ->label('event', 'functions.[functionId].deployments.[deploymentId].update')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'updateDeployment')
@@ -361,10 +372,12 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId')
->inject('response')
->inject('dbForProject')
->inject('project')
- ->action(function ($functionId, $deploymentId, $response, $dbForProject, $project) {
+ ->inject('events')
+ ->action(function ($functionId, $deploymentId, $response, $dbForProject, $project, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Database\Document $project */
+ /** @var Appwrite\Event\Event $events */
$function = $dbForProject->getDocument('functions', $functionId);
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
@@ -396,14 +409,18 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId')
])));
if ($next) { // Init first schedule
- ResqueScheduler::enqueueAt($next, 'v1-functions', 'FunctionsV1', [
- 'projectId' => $project->getId(),
- 'webhooks' => $project->getAttribute('webhooks', []),
- 'functionId' => $function->getId(),
- 'executionId' => null,
- 'trigger' => 'schedule',
- ]); // Async task rescheduale
+ $functionEvent = new Func();
+ $functionEvent
+ ->setType('schedule')
+ ->setFunction($function)
+ ->setProject($project);
+ $functionEvent->schedule($next);
}
+
+ $events
+ ->setParam('functionId', $function->getId())
+ ->setParam('deploymentId', $deployment->getId());
+
$response->dynamic($function, Response::MODEL_FUNCTION);
});
@@ -411,7 +428,7 @@ App::delete('/v1/functions/:functionId')
->groups(['api', 'functions'])
->desc('Delete Function')
->label('scope', 'functions.write')
- ->label('event', 'functions.delete')
+ ->label('event', 'functions.[functionId].delete')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'delete')
@@ -422,10 +439,12 @@ App::delete('/v1/functions/:functionId')
->inject('response')
->inject('dbForProject')
->inject('deletes')
- ->action(function ($functionId, $response, $dbForProject, $deletes) {
+ ->inject('events')
+ ->action(function ($functionId, $response, $dbForProject, $deletes, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $deletes */
+ /** @var Appwrite\Event\Delete $deletes */
+ /** @var Appwrite\Event\Event $events */
$function = $dbForProject->getDocument('functions', $functionId);
@@ -438,9 +457,10 @@ App::delete('/v1/functions/:functionId')
}
$deletes
- ->setParam('type', DELETE_TYPE_DOCUMENT)
- ->setParam('document', $function)
- ;
+ ->setType(DELETE_TYPE_DOCUMENT)
+ ->setDocument($function);
+
+ $events->setParam('functionId', $function->getId());
$response->noContent();
});
@@ -449,7 +469,7 @@ App::post('/v1/functions/:functionId/deployments')
->groups(['api', 'functions'])
->desc('Create Deployment')
->label('scope', 'functions.write')
- ->label('event', 'functions.deployments.create')
+ ->label('event', 'functions.[functionId].deployments.[deploymentId].create')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'createDeployment')
@@ -467,17 +487,17 @@ App::post('/v1/functions/:functionId/deployments')
->inject('response')
->inject('dbForProject')
->inject('usage')
- ->inject('user')
+ ->inject('events')
->inject('project')
->inject('deviceFunctions')
->inject('deviceLocal')
- ->action(function ($functionId, $entrypoint, $file, $activate, $request, $response, $dbForProject, $usage, $user, $project, $deviceFunctions, $deviceLocal) {
+ ->action(function ($functionId, $entrypoint, $file, $activate, $request, $response, $dbForProject, $usage, $events, $project, $deviceFunctions, $deviceLocal) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Appwrite\Event\Event $usage */
- /** @var Appwrite\Auth\User $user */
- /** @var Appwrite\Database\Document $project */
+ /** @var Appwrite\Event\Event $events */
+ /** @var Utopia\Database\Document $project */
/** @var Utopia\Storage\Device $deviceFunctions */
/** @var Utopia\Storage\Device $deviceLocal */
@@ -515,7 +535,7 @@ App::post('/v1/functions/:functionId/deployments')
$end = $request->getContentRangeEnd();
$fileSize = $request->getContentRangeSize();
$deploymentId = $request->getHeader('x-appwrite-id', $deploymentId);
- if(is_null($start) || is_null($end) || is_null($fileSize)) {
+ if (is_null($start) || is_null($end) || is_null($fileSize)) {
throw new Exception('Invalid content-range header', 400, Exception::STORAGE_INVALID_CONTENT_RANGE);
}
@@ -539,8 +559,8 @@ App::post('/v1/functions/:functionId/deployments')
// Save to storage
$fileSize ??= $deviceLocal->getFileSize($fileTmpName);
- $path = $deviceFunctions->getPath($deploymentId.'.'.\pathinfo($fileName, PATHINFO_EXTENSION));
-
+ $path = $deviceFunctions->getPath($deploymentId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION));
+
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
$metadata = ['content_type' => $deviceLocal->getFileMimeType($fileTmpName)];
@@ -560,7 +580,7 @@ App::post('/v1/functions/:functionId/deployments')
$activate = (bool) filter_var($activate, FILTER_VALIDATE_BOOLEAN);
- if($chunksUploaded === $chunks) {
+ if ($chunksUploaded === $chunks) {
if ($activate) {
// Remove deploy for all other deployments.
$activeDeployments = $dbForProject->find('deployments', [
@@ -574,7 +594,7 @@ App::post('/v1/functions/:functionId/deployments')
$dbForProject->updateDocument('deployments', $activeDeployment->getId(), $activeDeployment);
}
}
-
+
$fileSize = $deviceFunctions->getFileSize($path);
if ($deployment->isEmpty()) {
@@ -596,19 +616,18 @@ App::post('/v1/functions/:functionId/deployments')
$deployment = $dbForProject->updateDocument('deployments', $deploymentId, $deployment->setAttribute('size', $fileSize)->setAttribute('metadata', $metadata));
}
- // Enqueue a message to start the build
- Resque::enqueue(Event::BUILDS_QUEUE_NAME, Event::BUILDS_CLASS_NAME, [
- 'projectId' => $project->getId(),
- 'resourceId' => $function->getId(),
- 'deploymentId' => $deploymentId,
- 'type' => BUILD_TYPE_DEPLOYMENT
- ]);
+ // Start the build
+ $buildEvent = new Build();
+ $buildEvent
+ ->setType(BUILD_TYPE_DEPLOYMENT)
+ ->setResource($function)
+ ->setDeployment($deployment)
+ ->setProject($project)
+ ->trigger();
- $usage
- ->setParam('storage', $deployment->getAttribute('size', 0))
- ;
+ $usage->setParam('storage', $deployment->getAttribute('size', 0));
} else {
- if($deployment->isEmpty()) {
+ if ($deployment->isEmpty()) {
$deployment = $dbForProject->createDocument('deployments', new Document([
'$id' => $deploymentId,
'$read' => ['role:all'],
@@ -632,6 +651,10 @@ App::post('/v1/functions/:functionId/deployments')
$metadata = null;
+ $events
+ ->setParam('functionId', $function->getId())
+ ->setParam('deploymentId', $deployment->getId());
+
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($deployment, Response::MODEL_DEPLOYMENT);
});
@@ -742,7 +765,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
->groups(['api', 'functions'])
->desc('Delete Deployment')
->label('scope', 'functions.write')
- ->label('event', 'functions.deployments.delete')
+ ->label('event', 'functions.[functionId].deployments.[deploymentId].delete')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'deleteDeployment')
@@ -755,19 +778,21 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
->inject('dbForProject')
->inject('usage')
->inject('deletes')
+ ->inject('events')
->inject('deviceFunctions')
- ->action(function ($functionId, $deploymentId, $response, $dbForProject, $usage, $deletes, $deviceFunctions) {
+ ->action(function ($functionId, $deploymentId, $response, $dbForProject, $usage, $deletes, $events, $deviceFunctions) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Appwrite\Event\Event $usage */
- /** @var Appwrite\Event\Event $deletes */
+ /** @var Appwrite\Event\Delete $deletes */
+ /** @var Appwrite\Event\Event $events */
/** @var Utopia\Storage\Device $deviceFunctions */
$function = $dbForProject->getDocument('functions', $functionId);
if ($function->isEmpty()) {
throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND);
}
-
+
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
if ($deployment->isEmpty()) {
throw new Exception('Deployment not found', 404, Exception::DEPLOYMENT_NOT_FOUND);
@@ -783,20 +808,22 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
}
}
- if($function->getAttribute('deployment') === $deployment->getId()) { // Reset function deployment
+ if ($function->getAttribute('deployment') === $deployment->getId()) { // Reset function deployment
$function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
'deployment' => '',
])));
}
$usage
- ->setParam('storage', $deployment->getAttribute('size', 0) * -1)
- ;
+ ->setParam('storage', $deployment->getAttribute('size', 0) * -1);
+
+ $events
+ ->setParam('functionId', $function->getId())
+ ->setParam('deploymentId', $deployment->getId());
$deletes
- ->setParam('type', DELETE_TYPE_DOCUMENT)
- ->setParam('document', $deployment)
- ;
+ ->setType(DELETE_TYPE_DOCUMENT)
+ ->setDocument($deployment);
$response->noContent();
});
@@ -805,7 +832,7 @@ App::post('/v1/functions/:functionId/executions')
->groups(['api', 'functions'])
->desc('Create Execution')
->label('scope', 'execution.write')
- ->label('event', 'functions.executions.create')
+ ->label('event', 'functions.[functionId].executions.[executionId].create')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'createExecution')
@@ -822,13 +849,15 @@ App::post('/v1/functions/:functionId/executions')
->inject('project')
->inject('dbForProject')
->inject('user')
- ->action(function ($functionId, $data, $async, $response, $project, $dbForProject, $user) {
+ ->inject('events')
+ ->action(function ($functionId, $data, $async, $response, $project, $dbForProject, $user, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Database\Document $user */
+ /** @var Appwrite\Event\Event $events */
- $function = Authorization::skip(fn() => $dbForProject->getDocument('functions', $functionId));
+ $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
if ($function->isEmpty()) {
throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND);
@@ -842,7 +871,7 @@ App::post('/v1/functions/:functionId/executions')
throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported', 400, Exception::FUNCTION_RUNTIME_UNSUPPORTED);
}
- $deployment = Authorization::skip(fn() => $dbForProject->getDocument('deployments', $function->getAttribute('deployment', '')));
+ $deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deployment', '')));
if ($deployment->getAttribute('resourceId') !== $function->getId()) {
throw new Exception('Deployment not found. Deploy deployment before trying to execute a function', 404, Exception::DEPLOYMENT_NOT_FOUND);
@@ -853,7 +882,7 @@ App::post('/v1/functions/:functionId/executions')
}
/** Check if build has completed */
- $build = Authorization::skip(fn() => $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')));
+ $build = Authorization::skip(fn () => $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')));
if ($build->isEmpty()) {
throw new Exception('Build not found', 404, Exception::BUILD_NOT_FOUND);
}
@@ -870,7 +899,7 @@ App::post('/v1/functions/:functionId/executions')
$executionId = $dbForProject->getId();
- $execution = Authorization::skip(fn() => $dbForProject->createDocument('executions', new Document([
+ $execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', new Document([
'$id' => $executionId,
'$read' => (!$user->isEmpty()) ? ['user:' . $user->getId()] : [],
'$write' => [],
@@ -892,13 +921,14 @@ App::post('/v1/functions/:functionId/executions')
$sessions = $user->getAttribute('sessions', []);
$current = new Document();
- foreach ($sessions as $session) { /** @var Utopia\Database\Document $session */
+ foreach ($sessions as $session) {
+ /** @var Utopia\Database\Document $session */
if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too
$current = $session;
}
}
- if(!$current->isEmpty()) {
+ if (!$current->isEmpty()) {
$jwtObj = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
$jwt = $jwtObj->encode([
'userId' => $user->getId(),
@@ -907,19 +937,26 @@ App::post('/v1/functions/:functionId/executions')
}
}
+ $events
+ ->setParam('functionId', $function->getId())
+ ->setParam('executionId', $execution->getId())
+ ->setContext($function);
+
if ($async) {
- Resque::enqueue(Event::FUNCTIONS_QUEUE_NAME, Event::FUNCTIONS_CLASS_NAME, [
- 'projectId' => $project->getId(),
- 'functionId' => $function->getId(),
- 'webhooks' => $project->getAttribute('webhooks', []),
- 'executionId' => $execution->getId(),
- 'trigger' => 'http',
- 'data' => $data,
- 'userId' => $user->getId(),
- 'jwt' => $jwt,
- ]);
+ $event = new Func();
+ $event
+ ->setType('http')
+ ->setExecution($execution)
+ ->setFunction($function)
+ ->setData($data)
+ ->setJWT($jwt)
+ ->setProject($project)
+ ->setUser($user);
+
+ $event->trigger();
$response->setStatusCode(Response::STATUS_CODE_CREATED);
+
return $response->dynamic($execution, Response::MODEL_EXECUTION);
}
@@ -966,7 +1003,7 @@ App::post('/v1/functions/:functionId/executions')
Console::error($th->getMessage());
}
- Authorization::skip(fn() => $dbForProject->updateDocument('executions', $executionId, $execution));
+ Authorization::skip(fn () => $dbForProject->updateDocument('executions', $executionId, $execution));
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -996,7 +1033,7 @@ App::get('/v1/functions/:functionId/executions')
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
- $function = Authorization::skip(fn() => $dbForProject->getDocument('functions', $functionId));
+ $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
if ($function->isEmpty()) {
throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND);
@@ -1046,7 +1083,7 @@ App::get('/v1/functions/:functionId/executions/:executionId')
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
- $function = Authorization::skip(fn() => $dbForProject->getDocument('functions', $functionId));
+ $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
if ($function->isEmpty()) {
throw new Exception('Function not found', 404, Exception::FUNCTION_NOT_FOUND);
@@ -1069,7 +1106,7 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
->groups(['api', 'functions'])
->desc('Retry Build')
->label('scope', 'functions.write')
- ->label('event', 'functions.deployments.update')
+ ->label('event', 'functions.[functionId].deployments.[deploymentId].update')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'retryBuild')
@@ -1082,10 +1119,12 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
->inject('response')
->inject('dbForProject')
->inject('project')
- ->action(function ($functionId, $deploymentId, $buildId, $response, $dbForProject, $project) {
+ ->inject('events')
+ ->action(function ($functionId, $deploymentId, $buildId, $response, $dbForProject, $project, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Database\Document $project */
+ /** @var Appwrite\Event\Event $events */
$function = $dbForProject->getDocument('functions', $functionId);
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
@@ -1098,7 +1137,7 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
throw new Exception('Deployment not found', 404, Exception::DEPLOYMENT_NOT_FOUND);
}
- $build = Authorization::skip(fn() => $dbForProject->getDocument('builds', $buildId));
+ $build = Authorization::skip(fn () => $dbForProject->getDocument('builds', $buildId));
if ($build->isEmpty()) {
throw new Exception('Build not found', 404, Exception::BUILD_NOT_FOUND);
@@ -1108,13 +1147,18 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
throw new Exception('Build not failed', 400, Exception::BUILD_IN_PROGRESS);
}
- // Enqueue a message to start the build
- Resque::enqueue(Event::BUILDS_QUEUE_NAME, Event::BUILDS_CLASS_NAME, [
- 'projectId' => $project->getId(),
- 'resourceId' => $function->getId(),
- 'deploymentId' => $deploymentId,
- 'type' => BUILD_TYPE_RETRY
- ]);
+ $events
+ ->setParam('functionId', $function->getId())
+ ->setParam('deploymentId', $deployment->getId());
+
+ // Retry the build
+ $buildEvent = new Build();
+ $buildEvent
+ ->setType(BUILD_TYPE_RETRY)
+ ->setResource($function)
+ ->setDeployment($deployment)
+ ->setProject($project)
+ ->trigger();
$response->noContent();
- });
\ No newline at end of file
+ });
diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php
index a9267da13..80bc0c5f7 100644
--- a/app/controllers/api/projects.php
+++ b/app/controllers/api/projects.php
@@ -2,7 +2,9 @@
use Appwrite\Auth\Auth;
use Appwrite\Auth\Validator\Password;
-use Appwrite\Event\Event;
+use Appwrite\Event\Certificate;
+use Appwrite\Event\Delete;
+use Appwrite\Event\Validator\Event;
use Appwrite\Network\Validator\CNAME;
use Appwrite\Network\Validator\Domain as DomainValidator;
use Appwrite\Network\Validator\Origin;
@@ -523,7 +525,7 @@ App::delete('/v1/projects/:projectId')
->inject('user')
->inject('dbForConsole')
->inject('deletes')
- ->action(function (string $projectId, string $password, Response $response, Document $user, Database $dbForConsole, Event $deletes) {
+ ->action(function (string $projectId, string $password, Response $response, Document $user, Database $dbForConsole, Delete $deletes) {
if (!Auth::passwordVerify($password, $user->getAttribute('password'))) { // Double check user password
throw new Exception('Invalid credentials', 401, Exception::USER_INVALID_CREDENTIALS);
@@ -536,8 +538,8 @@ App::delete('/v1/projects/:projectId')
}
$deletes
- ->setParam('type', DELETE_TYPE_DOCUMENT)
- ->setParam('document', $project)
+ ->setType(DELETE_TYPE_DOCUMENT)
+ ->setDocument($project)
;
if (!$dbForConsole->deleteDocument('teams', $project->getAttribute('teamId', null))) {
@@ -565,7 +567,7 @@ App::post('/v1/projects/:projectId/webhooks')
->label('sdk.response.model', Response::MODEL_WEBHOOK)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
- ->param('events', null, new ArrayList(new WhiteList(array_keys(Config::getParam('events'), true), true)), 'Events list.')
+ ->param('events', null, new ArrayList(new Event()), 'Events list.')
->param('url', null, new URL(['http', 'https']), 'Webhook URL.')
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true)
@@ -681,7 +683,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
->param('projectId', null, new UID(), 'Project unique ID.')
->param('webhookId', null, new UID(), 'Webhook unique ID.')
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
- ->param('events', null, new ArrayList(new WhiteList(array_keys(Config::getParam('events'), true), true)), 'Events list.')
+ ->param('events', null, new ArrayList(new Event()), 'Events list.')
->param('url', null, new URL(['http', 'https']), 'Webhook URL.')
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true)
@@ -1347,9 +1349,10 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
$dbForConsole->deleteCachedDocument('projects', $project->getId());
// Issue a TLS certificate when domain is verified
- Resque::enqueue(Event::CERTIFICATES_QUEUE_NAME, Event::CERTIFICATES_CLASS_NAME, [
- 'domain' => $domain->getAttribute('domain'),
- ]);
+ $event = new Certificate();
+ $event
+ ->setDomain($domain)
+ ->trigger();
$response->dynamic($domain, Response::MODEL_DOMAIN);
});
@@ -1368,7 +1371,7 @@ App::delete('/v1/projects/:projectId/domains/:domainId')
->inject('response')
->inject('dbForConsole')
->inject('deletes')
- ->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole, $deletes) {
+ ->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole, Delete $deletes) {
$project = $dbForConsole->getDocument('projects', $projectId);
@@ -1390,9 +1393,8 @@ App::delete('/v1/projects/:projectId/domains/:domainId')
$dbForConsole->deleteCachedDocument('projects', $project->getId());
$deletes
- ->setParam('type', DELETE_TYPE_CERTIFICATES)
- ->setParam('document', $domain)
- ;
+ ->setType(DELETE_TYPE_CERTIFICATES)
+ ->setDocument($domain);
$response->noContent();
});
diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php
index 91727bb30..c11c4b7fc 100644
--- a/app/controllers/api/storage.php
+++ b/app/controllers/api/storage.php
@@ -2,6 +2,8 @@
use Appwrite\Auth\Auth;
use Appwrite\ClamAV\Network;
+use Appwrite\Event\Audit;
+use Appwrite\Event\Delete;
use Appwrite\Event\Event;
use Appwrite\Utopia\Database\Validator\CustomId;
use Appwrite\OpenSSL\OpenSSL;
@@ -43,7 +45,7 @@ App::post('/v1/storage/buckets')
->desc('Create bucket')
->groups(['api', 'storage'])
->label('scope', 'buckets.write')
- ->label('event', 'storage.buckets.create')
+ ->label('event', 'buckets.[bucketId].create')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'createBucket')
@@ -65,7 +67,8 @@ App::post('/v1/storage/buckets')
->inject('dbForProject')
->inject('audits')
->inject('usage')
- ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $audits, Stats $usage) {
+ ->inject('events')
+ ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $audits, Stats $usage, Event $events) {
$bucketId = $bucketId === 'unique()' ? $dbForProject->getId() : $bucketId;
try {
@@ -126,9 +129,12 @@ App::post('/v1/storage/buckets')
}
$audits
- ->setParam('event', 'storage.buckets.create')
- ->setParam('resource', 'storage/buckets/' . $bucket->getId())
- ->setParam('data', $bucket->getArrayCopy())
+ ->setResource('storage/buckets/' . $bucket->getId())
+ ->setPayload($bucket->getArrayCopy())
+ ;
+
+ $events
+ ->setParam('bucketId', $bucket->getId())
;
$usage->setParam('storage.buckets.create', 1);
@@ -209,7 +215,7 @@ App::put('/v1/storage/buckets/:bucketId')
->desc('Update Bucket')
->groups(['api', 'storage'])
->label('scope', 'buckets.write')
- ->label('event', 'storage.buckets.update')
+ ->label('event', 'buckets.[bucketId].update')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'updateBucket')
@@ -231,21 +237,21 @@ App::put('/v1/storage/buckets/:bucketId')
->inject('dbForProject')
->inject('audits')
->inject('usage')
- ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $audits, Stats $usage) {
-
+ ->inject('events')
+ ->action(function (string $bucketId, string $name, string $permission, ?array $read, ?array $write, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Audit $audits, Stats $usage, Event $events) {
$bucket = $dbForProject->getDocument('buckets', $bucketId);
if ($bucket->isEmpty()) {
throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND);
}
- $read??=$bucket->getAttribute('$read', []); // By default inherit read permissions
- $write??=$bucket->getAttribute('$write', []); // By default inherit write permissions
- $maximumFileSize??=$bucket->getAttribute('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0));
- $allowedFileExtensions??=$bucket->getAttribute('allowedFileExtensions', []);
- $enabled??=$bucket->getAttribute('enabled', true);
- $encryption??=$bucket->getAttribute('encryption', true);
- $antivirus??=$bucket->getAttribute('antivirus', true);
+ $read ??= $bucket->getAttribute('$read', []); // By default inherit read permissions
+ $write ??= $bucket->getAttribute('$write', []); // By default inherit write permissions
+ $maximumFileSize ??= $bucket->getAttribute('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0));
+ $allowedFileExtensions ??= $bucket->getAttribute('allowedFileExtensions', []);
+ $enabled ??= $bucket->getAttribute('enabled', true);
+ $encryption ??= $bucket->getAttribute('encryption', true);
+ $antivirus ??= $bucket->getAttribute('antivirus', true);
$bucket = $dbForProject->updateDocument('buckets', $bucket->getId(), $bucket
->setAttribute('name', $name)
@@ -260,9 +266,12 @@ App::put('/v1/storage/buckets/:bucketId')
);
$audits
- ->setParam('event', 'storage.buckets.update')
- ->setParam('resource', 'storage/buckets/' . $bucket->getId())
- ->setParam('data', $bucket->getArrayCopy())
+ ->setResource('storage/buckets/' . $bucket->getId())
+ ->setPayload($bucket->getArrayCopy())
+ ;
+
+ $events
+ ->setParam('bucketId', $bucket->getId())
;
$usage->setParam('storage.buckets.update', 1);
@@ -274,7 +283,7 @@ App::delete('/v1/storage/buckets/:bucketId')
->desc('Delete Bucket')
->groups(['api', 'storage'])
->label('scope', 'buckets.write')
- ->label('event', 'storage.buckets.delete')
+ ->label('event', 'buckets.[bucketId].delete')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'deleteBucket')
@@ -288,8 +297,7 @@ App::delete('/v1/storage/buckets/:bucketId')
->inject('deletes')
->inject('events')
->inject('usage')
- ->action(function (string $bucketId, Response $response, Database $dbForProject, Event $audits, Event $deletes, Event $events, Stats $usage) {
-
+ ->action(function (string $bucketId, Response $response, Database $dbForProject, Audit $audits, Delete $deletes, Event $events, Stats $usage) {
$bucket = $dbForProject->getDocument('buckets', $bucketId);
if ($bucket->isEmpty()) {
@@ -301,18 +309,17 @@ App::delete('/v1/storage/buckets/:bucketId')
}
$deletes
- ->setParam('type', DELETE_TYPE_DOCUMENT)
- ->setParam('document', $bucket)
- ;
+ ->setType(DELETE_TYPE_DOCUMENT)
+ ->setDocument($bucket);
$events
- ->setParam('eventData', $response->output($bucket, Response::MODEL_BUCKET))
+ ->setParam('bucketId', $bucket->getId())
+ ->setPayload($response->output($bucket, Response::MODEL_BUCKET))
;
$audits
- ->setParam('event', 'storage.buckets.delete')
- ->setParam('resource', 'storage/buckets/' . $bucket->getId())
- ->setParam('data', $bucket->getArrayCopy())
+ ->setResource('storage/buckets/' . $bucket->getId())
+ ->setPayload($bucket->getArrayCopy())
;
$usage->setParam('storage.buckets.delete', 1);
@@ -325,7 +332,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
->desc('Create File')
->groups(['api', 'storage'])
->label('scope', 'files.write')
- ->label('event', 'storage.files.create')
+ ->label('event', 'buckets.[bucketId].files.[fileId].create')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'createFile')
@@ -350,8 +357,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
->inject('mode')
->inject('deviceFiles')
->inject('deviceLocal')
- ->action(function (string $bucketId, string $fileId, array $file, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, Document $user, Event $audits, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) {
-
+ ->action(function (string $bucketId, string $fileId, array $file, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, Document $user, Audit $audits, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) {
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
if ($bucket->isEmpty()
@@ -557,9 +563,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
'metadata' => $metadata,
]);
if ($permissionBucket) {
- $file = Authorization::skip(function () use ($dbForProject, $bucket, $doc) {
- return $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc);
- });
+ $file = Authorization::skip(fn () => $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc));
} else {
$file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc);
}
@@ -579,9 +583,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
->setAttribute('chunksUploaded', $chunksUploaded);
if ($permissionBucket) {
- $file = Authorization::skip(function () use ($dbForProject, $bucket, $fileId, $file) {
- return $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
- });
+ $file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file));
} else {
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
}
@@ -594,8 +596,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
}
$audits
- ->setParam('event', 'storage.files.create')
- ->setParam('resource', 'storage/files/' . $file->getId())
+ ->setResource('storage/files/' . $file->getId())
;
$usage
@@ -627,9 +628,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
'metadata' => $metadata,
]);
if ($permissionBucket) {
- $file = Authorization::skip(function () use ($dbForProject, $bucket, $doc) {
- return $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc);
- });
+ $file = Authorization::skip(fn () => $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc));
} else {
$file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc);
}
@@ -639,9 +638,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
->setAttribute('metadata', $metadata);
if ($permissionBucket) {
- $file = Authorization::skip(function () use ($dbForProject, $bucket, $fileId, $file) {
- return $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
- });
+ $file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file));
} else {
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
}
@@ -653,13 +650,16 @@ App::post('/v1/storage/buckets/:bucketId/files')
}
}
- $events->setParam('bucket', $bucket->getArrayCopy());
+ $events
+ ->setParam('bucketId', $bucket->getId())
+ ->setParam('fileId', $file->getId())
+ ->setContext($bucket)
+ ;
$metadata = null; // was causing leaks as it was passed by reference
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($file, Response::MODEL_FILE);
- ;
});
App::get('/v1/storage/buckets/:bucketId/files')
@@ -1271,7 +1271,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
->desc('Update File')
->groups(['api', 'storage'])
->label('scope', 'files.write')
- ->label('event', 'storage.files.update')
+ ->label('event', 'buckets.[bucketId].files.[fileId].update')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'updateFile')
@@ -1290,8 +1290,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
->inject('usage')
->inject('mode')
->inject('events')
- ->action(function (string $bucketId, string $fileId, ?array $read, ?array $write,Response $response, Database $dbForProject, Document $user, Event $audits, Stats $usage, string $mode, Event $events) {
-
+ ->action(function (string $bucketId, string $fileId, ?array $read, ?array $write, Response $response, Database $dbForProject, Document $user, Audit $audits, Stats $usage, string $mode, Event $events) {
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$read = (is_null($read) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $read ?? []; // By default set read permissions for user
$write = (is_null($write) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $write ?? [];
@@ -1346,13 +1345,14 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
}
- $events->setParam('bucket', $bucket->getArrayCopy());
-
- $audits
- ->setParam('event', 'storage.files.update')
- ->setParam('resource', 'file/' . $file->getId())
+ $events
+ ->setParam('bucketId', $bucket->getId())
+ ->setParam('fileId', $file->getId())
+ ->setContext($bucket)
;
+ $audits->setResource('file/' . $file->getId());
+
$usage
->setParam('storage.files.update', 1)
->setParam('bucketId', $bucketId)
@@ -1366,7 +1366,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
->desc('Delete File')
->groups(['api', 'storage'])
->label('scope', 'files.write')
- ->label('event', 'storage.files.delete')
+ ->label('event', 'buckets.[bucketId].files.[fileId].delete')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'deleteFile')
@@ -1383,8 +1383,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
->inject('mode')
->inject('deviceFiles')
->inject('project')
- ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Event $audits, Stats $usage, string $mode, Device $deviceFiles, Document $project) {
-
+ ->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, Audit $audits, Stats $usage, string $mode, Device $deviceFiles, Document $project) {
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
if ($bucket->isEmpty()
@@ -1438,10 +1437,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
throw new Exception('Failed to delete file from device', 500, Exception::GENERAL_SERVER_ERROR);
}
- $audits
- ->setParam('event', 'storage.files.delete')
- ->setParam('resource', 'file/' . $file->getId())
- ;
+ $audits->setResource('file/' . $file->getId());
$usage
->setParam('storage', $file->getAttribute('size', 0) * -1)
@@ -1450,8 +1446,10 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
;
$events
- ->setParam('eventData', $response->output($file, Response::MODEL_FILE))
- ->setParam('bucket', $bucket->getArrayCopy())
+ ->setParam('bucketId', $bucket->getId())
+ ->setParam('fileId', $file->getId())
+ ->setContext($bucket)
+ ->setPayload($response->output($file, Response::MODEL_FILE))
;
$response->noContent();
diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php
index a6bb58ba3..c504fe40e 100644
--- a/app/controllers/api/teams.php
+++ b/app/controllers/api/teams.php
@@ -2,7 +2,10 @@
use Appwrite\Auth\Auth;
use Appwrite\Detector\Detector;
+use Appwrite\Event\Audit as EventAudit;
+use Appwrite\Event\Delete;
use Appwrite\Event\Event;
+use Appwrite\Event\Mail;
use Appwrite\Extend\Exception;
use Appwrite\Network\Validator\Email;
use Appwrite\Network\Validator\Host;
@@ -31,7 +34,7 @@ use Utopia\Validator\WhiteList;
App::post('/v1/teams')
->desc('Create Team')
->groups(['api', 'teams'])
- ->label('event', 'teams.create')
+ ->label('event', 'teams.[teamId].create')
->label('scope', 'teams.write')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
@@ -84,6 +87,8 @@ App::post('/v1/teams')
$dbForProject->deleteCachedDocument('users', $user->getId());
}
+ $events->setParam('teamId', $team->getId());
+
if (!empty($user->getId())) {
$events->setParam('userId', $user->getId());
}
@@ -170,7 +175,7 @@ App::get('/v1/teams/:teamId')
App::put('/v1/teams/:teamId')
->desc('Update Team')
->groups(['api', 'teams'])
- ->label('event', 'teams.update')
+ ->label('event', 'teams.[teamId].update')
->label('scope', 'teams.write')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
@@ -183,8 +188,9 @@ App::put('/v1/teams/:teamId')
->param('name', null, new Text(128), 'New team name. Max length: 128 chars.')
->inject('response')
->inject('dbForProject')
+ ->inject('events')
->inject('audits')
- ->action(function (string $teamId, string $name, Response $response, Database $dbForProject, Event $audits) {
+ ->action(function (string $teamId, string $name, Response $response, Database $dbForProject, Event $events, EventAudit $audits) {
$team = $dbForProject->getDocument('teams', $teamId);
@@ -197,11 +203,8 @@ App::put('/v1/teams/:teamId')
->setAttribute('search', implode(' ', [$teamId, $name]))
);
- $audits
- ->setParam('event', 'teams.update')
- ->setParam('resource', 'team/'.$teamId)
- ->setParam('data', $team->getArrayCopy())
- ;
+ $events->setParam('teamId', $team->getId());
+ $audits->setResource('team/' . $team->getId());
$response->dynamic($team, Response::MODEL_TEAM);
});
@@ -209,7 +212,7 @@ App::put('/v1/teams/:teamId')
App::delete('/v1/teams/:teamId')
->desc('Delete Team')
->groups(['api', 'teams'])
- ->label('event', 'teams.delete')
+ ->label('event', 'teams.[teamId].delete')
->label('scope', 'teams.write')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
@@ -223,7 +226,7 @@ App::delete('/v1/teams/:teamId')
->inject('events')
->inject('deletes')
->inject('audits')
- ->action(function (string $teamId, Response $response, Database $dbForProject, Event $events, Event $deletes, Event $audits) {
+ ->action(function (string $teamId, Response $response, Database $dbForProject, Event $events, Delete $deletes, EventAudit $audits) {
$team = $dbForProject->getDocument('teams', $teamId);
@@ -247,12 +250,12 @@ App::delete('/v1/teams/:teamId')
}
$deletes
- ->setParam('type', DELETE_TYPE_DOCUMENT)
- ->setParam('document', $team)
- ;
+ ->setType(DELETE_TYPE_DOCUMENT)
+ ->setDocument($team);
$events
- ->setParam('eventData', $response->output($team, Response::MODEL_TEAM))
+ ->setParam('teamId', $team->getId())
+ ->setPayload($response->output($team, Response::MODEL_TEAM))
;
$audits
@@ -267,7 +270,7 @@ App::delete('/v1/teams/:teamId')
App::post('/v1/teams/:teamId/memberships')
->desc('Create Team Membership')
->groups(['api', 'teams', 'auth'])
- ->label('event', 'teams.memberships.create')
+ ->label('event', 'teams.[teamId].memberships.[membershipId].create')
->label('scope', 'teams.write')
->label('auth.type', 'invites')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
@@ -290,7 +293,8 @@ App::post('/v1/teams/:teamId/memberships')
->inject('locale')
->inject('audits')
->inject('mails')
- ->action(function (string $teamId, string $email, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Event $audits, Event $mails) {
+ ->inject('events')
+ ->action(function (string $teamId, string $email, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, EventAudit $audits, Mail $mails, Event $events) {
if(empty(App::getEnv('_APP_SMTP_HOST'))) {
throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED);
@@ -399,24 +403,24 @@ App::post('/v1/teams/:teamId/memberships')
if (!$isPrivilegedUser && !$isAppUser) { // No need of confirmation when in admin or app mode
$mails
- ->setParam('event', 'teams.memberships.create')
- ->setParam('from', $project->getId())
- ->setParam('recipient', $email)
- ->setParam('name', $name)
- ->setParam('url', $url)
- ->setParam('locale', $locale->default)
- ->setParam('project', $project->getAttribute('name', ['[APP-NAME]']))
- ->setParam('owner', $user->getAttribute('name', ''))
- ->setParam('team', $team->getAttribute('name', '[TEAM-NAME]'))
- ->setParam('type', MAIL_TYPE_INVITATION)
+ ->setType(MAIL_TYPE_INVITATION)
+ ->setRecipient($email)
+ ->setUrl($url)
+ ->setName($name)
+ ->setLocale($locale->default)
+ ->setTeam($team)
+ ->setUser($user)
->trigger()
;
}
$audits
- ->setParam('userId', $invitee->getId())
- ->setParam('event', 'teams.memberships.create')
- ->setParam('resource', 'team/'.$teamId)
+ ->setResource('team/'.$teamId)
+ ;
+
+ $events
+ ->setParam('teamId', $team->getId())
+ ->setParam('membershipId', $membership->getId())
;
$response->setStatusCode(Response::STATUS_CODE_CREATED);
@@ -545,7 +549,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId')
App::patch('/v1/teams/:teamId/memberships/:membershipId')
->desc('Update Membership Roles')
->groups(['api', 'teams'])
- ->label('event', 'teams.memberships.update')
+ ->label('event', 'teams.[teamId].memberships.[membershipId].update')
->label('scope', 'teams.write')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
@@ -562,7 +566,8 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
->inject('user')
->inject('dbForProject')
->inject('audits')
- ->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Database $dbForProject, Event $audits) {
+ ->inject('events')
+ ->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Database $dbForProject, EventAudit $audits, Event $events) {
$team = $dbForProject->getDocument('teams', $teamId);
if ($team->isEmpty()) {
@@ -596,13 +601,13 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
/**
* Replace membership on profile
*/
-
$dbForProject->deleteCachedDocument('users', $profile->getId());
- $audits
- ->setParam('userId', $user->getId())
- ->setParam('event', 'teams.memberships.update')
- ->setParam('resource', 'team/' . $teamId);
+ $audits->setResource('team/' . $teamId);
+
+ $events
+ ->setParam('teamId', $team->getId())
+ ->setParam('membershipId', $membership->getId());
$response->dynamic(
$membership
@@ -615,7 +620,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
->desc('Update Team Membership Status')
->groups(['api', 'teams'])
- ->label('event', 'teams.memberships.update.status')
+ ->label('event', 'teams.[teamId].memberships.[membershipId].update.status')
->label('scope', 'public')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
@@ -634,8 +639,8 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
->inject('dbForProject')
->inject('geodb')
->inject('audits')
- ->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Reader $geodb, Event $audits) {
-
+ ->inject('events')
+ ->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Reader $geodb, EventAudit $audits, Event $events) {
$protocol = $request->getProtocol();
$membership = $dbForProject->getDocument('memberships', $membershipId);
@@ -658,7 +663,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
throw new Exception('Secret key not valid', 401, Exception::TEAM_INVALID_SECRET);
}
- if ($userId != $membership->getAttribute('userId')) {
+ if ($userId !== $membership->getAttribute('userId')) {
throw new Exception('Invite does not belong to current user ('.$user->getAttribute('email').')', 401, Exception::TEAM_INVITE_MISMATCH);
}
@@ -718,10 +723,11 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
$team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1)));
- $audits
- ->setParam('userId', $user->getId())
- ->setParam('event', 'teams.memberships.update.status')
- ->setParam('resource', 'team/'.$teamId)
+ $audits->setResource('team/'.$teamId);
+
+ $events
+ ->setParam('teamId', $team->getId())
+ ->setParam('membershipId', $membership->getId())
;
if (!Config::getParam('domainVerification')) {
@@ -744,7 +750,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
App::delete('/v1/teams/:teamId/memberships/:membershipId')
->desc('Delete Team Membership')
->groups(['api', 'teams'])
- ->label('event', 'teams.memberships.delete')
+ ->label('event', 'teams.[teamId].memberships.[membershipId].delete')
->label('scope', 'teams.write')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
@@ -758,7 +764,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
->inject('dbForProject')
->inject('audits')
->inject('events')
- ->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject, Event $audits, Event $events) {
+ ->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject, EventAudit $audits, Event $events) {
$membership = $dbForProject->getDocument('memberships', $membershipId);
@@ -797,14 +803,12 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team));
}
- $audits
- ->setParam('userId', $membership->getAttribute('userId'))
- ->setParam('event', 'teams.memberships.delete')
- ->setParam('resource', 'team/'.$teamId)
- ;
+ $audits->setResource('team/'.$teamId);
$events
- ->setParam('eventData', $response->output($membership, Response::MODEL_MEMBERSHIP))
+ ->setParam('teamId', $team->getId())
+ ->setParam('membershipId', $membership->getId())
+ ->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP))
;
$response->noContent();
diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php
index 2f33098bc..6e96f7264 100644
--- a/app/controllers/api/users.php
+++ b/app/controllers/api/users.php
@@ -25,7 +25,7 @@ use Utopia\Validator\Boolean;
App::post('/v1/users')
->desc('Create User')
->groups(['api', 'users'])
- ->label('event', 'users.create')
+ ->label('event', 'users.[userId].create')
->label('scope', 'users.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
@@ -41,10 +41,12 @@ App::post('/v1/users')
->inject('response')
->inject('dbForProject')
->inject('usage')
- ->action(function ($userId, $email, $password, $name, $response, $dbForProject, $usage) {
+ ->inject('events')
+ ->action(function ($userId, $email, $password, $name, $response, $dbForProject, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
$email = \strtolower($email);
@@ -77,6 +79,10 @@ App::post('/v1/users')
->setParam('users.create', 1)
;
+ $events
+ ->setParam('userId', $user->getId())
+ ;
+
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($user, Response::MODEL_USER);
});
@@ -281,26 +287,8 @@ App::get('/v1/users/:userId/logs')
}
$audit = new Audit($dbForProject);
- $auditEvents = [
- 'account.create',
- 'account.delete',
- 'account.update.name',
- 'account.update.email',
- 'account.update.password',
- 'account.update.prefs',
- 'account.sessions.create',
- 'account.sessions.update',
- 'account.sessions.delete',
- 'account.recovery.create',
- 'account.recovery.update',
- 'account.verification.create',
- 'account.verification.update',
- 'teams.membership.create',
- 'teams.membership.update',
- 'teams.membership.delete',
- ];
- $logs = $audit->getLogsByUserAndEvents($user->getId(), $auditEvents, $limit, $offset);
+ $logs = $audit->getLogsByUser($user->getId(), $limit, $offset);
$output = [];
@@ -348,7 +336,7 @@ App::get('/v1/users/:userId/logs')
;
$response->dynamic(new Document([
- 'total' => $audit->countLogsByUserAndEvents($user->getId(), $auditEvents),
+ 'total' => $audit->countLogsByUser($user->getId()),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@@ -356,7 +344,7 @@ App::get('/v1/users/:userId/logs')
App::patch('/v1/users/:userId/status')
->desc('Update User Status')
->groups(['api', 'users'])
- ->label('event', 'users.update.status')
+ ->label('event', 'users.[userId].update.status')
->label('scope', 'users.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
@@ -370,10 +358,12 @@ App::patch('/v1/users/:userId/status')
->inject('response')
->inject('dbForProject')
->inject('usage')
- ->action(function ($userId, $status, $response, $dbForProject, $usage) {
+ ->inject('events')
+ ->action(function ($userId, $status, $response, $dbForProject, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
$user = $dbForProject->getDocument('users', $userId);
@@ -386,13 +376,18 @@ App::patch('/v1/users/:userId/status')
$usage
->setParam('users.update', 1)
;
+
+ $events
+ ->setParam('userId', $user->getId())
+ ;
+
$response->dynamic($user, Response::MODEL_USER);
});
App::patch('/v1/users/:userId/verification')
->desc('Update Email Verification')
->groups(['api', 'users'])
- ->label('event', 'users.update.verification')
+ ->label('event', 'users.[userId].update.verification')
->label('scope', 'users.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
@@ -406,10 +401,12 @@ App::patch('/v1/users/:userId/verification')
->inject('response')
->inject('dbForProject')
->inject('usage')
- ->action(function ($userId, $emailVerification, $response, $dbForProject, $usage) {
+ ->inject('events')
+ ->action(function ($userId, $emailVerification, $response, $dbForProject, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
$user = $dbForProject->getDocument('users', $userId);
@@ -422,13 +419,18 @@ App::patch('/v1/users/:userId/verification')
$usage
->setParam('users.update', 1)
;
+
+ $events
+ ->setParam('userId', $user->getId())
+ ;
+
$response->dynamic($user, Response::MODEL_USER);
});
App::patch('/v1/users/:userId/name')
->desc('Update Name')
->groups(['api', 'users'])
- ->label('event', 'users.update.name')
+ ->label('event', 'users.[userId].update.name')
->label('scope', 'users.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
@@ -442,10 +444,12 @@ App::patch('/v1/users/:userId/name')
->inject('response')
->inject('dbForProject')
->inject('audits')
- ->action(function ($userId, $name, $response, $dbForProject, $audits) {
+ ->inject('events')
+ ->action(function ($userId, $name, $response, $dbForProject, $audits, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
+ /** @var Appwrite\Event\Event $events */
$user = $dbForProject->getDocument('users', $userId);
@@ -461,9 +465,11 @@ App::patch('/v1/users/:userId/name')
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
$audits
+ ->setResource('user/'.$user->getId())
+ ;
+
+ $events
->setParam('userId', $user->getId())
- ->setParam('event', 'users.update.name')
- ->setParam('resource', 'user/'.$user->getId())
;
$response->dynamic($user, Response::MODEL_USER);
@@ -472,7 +478,7 @@ App::patch('/v1/users/:userId/name')
App::patch('/v1/users/:userId/password')
->desc('Update Password')
->groups(['api', 'users'])
- ->label('event', 'users.update.password')
+ ->label('event', 'users.[userId].update.password')
->label('scope', 'users.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
@@ -486,10 +492,12 @@ App::patch('/v1/users/:userId/password')
->inject('response')
->inject('dbForProject')
->inject('audits')
- ->action(function ($userId, $password, $response, $dbForProject, $audits) {
+ ->inject('events')
+ ->action(function ($userId, $password, $response, $dbForProject, $audits, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
+ /** @var Appwrite\Event\Event $events */
$user = $dbForProject->getDocument('users', $userId);
@@ -504,9 +512,11 @@ App::patch('/v1/users/:userId/password')
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
$audits
+ ->setResource('user/'.$user->getId())
+ ;
+
+ $events
->setParam('userId', $user->getId())
- ->setParam('event', 'users.update.password')
- ->setParam('resource', 'user/'.$user->getId())
;
$response->dynamic($user, Response::MODEL_USER);
@@ -515,7 +525,7 @@ App::patch('/v1/users/:userId/password')
App::patch('/v1/users/:userId/email')
->desc('Update Email')
->groups(['api', 'users'])
- ->label('event', 'users.update.email')
+ ->label('event', 'users.[userId].update.email')
->label('scope', 'users.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
@@ -529,10 +539,12 @@ App::patch('/v1/users/:userId/email')
->inject('response')
->inject('dbForProject')
->inject('audits')
- ->action(function ($userId, $email, $response, $dbForProject, $audits) {
+ ->inject('events')
+ ->action(function ($userId, $email, $response, $dbForProject, $audits, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
+ /** @var Appwrite\Event\Event $events */
$user = $dbForProject->getDocument('users', $userId);
@@ -558,10 +570,13 @@ App::patch('/v1/users/:userId/email')
throw new Exception('Email already exists', 409, Exception::USER_EMAIL_ALREADY_EXISTS);
}
+
$audits
+ ->setResource('user/'.$user->getId())
+ ;
+
+ $events
->setParam('userId', $user->getId())
- ->setParam('event', 'users.update.email')
- ->setParam('resource', 'user/'.$user->getId())
;
$response->dynamic($user, Response::MODEL_USER);
@@ -570,7 +585,7 @@ App::patch('/v1/users/:userId/email')
App::patch('/v1/users/:userId/prefs')
->desc('Update User Preferences')
->groups(['api', 'users'])
- ->label('event', 'users.update.prefs')
+ ->label('event', 'users.[userId].update.prefs')
->label('scope', 'users.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
@@ -584,10 +599,12 @@ App::patch('/v1/users/:userId/prefs')
->inject('response')
->inject('dbForProject')
->inject('usage')
- ->action(function ($userId, $prefs, $response, $dbForProject, $usage) {
+ ->inject('events')
+ ->action(function ($userId, $prefs, $response, $dbForProject, $usage, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Appwrite\Stats\Stats $usage */
+ /** @var Appwrite\Event\Event $events */
$user = $dbForProject->getDocument('users', $userId);
@@ -600,13 +617,18 @@ App::patch('/v1/users/:userId/prefs')
$usage
->setParam('users.update', 1)
;
+
+ $events
+ ->setParam('userId', $user->getId())
+ ;
+
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
App::delete('/v1/users/:userId/sessions/:sessionId')
->desc('Delete User Session')
->groups(['api', 'users'])
- ->label('event', 'users.sessions.delete')
+ ->label('event', 'users.[userId].sessions.[sessionId].delete')
->label('scope', 'users.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
@@ -635,29 +657,30 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
$session = $dbForProject->getDocument('sessions', $sessionId);
if($session->isEmpty()) {
- throw new Exception('User not found', 404, Exception::USER_SESSION_NOT_FOUND);
+ throw new Exception('Session not found', 404, Exception::USER_SESSION_NOT_FOUND);
}
$dbForProject->deleteDocument('sessions', $session->getId());
-
$dbForProject->deleteCachedDocument('users', $user->getId());
- $events
- ->setParam('eventData', $response->output($user, Response::MODEL_USER))
- ;
$usage
->setParam('users.update', 1)
->setParam('users.sessions.delete', 1)
;
+ $events
+ ->setParam('userId', $user->getId())
+ ->setParam('sessionId', $sessionId)
+ ;
+
$response->noContent();
});
App::delete('/v1/users/:userId/sessions')
->desc('Delete User Sessions')
->groups(['api', 'users'])
- ->label('event', 'users.sessions.delete')
+ ->label('event', 'users.[userId].sessions.[sessionId].delete')
->label('scope', 'users.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
@@ -686,25 +709,28 @@ App::delete('/v1/users/:userId/sessions')
foreach ($sessions as $key => $session) { /** @var Document $session */
$dbForProject->deleteDocument('sessions', $session->getId());
+ //TODO: fix this
}
$dbForProject->deleteCachedDocument('users', $user->getId());
$events
- ->setParam('eventData', $response->output($user, Response::MODEL_USER))
+ ->setParam('userId', $user->getId())
+ ->setPayload($response->output($user, Response::MODEL_USER))
;
$usage
->setParam('users.update', 1)
->setParam('users.sessions.delete', 1)
;
+
$response->noContent();
});
App::delete('/v1/users/:userId')
->desc('Delete User')
->groups(['api', 'users'])
- ->label('event', 'users.delete')
+ ->label('event', 'users.[userId].delete')
->label('scope', 'users.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
@@ -722,9 +748,9 @@ App::delete('/v1/users/:userId')
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Appwrite\Event\Event $events */
- /** @var Appwrite\Event\Event $deletes */
+ /** @var Appwrite\Event\Delete $deletes */
/** @var Appwrite\Stats\Stats $usage */
-
+
$user = $dbForProject->getDocument('users', $userId);
if ($user->isEmpty() || $user->getAttribute('deleted')) {
@@ -735,7 +761,7 @@ App::delete('/v1/users/:userId')
* 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.
*/
-
+
// clone user object to send to workers
$clone = clone $user;
@@ -751,12 +777,13 @@ App::delete('/v1/users/:userId')
$dbForProject->updateDocument('users', $userId, $user);
$deletes
- ->setParam('type', DELETE_TYPE_DOCUMENT)
- ->setParam('document', $clone)
+ ->setType(DELETE_TYPE_DOCUMENT)
+ ->setDocument($clone)
;
$events
- ->setParam('eventData', $response->output($clone, Response::MODEL_USER))
+ ->setParam('userId', $user->getId())
+ ->setPayload($response->output($clone, Response::MODEL_USER))
;
$usage
diff --git a/app/controllers/general.php b/app/controllers/general.php
index b9c45443b..5c682efb4 100644
--- a/app/controllers/general.php
+++ b/app/controllers/general.php
@@ -12,7 +12,7 @@ use Appwrite\Extend\Exception;
use Utopia\Config\Config;
use Utopia\Domains\Domain;
use Appwrite\Auth\Auth;
-use Appwrite\Event\Event;
+use Appwrite\Event\Certificate;
use Appwrite\Network\Validator\Origin;
use Appwrite\Utopia\Response\Filters\V11 as ResponseV11;
use Appwrite\Utopia\Response\Filters\V12 as ResponseV12;
@@ -98,18 +98,18 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
'verification' => false,
'certificateId' => null,
]);
-
+
$domainDocument = $dbForConsole->createDocument('domains', $domainDocument);
Console::info('Issuing a TLS certificate for the main domain (' . $domain->get() . ') in a few seconds...');
-
- Resque::enqueue(Event::CERTIFICATES_QUEUE_NAME, Event::CERTIFICATES_CLASS_NAME, [
- 'domain' => $domain->get()
- ]);
+
+ (new Certificate())
+ ->setDomain($domainDocument)
+ ->trigger();
}
}
-
$domains[$domain->get()] = true;
+
Authorization::reset(); // ensure authorization is re-enabled
}
Config::setParam('domains', $domains);
diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php
index c5c6da616..e4ab00c04 100644
--- a/app/controllers/shared/api.php
+++ b/app/controllers/shared/api.php
@@ -1,19 +1,16 @@
setParam('projectId', $project->getId())
- ->setParam('webhooks', $project->getAttribute('webhooks', []))
- ->setParam('userId', $user->getId())
- ->setParam('event', $route->getLabel('event', ''))
- ->setParam('eventData', [])
- ->setParam('functionId', null)
- ->setParam('executionId', null)
- ->setParam('trigger', 'event')
+ ->setEvent($route->getLabel('event', ''))
+ ->setProject($project)
+ ->setUser($user)
+ ;
+
+ $mails
+ ->setProject($project)
+ ->setUser($user)
;
$audits
- ->setParam('projectId', $project->getId())
- ->setParam('userId', $user->getId())
- ->setParam('userEmail', $user->getAttribute('email'))
- ->setParam('userName', $user->getAttribute('name'))
- ->setParam('mode', $mode)
- ->setParam('event', '')
- ->setParam('resource', '')
- ->setParam('userAgent', $request->getUserAgent(''))
- ->setParam('ip', $request->getIP())
- ->setParam('data', [])
+ ->setMode($mode)
+ ->setUserAgent($request->getUserAgent(''))
+ ->setIP($request->getIP())
+ ->setEvent($route->getLabel('event', ''))
+ ->setProject($project)
+ ->setUser($user)
;
$usage
@@ -121,15 +115,10 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud
->setParam('networkResponseSize', 0)
->setParam('storage', 0)
;
-
- $deletes
- ->setParam('projectId', $project->getId())
- ;
- $database
- ->setParam('projectId', $project->getId())
- ;
-}, ['utopia', 'request', 'response', 'project', 'user', 'events', 'audits', 'usage', 'deletes', 'database', 'dbForProject', 'mode'], 'api');
+ $deletes->setProject($project);
+ $database->setProject($project);
+}, ['utopia', 'request', 'response', 'project', 'user', 'events', 'audits', 'mails', 'usage', 'deletes', 'database', 'dbForProject', 'mode'], 'api');
App::init(function ($utopia, $request, $project) {
/** @var Utopia\App $utopia */
@@ -184,56 +173,66 @@ App::init(function ($utopia, $request, $project) {
}, ['utopia', 'request', 'project'], 'auth');
-App::shutdown(function ($utopia, $request, $response, $project, $events, $audits, $usage, $deletes, $database, $mode) {
+App::shutdown(function ($utopia, $request, $response, $project, $events, $audits, $usage, $deletes, $database, $mode, $dbForProject) {
/** @var Utopia\App $utopia */
/** @var Appwrite\Utopia\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Document $project */
/** @var Appwrite\Event\Event $events */
- /** @var Appwrite\Event\Event $audits */
+ /** @var Appwrite\Event\Audit $audits */
/** @var Appwrite\Stats\Stats $usage */
- /** @var Appwrite\Event\Event $deletes */
- /** @var Appwrite\Event\Event $database */
+ /** @var Appwrite\Event\Delete $deletes */
+ /** @var Appwrite\Event\Database $database */
/** @var bool $mode */
+ /** @var Utopia\Database\Database $dbForProject */
- if (!empty($events->getParam('event'))) {
- if (empty($events->getParam('eventData'))) {
- $events->setParam('eventData', $response->getPayload());
+ if (!empty($events->getEvent())) {
+ if (empty($events->getPayload())) {
+ $events->setPayload($response->getPayload());
}
-
- $webhooks = clone $events;
- $functions = clone $events;
-
- $webhooks
- ->setQueue('v1-webhooks')
- ->setClass('WebhooksV1')
+ /**
+ * Trigger functions.
+ */
+ $events
+ ->setClass(Event::FUNCTIONS_CLASS_NAME)
+ ->setQueue(Event::FUNCTIONS_QUEUE_NAME)
->trigger();
- $functions
- ->setQueue('v1-functions')
- ->setClass('FunctionsV1')
+ /**
+ * Trigger webhooks.
+ */
+ $events
+ ->setClass(Event::WEBHOOK_CLASS_NAME)
+ ->setQueue(Event::WEBHOOK_QUEUE_NAME)
->trigger();
+ /**
+ * Trigger realtime.
+ */
if ($project->getId() !== 'console') {
- $payload = new Document($response->getPayload());
- $collection = new Document($events->getParam('collection') ?? []);
- $bucket = new Document($events->getParam('bucket') ?? []);
+ $allEvents = Event::generateEvents($events->getEvent(), $events->getParams());
+ $payload = new Document($events->getPayload());
+ $context = $events->getContext() ?? false;
+
+ $collection = ($context && $context->getCollection() === 'collections') ? $context : null;
+ $bucket = ($context && $context->getCollection() === 'buckets') ? $context : null;
$target = Realtime::fromPayload(
- event: $events->getParam('event'),
- payload: $payload,
- project: $project,
+ // Pass first, most verbose event pattern
+ event: $allEvents[0],
+ payload: $payload,
+ project: $project,
collection: $collection,
bucket: $bucket,
);
Realtime::send(
- $target['projectId'] ?? $project->getId(),
- $response->getPayload(),
- $events->getParam('event'),
- $target['channels'],
- $target['roles'],
- [
+ projectId: $target['projectId'] ?? $project->getId(),
+ payload: $events->getPayload(),
+ events: $allEvents,
+ channels: $target['channels'],
+ roles: $target['roles'],
+ options: [
'permissionsChanged' => $target['permissionsChanged'],
'userId' => $events->getParam('userId')
]
@@ -241,15 +240,18 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
}
}
- if (!empty($audits->getParam('event'))) {
+ if (!empty($audits->getResource())) {
+ foreach ($events->getParams() as $key => $value) {
+ $audits->setParam($key, $value);
+ }
$audits->trigger();
}
- if (!empty($deletes->getParam('type')) && !empty($deletes->getParam('document'))) {
+ if (!empty($deletes->getType())) {
$deletes->trigger();
}
- if (!empty($database->getParam('type')) && !empty($database->getParam('document'))) {
+ if (!empty($database->getType())) {
$database->trigger();
}
@@ -262,8 +264,7 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
$usage
->setParam('networkRequestSize', $request->getSize() + $usage->getParam('storage'))
->setParam('networkResponseSize', $response->getSize())
- ->submit()
- ;
+ ->submit();
}
-}, ['utopia', 'request', 'response', 'project', 'events', 'audits', 'usage', 'deletes', 'database', 'mode'], 'api');
\ No newline at end of file
+}, ['utopia', 'request', 'response', 'project', 'events', 'audits', 'usage', 'deletes', 'database', 'mode', 'dbForProject'], 'api');
\ No newline at end of file
diff --git a/app/controllers/web/console.php b/app/controllers/web/console.php
index 12cb625a8..58bc905db 100644
--- a/app/controllers/web/console.php
+++ b/app/controllers/web/console.php
@@ -165,7 +165,7 @@ App::get('/console/webhooks')
$page
->setParam('events', Config::getParam('events', []))
;
-
+
$layout
->setParam('title', APP_NAME.' - Webhooks')
->setParam('body', $page);
diff --git a/app/init.php b/app/init.php
index 269d860fe..8d5f41b01 100644
--- a/app/init.php
+++ b/app/init.php
@@ -22,7 +22,11 @@ use Ahc\Jwt\JWT;
use Ahc\Jwt\JWTException;
use Appwrite\Extend\Exception;
use Appwrite\Auth\Auth;
+use Appwrite\Event\Audit;
+use Appwrite\Event\Database as EventDatabase;
+use Appwrite\Event\Delete;
use Appwrite\Event\Event;
+use Appwrite\Event\Mail;
use Appwrite\Network\Validator\Email;
use Appwrite\Network\Validator\IP;
use Appwrite\Network\Validator\URL;
@@ -70,7 +74,7 @@ const APP_LIMIT_ANTIVIRUS = 20000000; //20MB
const APP_LIMIT_ENCRYPTION = 20000000; //20MB
const APP_LIMIT_COMPRESSION = 20000000; //20MB
const APP_CACHE_BUSTER = 304;
-const APP_VERSION_STABLE = '0.13.4';
+const APP_VERSION_STABLE = '0.14.0';
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
@@ -642,10 +646,10 @@ App::setResource('locale', fn() => new Locale(App::getEnv('_APP_LOCALE', 'en')))
// Queues
App::setResource('events', fn() => new Event('', ''));
-App::setResource('audits', fn() => new Event(Event::AUDITS_QUEUE_NAME, Event::AUDITS_CLASS_NAME));
-App::setResource('mails', fn() => new Event(Event::MAILS_QUEUE_NAME, Event::MAILS_CLASS_NAME));
-App::setResource('deletes', fn() => new Event(Event::DELETE_QUEUE_NAME, Event::DELETE_CLASS_NAME));
-App::setResource('database', fn() => new Event(Event::DATABASE_QUEUE_NAME, Event::DATABASE_CLASS_NAME));
+App::setResource('audits', fn() => new Audit());
+App::setResource('mails', fn() => new Mail());
+App::setResource('deletes', fn() => new Delete());
+App::setResource('database', fn() => new EventDatabase());
App::setResource('usage', function($register) {
return new Stats($register->get('statsd'));
}, ['register']);
diff --git a/app/realtime.php b/app/realtime.php
index 76b9af5a7..3f996b0bc 100644
--- a/app/realtime.php
+++ b/app/realtime.php
@@ -55,10 +55,10 @@ $adapter
$server = new Server($adapter);
-$logError = function(Throwable $error, string $action) use ($register) {
+$logError = function (Throwable $error, string $action) use ($register) {
$logger = $register->get('logger');
- if($logger) {
+ if ($logger) {
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
$log = new Log();
@@ -82,7 +82,7 @@ $logError = function(Throwable $error, string $action) use ($register) {
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
$responseCode = $logger->addLog($log);
- Console::info('Realtime log pushed with status code: '.$responseCode);
+ Console::info('Realtime log pushed with status code: ' . $responseCode);
}
Console::error('[Error] Type: ' . get_class($error));
@@ -113,10 +113,10 @@ function getDatabase(Registry &$register, string $namespace)
throw new Exception('Collection not ready');
}
break; // leave loop if successful
- } catch(\Exception $e) {
+ } catch (\Exception $e) {
Console::warning("Database not ready. Retrying connection ({$attempts})...");
if ($attempts >= DATABASE_RECONNECT_MAX_ATTEMPTS) {
- throw new \Exception('Failed to connect to database: '. $e->getMessage());
+ throw new \Exception('Failed to connect to database: ' . $e->getMessage());
}
sleep(DATABASE_RECONNECT_SLEEP);
}
@@ -129,7 +129,6 @@ function getDatabase(Registry &$register, string $namespace)
$register->get('redisPool')->put($redis);
}
];
-
};
$server->onStart(function () use ($stats, $register, $containerId, &$statsDocument, $logError) {
@@ -151,7 +150,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
'timestamp' => time(),
'value' => '{}'
]);
- $statsDocument = Authorization::skip(fn() => $database->createDocument('realtime', $document));
+ $statsDocument = Authorization::skip(fn () => $database->createDocument('realtime', $document));
} catch (\Throwable $th) {
call_user_func($logError, $th, "createWorkerDocument");
} finally {
@@ -178,7 +177,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
->setAttribute('timestamp', time())
->setAttribute('value', json_encode($payload));
- Authorization::skip(fn() => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument));
+ Authorization::skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument));
} catch (\Throwable $th) {
call_user_func($logError, $th, "updateWorkerDocument");
} finally {
@@ -203,9 +202,9 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
$payload = [];
- $list = Authorization::skip(fn() => $database->find('realtime', [
- new Query('timestamp', Query::TYPE_GREATER, [(time() - 15)])
- ]));
+ $list = Authorization::skip(fn () => $database->find('realtime', [
+ new Query('timestamp', Query::TYPE_GREATER, [(time() - 15)])
+ ]));
/**
* Aggregate stats across containers.
@@ -299,19 +298,16 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
if ($realtime->hasSubscriber($projectId, 'user:' . $userId)) {
$connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId]));
- } else {
- return;
+ [$database, $returnDatabase] = getDatabase($register, "_{$projectId}");
+
+ $user = $database->getDocument('users', $userId);
+
+ $roles = Auth::getRoles($user);
+
+ $realtime->subscribe($projectId, $connection, $roles, $realtime->connections[$connection]['channels']);
+
+ call_user_func($returnDatabase);
}
-
- [$database, $returnDatabase] = getDatabase($register, "_{$projectId}");
-
- $user = $database->getDocument('users', $userId);
-
- $roles = Auth::getRoles($user);
-
- $realtime->subscribe($projectId, $connection, $roles, $realtime->connections[$connection]['channels']);
-
- call_user_func($returnDatabase);
}
$receivers = $realtime->getSubscribers($event);
@@ -340,10 +336,9 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
Console::error('Pub/sub error: ' . $th->getMessage());
$register->get('redisPool')->put($redis);
$attempts++;
+ sleep(DATABASE_RECONNECT_SLEEP);
continue;
}
-
- $attempts++;
}
Console::error('Failed to restart pub/sub...');
@@ -361,10 +356,10 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
Console::info("Connection open (user: {$connection})");
- App::setResource('db', fn() => $db);
- App::setResource('cache', fn() => $redis);
- App::setResource('request', fn() => $request);
- App::setResource('response', fn() => $response);
+ App::setResource('db', fn () => $db);
+ App::setResource('cache', fn () => $redis);
+ App::setResource('request', fn () => $request);
+ App::setResource('response', fn () => $response);
try {
/** @var \Utopia\Database\Document $user */
@@ -512,7 +507,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
}
switch ($message['type']) {
- /**
+ /**
* This type is used to authenticate.
*/
case 'authentication':
diff --git a/app/tasks/maintenance.php b/app/tasks/maintenance.php
index 056ee59fc..3bb528c4d 100644
--- a/app/tasks/maintenance.php
+++ b/app/tasks/maintenance.php
@@ -3,13 +3,15 @@
global $cli;
global $register;
-use Appwrite\Event\Event;
+use Appwrite\Event\Certificate;
+use Appwrite\Event\Delete;
use Utopia\App;
use Utopia\Cache\Cache;
use Utopia\CLI\Console;
use Utopia\Database\Adapter\MariaDB;
use Utopia\Database\Database;
use Utopia\Cache\Adapter\Redis as RedisCache;
+use Utopia\Database\Document;
use Utopia\Database\Query;
function getConsoleDB(): Database
@@ -26,10 +28,10 @@ function getConsoleDB(): Database
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace('_console'); // Main DB
break; // leave loop if successful
- } catch(\Exception $e) {
+ } catch (\Exception $e) {
Console::warning("Database not ready. Retrying connection ({$attempts})...");
if ($attempts >= DATABASE_RECONNECT_MAX_ATTEMPTS) {
- throw new \Exception('Failed to connect to database: '. $e->getMessage());
+ throw new \Exception('Failed to connect to database: ' . $e->getMessage());
}
sleep(DATABASE_RECONNECT_SLEEP);
}
@@ -43,66 +45,68 @@ $cli
->desc('Schedules maintenance tasks and publishes them to resque')
->action(function () {
Console::title('Maintenance V1');
- Console::success(APP_NAME.' maintenance process v1 has started');
+ Console::success(APP_NAME . ' maintenance process v1 has started');
function notifyDeleteExecutionLogs(int $interval)
{
- Resque::enqueue(Event::DELETE_QUEUE_NAME, Event::DELETE_CLASS_NAME, [
- 'type' => DELETE_TYPE_EXECUTIONS,
- 'timestamp' => time() - $interval
- ]);
+ (new Delete())
+ ->setType(DELETE_TYPE_EXECUTIONS)
+ ->setTimestamp(time() - $interval)
+ ->trigger();
}
- function notifyDeleteAbuseLogs(int $interval)
+ function notifyDeleteAbuseLogs(int $interval)
{
- Resque::enqueue(Event::DELETE_QUEUE_NAME, Event::DELETE_CLASS_NAME, [
- 'type' => DELETE_TYPE_ABUSE,
- 'timestamp' => time() - $interval
- ]);
+ (new Delete())
+ ->setType(DELETE_TYPE_ABUSE)
+ ->setTimestamp(time() - $interval)
+ ->trigger();
}
- function notifyDeleteAuditLogs(int $interval)
+ function notifyDeleteAuditLogs(int $interval)
{
- Resque::enqueue(Event::DELETE_QUEUE_NAME, Event::DELETE_CLASS_NAME, [
- 'type' => DELETE_TYPE_AUDIT,
- 'timestamp' => time() - $interval
- ]);
+ (new Delete())
+ ->setType(DELETE_TYPE_AUDIT)
+ ->setTimestamp(time() - $interval)
+ ->trigger();
}
- function notifyDeleteUsageStats(int $interval30m, int $interval1d)
+ function notifyDeleteUsageStats(int $interval30m, int $interval1d)
{
- Resque::enqueue(Event::DELETE_QUEUE_NAME, Event::DELETE_CLASS_NAME, [
- 'type' => DELETE_TYPE_USAGE,
- 'timestamp1d' => time() - $interval1d,
- 'timestamp30m' => time() - $interval30m,
- ]);
+ (new Delete())
+ ->setType(DELETE_TYPE_USAGE)
+ ->setTimestamp1d(time() - $interval1d)
+ ->setTimestamp30m(time() - $interval30m)
+ ->trigger();
}
- function notifyDeleteConnections()
+ function notifyDeleteConnections()
{
- Resque::enqueue(Event::DELETE_QUEUE_NAME, Event::DELETE_CLASS_NAME, [
- 'type' => DELETE_TYPE_REALTIME,
- 'timestamp' => time() - 60
- ]);
+ (new Delete())
+ ->setType(DELETE_TYPE_REALTIME)
+ ->setTimestamp(time() - 60)
+ ->trigger();
}
function renewCertificates($dbForConsole)
{
$time = date('d-m-Y H:i:s', time());
- /** @var Utopia\Database\Database $dbForConsole */
-
$certificates = $dbForConsole->find('certificates', [
new Query('attempts', Query::TYPE_LESSEREQUAL, [5]), // Maximum 5 attempts
new Query('renewDate', Query::TYPE_LESSEREQUAL, [\time()]) // includes 60 days cooldown (we have 30 days to renew)
], 200); // Limit 200 comes from LetsEncrypt (300 orders per 3 hours, keeping some for new domains)
- if(\count($certificates) > 0) {
+
+ if (\count($certificates) > 0) {
Console::info("[{$time}] Found " . \count($certificates) . " certificates for renewal, scheduling jobs.");
+ $event = new Certificate();
foreach ($certificates as $certificate) {
- Resque::enqueue(Event::CERTIFICATES_QUEUE_NAME, Event::CERTIFICATES_CLASS_NAME, [
- 'domain' => $certificate->getAttribute('domain'),
- ]);
+ $event
+ ->setDomain(new Document([
+ 'domain' => $certificate->getAttribute('domain')
+ ]))
+ ->trigger();
}
} else {
Console::info("[{$time}] No certificates for renewal.");
@@ -114,10 +118,10 @@ $cli
$executionLogsRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_EXECUTION', '1209600');
$auditLogRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT', '1209600');
$abuseLogsRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_ABUSE', '86400');
- $usageStatsRetention30m = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_USAGE_30M', '129600');//36 hours
+ $usageStatsRetention30m = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_USAGE_30M', '129600'); //36 hours
$usageStatsRetention1d = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_USAGE_1D', '8640000'); // 100 days
- Console::loop(function() use ($interval, $executionLogsRetention, $abuseLogsRetention, $auditLogRetention, $usageStatsRetention30m, $usageStatsRetention1d) {
+ Console::loop(function () use ($interval, $executionLogsRetention, $abuseLogsRetention, $auditLogRetention, $usageStatsRetention30m, $usageStatsRetention1d) {
$database = getConsoleDB();
$time = date('d-m-Y H:i:s', time());
@@ -127,7 +131,6 @@ $cli
notifyDeleteAuditLogs($auditLogRetention);
notifyDeleteUsageStats($usageStatsRetention30m, $usageStatsRetention1d);
notifyDeleteConnections();
-
renewCertificates($database);
}, $interval);
- });
\ No newline at end of file
+ });
diff --git a/app/tasks/sdks.php b/app/tasks/sdks.php
index 166eec495..1b3b8411a 100644
--- a/app/tasks/sdks.php
+++ b/app/tasks/sdks.php
@@ -30,7 +30,7 @@ $cli
$production = ($git) ? (Console::confirm('Type "Appwrite" to push code to production git repos') == 'Appwrite') : false;
$message = ($git) ? Console::confirm('Please enter your commit message:') : '';
- if(!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', 'latest'])) {
+ if(!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', 'latest'])) {
throw new Exception('Unknown version given');
}
diff --git a/app/tasks/ssl.php b/app/tasks/ssl.php
index 743be92a9..345da1f22 100644
--- a/app/tasks/ssl.php
+++ b/app/tasks/ssl.php
@@ -2,9 +2,10 @@
global $cli;
-use Appwrite\Event\Event;
+use Appwrite\Event\Certificate;
use Utopia\App;
use Utopia\CLI\Console;
+use Utopia\Database\Document;
use Utopia\Validator\Hostname;
$cli
@@ -14,9 +15,10 @@ $cli
->action(function ($domain) {
Console::success('Scheduling a job to issue a TLS certificate for domain: ' . $domain);
- // Scheduje a job
- Resque::enqueue(Event::CERTIFICATES_QUEUE_NAME, Event::CERTIFICATES_CLASS_NAME, [
- 'domain' => $domain,
- 'skipCheck' => true
- ]);
- });
\ No newline at end of file
+ (new Certificate())
+ ->setDomain(new Document([
+ 'domain' => $domain
+ ]))
+ ->setSkipRenewCheck(true)
+ ->trigger();
+ });
diff --git a/app/workers/audits.php b/app/workers/audits.php
index d83c832c3..696eb6df5 100644
--- a/app/workers/audits.php
+++ b/app/workers/audits.php
@@ -1,17 +1,20 @@
args['projectId'];
- $userId = $this->args['userId'];
- $userName = $this->args['userName'];
- $userEmail = $this->args['userEmail'];
+ $events = $this->args['events'];
+ $payload = $this->args['payload'];
$mode = $this->args['mode'];
- $event = $this->args['event'];
$resource = $this->args['resource'];
$userAgent = $this->args['userAgent'];
$ip = $this->args['ip'];
- $data = $this->args['data'];
-
- $dbForProject = $this->getProjectDB($projectId);
- $audit = new Audit($dbForProject);
- $audit->log($userId, $event, $resource, $userAgent, $ip, '', [
- 'userName' => $userName,
- 'userEmail' => $userEmail,
- 'mode' => $mode,
- 'data' => $data,
- ]);
+ $user = new Document($this->args['user']);
+ $project = new Document($this->args['project']);
+
+ $userName = $user->getAttribute('name', '');
+ $userEmail = $user->getAttribute('email', '');
+
+ $dbForProject = $this->getProjectDB($project->getId());
+ $audit = new Audit($dbForProject);
+ $audit->log(
+ userId: $user->getId(),
+ // Pass first, most verbose event pattern
+ event: $events[0],
+ resource: $resource,
+ userAgent: $userAgent,
+ ip: $ip,
+ location: '',
+ data: [
+ 'userName' => $userName,
+ 'userEmail' => $userEmail,
+ 'mode' => $mode,
+ 'data' => $payload,
+ ]
+ );
}
public function shutdown(): void
{
- // ... Remove environment for this job
}
}
diff --git a/app/workers/builds.php b/app/workers/builds.php
index 031ffd84c..c1affa590 100644
--- a/app/workers/builds.php
+++ b/app/workers/builds.php
@@ -1,7 +1,9 @@
executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST'));
}
public function run(): void
{
$type = $this->args['type'] ?? '';
- $projectId = $this->args['projectId'] ?? '';
- $functionId = $this->args['resourceId'] ?? '';
- $deploymentId = $this->args['deploymentId'] ?? '';
-
+ $project = new Document($this->args['project'] ?? []);
+ $resource = new Document($this->args['resource'] ?? []);
+ $deployment = new Document($this->args['deployment'] ?? []);
+
switch ($type) {
case BUILD_TYPE_DEPLOYMENT:
case BUILD_TYPE_RETRY:
- Console::info("Creating build for deployment: $deploymentId");
- $this->buildDeployment($projectId, $functionId, $deploymentId);
+ Console::info('Creating build for deployment: ' . $deployment->getId());
+ $this->buildDeployment($project, $resource, $deployment);
break;
default:
@@ -56,18 +56,16 @@ class BuildsV1 extends Worker
}
}
- protected function buildDeployment(string $projectId, string $functionId, string $deploymentId)
+ protected function buildDeployment(Document $project, Document $function, Document $deployment)
{
- $dbForProject = $this->getProjectDB($projectId);
- $dbForConsole = $this->getConsoleDB();
- $project = $dbForConsole->getDocument('projects', $projectId);
-
- $function = $dbForProject->getDocument('functions', $functionId);
+ $dbForProject = $this->getProjectDB($project->getId());
+
+ $function = $dbForProject->getDocument('functions', $function->getId());
if ($function->isEmpty()) {
throw new Exception('Function not found', 404);
}
- $deployment = $dbForProject->getDocument('deployments', $deploymentId);
+ $deployment = $dbForProject->getDocument('deployments', $deployment->getId());
if ($deployment->isEmpty()) {
throw new Exception('Deployment not found', 404);
}
@@ -89,7 +87,7 @@ class BuildsV1 extends Worker
'$read' => [],
'$write' => [],
'startTime' => $startTime,
- 'deploymentId' => $deploymentId,
+ 'deploymentId' => $deployment->getId(),
'status' => 'processing',
'outputPath' => '',
'runtime' => $function->getAttribute('runtime'),
@@ -101,7 +99,7 @@ class BuildsV1 extends Worker
'duration' => 0
]));
$deployment->setAttribute('buildId', $buildId);
- $deployment = $dbForProject->updateDocument('deployments', $deploymentId, $deployment);
+ $deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
} else {
$build = $dbForProject->getDocument('builds', $buildId);
}
@@ -110,12 +108,39 @@ class BuildsV1 extends Worker
$build->setAttribute('status', 'building');
$build = $dbForProject->updateDocument('builds', $buildId, $build);
- /** Send realtime event */
- $target = Realtime::fromPayload('functions.deployments.update', $build, $project);
+ /** Trigger Webhook */
+ $deploymentModel = new Deployment();
+ $deploymentUpdate = new Event(Event::WEBHOOK_QUEUE_NAME, Event::WEBHOOK_CLASS_NAME);
+ $deploymentUpdate
+ ->setProject($project)
+ ->setEvent('functions.[functionId].deployments.[deploymentId].update')
+ ->setParam('functionId', $function->getId())
+ ->setParam('deploymentId', $deployment->getId())
+ ->setPayload($deployment->getArrayCopy(array_keys($deploymentModel->getRules())))
+ ->trigger();
+
+ /** Trigger Functions */
+ $deploymentUpdate
+ ->setClass(Event::FUNCTIONS_CLASS_NAME)
+ ->setQueue(Event::FUNCTIONS_QUEUE_NAME)
+ ->trigger();
+
+ /** Trigger Realtime */
+ $allEvents = Event::generateEvents('functions.[functionId].deployments.[deploymentId].update', [
+ 'functionId' => $function->getId(),
+ 'deploymentId' => $deployment->getId()
+ ]);
+ $target = Realtime::fromPayload(
+ // Pass first, most verbose event pattern
+ event: $allEvents[0],
+ payload: $build,
+ project: $project
+ );
+
Realtime::send(
projectId: 'console',
payload: $build->getArrayCopy(),
- event: 'functions.deployments.update',
+ events: $allEvents,
channels: $target['channels'],
roles: $target['roles']
);
@@ -126,13 +151,13 @@ class BuildsV1 extends Worker
try {
$response = $this->executor->createRuntime(
- projectId: $projectId,
- deploymentId: $deploymentId,
+ projectId: $project->getId(),
+ deploymentId: $deployment->getId(),
entrypoint: $deployment->getAttribute('entrypoint'),
source: $source,
- destination: APP_STORAGE_BUILDS . "/app-$projectId",
- vars: $vars,
- runtime: $key,
+ destination: APP_STORAGE_BUILDS . "/app-{$project->getId()}",
+ vars: $vars,
+ runtime: $key,
baseImage: $baseImage,
workdir: '/usr/code',
remove: true,
@@ -156,7 +181,7 @@ class BuildsV1 extends Worker
/** Set auto deploy */
if ($deployment->getAttribute('activate') === true) {
$function->setAttribute('deployment', $deployment->getId());
- $function = $dbForProject->updateDocument('functions', $functionId, $function);
+ $function = $dbForProject->updateDocument('functions', $function->getId(), $function);
}
/** Update function schedule */
@@ -164,8 +189,7 @@ class BuildsV1 extends Worker
$cron = (empty($function->getAttribute('deployment')) && !empty($schedule)) ? new CronExpression($schedule) : null;
$next = (empty($function->getAttribute('deployment')) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : 0;
$function->setAttribute('scheduleNext', (int)$next);
- $function = $dbForProject->updateDocument('functions', $functionId, $function);
-
+ $function = $dbForProject->updateDocument('functions', $function->getId(), $function);
} catch (\Throwable $th) {
$endtime = \time();
$build->setAttribute('endTime', $endtime);
@@ -177,18 +201,25 @@ class BuildsV1 extends Worker
$build = $dbForProject->updateDocument('builds', $buildId, $build);
/**
- * Send realtime Event
+ * Send realtime Event
*/
- $target = Realtime::fromPayload('functions.deployments.update', $build, $project);
+ $target = Realtime::fromPayload(
+ // Pass first, most verbose event pattern
+ event: $allEvents[0],
+ payload: $build,
+ project: $project
+ );
Realtime::send(
projectId: 'console',
payload: $build->getArrayCopy(),
- event: 'functions.deployments.update',
+ events: $allEvents,
channels: $target['channels'],
roles: $target['roles']
);
}
}
- public function shutdown(): void {}
+ public function shutdown(): void
+ {
+ }
}
diff --git a/app/workers/certificates.php b/app/workers/certificates.php
index f932e4b8f..888f4de8e 100644
--- a/app/workers/certificates.php
+++ b/app/workers/certificates.php
@@ -11,14 +11,14 @@ use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Domains\Domain;
-require_once __DIR__.'/../init.php';
+require_once __DIR__ . '/../init.php';
Console::title('Certificates V1 Worker');
Console::success(APP_NAME . ' certificates worker v1 has started');
class CertificatesV1 extends Worker
{
-
+
/**
* Database connection shared across all methods of this file
*
@@ -26,13 +26,13 @@ class CertificatesV1 extends Worker
*/
private Database $dbForConsole;
- public function getName(): string {
+ public function getName(): string
+ {
return "certificates";
}
public function init(): void
{
-
}
public function run(): void
@@ -73,16 +73,22 @@ class CertificatesV1 extends Worker
try {
// Read arguments
- $domain = $this->args['domain']; // String of domain (hostname)
- $skipCheck = $this->args['skipCheck'] ?? false; // If true, we won't double-check expiry from cert file
+ $document = new Document($this->args['domain'] ?? []);
+ $skipCheck = $this->args['skipRenewCheck'] ?? false; // If true, we won't double-check expiry from cert file
+
+ // Options
+ $domain = new Domain($document->getAttribute('domain'));
+ $expiry = 60 * 60 * 24 * 30 * 2; // 60 days
+ $safety = 60 * 60; // 1 hour
+ $renew = (\time() + $expiry);
$domain = new Domain((!empty($domain)) ? $domain : '');
// Get current certificate
- $certificate = $this->dbForConsole->findOne('certificates', [ new Query('domain', Query::TYPE_EQUAL, [$domain->get()]) ]);
+ $certificate = $this->dbForConsole->findOne('certificates', [new Query('domain', Query::TYPE_EQUAL, [$domain->get()])]);
// If we don't have certificate for domain yet, let's create new document. At the end we save it
- if(!$certificate) {
+ if (!$certificate) {
$certificate = new Document();
$certificate->setAttribute('domain', $domain->get());
}
@@ -92,16 +98,16 @@ class CertificatesV1 extends Worker
if (empty($email)) {
throw new Exception('You must set a valid security email address (_APP_SYSTEM_SECURITY_EMAIL_ADDRESS) to issue an SSL certificate.');
}
-
+
// Validate domain and DNS records. Skip if job is forced
- if(!$skipCheck) {
+ if (!$skipCheck) {
$mainDomain = $this->getMainDomain();
$isMainDomain = !isset($mainDomain) || $domain->get() === $mainDomain;
$this->validateDomain($domain, $isMainDomain);
}
// If certificate exists already, double-check expiry date. Skip if job is forced
- if(!$skipCheck && !$this->isRenewRequired($domain->get())) {
+ if (!$skipCheck && !$this->isRenewRequired($domain->get())) {
throw new Exception('Renew isn\'t required.');
}
@@ -114,15 +120,15 @@ class CertificatesV1 extends Worker
'stdout' => $letsEncryptData['stdout'],
'stderr' => $letsEncryptData['stderr'],
]));
-
+
// Give certificates to Traefik
$this->applyCertificateFiles($domain->get(), $letsEncryptData);
-
+
// Update certificate info stored in database
$certificate->setAttribute('renewDate', $this->getRenewDate($domain->get()));
$certificate->setAttribute('attempts', 0);
$certificate->setAttribute('issueDate', \time());
- } catch(Throwable $e) {
+ } catch (Throwable $e) {
// Set exception as log in certificate document
$certificate->setAttribute('log', $e->getMessage());
@@ -155,13 +161,14 @@ class CertificatesV1 extends Worker
*
* @return void
*/
- private function saveCertificateDocument(string $domain, Document $certificate): void {
+ private function saveCertificateDocument(string $domain, Document $certificate): void
+ {
// Check if update or insert required
- $certificateDocument = $this->dbForConsole->findOne('certificates', [ new Query('domain', Query::TYPE_EQUAL, [$domain]) ]);
+ $certificateDocument = $this->dbForConsole->findOne('certificates', [new Query('domain', Query::TYPE_EQUAL, [$domain])]);
if (!empty($certificateDocument) && !$certificateDocument->isEmpty()) {
// Merge new data with current data
$certificate = new Document(\array_merge($certificateDocument->getArrayCopy(), $certificate->getArrayCopy()));
-
+
$certificate = $this->dbForConsole->updateDocument('certificates', $certificate->getId(), $certificate);
} else {
$certificate = $this->dbForConsole->createDocument('certificates', $certificate);
@@ -176,12 +183,13 @@ class CertificatesV1 extends Worker
*
* @return null|string Returns main domain. If null, there is no main domain yet.
*/
- private function getMainDomain(): ?string {
+ private function getMainDomain(): ?string
+ {
if (!empty(App::getEnv('_APP_DOMAIN', ''))) {
return App::getEnv('_APP_DOMAIN', '');
} else {
$domainDocument = $this->dbForConsole->findOne('domains', [], 0, ['_id'], ['ASC']);
- if($domainDocument) {
+ if ($domainDocument) {
return $domainDocument->getAttribute('domain');
}
}
@@ -199,7 +207,8 @@ class CertificatesV1 extends Worker
*
* @return void
*/
- private function validateDomain(Domain $domain, bool $isMainDomain): void {
+ private function validateDomain(Domain $domain, bool $isMainDomain): void
+ {
if (empty($domain->get())) {
throw new Exception('Missing certificate domain.');
}
@@ -215,7 +224,7 @@ class CertificatesV1 extends Worker
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
if (!$target->isKnown() || $target->isTest()) {
- throw new Exception('Unreachable CNAME target ('.$target->get().'), please use a domain with a public suffix.');
+ throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.');
}
// Verify domain with DNS records
@@ -236,7 +245,8 @@ class CertificatesV1 extends Worker
*
* @return bool True, if certificate needs to be renewed
*/
- private function isRenewRequired(string $domain): bool {
+ private function isRenewRequired(string $domain): bool
+ {
$certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem';
if (\file_exists($certPath)) {
$validTo = null;
@@ -249,7 +259,7 @@ class CertificatesV1 extends Worker
}
// LetsEncrypt allows renewal 30 days before expiry
- $expiryInAdvance = (60*60*24*30);
+ $expiryInAdvance = (60 * 60 * 24 * 30);
if ($validTo - $expiryInAdvance > \time()) {
return false;
}
@@ -265,7 +275,8 @@ class CertificatesV1 extends Worker
*
* @return array Named array with keys 'stdout' and 'stderr', both string
*/
- private function issueCertificate(string $domain, string $email): array {
+ private function issueCertificate(string $domain, string $email): array
+ {
$staging = (App::isProduction()) ? '' : ' --dry-run';
$stdout = '';
@@ -295,11 +306,12 @@ class CertificatesV1 extends Worker
*
* @return int
*/
- private function getRenewDate(string $domain): int {
+ private function getRenewDate(string $domain): int
+ {
$certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem';
$certData = openssl_x509_parse(file_get_contents($certPath));
$validTo = $certData['validTo_time_t'] ?? 0;
- $expiryInAdvance = (60*60*24*30); // 30 days
+ $expiryInAdvance = (60 * 60 * 24 * 30); // 30 days
return $validTo - $expiryInAdvance;
}
@@ -311,7 +323,8 @@ class CertificatesV1 extends Worker
*
* @return void
*/
- private function applyCertificateFiles(string $domain, array $letsEncryptData): void {
+ private function applyCertificateFiles(string $domain, array $letsEncryptData): void
+ {
// Prepare folder in storage for domain
$path = APP_STORAGE_CERTIFICATES . '/' . $domain;
if (!\is_readable($path)) {
@@ -321,7 +334,7 @@ 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')) {
+ if (!@\rename('/etc/letsencrypt/live/' . $domain . '/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']);
}
@@ -343,7 +356,7 @@ class CertificatesV1 extends Worker
" - certFile: /storage/certificates/{$domain}/fullchain.pem",
" keyFile: /storage/certificates/{$domain}/privkey.pem"
]);
-
+
// Save configuration into Traefik using our new cert files
if (!\file_put_contents(APP_STORAGE_CONFIG . '/' . $domain . '.yml', $config)) {
throw new Exception('Failed to save Traefik configuration.');
@@ -359,7 +372,8 @@ class CertificatesV1 extends Worker
*
* @return void
*/
- private function notifyError(string $domain, string $errorMessage, int $attempt): void {
+ private function notifyError(string $domain, string $errorMessage, int $attempt): void
+ {
// Log error into console
Console::warning('Cannot renew domain (' . $domain . ') on attempt no. ' . $attempt . ' certificate: ' . $errorMessage);
@@ -391,7 +405,8 @@ class CertificatesV1 extends Worker
*
* @return void
*/
- private function updateDomainDocuments(string $certificateId, string $domain): void {
+ private function updateDomainDocuments(string $certificateId, string $domain): void
+ {
$domains = $this->dbForConsole->find('domains', [
new Query('domain', Query::TYPE_EQUAL, [$domain])
], 1000);
@@ -402,9 +417,9 @@ class CertificatesV1 extends Worker
$this->dbForConsole->updateDocument('domains', $domainDocument->getId(), $domainDocument);
- if($domainDocument->getAttribute('projectId')) {
+ if ($domainDocument->getAttribute('projectId')) {
$this->dbForConsole->deleteCachedDocument('projects', $domainDocument->getAttribute('projectId'));
}
- }
+ }
}
}
diff --git a/app/workers/database.php b/app/workers/database.php
index 5fd3e16e2..a3451461c 100644
--- a/app/workers/database.php
+++ b/app/workers/database.php
@@ -1,5 +1,6 @@
args['projectId'] ?? '';
- $type = $this->args['type'] ?? '';
- $collection = $this->args['collection'] ?? [];
- $collection = new Document($collection);
- $document = $this->args['document'] ?? [];
- $document = new Document($document);
+
+ $type = $this->args['type'];
+ $project = new Document($this->args['project']);
+ $collection = new Document($this->args['collection'] ?? []);
+ $document = new Document($this->args['document'] ?? []);
if($collection->isEmpty()) {
throw new Exception('Missing collection');
@@ -37,16 +37,16 @@ class DatabaseV1 extends Worker
switch (strval($type)) {
case DATABASE_TYPE_CREATE_ATTRIBUTE:
- $this->createAttribute($collection, $document, $projectId);
+ $this->createAttribute($collection, $document, $project->getId());
break;
case DATABASE_TYPE_DELETE_ATTRIBUTE:
- $this->deleteAttribute($collection, $document, $projectId);
+ $this->deleteAttribute($collection, $document, $project->getId());
break;
case DATABASE_TYPE_CREATE_INDEX:
- $this->createIndex($collection, $document, $projectId);
+ $this->createIndex($collection, $document, $project->getId());
break;
case DATABASE_TYPE_DELETE_INDEX:
- $this->deleteIndex($collection, $document, $projectId);
+ $this->deleteIndex($collection, $document, $project->getId());
break;
default:
@@ -71,12 +71,15 @@ class DatabaseV1 extends Worker
$dbForConsole = $this->getConsoleDB();
$dbForProject = $this->getProjectDB($projectId);
+ $events = Event::generateEvents('collections.[collectionId].attributes.[attributeId].update', [
+ 'collectionId' => $collection->getId(),
+ 'attributeId' => $attribute->getId()
+ ]);
/**
* Fetch attribute from the database, since with Resque float values are loosing informations.
*/
$attribute = $dbForProject->getDocument('attributes', $attribute->getId());
- $event = 'database.attributes.update';
$collectionId = $collection->getId();
$key = $attribute->getAttribute('key', '');
$type = $attribute->getAttribute('type', '');
@@ -99,12 +102,17 @@ class DatabaseV1 extends Worker
Console::error($th->getMessage());
$dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'failed'));
} finally {
- $target = Realtime::fromPayload($event, $attribute, $project);
+ $target = Realtime::fromPayload(
+ // Pass first, most verbose event pattern
+ event: $events[0],
+ payload: $attribute,
+ project: $project
+ );
Realtime::send(
projectId: 'console',
payload: $attribute->getArrayCopy(),
- event: $event,
+ events: $events,
channels: $target['channels'],
roles: $target['roles'],
options: [
@@ -127,7 +135,10 @@ class DatabaseV1 extends Worker
$dbForConsole = $this->getConsoleDB();
$dbForProject = $this->getProjectDB($projectId);
- $event = 'database.attributes.delete';
+ $events = Event::generateEvents('collections.[collectionId].attributes.[attributeId].delete', [
+ 'collectionId' => $collection->getId(),
+ 'attributeId' => $attribute->getId()
+ ]);
$collectionId = $collection->getId();
$key = $attribute->getAttribute('key', '');
$status = $attribute->getAttribute('status', '');
@@ -148,12 +159,17 @@ class DatabaseV1 extends Worker
Console::error($th->getMessage());
$dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'stuck'));
} finally {
- $target = Realtime::fromPayload($event, $attribute, $project);
+ $target = Realtime::fromPayload(
+ // Pass first, most verbose event pattern
+ event: $events[0],
+ payload: $attribute,
+ project: $project
+ );
Realtime::send(
projectId: 'console',
payload: $attribute->getArrayCopy(),
- event: $event,
+ events: $events,
channels: $target['channels'],
roles: $target['roles'],
options: [
@@ -228,7 +244,10 @@ class DatabaseV1 extends Worker
$dbForConsole = $this->getConsoleDB();
$dbForProject = $this->getProjectDB($projectId);
- $event = 'database.indexes.update';
+ $events = Event::generateEvents('collections.[collectionId].indexes.[indexId].update', [
+ 'collectionId' => $collection->getId(),
+ 'indexId' => $index->getId()
+ ]);
$collectionId = $collection->getId();
$key = $index->getAttribute('key', '');
$type = $index->getAttribute('type', '');
@@ -246,12 +265,17 @@ class DatabaseV1 extends Worker
Console::error($th->getMessage());
$dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'failed'));
} finally {
- $target = Realtime::fromPayload($event, $index, $project);
+ $target = Realtime::fromPayload(
+ // Pass first, most verbose event pattern
+ event: $events[0],
+ payload: $index,
+ project: $project
+ );
Realtime::send(
projectId: 'console',
payload: $index->getArrayCopy(),
- event: $event,
+ events: $events,
channels: $target['channels'],
roles: $target['roles'],
options: [
@@ -274,10 +298,12 @@ class DatabaseV1 extends Worker
$dbForConsole = $this->getConsoleDB();
$dbForProject = $this->getProjectDB($projectId);
- $collectionId = $collection->getId();
+ $events = Event::generateEvents('collections.[collectionId].indexes.[indexId].delete', [
+ 'collectionId' => $collection->getId(),
+ 'indexId' => $index->getId()
+ ]);
$key = $index->getAttribute('key');
$status = $index->getAttribute('status', '');
- $event = 'database.indexes.delete';
$project = $dbForConsole->getDocument('projects', $projectId);
try {
@@ -289,12 +315,17 @@ class DatabaseV1 extends Worker
Console::error($th->getMessage());
$dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'stuck'));
} finally {
- $target = Realtime::fromPayload($event, $index, $project);
+ $target = Realtime::fromPayload(
+ // Pass first, most verbose event pattern
+ event: $events[0],
+ payload: $index,
+ project: $project
+ );
Realtime::send(
projectId: 'console',
payload: $index->getArrayCopy(),
- event: $event,
+ events: $events,
channels: $target['channels'],
roles: $target['roles'],
options: [
@@ -304,6 +335,6 @@ class DatabaseV1 extends Worker
);
}
- $dbForProject->deleteCachedDocument('collections', $collectionId);
+ $dbForProject->deleteCachedDocument('collections', $collection->getId());
}
}
diff --git a/app/workers/deletes.php b/app/workers/deletes.php
index 29b9bc5c4..295a82c71 100644
--- a/app/workers/deletes.php
+++ b/app/workers/deletes.php
@@ -41,8 +41,7 @@ class DeletesV1 extends Worker
public function run(): void
{
-
- $projectId = $this->args['projectId'] ?? '';
+ $project = new Document($this->args['project'] ?? []);
$type = $this->args['type'] ?? '';
switch (strval($type)) {
@@ -51,25 +50,25 @@ class DeletesV1 extends Worker
switch ($document->getCollection()) {
case DELETE_TYPE_COLLECTIONS:
- $this->deleteCollection($document, $projectId);
+ $this->deleteCollection($document, $project->getId());
break;
case DELETE_TYPE_PROJECTS:
$this->deleteProject($document);
break;
case DELETE_TYPE_FUNCTIONS:
- $this->deleteFunction($document, $projectId);
+ $this->deleteFunction($document, $project->getId());
break;
case DELETE_TYPE_DEPLOYMENTS:
- $this->deleteDeployment($document, $projectId);
+ $this->deleteDeployment($document, $project->getId());
break;
case DELETE_TYPE_USERS:
- $this->deleteUser($document, $projectId);
+ $this->deleteUser($document, $project->getId());
break;
case DELETE_TYPE_TEAMS:
- $this->deleteMemberships($document, $projectId);
+ $this->deleteMemberships($document, $project->getId());
break;
case DELETE_TYPE_BUCKETS:
- $this->deleteBucket($document, $projectId);
+ $this->deleteBucket($document, $project->getId());
break;
default:
Console::error('No lazy delete operation available for document of type: ' . $document->getCollection());
@@ -82,15 +81,15 @@ class DeletesV1 extends Worker
break;
case DELETE_TYPE_AUDIT:
- $timestamp = $this->args['timestamp'] ?? 0;
- $document = new Document($this->args['document'] ?? []);
+ $timestamp = $payload['timestamp'] ?? 0;
+ $document = new Document($payload['document'] ?? []);
if (!empty($timestamp)) {
$this->deleteAuditLogs($this->args['timestamp']);
}
if (!$document->isEmpty()) {
- $this->deleteAuditLogsByResource('document/' . $document->getId(), $projectId);
+ $this->deleteAuditLogsByResource('document/' . $document->getId(), $project->getId());
}
break;
@@ -207,7 +206,7 @@ class DeletesV1 extends Worker
* 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();
// Delete all sessions of this user from the sessions table and update the sessions field of the user record
diff --git a/app/workers/functions.php b/app/workers/functions.php
index 96f12fddf..1a6ae838b 100644
--- a/app/workers/functions.php
+++ b/app/workers/functions.php
@@ -1,13 +1,13 @@
args['projectId'] ?? '';
- $functionId = $this->args['functionId'] ?? '';
- $webhooks = $this->args['webhooks'] ?? [];
- $executionId = $this->args['executionId'] ?? '';
- $trigger = $this->args['trigger'] ?? '';
- $event = $this->args['event'] ?? '';
- $scheduleOriginal = $this->args['scheduleOriginal'] ?? '';
- $eventData = (!empty($this->args['eventData'])) ? json_encode($this->args['eventData']) : '';
- $data = $this->args['data'] ?? '';
- $userId = $this->args['userId'] ?? '';
- $jwt = $this->args['jwt'] ?? '';
+ $type = $this->args['type'] ?? '';
+ $events = $this->args['events'] ?? [];
+ $project = new Document($this->args['project'] ?? []);
+ $user = new Document($this->args['user'] ?? []);
+ $payload = json_encode($this->args['payload'] ?? []);
- $database = $this->getProjectDB($projectId);
+ $database = $this->getProjectDB($project->getId());
- switch ($trigger) {
- case 'event':
- $limit = 30;
- $sum = 30;
- $offset = 0;
- $functions = [];
- /** @var Document[] $functions */
+ /**
+ * Handle Event execution.
+ */
+ if (!empty($events)) {
+ $limit = 30;
+ $sum = 30;
+ $offset = 0;
+ $functions = [];
+ /** @var Document[] $functions */
- while ($sum >= $limit) {
- $functions = Authorization::skip(fn() => $database->find('functions', [], $limit, $offset, ['name'], [Database::ORDER_ASC]));
- $sum = \count($functions);
- $offset = $offset + $limit;
+ while ($sum >= $limit) {
+ $functions = Authorization::skip(fn () => $database->find('functions', [], $limit, $offset, ['name'], [Database::ORDER_ASC]));
+ $sum = \count($functions);
+ $offset = $offset + $limit;
- Console::log('Fetched ' . $sum . ' functions...');
+ Console::log('Fetched ' . $sum . ' functions...');
- foreach ($functions as $function) {
- $events = $function->getAttribute('events', []);
-
- if (!\in_array($event, $events)) {
- continue;
- }
-
- Console::success('Iterating function: ' . $function->getAttribute('name'));
-
- $this->execute(
- projectId: $projectId,
- function: $function,
- dbForProject: $database,
- executionId: $executionId,
- webhooks: $webhooks,
- trigger: $trigger,
- event: $event,
- eventData: $eventData,
- data: $data,
- userId: $userId,
- jwt: $jwt
- );
-
- Console::success('Triggered function: ' . $event);
+ foreach ($functions as $function) {
+ if (!array_intersect($events, $function->getAttribute('events', []))) {
+ continue;
}
+
+ Console::success('Iterating function: ' . $function->getAttribute('name'));
+
+ $this->execute(
+ project: $project,
+ function: $function,
+ dbForProject: $database,
+ trigger: 'event',
+ // Pass first, most verbose event pattern
+ event: $events[0],
+ eventData: $payload,
+ user: $user
+ );
+
+ Console::success('Triggered function: ' . $events[0]);
}
+ }
+
+ return;
+ }
+
+ /**
+ * Handle Schedule and HTTP execution.
+ */
+ $user = new Document($this->args['user'] ?? []);
+ $project = new Document($this->args['project'] ?? []);
+ $execution = new Document($this->args['execution'] ?? []);
+
+ switch ($type) {
+ case 'http':
+ $jwt = $this->args['jwt'] ?? '';
+ $data = $this->args['data'] ?? '';
+
+ $function = Authorization::skip(fn () => $database->getDocument('functions', $execution->getAttribute('functionId')));
+
+ $this->execute(
+ project: $project,
+ function: $function,
+ dbForProject: $database,
+ executionId: $execution->getId(),
+ trigger: 'http',
+ data: $data,
+ user: $user,
+ jwt: $jwt
+ );
break;
case 'schedule':
+ $scheduleOriginal = $execution->getAttribute('scheduleOriginal', '');
+ $function = Authorization::skip(fn () => $database->getDocument('functions', $execution->getAttribute('functionId')));
+
/*
* 1. Get Original Task
* 2. Check for updates
@@ -115,10 +133,8 @@ class FunctionsV1 extends Worker
*/
// Reschedule
- $function = Authorization::skip(fn() => $database->getDocument('functions', $functionId));
-
if (empty($function->getId())) {
- throw new Exception('Function not found ('.$functionId.')');
+ throw new Exception('Function not found (' . $function->getId() . ')');
}
if ($scheduleOriginal && $scheduleOriginal !== $function->getAttribute('schedule')) { // Schedule has changed from previous run, ignore this run.
@@ -132,61 +148,31 @@ class FunctionsV1 extends Worker
->setAttribute('scheduleNext', $next)
->setAttribute('schedulePrevious', \time());
- $function = Authorization::skip(function() use ($database, $function, $next, $functionId) {
- $function = $database->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
- 'scheduleNext' => (int)$next,
- ])));
-
- if ($function === false) {
- throw new Exception('Function update failed (' . $functionId . ')');
- }
- return $function;
- });
+ $function = Authorization::skip(fn () => $database->updateDocument(
+ 'functions',
+ $function->getId(),
+ $function->setAttribute('scheduleNext', (int) $next)
+ ));
- ResqueScheduler::enqueueAt($next, Event::FUNCTIONS_QUEUE_NAME, Event::FUNCTIONS_CLASS_NAME, [
- 'projectId' => $projectId,
- 'webhooks' => $webhooks,
- 'functionId' => $function->getId(),
- 'userId' => $userId,
- 'executionId' => null,
- 'trigger' => 'schedule',
- 'scheduleOriginal' => $function->getAttribute('schedule', ''),
- ]); // Async task reschedule
-
- $this->execute(
- projectId: $projectId,
- function: $function,
- dbForProject: $database,
- executionId: $executionId,
- webhooks: $webhooks,
- trigger: $trigger,
- event: $event,
- eventData: $eventData,
- data: $data,
- userId: $userId,
- jwt: $jwt
- );
- break;
-
- case 'http':
- $function = Authorization::skip(fn() => $database->getDocument('functions', $functionId));
-
- if (empty($function->getId())) {
- throw new Exception('Function not found ('.$functionId.')');
+ if ($function === false) {
+ throw new Exception('Function update failed.');
}
+ $reschedule = new Func();
+ $reschedule
+ ->setFunction($function)
+ ->setType('schedule')
+ ->setUser($user)
+ ->setProject($project);
+
+ // Async task reschedule
+ $reschedule->schedule($next);
+
$this->execute(
- projectId: $projectId,
+ project: $project,
function: $function,
dbForProject: $database,
- executionId: $executionId,
- webhooks: $webhooks,
- trigger: $trigger,
- event: $event,
- eventData: $eventData,
- data: $data,
- userId: $userId,
- jwt: $jwt
+ trigger: 'schedule'
);
break;
@@ -194,24 +180,23 @@ class FunctionsV1 extends Worker
}
private function execute(
- string $projectId,
+ Document $project,
Document $function,
Database $dbForProject,
- string $executionId,
- array $webhooks,
string $trigger,
- string $event,
- string $eventData,
- string $data,
- string $userId,
- string $jwt
+ string $executionId = null,
+ string $event = null,
+ string $eventData = null,
+ string $data = null,
+ ?Document $user = null,
+ string $jwt = null
) {
$functionId = $function->getId();
$deploymentId = $function->getAttribute('deployment', '');
/** Check if deployment exists */
- $deployment = Authorization::skip(fn() => $dbForProject->getDocument('deployments', $deploymentId));
+ $deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $deploymentId));
if ($deployment->getAttribute('resourceId') !== $functionId) {
throw new Exception('Deployment not found. Create deployment before trying to execute a function', 404);
@@ -222,7 +207,7 @@ class FunctionsV1 extends Worker
}
/** Check if build has exists */
- $build = Authorization::skip(fn() => $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')));
+ $build = Authorization::skip(fn () => $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')));
if ($build->isEmpty()) {
throw new Exception('Build not found', 404);
}
@@ -233,20 +218,21 @@ class FunctionsV1 extends Worker
/** Check if runtime is supported */
$runtimes = Config::getParam('runtimes', []);
- $runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null;
- if (\is_null($runtime)) {
+ if (!\array_key_exists($function->getAttribute('runtime'), $runtimes)) {
throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported', 400);
}
+ $runtime = $runtimes[$function->getAttribute('runtime')];
+
/** Create execution or update execution status */
- $execution = Authorization::skip(function() use ($dbForProject, &$executionId, $functionId, $deploymentId, $trigger, $userId) {
+ $execution = Authorization::skip(function () use ($dbForProject, &$executionId, $functionId, $deploymentId, $trigger, $user) {
$execution = $dbForProject->getDocument('executions', $executionId);
if ($execution->isEmpty()) {
$executionId = $dbForProject->getId();
$execution = $dbForProject->createDocument('executions', new Document([
'$id' => $executionId,
- '$read' => $userId ? ['user:' . $userId] : [],
+ '$read' => $user->getId() ? ['user:' . $user->getId()] : [],
'$write' => [],
'dateCreated' => time(),
'functionId' => $functionId,
@@ -259,13 +245,14 @@ class FunctionsV1 extends Worker
'time' => 0.0,
'search' => implode(' ', [$functionId, $executionId]),
]));
-
+
if ($execution->isEmpty()) {
throw new Exception('Failed to create or read execution');
}
}
$execution->setAttribute('status', 'processing');
$execution = $dbForProject->updateDocument('executions', $executionId, $execution);
+
return $execution;
});
@@ -280,8 +267,8 @@ class FunctionsV1 extends Worker
'APPWRITE_FUNCTION_EVENT' => $event,
'APPWRITE_FUNCTION_EVENT_DATA' => $eventData,
'APPWRITE_FUNCTION_DATA' => $data,
- 'APPWRITE_FUNCTION_PROJECT_ID' => $projectId,
- 'APPWRITE_FUNCTION_USER_ID' => $userId,
+ 'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(),
+ 'APPWRITE_FUNCTION_USER_ID' => $user->getId(),
'APPWRITE_FUNCTION_JWT' => $jwt,
];
$vars = \array_merge($function->getAttribute('vars', []), $vars);
@@ -289,7 +276,7 @@ class FunctionsV1 extends Worker
/** Execute function */
try {
$executionResponse = $this->executor->createExecution(
- projectId: $projectId,
+ projectId: $project->getId(),
deploymentId: $deploymentId,
path: $build->getAttribute('outputPath', ''),
vars: $vars,
@@ -301,44 +288,62 @@ class FunctionsV1 extends Worker
);
/** Update execution status */
- $execution->setAttribute('status', $executionResponse['status']);
- $execution->setAttribute('statusCode', $executionResponse['statusCode']);
- $execution->setAttribute('response', $executionResponse['response']);
- $execution->setAttribute('stderr', $executionResponse['stderr']);
- $execution->setAttribute('time', $executionResponse['time']);
+ $execution
+ ->setAttribute('status', $executionResponse['status'])
+ ->setAttribute('statusCode', $executionResponse['statusCode'])
+ ->setAttribute('response', $executionResponse['response'])
+ ->setAttribute('stderr', $executionResponse['stderr'])
+ ->setAttribute('time', $executionResponse['time']);
} catch (\Throwable $th) {
- $execution->setAttribute('status', 'failed');
- $execution->setAttribute('statusCode', $th->getCode());
- $execution->setAttribute('stderr', $th->getMessage());
+ $execution
+ ->setAttribute('status', 'failed')
+ ->setAttribute('statusCode', $th->getCode())
+ ->setAttribute('stderr', $th->getMessage());
Console::error($th->getMessage());
}
- $execution = Authorization::skip(fn() => $dbForProject->updateDocument('executions', $executionId, $execution));
+ $execution = Authorization::skip(fn () => $dbForProject->updateDocument('executions', $executionId, $execution));
+ /** @var Document $execution */
/** Trigger Webhook */
$executionModel = new Execution();
$executionUpdate = new Event(Event::WEBHOOK_QUEUE_NAME, Event::WEBHOOK_CLASS_NAME);
$executionUpdate
- ->setParam('projectId', $projectId)
- ->setParam('userId', $userId)
- ->setParam('webhooks', $webhooks)
- ->setParam('event', 'functions.executions.update')
- ->setParam('eventData', $execution->getArrayCopy(array_keys($executionModel->getRules())));
- $executionUpdate->trigger();
+ ->setProject($project)
+ ->setUser($user)
+ ->setEvent('functions.[functionId].executions.[executionId].update')
+ ->setParam('functionId', $function->getId())
+ ->setParam('executionId', $execution->getId())
+ ->setPayload($execution->getArrayCopy(array_keys($executionModel->getRules())))
+ ->trigger();
+
+ /** Trigger Functions */
+ $executionUpdate
+ ->setClass(Event::FUNCTIONS_CLASS_NAME)
+ ->setQueue(Event::FUNCTIONS_QUEUE_NAME)
+ ->trigger();
/** Trigger realtime event */
- $target = Realtime::fromPayload('functions.executions.update', $execution);
+ $allEvents = Event::generateEvents('functions.[functionId].executions.[executionId].update', [
+ 'functionId' => $function->getId(),
+ 'executionId' => $execution->getId()
+ ]);
+ $target = Realtime::fromPayload(
+ // Pass first, most verbose event pattern
+ event: $allEvents[0],
+ payload: $execution
+ );
Realtime::send(
projectId: 'console',
payload: $execution->getArrayCopy(),
- event: 'functions.executions.update',
+ events: $allEvents,
channels: $target['channels'],
roles: $target['roles']
);
Realtime::send(
- projectId: $projectId,
+ projectId: $project->getId(),
payload: $execution->getArrayCopy(),
- event: 'functions.executions.update',
+ events: $allEvents,
channels: $target['channels'],
roles: $target['roles']
);
@@ -349,7 +354,7 @@ class FunctionsV1 extends Worker
$statsd = $register->get('statsd');
$usage = new Stats($statsd);
$usage
- ->setParam('projectId', $projectId)
+ ->setParam('projectId', $project->getId())
->setParam('functionId', $function->getId())
->setParam('functionExecution', 1)
->setParam('functionStatus', $execution->getAttribute('status', ''))
@@ -357,7 +362,6 @@ class FunctionsV1 extends Worker
->setParam('networkRequestSize', 0)
->setParam('networkResponseSize', 0)
->submit();
- $usage->submit();
}
}
diff --git a/app/workers/mails.php b/app/workers/mails.php
index 6905593a8..8c78ff900 100644
--- a/app/workers/mails.php
+++ b/app/workers/mails.php
@@ -4,6 +4,7 @@ use Appwrite\Resque\Worker;
use Appwrite\Template\Template;
use Utopia\App;
use Utopia\CLI\Console;
+use Utopia\Database\Document;
use Utopia\Locale\Locale;
require_once __DIR__ . '/../init.php';
@@ -30,19 +31,23 @@ class MailsV1 extends Worker
return;
}
+ $project = new Document($this->args['project']);
+ $user = new Document($this->args['user'] ?? []);
+ $team = new Document($this->args['team'] ?? []);
+
$recipient = $this->args['recipient'];
- $name = $this->args['name'];
$url = $this->args['url'];
- $project = $this->args['project'];
+ $name = $this->args['name'];
$type = $this->args['type'];
$prefix = $this->getPrefix($type);
$locale = new Locale($this->args['locale']);
+ $projectName = $project->getAttribute('name', '[APP-NAME]');
if (!$this->doesLocaleExist($locale, $prefix)) {
$locale->setDefault('en');
}
- $from = $this->args['from'] === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $project);
+ $from = $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName);
$body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl');
$subject = '';
switch ($type) {
@@ -57,9 +62,9 @@ class MailsV1 extends Worker
$body->setParam('{{attempt}}', $attempt);
break;
case MAIL_TYPE_INVITATION:
- $subject = \sprintf($locale->getText("$prefix.subject"), $this->args['team'], $project);
- $body->setParam('{{owner}}', $this->args['owner']);
- $body->setParam('{{team}}', $this->args['team']);
+ $subject = \sprintf($locale->getText("$prefix.subject"), $team->getAttribute('name'), $projectName);
+ $body->setParam('{{owner}}', $user->getAttribute('name'));
+ $body->setParam('{{team}}', $team->getAttribute('name'));
break;
case MAIL_TYPE_RECOVERY:
case MAIL_TYPE_VERIFICATION:
@@ -79,7 +84,7 @@ class MailsV1 extends Worker
->setParam('{{footer}}', $locale->getText("$prefix.footer"))
->setParam('{{thanks}}', $locale->getText("$prefix.thanks"))
->setParam('{{signature}}', $locale->getText("$prefix.signature"))
- ->setParam('{{project}}', $project)
+ ->setParam('{{project}}', $projectName)
->setParam('{{direction}}', $locale->getText('settings.direction'))
->setParam('{{bg-body}}', '#f7f7f7')
->setParam('{{bg-content}}', '#ffffff')
diff --git a/app/workers/webhooks.php b/app/workers/webhooks.php
index 861347221..e44881c1b 100644
--- a/app/workers/webhooks.php
+++ b/app/workers/webhooks.php
@@ -3,15 +3,19 @@
use Appwrite\Resque\Worker;
use Utopia\App;
use Utopia\CLI\Console;
+use Utopia\Database\Document;
-require_once __DIR__.'/../init.php';
+require_once __DIR__ . '/../init.php';
Console::title('Webhooks V1 Worker');
Console::success(APP_NAME . ' webhooks worker v1 has started');
class WebhooksV1 extends Worker
{
- public function getName(): string {
+ protected array $errors = [];
+
+ public function getName(): string
+ {
return "webhooks";
}
@@ -21,77 +25,72 @@ class WebhooksV1 extends Worker
public function run(): void
{
- $errors = [];
+ $events = $this->args['events'];
+ $payload = json_encode($this->args['payload']);
+ $project = new Document($this->args['project']);
+ $user = new Document($this->args['user'] ?? []);
- // Event
- $projectId = $this->args['projectId'] ?? '';
- $webhooks = $this->args['webhooks'] ?? [];
- $userId = $this->args['userId'] ?? '';
- $event = $this->args['event'] ?? '';
- $eventData = \json_encode($this->args['eventData']);
-
- foreach ($webhooks as $webhook) {
- if (!(isset($webhook['events']) && \is_array($webhook['events']) && \in_array($event, $webhook['events']))) {
- continue;
+ foreach ($project->getAttribute('webhooks', []) as $webhook) {
+ if (array_intersect($webhook->getAttribute('events', []), $events)) {
+ $this->execute($events, $payload, $webhook, $user, $project);
}
-
- $id = $webhook['$id'] ?? '';
- $name = $webhook['name'] ?? '';
- $signature = $webhook['signature'] ?? 'not-yet-implemented';
- $url = $webhook['url'] ?? '';
- $security = (bool) ($webhook['security'] ?? true);
- $httpUser = $webhook['httpUser'] ?? null;
- $httpPass = $webhook['httpPass'] ?? null;
-
- $ch = \curl_init($url);
-
- \curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
- \curl_setopt($ch, CURLOPT_POSTFIELDS, $eventData);
- \curl_setopt($ch, CURLOPT_HEADER, 0);
- \curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
- \curl_setopt($ch, CURLOPT_USERAGENT, \sprintf(
- APP_USERAGENT,
- App::getEnv('_APP_VERSION', 'UNKNOWN'),
- App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS', APP_EMAIL_SECURITY)
- ));
- \curl_setopt(
- $ch,
- CURLOPT_HTTPHEADER,
- [
- 'Content-Type: application/json',
- 'Content-Length: ' . \strlen($eventData),
- 'X-' . APP_NAME . '-Webhook-Id: ' . $id,
- 'X-' . APP_NAME . '-Webhook-Event: ' . $event,
- 'X-' . APP_NAME . '-Webhook-Name: ' . $name,
- 'X-' . APP_NAME . '-Webhook-User-Id: ' . $userId,
- 'X-' . APP_NAME . '-Webhook-Project-Id: ' . $projectId,
- 'X-' . APP_NAME . '-Webhook-Signature: ' . $signature,
- ]
- );
-
- if (!$security) {
- \curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
- \curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
- }
-
- if (!empty($httpUser) && !empty($httpPass)) {
- \curl_setopt($ch, CURLOPT_USERPWD, "$httpUser:$httpPass");
- \curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
- }
-
- if (false === \curl_exec($ch)) {
- $errors[] = \curl_error($ch) . ' in event ' . $event . ' for webhook ' . $name;
- }
-
- \curl_close($ch);
}
- if (!empty($errors)) {
- throw new Exception(\implode(" / \n\n", $errors));
+ if (!empty($this->errors)) {
+ throw new Exception(\implode(" / \n\n", $this->errors));
}
}
+ protected function execute(array $events, string $payload, Document $webhook, Document $user, Document $project): void
+ {
+ $httpUser = $webhook->getAttribute('httpUser');
+ $httpPass = $webhook->getAttribute('httpPass');
+
+ $ch = \curl_init($webhook->getAttribute('url'));
+
+ \curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
+ \curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
+ \curl_setopt($ch, CURLOPT_HEADER, 0);
+ \curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ \curl_setopt($ch, CURLOPT_USERAGENT, \sprintf(
+ APP_USERAGENT,
+ App::getEnv('_APP_VERSION', 'UNKNOWN'),
+ App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS', APP_EMAIL_SECURITY)
+ ));
+ \curl_setopt(
+ $ch,
+ CURLOPT_HTTPHEADER,
+ [
+ 'Content-Type: application/json',
+ 'Content-Length: ' . \strlen($payload),
+ 'X-' . APP_NAME . '-Webhook-Id: ' . $webhook->getId(),
+ 'X-' . APP_NAME . '-Webhook-Events: ' . implode(',', $events),
+ 'X-' . APP_NAME . '-Webhook-Name: ' . $webhook->getAttribute('name', ''),
+ 'X-' . APP_NAME . '-Webhook-User-Id: ' . $user->getId(),
+ 'X-' . APP_NAME . '-Webhook-Project-Id: ' . $project->getId(),
+ 'X-' . APP_NAME . '-Webhook-Signature: ' . $webhook->getAttribute('signature', 'not-yet-implemented'),
+ ]
+ );
+
+ if (!$webhook->getAttribute('security', true)) {
+ \curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+ \curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ }
+
+ if (!empty($httpUser) && !empty($httpPass)) {
+ \curl_setopt($ch, CURLOPT_USERPWD, "$httpUser:$httpPass");
+ \curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+ }
+
+ if (false === \curl_exec($ch)) {
+ $this->errors[] = \curl_error($ch) . ' in events ' . implode(', ', $events) . ' for webhook ' . $webhook->getAttribute('name');
+ }
+
+ \curl_close($ch);
+ }
+
public function shutdown(): void
{
+ $this->errors = [];
}
}
diff --git a/composer.json b/composer.json
index 75bab2aed..71a810ac7 100644
--- a/composer.json
+++ b/composer.json
@@ -45,7 +45,7 @@
"utopia-php/cache": "0.6.*",
"utopia-php/cli": "0.12.*",
"utopia-php/config": "0.2.*",
- "utopia-php/database": "0.15.*",
+ "utopia-php/database": "0.16.*",
"utopia-php/locale": "0.4.*",
"utopia-php/registry": "0.5.*",
"utopia-php/preloader": "0.2.*",
diff --git a/composer.lock b/composer.lock
index c2b51c52d..751b5bbf2 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": "78c5402d7bf745469d0063a9bc955df0",
+ "content-hash": "23a43ddfd26689ff154463410f7da3a4",
"packages": [
{
"name": "adhocore/jwt",
@@ -2133,16 +2133,16 @@
},
{
"name": "utopia-php/database",
- "version": "0.15.5",
+ "version": "0.16.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
- "reference": "6507b58ef3e22703b9df68d3dbd5e822d5bb023f"
+ "reference": "7c484e2f71c551d2f8f43bf721938af3726c7455"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/database/zipball/6507b58ef3e22703b9df68d3dbd5e822d5bb023f",
- "reference": "6507b58ef3e22703b9df68d3dbd5e822d5bb023f",
+ "url": "https://api.github.com/repos/utopia-php/database/zipball/7c484e2f71c551d2f8f43bf721938af3726c7455",
+ "reference": "7c484e2f71c551d2f8f43bf721938af3726c7455",
"shasum": ""
},
"require": {
@@ -2190,9 +2190,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
- "source": "https://github.com/utopia-php/database/tree/0.15.5"
+ "source": "https://github.com/utopia-php/database/tree/0.16.0"
},
- "time": "2022-04-04T13:42:00+00:00"
+ "time": "2022-05-08T16:07:02+00:00"
},
{
"name": "utopia-php/domains",
@@ -6576,5 +6576,5 @@
"platform-overrides": {
"php": "8.0"
},
- "plugin-api-version": "2.3.0"
+ "plugin-api-version": "2.1.0"
}
diff --git a/phpunit.xml b/phpunit.xml
index 2fbb75e22..9f5e42b84 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -29,7 +29,6 @@
./tests/e2e/Services/Storage
./tests/e2e/Services/Teams
./tests/e2e/Services/Users
- ./tests/e2e/Services/Workers
./tests/e2e/Services/Webhooks
./tests/e2e/Services/Functions/FunctionsBase.php
./tests/e2e/Services/Functions/FunctionsCustomServerTest.php
diff --git a/public/dist/scripts/app-all.js b/public/dist/scripts/app-all.js
index 10fd74576..a973062ef 100644
--- a/public/dist/scripts/app-all.js
+++ b/public/dist/scripts/app-all.js
@@ -3838,8 +3838,8 @@ list["filters-"+filter.key]=params[key][i];}}}}
return list;};let apply=function(params){let cached=container.get(name);cached=cached?cached.params:[];params=Object.assign(cached,params);container.set(name,{name:name,params:params,query:serialize(params),forward:parseInt(params.offset)+parseInt(params.limit),backward:parseInt(params.offset)-parseInt(params.limit),keys:flatten(params)},true,name);document.dispatchEvent(new CustomEvent(name+"-changed",{bubbles:false,cancelable:true}));};switch(element.tagName){case"INPUT":break;case"TEXTAREA":break;case"BUTTON":element.addEventListener("click",function(){apply(JSON.parse(expression.parse(element.dataset["params"]||"{}")));});break;case"FORM":element.addEventListener("input",function(){apply(form.toJson(element));});element.addEventListener("change",function(){apply(form.toJson(element));});element.addEventListener("reset",function(){setTimeout(function(){apply(form.toJson(element));},0);});events=events.trim().split(",");for(let y=0;y=distance)&&(distance>=0)){if(minLink){minLink.classList.remove('selected');}
-console.log('old',minLink);minDistance=distance;minElement=title;minLink=links[i];minLink.classList.add('selected');console.log('new',minLink);}}};window.addEventListener('scroll',check);check();}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-oauth-custom",controller:function(element){let providers={"Microsoft":{"clientSecret":"oauth2MicrosoftClientSecret","tenantID":"oauth2MicrosoftTenantId"},"Apple":{"keyID":"oauth2AppleKeyId","teamID":"oauth2AppleTeamId","p8":"oauth2AppleP8"}}
-let provider=element.getAttribute("data-forms-oauth-custom");if(!provider||!providers.hasOwnProperty(provider)){console.error("Provider for custom form not set or unkown")}
+console.log('old',minLink);minDistance=distance;minElement=title;minLink=links[i];minLink.classList.add('selected');console.log('new',minLink);}}};window.addEventListener('scroll',check);check();}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-oauth-custom",controller:function(element){let providers={"Microsoft":{"clientSecret":"oauth2MicrosoftClientSecret","tenantID":"oauth2MicrosoftTenantId"},"Apple":{"keyID":"oauth2AppleKeyId","teamID":"oauth2AppleTeamId","p8":"oauth2AppleP8"},"Okta":{"clientSecret":"oauth2OktaClientSecret","oktaDomain":"oauth2OktaDomain","authorizationServerId":"oauth2OktaAuthorizationServerId"},"Auth0":{"clientSecret":"oauth2Auth0ClientSecret","auth0Domain":"oauth2Auth0Domain"}}
+let provider=element.getAttribute("data-forms-oauth-custom");if(!provider||!providers.hasOwnProperty(provider)){console.error("Provider for custom form not set or unknown")}
let config=providers[provider];element.addEventListener('change',sync);let elements={};for(const key in config){if(Object.hasOwnProperty.call(config,key)){elements[key]=document.getElementById(config[key]);elements[key].addEventListener('change',update);}}
function update(){let json={};for(const key in elements){if(Object.hasOwnProperty.call(elements,key)){json[key]=elements[key].value}}
element.value=JSON.stringify(json);}
diff --git a/public/dist/scripts/app.js b/public/dist/scripts/app.js
index 7240e243c..454c8586e 100644
--- a/public/dist/scripts/app.js
+++ b/public/dist/scripts/app.js
@@ -785,8 +785,8 @@ list["filters-"+filter.key]=params[key][i];}}}}
return list;};let apply=function(params){let cached=container.get(name);cached=cached?cached.params:[];params=Object.assign(cached,params);container.set(name,{name:name,params:params,query:serialize(params),forward:parseInt(params.offset)+parseInt(params.limit),backward:parseInt(params.offset)-parseInt(params.limit),keys:flatten(params)},true,name);document.dispatchEvent(new CustomEvent(name+"-changed",{bubbles:false,cancelable:true}));};switch(element.tagName){case"INPUT":break;case"TEXTAREA":break;case"BUTTON":element.addEventListener("click",function(){apply(JSON.parse(expression.parse(element.dataset["params"]||"{}")));});break;case"FORM":element.addEventListener("input",function(){apply(form.toJson(element));});element.addEventListener("change",function(){apply(form.toJson(element));});element.addEventListener("reset",function(){setTimeout(function(){apply(form.toJson(element));},0);});events=events.trim().split(",");for(let y=0;y=distance)&&(distance>=0)){if(minLink){minLink.classList.remove('selected');}
-console.log('old',minLink);minDistance=distance;minElement=title;minLink=links[i];minLink.classList.add('selected');console.log('new',minLink);}}};window.addEventListener('scroll',check);check();}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-oauth-custom",controller:function(element){let providers={"Microsoft":{"clientSecret":"oauth2MicrosoftClientSecret","tenantID":"oauth2MicrosoftTenantId"},"Apple":{"keyID":"oauth2AppleKeyId","teamID":"oauth2AppleTeamId","p8":"oauth2AppleP8"}}
-let provider=element.getAttribute("data-forms-oauth-custom");if(!provider||!providers.hasOwnProperty(provider)){console.error("Provider for custom form not set or unkown")}
+console.log('old',minLink);minDistance=distance;minElement=title;minLink=links[i];minLink.classList.add('selected');console.log('new',minLink);}}};window.addEventListener('scroll',check);check();}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-oauth-custom",controller:function(element){let providers={"Microsoft":{"clientSecret":"oauth2MicrosoftClientSecret","tenantID":"oauth2MicrosoftTenantId"},"Apple":{"keyID":"oauth2AppleKeyId","teamID":"oauth2AppleTeamId","p8":"oauth2AppleP8"},"Okta":{"clientSecret":"oauth2OktaClientSecret","oktaDomain":"oauth2OktaDomain","authorizationServerId":"oauth2OktaAuthorizationServerId"},"Auth0":{"clientSecret":"oauth2Auth0ClientSecret","auth0Domain":"oauth2Auth0Domain"}}
+let provider=element.getAttribute("data-forms-oauth-custom");if(!provider||!providers.hasOwnProperty(provider)){console.error("Provider for custom form not set or unknown")}
let config=providers[provider];element.addEventListener('change',sync);let elements={};for(const key in config){if(Object.hasOwnProperty.call(config,key)){elements[key]=document.getElementById(config[key]);elements[key].addEventListener('change',update);}}
function update(){let json={};for(const key in elements){if(Object.hasOwnProperty.call(elements,key)){json[key]=elements[key].value}}
element.value=JSON.stringify(json);}
diff --git a/src/Appwrite/Event/Audit.php b/src/Appwrite/Event/Audit.php
new file mode 100644
index 000000000..b2d34424e
--- /dev/null
+++ b/src/Appwrite/Event/Audit.php
@@ -0,0 +1,130 @@
+resource = $resource;
+
+ return $this;
+ }
+
+ /**
+ * Returns the set audit resource.
+ *
+ * @return string
+ */
+ public function getResource(): string
+ {
+ return $this->resource;
+ }
+
+ /**
+ * Set mode for this audit event
+ *
+ * @param string $mode
+ * @return self
+ */
+ public function setMode(string $mode): self
+ {
+ $this->mode = $mode;
+
+ return $this;
+ }
+
+ /**
+ * Returns the set audit mode.
+ *
+ * @return string
+ */
+ public function getMode(): string
+ {
+ return $this->mode;
+ }
+
+ /**
+ * Set user agent for this audit event.
+ *
+ * @param string $userAgent
+ * @return self
+ */
+ public function setUserAgent(string $userAgent): self
+ {
+ $this->userAgent = $userAgent;
+
+ return $this;
+ }
+
+ /**
+ * Returns the set audit user agent.
+ *
+ * @return string
+ */
+ public function getUserAgent(): string
+ {
+ return $this->userAgent;
+ }
+
+ /**
+ * Set IP for this audit event.
+ *
+ * @param string $ip
+ * @return self
+ */
+ public function setIP(string $ip): self
+ {
+ $this->ip = $ip;
+
+ return $this;
+ }
+
+ /**
+ * Returns the set audit IP.
+ *
+ * @return string
+ */
+ public function getIP(): string
+ {
+ return $this->ip;
+ }
+
+ /**
+ * Executes the event and sends it to the audit worker.
+ *
+ * @return string|bool
+ * @throws \InvalidArgumentException
+ */
+ public function trigger(): string|bool
+ {
+ return Resque::enqueue($this->queue, $this->class, [
+ 'project' => $this->project,
+ 'user' => $this->user,
+ 'payload' => $this->payload,
+ 'resource' => $this->resource,
+ 'mode' => $this->mode,
+ 'ip' => $this->ip,
+ 'userAgent' => $this->userAgent,
+ 'events' => Event::generateEvents($this->getEvent(), $this->getParams())
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/src/Appwrite/Event/Build.php b/src/Appwrite/Event/Build.php
new file mode 100644
index 000000000..970de8265
--- /dev/null
+++ b/src/Appwrite/Event/Build.php
@@ -0,0 +1,103 @@
+resource = $resource;
+
+ return $this;
+ }
+
+ /**
+ * Returns set resource document for the build event.
+ *
+ * @return null|Document
+ */
+ public function getResource(): ?Document
+ {
+ return $this->resource;
+ }
+
+ /**
+ * Sets deployment for the build event.
+ *
+ * @param Document $deployment
+ * @return self
+ */
+ public function setDeployment(Document $deployment): self
+ {
+ $this->deployment = $deployment;
+
+ return $this;
+ }
+
+ /**
+ * Returns set deployment for the build event.
+ *
+ * @return null|Document
+ */
+ public function getDeployment(): ?Document
+ {
+ return $this->deployment;
+ }
+
+ /**
+ * Sets type for the build event.
+ *
+ * @param string $type Can be `BUILD_TYPE_DEPLOYMENT` or `BUILD_TYPE_RETRY`.
+ * @return self
+ */
+ public function setType(string $type): self
+ {
+ $this->type = $type;
+
+ return $this;
+ }
+
+ /**
+ * Returns set type for the function event.
+ *
+ * @return string
+ */
+ public function getType(): string
+ {
+ return $this->type;
+ }
+
+ /**
+ * Executes the function event and sends it to the functions worker.
+ *
+ * @return string|bool
+ * @throws \InvalidArgumentException
+ */
+ public function trigger(): string|bool
+ {
+ return Resque::enqueue($this->queue, $this->class, [
+ 'project' => $this->project,
+ 'resource' => $this->resource,
+ 'deployment' => $this->deployment,
+ 'type' => $this->type
+ ]);
+ }
+}
diff --git a/src/Appwrite/Event/Certificate.php b/src/Appwrite/Event/Certificate.php
new file mode 100644
index 000000000..894c09496
--- /dev/null
+++ b/src/Appwrite/Event/Certificate.php
@@ -0,0 +1,79 @@
+domain = $domain;
+
+ return $this;
+ }
+
+ /**
+ * Returns the set domain for this certificate event.
+ *
+ * @return null|Document
+ */
+ public function getDomain(): ?Document
+ {
+ return $this->domain;
+ }
+
+ /**
+ * Set if the certificate needs to be validated.
+ *
+ * @param bool $skipRenewCheck
+ * @return self
+ */
+ public function setSkipRenewCheck(bool $skipRenewCheck): self
+ {
+ $this->skipRenewCheck = $skipRenewCheck;
+
+ return $this;
+ }
+
+ /**
+ * Return if the certificate needs be validated.
+ *
+ * @return bool
+ */
+ public function getSkipRenewCheck(): bool
+ {
+ return $this->skipRenewCheck;
+ }
+
+ /**
+ * Executes the event and sends it to the certificates worker.
+ *
+ * @return string|bool
+ * @throws \InvalidArgumentException
+ */
+ public function trigger(): string|bool
+ {
+ return Resque::enqueue($this->queue, $this->class, [
+ 'project' => $this->project,
+ 'domain' => $this->domain,
+ 'validateTarget' => $this->validateTarget,
+ 'validateCNAME' => $this->validateCNAME
+ ]);
+ }
+}
diff --git a/src/Appwrite/Event/Database.php b/src/Appwrite/Event/Database.php
new file mode 100644
index 000000000..5e5e68785
--- /dev/null
+++ b/src/Appwrite/Event/Database.php
@@ -0,0 +1,103 @@
+type = $type;
+
+ return $this;
+ }
+
+ /**
+ * Returns the set type for the database event.
+ * @return string
+ */
+ public function getType(): string
+ {
+ return $this->type;
+ }
+
+ /**
+ * Set the collection for this database event.
+ *
+ * @param Document $collection
+ * @return self
+ */
+ public function setCollection(Document $collection): self
+ {
+ $this->collection = $collection;
+
+ return $this;
+ }
+
+ /**
+ * Returns set collection for this event.
+ *
+ * @return null|Document
+ */
+ public function getCollection(): ?Document
+ {
+ return $this->collection;
+ }
+
+ /**
+ * Set the document for this database event.
+ *
+ * @param Document $document
+ * @return self
+ */
+ public function setDocument(Document $document): self
+ {
+ $this->document = $document;
+
+ return $this;
+ }
+
+ /**
+ * Returns set document for this database event.
+ * @return null|Document
+ */
+ public function getDocument(): ?Document
+ {
+ return $this->document;
+ }
+
+ /**
+ * Executes the event and send it to the database worker.
+ *
+ * @return string|bool
+ * @throws \InvalidArgumentException
+ */
+ public function trigger(): string|bool
+ {
+ return Resque::enqueue($this->queue, $this->class, [
+ 'project' => $this->project,
+ 'user' => $this->user,
+ 'type' => $this->type,
+ 'collection' => $this->collection,
+ 'document' => $this->document,
+ 'events' => Event::generateEvents($this->getEvent(), $this->getParams())
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/src/Appwrite/Event/Delete.php b/src/Appwrite/Event/Delete.php
new file mode 100644
index 000000000..1c2be4b01
--- /dev/null
+++ b/src/Appwrite/Event/Delete.php
@@ -0,0 +1,123 @@
+type = $type;
+
+ return $this;
+ }
+
+ /**
+ * Returns the set type for the delete event.
+ *
+ * @return string
+ */
+ public function getType(): string
+ {
+ return $this->type;
+ }
+
+ /**
+ * Set timestamp.
+ *
+ * @param int $timestamp
+ * @return self
+ */
+ public function setTimestamp(int $timestamp): self
+ {
+ $this->timestamp = $timestamp;
+
+ return $this;
+ }
+
+ /**
+ * Set timestamp for 1 day interval.
+ *
+ * @param int $timestamp
+ * @return self
+ */
+ public function setTimestamp1d(int $timestamp): self
+ {
+ $this->timestamp1d = $timestamp;
+
+ return $this;
+ }
+
+ /**
+ * Sets timestamp for 30m interval.
+ *
+ * @param int $timestamp
+ * @return self
+ */
+ public function setTimestamp30m(int $timestamp): self
+ {
+ $this->timestamp30m = $timestamp;
+
+ return $this;
+ }
+
+ /**
+ * Sets the document for the delete event.
+ *
+ * @param Document $document
+ * @return self
+ */
+ public function setDocument(Document $document): self
+ {
+ $this->document = $document;
+
+ return $this;
+ }
+
+ /**
+ * Returns the set document for the delete event.
+ *
+ * @return null|Document
+ */
+ public function getDocument(): ?Document
+ {
+ return $this->document;
+ }
+
+ /**
+ * Executes this event and sends it to the deletes worker.
+ *
+ * @return string|bool
+ * @throws \InvalidArgumentException
+ */
+ public function trigger(): string|bool
+ {
+ return Resque::enqueue($this->queue, $this->class, [
+ 'project' => $this->project,
+ 'type' => $this->type,
+ 'document' => $this->document,
+ 'timestamp' => $this->timestamp,
+ 'timestamp1d' => $this->timestamp1d,
+ 'timestamp30m' => $this->timestamp30m
+ ]);
+ }
+}
diff --git a/src/Appwrite/Event/Event.php b/src/Appwrite/Event/Event.php
index 4b15f5d04..871c4c4f4 100644
--- a/src/Appwrite/Event/Event.php
+++ b/src/Appwrite/Event/Event.php
@@ -2,12 +2,13 @@
namespace Appwrite\Event;
+use InvalidArgumentException;
use Resque;
+use Utopia\Database\Document;
class Event
{
-
- const DATABASE_QUEUE_NAME= 'v1-database';
+ const DATABASE_QUEUE_NAME = 'v1-database';
const DATABASE_CLASS_NAME = 'DatabaseV1';
const DELETE_QUEUE_NAME = 'v1-deletes';
@@ -30,27 +31,20 @@ class Event
const BUILDS_QUEUE_NAME = 'v1-builds';
const BUILDS_CLASS_NAME = 'BuildsV1';
-
- /**
- * @var string
- */
- protected $queue = '';
+
+ protected string $queue = '';
+ protected string $class = '';
+ protected string $event = '';
+ protected array $params = [];
+ protected array $payload = [];
+ protected ?Document $project = null;
+ protected ?Document $user = null;
+ protected ?Document $context = null;
/**
- * @var string
- */
- protected $class = '';
-
- /**
- * @var array
- */
- protected $params = [];
-
- /**
- * Event constructor.
- *
* @param string $queue
* @param string $class
+ * @return void
*/
public function __construct(string $queue, string $class)
{
@@ -59,48 +53,172 @@ class Event
}
/**
+ * Set queue used for this event.
+ *
* @param string $queue
- * return $this
+ * @return Event
*/
public function setQueue(string $queue): self
{
$this->queue = $queue;
+
return $this;
}
/**
+ * Get queue used for this event.
+ *
* @return string
*/
- public function getQueue()
+ public function getQueue(): string
{
return $this->queue;
}
/**
- * @param string $class
- * return $this
+ * Set event name used for this event.
+ * @param string $event
+ * @return Event
*/
- public function setClass(string $class): self
+ public function setEvent(string $event): self
{
- $this->class = $class;
+ $this->event = $event;
+
return $this;
}
/**
+ * Get event name used for this event.
+ *
* @return string
*/
- public function getClass()
+ public function getEvent(): string
+ {
+ return $this->event;
+ }
+
+ /**
+ * Set project for this event.
+ *
+ * @param Document $project
+ * @return self
+ */
+ public function setProject(Document $project): self
+ {
+ $this->project = $project;
+
+ return $this;
+ }
+
+ /**
+ * Get project for this event.
+ *
+ * @return Document
+ */
+ public function getProject(): Document
+ {
+ return $this->project;
+ }
+
+ /**
+ * Set user for this event.
+ *
+ * @param Document $user
+ * @return self
+ */
+ public function setUser(Document $user): self
+ {
+ $this->user = $user;
+
+ return $this;
+ }
+
+ /**
+ * Get project for this event.
+ *
+ * @return Document
+ */
+ public function getUser(): Document
+ {
+ return $this->user;
+ }
+
+ /**
+ * Set payload for this event.
+ *
+ * @param Document $payload
+ * @return self
+ */
+ public function setPayload(array $payload): self
+ {
+ $this->payload = $payload;
+
+ return $this;
+ }
+
+ /**
+ * Get payload for this event.
+ *
+ * @return Document
+ */
+ public function getPayload(): array
+ {
+ return $this->payload;
+ }
+
+ /**
+ * Set context for this event.
+ *
+ * @param Document $context
+ * @return self
+ */
+ public function setContext(Document $context): self
+ {
+ $this->context = $context;
+
+ return $this;
+ }
+
+ /**
+ * Get context for this event.
+ *
+ * @return Document
+ */
+ public function getContext(): ?Document
+ {
+ return $this->context;
+ }
+
+ /**
+ * Set class used for this event.
+ * @param string $class
+ * @return self
+ */
+ public function setClass(string $class): self
+ {
+ $this->class = $class;
+
+ return $this;
+ }
+
+ /**
+ * Get class used for this event.
+ *
+ * @return string
+ */
+ public function getClass(): string
{
return $this->class;
}
/**
- * @param string $key
- * @param mixed $value
+ * Set param of event.
*
- * @return $this
+ * @param string $key
+ * @param mixed $value
+ * @return self
*/
- public function setParam(string $key, $value): self
+ public function setParam(string $key, mixed $value): self
{
$this->params[$key] = $value;
@@ -108,29 +226,186 @@ class Event
}
/**
- * @param string $key
+ * Get param of event.
*
- * @return mixed|null
+ * @param string $key
+ * @return mixed
*/
- public function getParam(string $key)
+ public function getParam(string $key): mixed
{
- return (isset($this->params[$key])) ? $this->params[$key] : null;
+ return $this->params[$key] ?? null;
+ }
+
+ /**
+ * Get all params of the event.
+ *
+ * @return array
+ */
+ public function getParams(): array
+ {
+ return $this->params;
}
/**
* Execute Event.
+ *
+ * @return string|bool
+ * @throws InvalidArgumentException
*/
- public function trigger(): void
+ public function trigger(): string|bool
{
- Resque::enqueue($this->queue, $this->class, $this->params);
-
- $this->reset();
+ return Resque::enqueue($this->queue, $this->class, [
+ 'project' => $this->project,
+ 'user' => $this->user,
+ 'payload' => $this->payload,
+ 'context' => $this->context,
+ 'events' => Event::generateEvents($this->getEvent(), $this->getParams())
+ ]);
}
+ /**
+ * Resets event.
+ *
+ * @return self
+ */
public function reset(): self
{
$this->params = [];
return $this;
}
+
+ /**
+ * Parses event pattern and returns the parts in their respective section.
+ *
+ * @param string $pattern
+ * @return array
+ */
+ public static function parseEventPattern(string $pattern): array
+ {
+ $parts = \explode('.', $pattern);
+ $count = \count($parts);
+
+ /**
+ * Identify all sections of the pattern.
+ */
+ $type = $parts[0] ?? false;
+ $resource = $parts[1] ?? false;
+ $hasSubResource = $count > 3 && \str_starts_with($parts[3], '[');
+
+ if ($hasSubResource) {
+ $subType = $parts[2];
+ $subResource = $parts[3];
+ if ($count === 6) {
+ $attribute = $parts[5];
+ }
+ } else {
+ if ($count === 4) {
+ $attribute = $parts[3];
+ }
+ }
+
+ $subType ??= false;
+ $subResource ??= false;
+ $attribute ??= false;
+ $action = match (true) {
+ !$hasSubResource && $count > 2 => $parts[2],
+ $hasSubResource && $count > 4 => $parts[4],
+ default => false
+ };
+
+ return [
+ 'type' => $type,
+ 'resource' => $resource,
+ 'subType' => $subType,
+ 'subResource' => $subResource,
+ 'action' => $action,
+ 'attribute' => $attribute,
+ ];
+ }
+
+ /**
+ * Generates all possible events from a pattern.
+ *
+ * @param string $pattern
+ * @param array $params
+ * @return array
+ * @throws \InvalidArgumentException
+ */
+ static function generateEvents(string $pattern, array $params = []): array
+ {
+ // $params = \array_filter($params, fn($param) => !\is_array($param));
+ $paramKeys = \array_keys($params);
+ $paramValues = \array_values($params);
+
+ $patterns = [];
+
+ $parsed = self::parseEventPattern($pattern);
+ $type = $parsed['type'];
+ $resource = $parsed['resource'];
+ $subType = $parsed['subType'];
+ $subResource = $parsed['subResource'];
+ $action = $parsed['action'];
+ $attribute = $parsed['attribute'];
+
+ if ($resource && !\in_array(\trim($resource, "\[\]"), $paramKeys)) {
+ throw new InvalidArgumentException("{$resource} is missing from the params.");
+ }
+
+ if ($subResource && !\in_array(\trim($subResource, "\[\]"), $paramKeys)) {
+ throw new InvalidArgumentException("{$subResource} is missing from the params.");
+ }
+
+ /**
+ * Create all possible patterns including placeholders.
+ */
+ if ($action) {
+ if ($subResource) {
+ if ($attribute) {
+ $patterns[] = \implode('.', [$type, $resource, $subType, $subResource, $action, $attribute]);
+ }
+ $patterns[] = \implode('.', [$type, $resource, $subType, $subResource, $action]);
+ $patterns[] = \implode('.', [$type, $resource, $subType, $subResource]);
+ } else {
+ $patterns[] = \implode('.', [$type, $resource, $action]);
+ }
+ if ($attribute) {
+ $patterns[] = \implode('.', [$type, $resource, $action, $attribute]);
+ }
+ }
+ if ($subResource) {
+ $patterns[] = \implode('.', [$type, $resource, $subType, $subResource]);
+ }
+ $patterns[] = \implode('.', [$type, $resource]);
+
+ /**
+ * Removes all duplicates.
+ */
+ $patterns = \array_unique($patterns);
+
+ /**
+ * Set all possible values of the patterns and replace placeholders.
+ */
+ $events = [];
+ foreach ($patterns as $eventPattern) {
+ $events[] = \str_replace($paramKeys, $paramValues, $eventPattern);
+ $events[] = \str_replace($paramKeys, '*', $eventPattern);
+ foreach ($paramKeys as $key) {
+ foreach ($paramKeys as $current) {
+ if ($current === $key) continue;
+
+ $filtered = \array_filter($paramKeys, fn(string $k) => $k === $current);
+ $events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered, '*', $eventPattern));
+ }
+ }
+ }
+
+ /**
+ * Remove [] from the events.
+ */
+ $events = \array_map(fn (string $event) => \str_replace(['[', ']'], '', $event), $events);
+ $events = \array_unique($events);
+
+ return $events;
+ }
}
diff --git a/src/Appwrite/Event/Func.php b/src/Appwrite/Event/Func.php
new file mode 100644
index 000000000..98652431f
--- /dev/null
+++ b/src/Appwrite/Event/Func.php
@@ -0,0 +1,178 @@
+function = $function;
+
+ return $this;
+ }
+
+ /**
+ * Returns set function document for the function event.
+ *
+ * @return null|Document
+ */
+ public function getFunction(): ?Document
+ {
+ return $this->function;
+ }
+
+ /**
+ * Sets execution for the function event.
+ *
+ * @param Document $execution
+ * @return self
+ */
+ public function setExecution(Document $execution): self
+ {
+ $this->execution = $execution;
+
+ return $this;
+ }
+
+ /**
+ * Returns set execution for the function event.
+ *
+ * @return null|Document
+ */
+ public function getExecution(): ?Document
+ {
+ return $this->execution;
+ }
+
+ /**
+ * Sets type for the function event.
+ *
+ * @param string $type Can be `schedule`, `event` or `http`.
+ * @return self
+ */
+ public function setType(string $type): self
+ {
+ $this->type = $type;
+
+ return $this;
+ }
+
+ /**
+ * Returns set type for the function event.
+ *
+ * @return string
+ */
+ public function getType(): string
+ {
+ return $this->type;
+ }
+
+ /**
+ * Sets custom data for the function event.
+ *
+ * @param string $data
+ * @return self
+ */
+ public function setData(string $data): self
+ {
+ $this->data = $data;
+
+ return $this;
+ }
+
+ /**
+ * Returns set custom data for the function event.
+ *
+ * @return string
+ */
+ public function getData(): string
+ {
+ return $this->data;
+ }
+
+ /**
+ * Sets JWT for the function event.
+ *
+ * @param string $jwt
+ * @return self
+ */
+ public function setJWT(string $jwt): self
+ {
+ $this->jwt = $jwt;
+
+ return $this;
+ }
+
+ /**
+ * Returns set JWT for the function event.
+ *
+ * @return string
+ */
+ public function getJWT(): string
+ {
+ return $this->jwt;
+ }
+
+ /**
+ * Executes the function event and sends it to the functions worker.
+ *
+ * @return string|bool
+ * @throws \InvalidArgumentException
+ */
+ public function trigger(): string|bool
+ {
+ return Resque::enqueue($this->queue, $this->class, [
+ 'project' => $this->project,
+ 'user' => $this->user,
+ 'function' => $this->function,
+ 'execution' => $this->execution,
+ 'type' => $this->type,
+ 'jwt' => $this->jwt,
+ 'payload' => $this->payload,
+ 'data' => $this->data
+ ]);
+ }
+
+ /**
+ * Schedules the function event and schedules it in the functions worker queue.
+ *
+ * @param \DateTime|int $at
+ * @return void
+ * @throws \Resque_Exception
+ * @throws \ResqueScheduler_InvalidTimestampException
+ */
+ public function schedule(DateTime|int $at): void
+ {
+ ResqueScheduler::enqueueAt($at, $this->queue, $this->class, [
+ 'project' => $this->project,
+ 'user' => $this->user,
+ 'function' => $this->function,
+ 'execution' => $this->execution,
+ 'type' => $this->type,
+ 'payload' => $this->payload,
+ 'data' => $this->data
+ ]);
+ }
+}
diff --git a/src/Appwrite/Event/Mail.php b/src/Appwrite/Event/Mail.php
new file mode 100644
index 000000000..b3325c00b
--- /dev/null
+++ b/src/Appwrite/Event/Mail.php
@@ -0,0 +1,181 @@
+team = $team;
+
+ return $this;
+ }
+
+ /**
+ * Returns set team for the mail event.
+ *
+ * @return null|Document
+ */
+ public function getTeam(): ?Document
+ {
+ return $this->team;
+ }
+
+ /**
+ * Sets recipient for the mail event.
+ *
+ * @param string $recipient
+ * @return self
+ */
+ public function setRecipient(string $recipient): self
+ {
+ $this->recipient = $recipient;
+
+ return $this;
+ }
+
+ /**
+ * Returns set recipient for mail event.
+ *
+ * @return string
+ */
+ public function getRecipient(): string
+ {
+ return $this->recipient;
+ }
+
+ /**
+ * Sets url for the mail event.
+ *
+ * @param string $url
+ * @return self
+ */
+ public function setUrl(string $url): self
+ {
+ $this->url = $url;
+
+ return $this;
+ }
+
+ /**
+ * Returns set url for the mail event.
+ *
+ * @return string
+ */
+ public function getURL(): string
+ {
+ return $this->url;
+ }
+
+ /**
+ * Sets type for the mail event (use the constants starting with MAIL_TYPE_*).
+ *
+ * @param string $type
+ * @return self
+ */
+ public function setType(string $type): self
+ {
+ $this->type = $type;
+
+ return $this;
+ }
+
+ /**
+ * Returns set type for the mail event.
+ *
+ * @return string
+ */
+ public function getType(): string
+ {
+ return $this->type;
+ }
+
+ /**
+ * Sets name for the mail event.
+ *
+ * @param string $name
+ * @return self
+ */
+ public function setName(string $name): self
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ /**
+ * Returns set name for the mail event.
+ *
+ * @return string
+ */
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ /**
+ * Sets locale for the mail event.
+ *
+ * @param string $locale
+ * @return self
+ */
+ public function setLocale(string $locale): self
+ {
+ $this->locale = $locale;
+
+ return $this;
+ }
+
+ /**
+ * Returns set locale for the mail event.
+ *
+ * @return string
+ */
+ public function getLocale(): string
+ {
+ return $this->locale;
+ }
+
+ /**
+ * Executes the event and sends it to the mails worker.
+ *
+ * @return string|bool
+ * @throws \InvalidArgumentException
+ */
+ public function trigger(): string|bool
+ {
+ return Resque::enqueue($this->queue, $this->class, [
+ 'project' => $this->project,
+ 'user' => $this->user,
+ 'payload' => $this->payload,
+ 'recipient' => $this->recipient,
+ 'url' => $this->url,
+ 'locale' => $this->locale,
+ 'type' => $this->type,
+ 'name' => $this->name,
+ 'team' => $this->team,
+ 'events' => Event::generateEvents($this->getEvent(), $this->getParams())
+ ]);
+ }
+}
diff --git a/src/Appwrite/Event/Validator/Event.php b/src/Appwrite/Event/Validator/Event.php
new file mode 100644
index 000000000..b68cdfaa0
--- /dev/null
+++ b/src/Appwrite/Event/Validator/Event.php
@@ -0,0 +1,127 @@
+ 6) {
+ return false;
+ }
+
+ /**
+ * Identify all sections of the pattern.
+ */
+ $type = $parts[0] ?? false;
+ $resource = $parts[1] ?? false;
+ $hasSubResource = $count > 3 && ($events[$type]['$resource'] ?? false) && ($events[$type][$parts[2]]['$resource'] ?? false);
+
+ if (!$type || !$resource) {
+ return false;
+ }
+
+ if ($hasSubResource) {
+ $subType = $parts[2];
+ $subResource = $parts[3];
+ if ($count === 6) {
+ $attribute = $parts[5];
+ }
+ } else {
+ if ($count === 4) {
+ $attribute = $parts[3];
+ }
+ }
+
+ $subType ??= false;
+ $subResource ??= false;
+ $attribute ??= false;
+
+ $action = match (true) {
+ !$hasSubResource && $count > 2 => $parts[2],
+ $hasSubResource && $count > 4 => $parts[4],
+ default => false
+ };
+
+ if (!\array_key_exists($type, $events)) {
+ return false;
+ }
+
+ if ($subType) {
+ if ($action && !\array_key_exists($action, $events[$type][$subType])) {
+ return false;
+ }
+ if (!($subResource) || !\array_key_exists($subType, $events[$type])) {
+ return false;
+ }
+ } else {
+ if ($action && !\array_key_exists($action, $events[$type])) {
+ return false;
+ }
+ }
+
+ if ($attribute) {
+ if (($subType)) {
+ if (!\array_key_exists($attribute, $events[$type][$subType][$action])) {
+ return false;
+ }
+ } else {
+ if (!\array_key_exists($attribute, $events[$type][$action])) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Is array
+ *
+ * Function will return true if object is array.
+ *
+ * @return bool
+ */
+ public function isArray(): bool
+ {
+ return false;
+ }
+
+ /**
+ * Get Type
+ *
+ * Returns validator type.
+ *
+ * @return string
+ */
+ public function getType(): string
+ {
+ return self::TYPE_STRING;
+ }
+}
diff --git a/src/Appwrite/Messaging/Adapter.php b/src/Appwrite/Messaging/Adapter.php
index 6ef2d5cfd..191084724 100644
--- a/src/Appwrite/Messaging/Adapter.php
+++ b/src/Appwrite/Messaging/Adapter.php
@@ -6,5 +6,5 @@ abstract class Adapter
{
public abstract function subscribe(string $projectId, mixed $identifier, array $roles, array $channels): void;
public abstract function unsubscribe(mixed $identifier): void;
- public static abstract function send(string $projectId, array $payload, string $event, array $channels, array $roles, array $options): void;
+ public static abstract function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options): void;
}
diff --git a/src/Appwrite/Messaging/Adapter/Realtime.php b/src/Appwrite/Messaging/Adapter/Realtime.php
index d7d138a79..ad38444cb 100644
--- a/src/Appwrite/Messaging/Adapter/Realtime.php
+++ b/src/Appwrite/Messaging/Adapter/Realtime.php
@@ -11,7 +11,7 @@ class Realtime extends Adapter
/**
* Connection Tree
*
- * [CONNECTION_ID] ->
+ * [CONNECTION_ID] ->
* 'projectId' -> [PROJECT_ID]
* 'roles' -> [ROLE_x, ROLE_Y]
* 'channels' -> [CHANNEL_NAME_X, CHANNEL_NAME_Y, CHANNEL_NAME_Z]
@@ -20,13 +20,13 @@ class Realtime extends Adapter
/**
* Subscription Tree
- *
- * [PROJECT_ID] ->
- * [ROLE_X] ->
+ *
+ * [PROJECT_ID] ->
+ * [ROLE_X] ->
* [CHANNEL_NAME_X] -> [CONNECTION_ID]
* [CHANNEL_NAME_Y] -> [CONNECTION_ID]
* [CHANNEL_NAME_Z] -> [CONNECTION_ID]
- * [ROLE_Y] ->
+ * [ROLE_Y] ->
* [CHANNEL_NAME_X] -> [CONNECTION_ID]
* [CHANNEL_NAME_Y] -> [CONNECTION_ID]
* [CHANNEL_NAME_Z] -> [CONNECTION_ID]
@@ -35,12 +35,12 @@ class Realtime extends Adapter
/**
* Adds a subscription.
- *
- * @param string $projectId
- * @param mixed $identifier
- * @param array $roles
- * @param array $channels
- * @return void
+ *
+ * @param string $projectId
+ * @param mixed $identifier
+ * @param array $roles
+ * @param array $channels
+ * @return void
*/
public function subscribe(string $projectId, mixed $identifier, array $roles, array $channels): void
{
@@ -69,7 +69,7 @@ class Realtime extends Adapter
* Removes Subscription.
*
* @param mixed $connection
- * @return void
+ * @return void
*/
public function unsubscribe(mixed $connection): void
{
@@ -99,9 +99,9 @@ class Realtime extends Adapter
/**
* Checks if Channel has a subscriber.
- * @param string $projectId
- * @param string $role
- * @param string $channel
+ * @param string $projectId
+ * @param string $role
+ * @param string $channel
* @return bool
*/
public function hasSubscriber(string $projectId, string $role, string $channel = ''): bool
@@ -118,16 +118,16 @@ class Realtime extends Adapter
}
/**
- * Sends an event to the Realtime Server.
- * @param string $projectId
- * @param array $payload
- * @param string $event
- * @param array $channels
- * @param array $roles
- * @param array $options
- * @return void
+ * Sends an event to the Realtime Server
+ * @param string $projectId
+ * @param array $payload
+ * @param string $event
+ * @param array $channels
+ * @param array $roles
+ * @param array $options
+ * @return void
*/
- public static function send(string $projectId, array $payload, string $event, array $channels, array $roles, array $options = []): void
+ public static function send(string $projectId, array $payload, array $events, array $channels, array $roles, array $options = []): void
{
if (empty($channels) || empty($roles) || empty($projectId)) return;
@@ -142,7 +142,7 @@ class Realtime extends Adapter
'permissionsChanged' => $permissionsChanged,
'userId' => $userId,
'data' => [
- 'event' => $event,
+ 'events' => $events,
'channels' => $channels,
'timestamp' => time(),
'payload' => $payload
@@ -152,7 +152,7 @@ class Realtime extends Adapter
/**
* Identifies the receivers of all subscriptions, based on the permissions and event.
- *
+ *
* Example of performance with an event with user:XXX permissions and with X users spread across 10 different channels:
* - 0.014 ms (±6.88%) | 10 Connections / 100 Subscriptions
* - 0.070 ms (±3.71%) | 100 Connections / 1,000 Subscriptions
@@ -160,7 +160,7 @@ class Realtime extends Adapter
* - 10.866 ms (±1.01%) | 10,000 Connections / 100,000 Subscriptions
* - 110.201 ms (±2.32%) | 100,000 Connections / 1,000,000 Subscriptions
* - 1,121.328 ms (±0.84%) | 1,000,000 Connections / 10,000,000 Subscriptions
- *
+ *
* @param array $event
*/
public function getSubscribers(array $event)
@@ -205,10 +205,10 @@ class Realtime extends Adapter
}
/**
- * Converts the channels from the Query Params into an array.
+ * Converts the channels from the Query Params into an array.
* Also renames the account channel to account.USER_ID and removes all illegal account channel variations.
- * @param array $channels
- * @param string $userId
+ * @param array $channels
+ * @param string $userId
* @return array
*/
public static function convertChannels(array $channels, string $userId): array
@@ -235,9 +235,9 @@ class Realtime extends Adapter
/**
* Create channels array based on the event name and payload.
*
- * @param string $event
- * @param Document $payload
- * @param Document|null $project
+ * @param string $event
+ * @param Document $payload
+ * @param Document|null $project
* @return array
*/
public static function fromPayload(string $event, Document $payload, Document $project = null, Document $collection = null, Document $bucket = null): array
@@ -246,77 +246,73 @@ class Realtime extends Adapter
$roles = [];
$permissionsChanged = false;
$projectId = null;
+ // TODO: add method here to remove all the magic index accesses
+ $parts = explode('.', $event);
- switch (true) {
- case strpos($event, 'account.recovery.') === 0:
- case strpos($event, 'account.sessions.') === 0:
- case strpos($event, 'account.verification.') === 0:
+ switch ($parts[0]) {
+ case 'users':
$channels[] = 'account';
- $channels[] = 'account.' . $payload->getAttribute('userId');
- $roles = ['user:' . $payload->getAttribute('userId')];
+ $channels[] = 'account.' . $parts[1];
+ $roles = ['user:' . $parts[1]];
break;
- case strpos($event, 'account.') === 0:
- $channels[] = 'account';
- $channels[] = 'account.' . $payload->getId();
- $roles = ['user:' . $payload->getId()];
-
- break;
- case strpos($event, 'teams.memberships') === 0:
- $permissionsChanged = in_array($event, ['teams.memberships.update', 'teams.memberships.delete', 'teams.memberships.update.status']);
- $channels[] = 'memberships';
- $channels[] = 'memberships.' . $payload->getId();
- $roles = ['team:' . $payload->getAttribute('teamId')];
-
- break;
- case strpos($event, 'teams.') === 0:
- $permissionsChanged = $event === 'teams.create';
- $channels[] = 'teams';
- $channels[] = 'teams.' . $payload->getId();
- $roles = ['team:' . $payload->getId()];
-
- break;
- case strpos($event, 'database.attributes.') === 0:
- case strpos($event, 'database.indexes.') === 0:
- $channels[] = 'console';
- $projectId = 'console';
- $roles = ['team:' . $project->getAttribute('teamId')];
-
- break;
- case strpos($event, 'database.documents.') === 0:
- if ($collection->isEmpty()) {
- throw new \Exception('Collection needs to be passed to Realtime for Document events in the Database.');
+ case 'teams':
+ if ($parts[2] === 'memberships') {
+ $permissionsChanged = $parts[4] ?? false;
+ $channels[] = 'memberships';
+ $channels[] = 'memberships.' . $parts[3];
+ $roles = ['team:' . $parts[1]];
+ } else {
+ $permissionsChanged = $parts[2] === 'create';
+ $channels[] = 'teams';
+ $channels[] = 'teams.' . $parts[1];
+ $roles = ['team:' . $parts[1]];
}
-
- $channels[] = 'documents';
- $channels[] = 'collections.' . $payload->getAttribute('$collection') . '.documents';
- $channels[] = 'collections.' . $payload->getAttribute('$collection') . '.documents.' . $payload->getId();
-
- $roles = ($collection->getAttribute('permission') === 'collection') ? $collection->getRead() : $payload->getRead();
-
break;
- case strpos($event, 'storage.files') === 0:
- if($bucket->isEmpty()) {
- throw new \Exception('Bucket needs to be pased to Realtime for File events in the Storage.');
- }
- $channels[] = 'files';
- $channels[] = 'buckets.' . $payload->getAttribute('bucketId') . '.files';
- $channels[] = 'buckets.' . $payload->getAttribute('bucketId') . '.files.' . $payload->getId();
- $roles = $payload->getRead();
-
- break;
- case strpos($event, 'functions.executions.') === 0:
- if (!empty($payload->getRead())) {
+ case 'collections':
+ if (in_array($parts[2], ['attributes', 'indexes'])) {
$channels[] = 'console';
- $channels[] = 'executions';
- $channels[] = 'executions.' . $payload->getId();
- $channels[] = 'functions.' . $payload->getAttribute('functionId');
- $roles = $payload->getRead();
+ $projectId = 'console';
+ $roles = ['team:' . $project->getAttribute('teamId')];
+ } elseif ($parts[2] === 'documents') {
+ if ($collection->isEmpty()) {
+ throw new \Exception('Collection needs to be passed to Realtime for Document events in the Database.');
+ }
+
+ $channels[] = 'documents';
+ $channels[] = 'collections.' . $payload->getCollection() . '.documents';
+ $channels[] = 'collections.' . $payload->getCollection() . '.documents.' . $payload->getId();
+
+ $roles = ($collection->getAttribute('permission') === 'collection') ? $collection->getRead() : $payload->getRead();
}
break;
- case strpos($event, 'functions.deployments.') === 0:
- $channels[] = 'console';
- $roles = ['team:' . $project->getAttribute('teamId')];
+ case 'buckets':
+ if ($parts[2] === 'files') {
+ if ($bucket->isEmpty()) {
+ throw new \Exception('Bucket needs to be pased to Realtime for File events in the Storage.');
+ }
+ $channels[] = 'files';
+ $channels[] = 'buckets.' . $payload->getAttribute('bucketId') . '.files';
+ $channels[] = 'buckets.' . $payload->getAttribute('bucketId') . '.files.' . $payload->getId();
+ $roles = ($bucket->getAttribute('permission') === 'bucket') ? $bucket->getRead() : $payload->getRead();
+ }
+
+ break;
+
+ case 'functions':
+ if ($parts[2] === 'executions') {
+ if (!empty($payload->getRead())) {
+ $channels[] = 'console';
+ $channels[] = 'executions';
+ $channels[] = 'executions.' . $payload->getId();
+ $channels[] = 'functions.' . $payload->getAttribute('functionId');
+ $roles = $payload->getRead();
+ }
+ } elseif ($parts[2] === 'deployments') {
+ $channels[] = 'console';
+ $roles = ['team:' . $project->getAttribute('teamId')];
+ }
+
break;
}
diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php
index 723f210b8..f66936061 100644
--- a/src/Appwrite/Migration/Migration.php
+++ b/src/Appwrite/Migration/Migration.php
@@ -40,6 +40,7 @@ abstract class Migration
'0.13.2' => 'V12',
'0.13.3' => 'V12',
'0.13.4' => 'V12',
+ '0.14.0' => 'V13',
];
/**
diff --git a/src/Appwrite/Migration/Version/V13.php b/src/Appwrite/Migration/Version/V13.php
new file mode 100644
index 000000000..4f1003af5
--- /dev/null
+++ b/src/Appwrite/Migration/Version/V13.php
@@ -0,0 +1,215 @@
+project->getAttribute('name') . ' (' . $this->project->getId() . ')');
+ Console::info('Migrating Collections');
+ $this->migrateCollections();
+ Console::info('Migrating Documents');
+ $this->forEachDocument([$this, 'fixDocument']);
+ }
+
+ /**
+ * Migrate all Collections.
+ *
+ * @return void
+ */
+ protected function migrateCollections(): void
+ {
+ foreach ($this->collections as $collection) {
+ $id = $collection['$id'];
+
+ Console::log("- {$id}");
+ switch ($id) {
+ case 'executions':
+ try {
+ /**
+ * Rename stdout to response
+ */
+ $this->projectDB->renameAttribute($id, 'stdout', 'response');
+ } catch (\Throwable $th) {
+ Console::warning("'stdout' from {$id}: {$th->getMessage()}");
+ }
+ break;
+ case 'projects':
+ try {
+ /**
+ * Rename providers to authProviders
+ */
+ $this->projectDB->renameAttribute($id, 'providers', 'authProviders');
+ } catch (\Throwable $th) {
+ Console::warning("'providers' from {$id}: {$th->getMessage()}");
+ }
+ break;
+ }
+ usleep(100000);
+ }
+ }
+
+ /**
+ * Fix run on each document
+ *
+ * @param \Utopia\Database\Document $document
+ * @return \Utopia\Database\Document
+ */
+ protected function fixDocument(Document $document)
+ {
+ switch ($document->getCollection()) {
+ case 'projects':
+ /**
+ * Bump Project version number.
+ */
+ $document->setAttribute('version', '0.14.0');
+
+ break;
+
+ case 'functions':
+ /**
+ * Migrate events.
+ */
+ if (!empty($document->getAttribute('events'))) {
+ $document->setAttribute('events', $this->migrateEvents($document->getAttribute('events')));
+ }
+
+ break;
+
+ case 'webhooks':
+ /**
+ * Migrate events.
+ */
+ if (!empty($document->getAttribute('events'))) {
+ $document->setAttribute('events', $this->migrateEvents($document->getAttribute('events')));
+ }
+
+ break;
+ }
+
+ return $document;
+ }
+
+ public function migrateEvents(array $events): array
+ {
+ return array_filter(array_unique(array_map(function ($event) {
+ if (!in_array($event, $this->events)) return $event;
+ $parts = \explode('.', $event);
+ $first = array_shift($parts);
+ switch ($first) {
+ case 'account':
+ case 'users':
+ $first = 'users';
+
+ switch ($parts[0]) {
+ case 'recovery':
+ case 'sessions':
+ case 'verification':
+ $second = array_shift($parts);
+ return 'users.*.' . $second . '.*.' . implode('.', $parts);
+
+ default:
+ return 'users.*.' . implode('.', $parts);
+ }
+ case 'functions':
+ switch ($parts[0]) {
+ case 'deployments':
+ case 'executions':
+ $second = array_shift($parts);
+ return 'functions.*.' . $second . '.*.' . implode('.', $parts);
+
+ default:
+ return 'functions.*.' . implode('.', $parts);
+ }
+ case 'teams':
+ switch ($parts[0]) {
+ case 'memberships':
+ $second = array_shift($parts);
+ return 'teams.*.' . $second . '.*.' . implode('.', $parts);
+
+ default:
+ return 'teams.*.' . implode('.', $parts);
+ }
+ case 'storage':
+ $second = array_shift($parts);
+ switch ($second) {
+ case 'buckets':
+ return 'buckets.*.' . implode('.', $parts);
+ case 'files':
+ return 'buckets.*.' . $second . '.*.' . implode('.', $parts);
+ }
+ case 'database':
+ $second = array_shift($parts);
+ switch ($second) {
+ case 'collections':
+ return 'collections.*.' . implode('.', $parts);
+ case 'documents':
+ case 'indexes':
+ case 'attributes':
+ return 'collections.*.' . $second . '.*.' . implode('.', $parts);
+ }
+ }
+ return '';
+ }, $events)));
+ }
+}
diff --git a/tests/e2e/Scopes/ProjectCustom.php b/tests/e2e/Scopes/ProjectCustom.php
index 07b5d3be5..049583743 100644
--- a/tests/e2e/Scopes/ProjectCustom.php
+++ b/tests/e2e/Scopes/ProjectCustom.php
@@ -98,54 +98,11 @@ trait ProjectCustom
], [
'name' => 'Webhook Test',
'events' => [
- 'account.create',
- 'account.update.email',
- 'account.update.name',
- 'account.update.password',
- 'account.update.prefs',
- 'account.recovery.create',
- 'account.recovery.update',
- 'account.verification.create',
- 'account.verification.update',
- 'account.delete',
- 'account.sessions.create',
- 'account.sessions.update',
- 'account.sessions.delete',
- 'database.collections.create',
- 'database.collections.update',
- 'database.collections.delete',
- 'database.attributes.create',
- 'database.attributes.delete',
- 'database.indexes.create',
- 'database.indexes.delete',
- 'database.documents.create',
- 'database.documents.update',
- 'database.documents.delete',
- 'functions.create',
- 'functions.update',
- 'functions.delete',
- 'functions.deployments.create',
- 'functions.deployments.update',
- 'functions.deployments.delete',
- 'functions.executions.create',
- 'functions.executions.update',
- 'storage.files.create',
- 'storage.files.update',
- 'storage.files.delete',
- 'storage.buckets.create',
- 'storage.buckets.update',
- 'storage.buckets.delete',
- 'users.create',
- 'users.update.prefs',
- 'users.update.status',
- 'users.delete',
- 'users.sessions.delete',
- 'teams.create',
- 'teams.update',
- 'teams.delete',
- 'teams.memberships.create',
- 'teams.memberships.update.status',
- 'teams.memberships.delete',
+ 'collections.*',
+ 'functions.*',
+ 'buckets.*',
+ 'teams.*',
+ 'users.*'
],
'url' => 'http://request-catcher:5000/webhook',
'security' => false,
diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php
index 3aa368baa..301ffff8a 100644
--- a/tests/e2e/Services/Account/AccountBase.php
+++ b/tests/e2e/Services/Account/AccountBase.php
@@ -310,7 +310,8 @@ trait AccountBase
{
sleep(10);
$session = $data['session'] ?? '';
-
+ $sessionId = $data['sessionId'] ?? '';
+ $userId = $data['id'] ?? '';
/**
* Test for SUCCESS
*/
@@ -326,8 +327,7 @@ trait AccountBase
$this->assertNotEmpty($response['body']['logs']);
$this->assertCount(2, $response['body']['logs']);
$this->assertIsNumeric($response['body']['total']);
-
- $this->assertContains($response['body']['logs'][0]['event'], ['account.create', 'account.sessions.create']);
+ $this->assertContains($response['body']['logs'][0]['event'], ["users.{$userId}.create", "users.{$userId}.sessions.{$sessionId}.create"]);
$this->assertEquals($response['body']['logs'][0]['ip'], filter_var($response['body']['logs'][0]['ip'], FILTER_VALIDATE_IP));
$this->assertIsNumeric($response['body']['logs'][0]['time']);
@@ -349,7 +349,7 @@ trait AccountBase
$this->assertEquals('--', $response['body']['logs'][0]['countryCode']);
$this->assertEquals('Unknown', $response['body']['logs'][0]['countryName']);
- $this->assertContains($response['body']['logs'][1]['event'], ['account.create', 'account.sessions.create']);
+ $this->assertContains($response['body']['logs'][1]['event'], ["users.{$userId}.create", "users.{$userId}.sessions.{$sessionId}.create"]);
$this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP));
$this->assertIsNumeric($response['body']['logs'][1]['time']);
diff --git a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php
index a0f6cca5e..0180a87de 100644
--- a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php
+++ b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php
@@ -28,8 +28,8 @@ class FunctionsConsoleClientTest extends Scope
'funcKey3' => 'funcValue3',
],
'events' => [
- 'account.create',
- 'account.delete',
+ 'users.*.create',
+ 'users.*.delete',
],
'schedule' => '0 0 1 1 *',
'timeout' => 10,
diff --git a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php
index a89599565..892730281 100644
--- a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php
+++ b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php
@@ -33,8 +33,8 @@ class FunctionsCustomClientTest extends Scope
'funcKey3' => 'funcValue3',
],
'events' => [
- 'account.create',
- 'account.delete',
+ 'users.*.create',
+ 'users.*.delete',
],
'schedule' => '0 0 1 1 *',
'timeout' => 10,
@@ -65,8 +65,8 @@ class FunctionsCustomClientTest extends Scope
'funcKey3' => 'funcValue3',
],
'events' => [
- 'account.create',
- 'account.delete',
+ 'users.*.create',
+ 'users.*.delete',
],
'schedule' => '0 0 1 1 *',
'timeout' => 10,
diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
index 3431e13ca..a766b269e 100644
--- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
+++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
@@ -16,7 +16,7 @@ class FunctionsCustomServerTest extends Scope
use ProjectCustom;
use SideServer;
- public function testCreate():array
+ public function testCreate(): array
{
/**
* Test for SUCCESS
@@ -34,8 +34,8 @@ class FunctionsCustomServerTest extends Scope
'funcKey3' => 'funcValue3',
],
'events' => [
- 'account.create',
- 'account.delete',
+ 'users.*.create',
+ 'users.*.delete',
],
'schedule' => '0 0 1 1 *',
'timeout' => 10,
@@ -56,12 +56,12 @@ class FunctionsCustomServerTest extends Scope
'funcKey3' => 'funcValue3',
], $response1['body']['vars']);
$this->assertEquals([
- 'account.create',
- 'account.delete',
+ 'users.*.create',
+ 'users.*.delete',
], $response1['body']['events']);
$this->assertEquals('0 0 1 1 *', $response1['body']['schedule']);
$this->assertEquals(10, $response1['body']['timeout']);
-
+
/**
* Test for FAILURE
*/
@@ -74,7 +74,7 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testCreate
*/
- public function testList(array $data):array
+ public function testList(array $data): array
{
/**
* Test for SUCCESS
@@ -132,8 +132,8 @@ class FunctionsCustomServerTest extends Scope
'funcKey3' => 'funcValue3',
],
'events' => [
- 'account.create',
- 'account.delete',
+ 'users.*.create',
+ 'users.*.delete',
],
'schedule' => '0 0 1 1 *',
'timeout' => 10,
@@ -193,7 +193,7 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testList
*/
- public function testGet(array $data):array
+ public function testGet(array $data): array
{
/**
* Test for SUCCESS
@@ -222,12 +222,12 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testGet
*/
- public function testUpdate($data):array
+ public function testUpdate($data): array
{
/**
* Test for SUCCESS
*/
- $response1 = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'], array_merge([
+ $response1 = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -238,8 +238,8 @@ class FunctionsCustomServerTest extends Scope
'key6' => 'value6',
],
'events' => [
- 'account.update.name',
- 'account.update.email',
+ 'users.*.update.name',
+ 'users.*.update.email',
],
'schedule' => '0 0 1 1 *',
'timeout' => 5,
@@ -257,12 +257,12 @@ class FunctionsCustomServerTest extends Scope
'key6' => 'value6',
], $response1['body']['vars']);
$this->assertEquals([
- 'account.update.name',
- 'account.update.email',
+ 'users.*.update.name',
+ 'users.*.update.email',
], $response1['body']['events']);
$this->assertEquals('0 0 1 1 *', $response1['body']['schedule']);
$this->assertEquals(5, $response1['body']['timeout']);
-
+
/**
* Test for FAILURE
*/
@@ -273,16 +273,16 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testUpdate
*/
- public function testCreateDeployment($data):array
+ public function testCreateDeployment($data): array
{
/**
* Test for SUCCESS
*/
$folder = 'php';
- $code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz";
+ $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
$this->packageCode($folder);
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/deployments', array_merge([
+ $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/deployments', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -306,16 +306,17 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testUpdate
*/
- public function testCreateDeploymentLarge($data): array {
+ public function testCreateDeploymentLarge($data): array
+ {
/**
* Test for Large Code File SUCCESS
*/
$folder = 'php-large';
- $code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz";
+ $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
$this->packageCode($folder);
- $chunkSize = 5*1024*1024;
+ $chunkSize = 5 * 1024 * 1024;
$handle = @fopen($code, "rb");
$mimeType = 'application/x-gzip';
$counter = 0;
@@ -328,10 +329,10 @@ class FunctionsCustomServerTest extends Scope
while (!feof($handle)) {
$curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'php-large-fx.tar.gz');
$headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size) . '/' . $size;
- if(!empty($id)) {
+ if (!empty($id)) {
$headers['x-appwrite-id'] = $id;
}
- $largeTag = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/deployments', array_merge($headers, $this->getHeaders()), [
+ $largeTag = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/deployments', array_merge($headers, $this->getHeaders()), [
'entrypoint' => 'index.php',
'code' => $curlFile,
]);
@@ -345,19 +346,19 @@ class FunctionsCustomServerTest extends Scope
$this->assertIsInt($largeTag['body']['dateCreated']);
$this->assertEquals('index.php', $largeTag['body']['entrypoint']);
$this->assertGreaterThan(10000, $largeTag['body']['size']);
-
+
return $data;
}
/**
* @depends testCreateDeployment
*/
- public function testUpdateDeployment($data):array
+ public function testUpdateDeployment($data): array
{
/**
* Test for SUCCESS
*/
- $response = $this->client->call(Client::METHOD_PATCH, '/functions/'.$data['functionId'].'/deployments/'.$data['deploymentId'], array_merge([
+ $response = $this->client->call(Client::METHOD_PATCH, '/functions/' . $data['functionId'] . '/deployments/' . $data['deploymentId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -367,7 +368,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertIsInt($response['body']['dateCreated']);
$this->assertIsInt($response['body']['dateUpdated']);
$this->assertEquals($data['deploymentId'], $response['body']['deployment']);
-
+
/**
* Test for FAILURE
*/
@@ -378,12 +379,12 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testCreateDeployment
*/
- public function testListDeployments(array $data):array
+ public function testListDeployments(array $data): array
{
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments', array_merge([
+ $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -396,7 +397,7 @@ class FunctionsCustomServerTest extends Scope
/**
* Test search queries
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments', array_merge([
+ $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders(), [
@@ -409,7 +410,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertCount(2, $function['body']['deployments']);
$this->assertEquals($function['body']['deployments'][0]['$id'], $data['deploymentId']);
- $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments', array_merge([
+ $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders(), [
@@ -422,7 +423,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertCount(2, $function['body']['deployments']);
$this->assertEquals($function['body']['deployments'][0]['$id'], $data['deploymentId']);
- $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments', array_merge([
+ $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders(), [
@@ -441,12 +442,12 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testCreateDeployment
*/
- public function testGetDeployment(array $data):array
+ public function testGetDeployment(array $data): array
{
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments/' . $data['deploymentId'], array_merge([
+ $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments/' . $data['deploymentId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -456,7 +457,7 @@ class FunctionsCustomServerTest extends Scope
/**
* Test for FAILURE
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments/x', array_merge([
+ $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments/x', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -469,12 +470,12 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testUpdateDeployment
*/
- public function testCreateExecution($data):array
+ public function testCreateExecution($data): array
{
/**
* Test for SUCCESS
*/
- $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/executions', array_merge([
+ $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -496,7 +497,7 @@ class FunctionsCustomServerTest extends Scope
sleep(5);
- $execution = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions/'.$executionId, array_merge([
+ $execution = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions/' . $executionId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -529,12 +530,12 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testCreateExecution
*/
- public function testListExecutions(array $data):array
+ public function testListExecutions(array $data): array
{
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions', array_merge([
+ $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -549,7 +550,7 @@ class FunctionsCustomServerTest extends Scope
* Test search queries
*/
- $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions', array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -562,7 +563,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertCount(1, $response['body']['executions']);
$this->assertEquals($data['functionId'], $response['body']['executions'][0]['functionId']);
- $response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions', array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -581,12 +582,12 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testUpdateDeployment
*/
- public function testSyncCreateExecution($data):array
+ public function testSyncCreateExecution($data): array
{
/**
* Test for SUCCESS
*/
- $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/executions', array_merge([
+ $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -610,12 +611,12 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testListExecutions
*/
- public function testGetExecution(array $data):array
+ public function testGetExecution(array $data): array
{
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions/' . $data['executionId'], array_merge([
+ $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions/' . $data['executionId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -626,7 +627,7 @@ class FunctionsCustomServerTest extends Scope
/**
* Test for FAILURE
*/
- $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions/x', array_merge([
+ $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/executions/x', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -639,12 +640,12 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testGetExecution
*/
- public function testDeleteDeployment($data):array
+ public function testDeleteDeployment($data): array
{
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_DELETE, '/functions/'.$data['functionId'].'/deployments/' . $data['deploymentId'], array_merge([
+ $function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/deployments/' . $data['deploymentId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -652,11 +653,11 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(204, $function['headers']['status-code']);
$this->assertEmpty($function['body']);
- $function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/deployments/' . $data['deploymentId'], array_merge([
+ $function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments/' . $data['deploymentId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
-
+
$this->assertEquals(404, $function['headers']['status-code']);
/**
@@ -669,12 +670,12 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testCreateDeployment
*/
- public function testDelete($data):array
+ public function testDelete($data): array
{
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_DELETE, '/functions/'. $data['functionId'], array_merge([
+ $function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -686,7 +687,7 @@ class FunctionsCustomServerTest extends Scope
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
-
+
$this->assertEquals(404, $function['headers']['status-code']);
/**
@@ -702,15 +703,15 @@ class FunctionsCustomServerTest extends Scope
$entrypoint = 'index.php';
$timeout = 2;
$folder = 'timeout';
- $code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz";
+ $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
$this->packageCode($folder);
-
+
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'functionId' => 'unique()',
- 'name' => 'Test '.$name,
+ 'name' => 'Test ' . $name,
'runtime' => $name,
'vars' => [],
'events' => [],
@@ -722,7 +723,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $function['headers']['status-code']);
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', array_merge([
+ $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -735,8 +736,8 @@ class FunctionsCustomServerTest extends Scope
// Allow build step to run
sleep(20);
-
- $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
+
+ $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -744,12 +745,12 @@ class FunctionsCustomServerTest extends Scope
]);
$executionId = $execution['body']['$id'] ?? '';
-
+
$this->assertEquals(201, $execution['headers']['status-code']);
sleep(5);
- $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -768,7 +769,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals($executions['body']['executions'][0]['stderr'], 'Execution timed out.');
// Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
+ $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
@@ -786,7 +787,7 @@ class FunctionsCustomServerTest extends Scope
$entrypoint = 'index.php';
$timeout = 2;
$folder = 'php-fn';
- $code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz";
+ $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
$this->packageCode($folder);
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
@@ -794,7 +795,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'functionId' => 'unique()',
- 'name' => 'Test '.$name,
+ 'name' => 'Test ' . $name,
'runtime' => $name,
'vars' => [],
'events' => [],
@@ -806,7 +807,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $function['headers']['status-code']);
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', array_merge([
+ $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -820,14 +821,14 @@ class FunctionsCustomServerTest extends Scope
// Allow build step to run
sleep(10);
- $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployments/'.$deploymentId, array_merge([
+ $deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
$this->assertEquals(200, $deployment['headers']['status-code']);
-
- $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
+
+ $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -835,14 +836,14 @@ class FunctionsCustomServerTest extends Scope
]);
$executionId = $execution['body']['$id'] ?? '';
-
+
$this->assertEquals(201, $execution['headers']['status-code']);
$executionId = $execution['body']['$id'] ?? '';
-
+
sleep(10);
- $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -852,7 +853,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(200, $executions['headers']['status-code']);
$this->assertEquals('completed', $executions['body']['status']);
$this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']);
- $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']);
+ $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']);
$this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']);
$this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']);
$this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
@@ -864,11 +865,11 @@ class FunctionsCustomServerTest extends Scope
$this->assertEmpty($output['APPWRITE_FUNCTION_JWT']);
$this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']);
- $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
-
+
$this->assertEquals($executions['headers']['status-code'], 200);
$this->assertEquals($executions['body']['total'], 1);
$this->assertIsArray($executions['body']['executions']);
@@ -878,7 +879,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']);
// Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
+ $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
@@ -892,9 +893,9 @@ class FunctionsCustomServerTest extends Scope
{
$name = 'node-17.0';
$folder = 'node';
- $code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz";
+ $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
$this->packageCode($folder);
-
+
$entrypoint = 'index.js';
$timeout = 2;
@@ -903,7 +904,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'functionId' => 'unique()',
- 'name' => 'Test '.$name,
+ 'name' => 'Test ' . $name,
'runtime' => $name,
'vars' => [
'CUSTOM_VARIABLE' => 'variable',
@@ -917,7 +918,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $function['headers']['status-code']);
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', array_merge([
+ $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -932,7 +933,7 @@ class FunctionsCustomServerTest extends Scope
// Allow build step to run
sleep(10);
- $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
+ $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -940,14 +941,14 @@ class FunctionsCustomServerTest extends Scope
]);
$executionId = $execution['body']['$id'] ?? '';
-
+
$this->assertEquals(201, $execution['headers']['status-code']);
$executionId = $execution['body']['$id'] ?? '';
-
+
sleep(10);
- $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -957,7 +958,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(200, $executions['headers']['status-code']);
$this->assertEquals('completed', $executions['body']['status']);
$this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']);
- $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']);
+ $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']);
$this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']);
$this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']);
$this->assertEquals('Node.js', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
@@ -970,11 +971,11 @@ class FunctionsCustomServerTest extends Scope
$this->assertEmpty($output['APPWRITE_FUNCTION_JWT']);
$this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']);
- $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
-
+
$this->assertEquals($executions['headers']['status-code'], 200);
$this->assertEquals($executions['body']['total'], 1);
$this->assertIsArray($executions['body']['executions']);
@@ -984,7 +985,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']);
// Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
+ $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
@@ -997,7 +998,7 @@ class FunctionsCustomServerTest extends Scope
{
$name = 'python-3.9';
$folder = 'python';
- $code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz";
+ $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
$this->packageCode($folder);
$entrypoint = 'main.py';
@@ -1008,7 +1009,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'functionId' => 'unique()',
- 'name' => 'Test '.$name,
+ 'name' => 'Test ' . $name,
'runtime' => $name,
'vars' => [
'CUSTOM_VARIABLE' => 'variable',
@@ -1022,7 +1023,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $function['headers']['status-code']);
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', array_merge([
+ $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1037,7 +1038,7 @@ class FunctionsCustomServerTest extends Scope
// Allow build step to run
sleep(30);
- $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
+ $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1045,14 +1046,14 @@ class FunctionsCustomServerTest extends Scope
]);
$executionId = $execution['body']['$id'] ?? '';
-
+
$this->assertEquals(201, $execution['headers']['status-code']);
$executionId = $execution['body']['$id'] ?? '';
-
+
sleep(30);
- $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -1062,7 +1063,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(200, $executions['headers']['status-code']);
$this->assertEquals('completed', $executions['body']['status']);
$this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']);
- $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']);
+ $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']);
$this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']);
$this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']);
$this->assertEquals('Python', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
@@ -1075,11 +1076,11 @@ class FunctionsCustomServerTest extends Scope
$this->assertEmpty($output['APPWRITE_FUNCTION_JWT']);
$this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']);
- $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
-
+
$this->assertEquals($executions['headers']['status-code'], 200);
$this->assertEquals($executions['body']['total'], 1);
$this->assertIsArray($executions['body']['executions']);
@@ -1089,7 +1090,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']);
// Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
+ $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
@@ -1102,9 +1103,9 @@ class FunctionsCustomServerTest extends Scope
{
$name = 'dart-2.15';
$folder = 'dart';
- $code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz";
+ $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
$this->packageCode($folder);
-
+
$entrypoint = 'main.dart';
$timeout = 2;
@@ -1113,7 +1114,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'functionId' => 'unique()',
- 'name' => 'Test '.$name,
+ 'name' => 'Test ' . $name,
'runtime' => $name,
'vars' => [
'CUSTOM_VARIABLE' => 'variable',
@@ -1127,7 +1128,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $function['headers']['status-code']);
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', array_merge([
+ $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1142,7 +1143,7 @@ class FunctionsCustomServerTest extends Scope
// Allow build step to run
sleep(40);
- $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
+ $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1150,14 +1151,14 @@ class FunctionsCustomServerTest extends Scope
]);
$executionId = $execution['body']['$id'] ?? '';
-
+
$this->assertEquals(201, $execution['headers']['status-code']);
$executionId = $execution['body']['$id'] ?? '';
-
+
sleep(10);
- $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -1167,7 +1168,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(200, $executions['headers']['status-code']);
$this->assertEquals('completed', $executions['body']['status']);
$this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']);
- $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']);
+ $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']);
$this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']);
$this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']);
$this->assertEquals('Dart', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
@@ -1180,11 +1181,11 @@ class FunctionsCustomServerTest extends Scope
$this->assertEmpty($output['APPWRITE_FUNCTION_JWT']);
$this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']);
- $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
-
+
$this->assertEquals($executions['headers']['status-code'], 200);
$this->assertEquals($executions['body']['total'], 1);
$this->assertIsArray($executions['body']['executions']);
@@ -1194,7 +1195,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']);
// Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
+ $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
@@ -1207,9 +1208,9 @@ class FunctionsCustomServerTest extends Scope
{
$name = 'ruby-3.1';
$folder = 'ruby';
- $code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz";
+ $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
$this->packageCode($folder);
-
+
$entrypoint = 'main.rb';
$timeout = 2;
@@ -1218,7 +1219,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'functionId' => 'unique()',
- 'name' => 'Test '.$name,
+ 'name' => 'Test ' . $name,
'runtime' => $name,
'vars' => [
'CUSTOM_VARIABLE' => 'variable',
@@ -1232,7 +1233,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $function['headers']['status-code']);
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', array_merge([
+ $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1247,7 +1248,7 @@ class FunctionsCustomServerTest extends Scope
// Allow build step to run
sleep(30);
- $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
+ $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1255,14 +1256,14 @@ class FunctionsCustomServerTest extends Scope
]);
$executionId = $execution['body']['$id'] ?? '';
-
+
$this->assertEquals(201, $execution['headers']['status-code']);
$executionId = $execution['body']['$id'] ?? '';
-
+
sleep(10);
- $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions/' . $executionId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -1272,7 +1273,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(200, $executions['headers']['status-code']);
$this->assertEquals('completed', $executions['body']['status']);
$this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']);
- $this->assertEquals('Test '.$name, $output['APPWRITE_FUNCTION_NAME']);
+ $this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']);
$this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']);
$this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']);
$this->assertEquals('Ruby', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
@@ -1285,11 +1286,11 @@ class FunctionsCustomServerTest extends Scope
$this->assertEmpty($output['APPWRITE_FUNCTION_JWT']);
$this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']);
- $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([
+ $executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
-
+
$this->assertEquals($executions['headers']['status-code'], 200);
$this->assertEquals($executions['body']['total'], 1);
$this->assertIsArray($executions['body']['executions']);
@@ -1299,7 +1300,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']);
// Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
+ $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
@@ -1314,7 +1315,7 @@ class FunctionsCustomServerTest extends Scope
// $folder = 'swift';
// $code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz";
// $this->packageCode($folder);
-
+
// $entrypoint = 'index.swift';
// $timeout = 5;
@@ -1360,11 +1361,11 @@ class FunctionsCustomServerTest extends Scope
// ]);
// $executionId = $execution['body']['$id'] ?? '';
-
+
// $this->assertEquals(201, $execution['headers']['status-code']);
// $executionId = $execution['body']['$id'] ?? '';
-
+
// sleep(10);
// $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, array_merge([
@@ -1394,7 +1395,7 @@ class FunctionsCustomServerTest extends Scope
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $this->getProject()['$id'],
// ], $this->getHeaders()));
-
+
// $this->assertEquals($executions['headers']['status-code'], 200);
// $this->assertEquals($executions['body']['total'], 1);
// $this->assertIsArray($executions['body']['executions']);
@@ -1432,6 +1433,5 @@ class FunctionsCustomServerTest extends Scope
$this->assertArrayHasKey('image', $runtime);
$this->assertArrayHasKey('base', $runtime);
$this->assertArrayHasKey('supports', $runtime);
-
}
-}
\ No newline at end of file
+}
diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php
index 5d1b0937f..e0a7cb158 100644
--- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php
+++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php
@@ -81,7 +81,7 @@ class ProjectsConsoleClientTest extends Scope
/**
* @depends testCreateProject
*/
- public function testListProject($data):array
+ public function testListProject($data): array
{
$id = $data['projectId'] ?? '';
@@ -174,7 +174,7 @@ class ProjectsConsoleClientTest extends Scope
$response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()),[
+ ], $this->getHeaders()), [
'cursor' => $response['body']['projects'][0]['$id']
]);
@@ -186,7 +186,7 @@ class ProjectsConsoleClientTest extends Scope
$response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()),[
+ ], $this->getHeaders()), [
'cursor' => $response['body']['projects'][0]['$id'],
'cursorDirection' => Database::CURSOR_BEFORE
]);
@@ -202,7 +202,7 @@ class ProjectsConsoleClientTest extends Scope
$response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()),[
+ ], $this->getHeaders()), [
'cursor' => 'unknown'
]);
@@ -214,14 +214,14 @@ class ProjectsConsoleClientTest extends Scope
/**
* @depends testCreateProject
*/
- public function testGetProject($data):array
+ public function testGetProject($data): array
{
$id = $data['projectId'] ?? '';
/**
* Test for SUCCESS
*/
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -255,14 +255,14 @@ class ProjectsConsoleClientTest extends Scope
/**
* @depends testCreateProject
*/
- public function testGetProjectUsage($data):array
+ public function testGetProjectUsage($data): array
{
$id = $data['projectId'] ?? '';
/**
* Test for SUCCESS
*/
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/usage', array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/usage', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -303,14 +303,14 @@ class ProjectsConsoleClientTest extends Scope
/**
* @depends testGetProjectUsage
*/
- public function testUpdateProject($data):array
+ public function testUpdateProject($data): array
{
$id = $data['projectId'] ?? '';
/**
* Test for SUCCESS
*/
- $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id, array_merge([
+ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -330,7 +330,7 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
-
+
$response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -347,7 +347,7 @@ class ProjectsConsoleClientTest extends Scope
/**
* @depends testGetProjectUsage
*/
- public function testUpdateProjectOAuth($data):array
+ public function testUpdateProjectOAuth($data): array
{
$id = $data['projectId'] ?? '';
$providers = require('app/config/providers.php');
@@ -357,20 +357,20 @@ class ProjectsConsoleClientTest extends Scope
*/
foreach ($providers as $key => $provider) {
- $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/oauth2', array_merge([
+ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/oauth2', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'provider' => $key,
- 'appId' => 'AppId-'.ucfirst($key),
- 'secret' => 'Secret-'.ucfirst($key),
+ 'appId' => 'AppId-' . ucfirst($key),
+ 'secret' => 'Secret-' . ucfirst($key),
]);
-
+
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
}
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -380,15 +380,15 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals($id, $response['body']['$id']);
foreach ($providers as $key => $provider) {
- $this->assertEquals('AppId-'.ucfirst($key), $response['body']['provider'.ucfirst($key).'Appid']);
- $this->assertEquals('Secret-'.ucfirst($key), $response['body']['provider'.ucfirst($key).'Secret']);
+ $this->assertEquals('AppId-' . ucfirst($key), $response['body']['provider' . ucfirst($key) . 'Appid']);
+ $this->assertEquals('Secret-' . ucfirst($key), $response['body']['provider' . ucfirst($key) . 'Secret']);
}
/**
* Test for FAILURE
*/
-
- $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/oauth2', array_merge([
+
+ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/oauth2', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -405,15 +405,15 @@ class ProjectsConsoleClientTest extends Scope
/**
* @depends testGetProjectUsage
*/
- public function testUpdateProjectAuthStatus($data):array
+ public function testUpdateProjectAuthStatus($data): array
{
$id = $data['projectId'] ?? '';
$auth = require('app/config/auth.php');
-
- $originalEmail = uniqid().'user@localhost.test';
+
+ $originalEmail = uniqid() . 'user@localhost.test';
$originalPassword = 'password';
$originalName = 'User Name';
-
+
$response = $this->client->call(Client::METHOD_POST, '/account', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
@@ -434,33 +434,33 @@ class ProjectsConsoleClientTest extends Scope
'password' => $originalPassword,
]);
- $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$id];
+ $session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $id];
/**
* Test for SUCCESS
*/
foreach ($auth as $index => $method) {
- $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/'.$index, array_merge([
+ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/' . $index, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'status' => false,
]);
-
+
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
- $this->assertEquals(false, $response['body']['auth'. ucfirst($method['key'])]);
+ $this->assertEquals(false, $response['body']['auth' . ucfirst($method['key'])]);
}
-
- $email = uniqid().'user@localhost.test';
+
+ $email = uniqid() . 'user@localhost.test';
$password = 'password';
$name = 'User Name';
@@ -483,7 +483,7 @@ class ProjectsConsoleClientTest extends Scope
$response = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $id,
- 'cookie' => 'a_session_'.$id.'='.$session,
+ 'cookie' => 'a_session_' . $id . '=' . $session,
]), [
'teamId' => 'unique()',
'name' => 'Arsenal'
@@ -493,10 +493,10 @@ class ProjectsConsoleClientTest extends Scope
$teamUid = $response['body']['$id'];
- $response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $id,
- 'cookie' => 'a_session_'.$id.'=' . $session,
+ 'cookie' => 'a_session_' . $id . '=' . $session,
]), [
'email' => $email,
'name' => 'Friend User',
@@ -509,7 +509,7 @@ class ProjectsConsoleClientTest extends Scope
$response = $this->client->call(Client::METHOD_POST, '/account/jwt', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $id,
- 'cookie' => 'a_session_'.$id.'=' . $session,
+ 'cookie' => 'a_session_' . $id . '=' . $session,
]));
$this->assertEquals($response['headers']['status-code'], 501);
@@ -522,7 +522,7 @@ class ProjectsConsoleClientTest extends Scope
'email' => $originalEmail,
'password' => $originalPassword,
]);
-
+
$this->assertEquals($response['headers']['status-code'], 501);
$response = $this->client->call(Client::METHOD_POST, '/account/anonymous', array_merge([
@@ -536,7 +536,7 @@ class ProjectsConsoleClientTest extends Scope
// Cleanup
foreach ($auth as $index => $method) {
- $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/'.$index, array_merge([
+ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/' . $index, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -550,14 +550,14 @@ class ProjectsConsoleClientTest extends Scope
/**
* @depends testGetProjectUsage
*/
- public function testUpdateProjectAuthLimit($data):array
+ public function testUpdateProjectAuthLimit($data): array
{
$id = $data['projectId'] ?? '';
-
+
/**
* Test for SUCCESS
*/
- $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/limit', array_merge([
+ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/limit', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -566,8 +566,8 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
-
- $email = uniqid().'user@localhost.test';
+
+ $email = uniqid() . 'user@localhost.test';
$password = 'password';
$name = 'User Name';
@@ -590,7 +590,7 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/auth/limit', array_merge([
+ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/limit', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -599,7 +599,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
-
+
$response = $this->client->call(Client::METHOD_POST, '/account', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
@@ -649,13 +649,13 @@ class ProjectsConsoleClientTest extends Scope
* Test for Disabled
*/
foreach ($services as $service) {
- if(!$service['optional']) {
+ if (!$service['optional']) {
continue;
}
$key = $service['key'] ?? '';
-
- $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service', array_merge([
+
+ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
@@ -667,7 +667,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
@@ -675,13 +675,13 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
- $this->assertEquals(false, $response['body']['serviceStatusFor'.ucfirst($key)]);
+ $this->assertEquals(false, $response['body']['serviceStatusFor' . ucfirst($key)]);
}
-
+
/**
* Admin request must succeed
*/
-
+
$response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
@@ -690,17 +690,17 @@ class ProjectsConsoleClientTest extends Scope
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
'x-appwrite-mode' => 'admin'
]));
-
+
$this->assertEquals(200, $response['headers']['status-code']);
foreach ($services as $service) {
- if(!$service['optional']) {
+ if (!$service['optional']) {
continue;
}
$key = $service['key'] ?? '';
- $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service/', array_merge([
+ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service/', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -713,7 +713,7 @@ class ProjectsConsoleClientTest extends Scope
}
/** @depends testUpdateProjectServiceStatusAdmin */
- public function testUpdateProjectServiceStatus($data):void
+ public function testUpdateProjectServiceStatus($data): void
{
$id = $data['projectId'];
@@ -723,13 +723,13 @@ class ProjectsConsoleClientTest extends Scope
* Test for Disabled
*/
foreach ($services as $service) {
- if(!$service['optional']) {
+ if (!$service['optional']) {
continue;
}
$key = $service['key'] ?? '';
- $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service', array_merge([
+ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
@@ -741,7 +741,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
@@ -749,7 +749,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
- $this->assertEquals(false, $response['body']['serviceStatusFor'.ucfirst($key)]);
+ $this->assertEquals(false, $response['body']['serviceStatusFor' . ucfirst($key)]);
}
/**
@@ -776,7 +776,7 @@ class ProjectsConsoleClientTest extends Scope
// Cleanup
foreach ($services as $service) {
- $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/service/', array_merge([
+ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service/', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -793,12 +793,12 @@ class ProjectsConsoleClientTest extends Scope
{
$id = $data['projectId'] ?? '';
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/webhooks', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Webhook Test',
- 'events' => ['account.create', 'account.update.email'],
+ 'events' => ['users.*.create', 'users.*.update.email'],
'url' => 'https://appwrite.io',
'security' => true,
'httpUser' => 'username',
@@ -807,25 +807,25 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
- $this->assertContains('account.create', $response['body']['events']);
- $this->assertContains('account.update.email', $response['body']['events']);
+ $this->assertContains('users.*.create', $response['body']['events']);
+ $this->assertContains('users.*.update.email', $response['body']['events']);
$this->assertCount(2, $response['body']['events']);
$this->assertEquals('https://appwrite.io', $response['body']['url']);
$this->assertIsBool($response['body']['security']);
$this->assertEquals(true, $response['body']['security']);
$this->assertEquals('username', $response['body']['httpUser']);
-
+
$data = array_merge($data, ['webhookId' => $response['body']['$id']]);
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/webhooks', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Webhook Test',
- 'events' => ['account.unknown', 'account.update.email'],
+ 'events' => ['account.unknown', 'users.*.update.email'],
'url' => 'https://appwrite.io',
'security' => true,
'httpUser' => 'username',
@@ -834,12 +834,12 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(400, $response['headers']['status-code']);
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/webhooks', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Webhook Test',
- 'events' => ['account.create', 'account.update.email'],
+ 'events' => ['users.*.create', 'users.*.update.email'],
'url' => 'invalid://appwrite.io',
]);
@@ -855,14 +855,14 @@ class ProjectsConsoleClientTest extends Scope
{
$id = $data['projectId'] ?? '';
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks', array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks', 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']['total']);
-
+
/**
* Test for FAILURE
*/
@@ -878,7 +878,7 @@ class ProjectsConsoleClientTest extends Scope
$id = $data['projectId'] ?? '';
$webhookId = $data['webhookId'] ?? '';
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -886,17 +886,17 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals($webhookId, $response['body']['$id']);
- $this->assertContains('account.create', $response['body']['events']);
- $this->assertContains('account.update.email', $response['body']['events']);
+ $this->assertContains('users.*.create', $response['body']['events']);
+ $this->assertContains('users.*.update.email', $response['body']['events']);
$this->assertCount(2, $response['body']['events']);
$this->assertEquals('https://appwrite.io', $response['body']['url']);
$this->assertEquals('username', $response['body']['httpUser']);
$this->assertEquals('password', $response['body']['httpPass']);
-
+
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks/error', array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/error', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -914,12 +914,12 @@ class ProjectsConsoleClientTest extends Scope
$id = $data['projectId'] ?? '';
$webhookId = $data['webhookId'] ?? '';
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Webhook Test Update',
- 'events' => ['account.delete', 'account.sessions.delete', 'storage.files.create'],
+ 'events' => ['users.*.delete', 'users.*.sessions.*.delete', 'buckets.*.files.*.create'],
'url' => 'https://appwrite.io/new',
'security' => false,
'httpUser' => '',
@@ -930,9 +930,9 @@ class ProjectsConsoleClientTest extends Scope
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals($webhookId, $response['body']['$id']);
$this->assertEquals('Webhook Test Update', $response['body']['name']);
- $this->assertContains('account.delete', $response['body']['events']);
- $this->assertContains('account.sessions.delete', $response['body']['events']);
- $this->assertContains('storage.files.create', $response['body']['events']);
+ $this->assertContains('users.*.delete', $response['body']['events']);
+ $this->assertContains('users.*.sessions.*.delete', $response['body']['events']);
+ $this->assertContains('buckets.*.files.*.create', $response['body']['events']);
$this->assertCount(3, $response['body']['events']);
$this->assertEquals('https://appwrite.io/new', $response['body']['url']);
$this->assertIsBool($response['body']['security']);
@@ -940,7 +940,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals('', $response['body']['httpUser']);
$this->assertEquals('', $response['body']['httpPass']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -949,25 +949,25 @@ class ProjectsConsoleClientTest extends Scope
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals($webhookId, $response['body']['$id']);
$this->assertEquals('Webhook Test Update', $response['body']['name']);
- $this->assertContains('account.delete', $response['body']['events']);
- $this->assertContains('account.sessions.delete', $response['body']['events']);
- $this->assertContains('storage.files.create', $response['body']['events']);
+ $this->assertContains('users.*.delete', $response['body']['events']);
+ $this->assertContains('users.*.sessions.*.delete', $response['body']['events']);
+ $this->assertContains('buckets.*.files.*.create', $response['body']['events']);
$this->assertCount(3, $response['body']['events']);
$this->assertEquals('https://appwrite.io/new', $response['body']['url']);
$this->assertIsBool($response['body']['security']);
$this->assertEquals(false, $response['body']['security']);
$this->assertEquals('', $response['body']['httpUser']);
$this->assertEquals('', $response['body']['httpPass']);
-
+
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Webhook Test Update',
- 'events' => ['account.delete', 'account.sessions.delete', 'storage.files.create', 'unknown'],
+ 'events' => ['users.*.delete', 'users.*.sessions.*.delete', 'buckets.*.files.*.unknown'],
'url' => 'https://appwrite.io/new',
'security' => false,
'httpUser' => '',
@@ -976,12 +976,12 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(400, $response['headers']['status-code']);
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Webhook Test Update',
- 'events' => ['account.delete', 'account.sessions.delete', 'storage.files.create'],
+ 'events' => ['users.*.delete', 'users.*.sessions.*.delete', 'buckets.*.files.*.create'],
'url' => 'appwrite.io/new',
'security' => false,
'httpUser' => '',
@@ -990,12 +990,12 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(400, $response['headers']['status-code']);
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Webhook Test Update',
- 'events' => ['account.delete', 'account.sessions.delete', 'storage.files.create'],
+ 'events' => ['users.*.delete', 'users.*.sessions.*.delete', 'buckets.*.files.*.create'],
'url' => 'invalid://appwrite.io/new',
]);
@@ -1012,7 +1012,7 @@ class ProjectsConsoleClientTest extends Scope
$id = $data['projectId'] ?? '';
$webhookId = $data['webhookId'] ?? '';
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1020,17 +1020,17 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEmpty($response['body']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
$this->assertEquals(404, $response['headers']['status-code']);
-
+
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/webhooks/error', array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/webhooks/error', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1049,7 +1049,7 @@ class ProjectsConsoleClientTest extends Scope
{
$id = $data['projectId'] ?? '';
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1063,13 +1063,13 @@ class ProjectsConsoleClientTest extends Scope
$this->assertContains('teams.read', $response['body']['scopes']);
$this->assertContains('teams.write', $response['body']['scopes']);
$this->assertNotEmpty($response['body']['secret']);
-
+
$data = array_merge($data, ['keyId' => $response['body']['$id']]);
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/keys', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/keys', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1089,14 +1089,14 @@ class ProjectsConsoleClientTest extends Scope
{
$id = $data['projectId'] ?? '';
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys', array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys', 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']['total']);
-
+
/**
* Test for FAILURE
*/
@@ -1112,7 +1112,7 @@ class ProjectsConsoleClientTest extends Scope
$id = $data['projectId'] ?? '';
$keyId = $data['keyId'] ?? '';
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/'.$keyId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/' . $keyId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1125,11 +1125,11 @@ class ProjectsConsoleClientTest extends Scope
$this->assertContains('teams.write', $response['body']['scopes']);
$this->assertCount(2, $response['body']['scopes']);
$this->assertNotEmpty($response['body']['secret']);
-
+
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/error', array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/error', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1147,7 +1147,7 @@ class ProjectsConsoleClientTest extends Scope
$id = $data['projectId'] ?? '';
$keyId = $data['keyId'] ?? '';
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/keys/'.$keyId, array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/keys/' . $keyId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1164,7 +1164,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertContains('collections.read', $response['body']['scopes']);
$this->assertCount(3, $response['body']['scopes']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/'.$keyId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/' . $keyId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1177,11 +1177,11 @@ class ProjectsConsoleClientTest extends Scope
$this->assertContains('users.write', $response['body']['scopes']);
$this->assertContains('collections.read', $response['body']['scopes']);
$this->assertCount(3, $response['body']['scopes']);
-
+
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/keys/'.$keyId, array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/keys/' . $keyId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1202,7 +1202,7 @@ class ProjectsConsoleClientTest extends Scope
$id = $data['projectId'] ?? '';
$keyId = $data['keyId'] ?? '';
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/keys/'.$keyId, array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/keys/' . $keyId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1210,17 +1210,17 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEmpty($response['body']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/keys/'.$keyId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/' . $keyId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
$this->assertEquals(404, $response['headers']['status-code']);
-
+
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/keys/error', array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/keys/error', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1239,7 +1239,7 @@ class ProjectsConsoleClientTest extends Scope
{
$id = $data['projectId'] ?? '';
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1257,10 +1257,10 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals('', $response['body']['key']);
$this->assertEquals('', $response['body']['store']);
$this->assertEquals('localhost', $response['body']['hostname']);
-
+
$data = array_merge($data, ['platformWebId' => $response['body']['$id']]);
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1278,10 +1278,10 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals('com.example.ios', $response['body']['key']);
$this->assertEquals('', $response['body']['store']);
$this->assertEquals('', $response['body']['hostname']);
-
+
$data = array_merge($data, ['platformFultteriOSId' => $response['body']['$id']]);
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1299,10 +1299,10 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals('com.example.android', $response['body']['key']);
$this->assertEquals('', $response['body']['store']);
$this->assertEquals('', $response['body']['hostname']);
-
+
$data = array_merge($data, ['platformFultterAndroidId' => $response['body']['$id']]);
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1323,7 +1323,7 @@ class ProjectsConsoleClientTest extends Scope
$data = array_merge($data, ['platformAppleIosId' => $response['body']['$id']]);
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1344,7 +1344,7 @@ class ProjectsConsoleClientTest extends Scope
$data = array_merge($data, ['platformAppleMacOsId' => $response['body']['$id']]);
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1365,7 +1365,7 @@ class ProjectsConsoleClientTest extends Scope
$data = array_merge($data, ['platformAppleWatchOsId' => $response['body']['$id']]);
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1389,7 +1389,7 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1414,7 +1414,7 @@ class ProjectsConsoleClientTest extends Scope
sleep(1);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms', array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1425,7 +1425,7 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
-
+
return $data;
}
@@ -1438,7 +1438,7 @@ class ProjectsConsoleClientTest extends Scope
$platformWebId = $data['platformWebId'] ?? '';
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformWebId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformWebId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1451,10 +1451,10 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals('', $response['body']['key']);
$this->assertEquals('', $response['body']['store']);
$this->assertEquals('localhost', $response['body']['hostname']);
-
+
$platformFultteriOSId = $data['platformFultteriOSId'] ?? '';
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultteriOSId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultteriOSId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1467,10 +1467,10 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals('com.example.ios', $response['body']['key']);
$this->assertEquals('', $response['body']['store']);
$this->assertEquals('', $response['body']['hostname']);
-
+
$platformFultterAndroidId = $data['platformFultterAndroidId'] ?? '';
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultterAndroidId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultterAndroidId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1486,7 +1486,7 @@ class ProjectsConsoleClientTest extends Scope
$platformAppleIosId = $data['platformAppleIosId'] ?? '';
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleIosId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleIosId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1502,7 +1502,7 @@ class ProjectsConsoleClientTest extends Scope
$platformAppleMacOsId = $data['platformAppleMacOsId'] ?? '';
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleMacOsId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleMacOsId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1518,7 +1518,7 @@ class ProjectsConsoleClientTest extends Scope
$platformAppleWatchOsId = $data['platformAppleWatchOsId'] ?? '';
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleWatchOsId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleWatchOsId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1534,7 +1534,7 @@ class ProjectsConsoleClientTest extends Scope
$platformAppleTvOsId = $data['platformAppleTvOsId'] ?? '';
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleTvOsId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleTvOsId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1551,7 +1551,7 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/error', array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/error', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1570,7 +1570,7 @@ class ProjectsConsoleClientTest extends Scope
$platformWebId = $data['platformWebId'] ?? '';
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformWebId, array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformWebId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1591,7 +1591,7 @@ class ProjectsConsoleClientTest extends Scope
$platformFultteriOSId = $data['platformFultteriOSId'] ?? '';
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformFultteriOSId, array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformFultteriOSId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1609,10 +1609,10 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals('com.example.ios2', $response['body']['key']);
$this->assertEquals('', $response['body']['store']);
$this->assertEquals('', $response['body']['hostname']);
-
+
$platformFultterAndroidId = $data['platformFultterAndroidId'] ?? '';
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformFultterAndroidId, array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformFultterAndroidId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1633,7 +1633,7 @@ class ProjectsConsoleClientTest extends Scope
$platformAppleIosId = $data['platformAppleIosId'] ?? '';
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformAppleIosId, array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformAppleIosId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1654,7 +1654,7 @@ class ProjectsConsoleClientTest extends Scope
$platformAppleMacOsId = $data['platformAppleMacOsId'] ?? '';
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformAppleMacOsId, array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformAppleMacOsId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1675,7 +1675,7 @@ class ProjectsConsoleClientTest extends Scope
$platformAppleWatchOsId = $data['platformAppleWatchOsId'] ?? '';
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformAppleWatchOsId, array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformAppleWatchOsId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1696,7 +1696,7 @@ class ProjectsConsoleClientTest extends Scope
$platformAppleTvOsId = $data['platformAppleTvOsId'] ?? '';
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/'.$platformAppleTvOsId, array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/' . $platformAppleTvOsId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1718,7 +1718,7 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/platforms/error', array_merge([
+ $response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/platforms/error', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1739,10 +1739,10 @@ class ProjectsConsoleClientTest extends Scope
public function testDeleteProjectPlatform($data): array
{
$id = $data['projectId'] ?? '';
-
+
$platformWebId = $data['platformWebId'] ?? '';
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformWebId, array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformWebId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1750,7 +1750,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEmpty($response['body']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformWebId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformWebId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1759,7 +1759,7 @@ class ProjectsConsoleClientTest extends Scope
$platformFultteriOSId = $data['platformFultteriOSId'] ?? '';
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformFultteriOSId, array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformFultteriOSId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1767,7 +1767,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEmpty($response['body']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultteriOSId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultteriOSId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1776,7 +1776,7 @@ class ProjectsConsoleClientTest extends Scope
$platformFultterAndroidId = $data['platformFultterAndroidId'] ?? '';
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformFultterAndroidId, array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformFultterAndroidId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1784,7 +1784,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEmpty($response['body']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformFultterAndroidId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformFultterAndroidId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1793,7 +1793,7 @@ class ProjectsConsoleClientTest extends Scope
$platformAppleIosId = $data['platformAppleIosId'] ?? '';
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformAppleIosId, array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformAppleIosId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1801,7 +1801,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEmpty($response['body']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleIosId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleIosId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1810,7 +1810,7 @@ class ProjectsConsoleClientTest extends Scope
$platformAppleMacOsId = $data['platformAppleMacOsId'] ?? '';
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformAppleMacOsId, array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformAppleMacOsId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1818,7 +1818,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEmpty($response['body']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleMacOsId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleMacOsId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1827,7 +1827,7 @@ class ProjectsConsoleClientTest extends Scope
$platformAppleWatchOsId = $data['platformAppleWatchOsId'] ?? '';
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformAppleWatchOsId, array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformAppleWatchOsId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1835,7 +1835,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEmpty($response['body']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleWatchOsId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleWatchOsId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1844,7 +1844,7 @@ class ProjectsConsoleClientTest extends Scope
$platformAppleTvOsId = $data['platformAppleTvOsId'] ?? '';
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/platforms/'.$platformAppleTvOsId, array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/platforms/' . $platformAppleTvOsId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1852,7 +1852,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEmpty($response['body']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/platforms/'.$platformAppleTvOsId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms/' . $platformAppleTvOsId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1862,7 +1862,7 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/webhooks/error', array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/webhooks/error', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1881,7 +1881,7 @@ class ProjectsConsoleClientTest extends Scope
{
$id = $data['projectId'] ?? '';
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/domains', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/domains', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -1895,19 +1895,19 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals('com', $response['body']['tld']);
$this->assertEquals('example.com', $response['body']['registerable']);
$this->assertEquals(false, $response['body']['verification']);
-
+
$data = array_merge($data, ['domainId' => $response['body']['$id']]);
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/platforms', array_merge([
+ $response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/platforms', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'domain' => '123',
]);
-
+
$this->assertEquals(400, $response['headers']['status-code']);
return $data;
@@ -1919,8 +1919,8 @@ class ProjectsConsoleClientTest extends Scope
public function testListProjectDomain($data): array
{
$id = $data['projectId'] ?? '';
-
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/domains', array_merge([
+
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1931,7 +1931,7 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
-
+
return $data;
}
@@ -1943,7 +1943,7 @@ class ProjectsConsoleClientTest extends Scope
$id = $data['projectId'] ?? '';
$domainId = $data['domainId'] ?? '';
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/domains/'.$domainId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains/' . $domainId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1956,11 +1956,11 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals('com', $response['body']['tld']);
$this->assertEquals('example.com', $response['body']['registerable']);
$this->assertEquals(false, $response['body']['verification']);
-
+
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/domains/error', array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains/error', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -1978,7 +1978,7 @@ class ProjectsConsoleClientTest extends Scope
$id = $data['projectId'] ?? '';
$domainId = $data['domainId'] ?? '';
- $response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$id.'/domains/'.$domainId.'/verification', array_merge([
+ $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/domains/' . $domainId . '/verification', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -2000,7 +2000,7 @@ class ProjectsConsoleClientTest extends Scope
$id = $data['projectId'] ?? '';
$domainId = $data['domainId'] ?? '';
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/domains/'.$domainId, array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/domains/' . $domainId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -2008,7 +2008,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEmpty($response['body']);
- $response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/domains/'.$domainId, array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/domains/' . $domainId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -2018,7 +2018,7 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
- $response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/domains/error', array_merge([
+ $response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/domains/error', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
diff --git a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php
index 0b19665bf..9d75bc159 100644
--- a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php
+++ b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php
@@ -2,17 +2,10 @@
namespace Tests\E2E\Services\Realtime;
-use Exception;
-use SebastianBergmann\RecursionContext\InvalidArgumentException;
-use PHPUnit\Framework\ExpectationFailedException;
-use PHPUnit\Framework\Exception as FrameworkException;
use Tests\E2E\Client;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\SideConsole;
-use WebSocket\BadOpcodeException;
-use WebSocket\ConnectionException;
-use WebSocket\TimeoutException;
class RealtimeConsoleClientTest extends Scope
{
@@ -23,12 +16,11 @@ class RealtimeConsoleClientTest extends Scope
public function testAttributes()
{
$user = $this->getUser();
- $session = $user['session'] ?? '';
$projectId = 'console';
$client = $this->getWebsocket(['console'], [
'origin' => 'http://localhost',
- 'cookie' => 'a_session_console='. $this->getRoot()['session'],
+ 'cookie' => 'a_session_console=' . $this->getRoot()['session'],
], $projectId);
$response = json_decode($client->receive(), true);
@@ -55,9 +47,9 @@ class RealtimeConsoleClientTest extends Scope
'permission' => 'collection'
]);
- $data = ['actorsId' => $actors['body']['$id']];
+ $actorsId = $actors['body']['$id'];
- $name = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/attributes/string', array_merge([
+ $name = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actorsId . '/attributes/string', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -66,6 +58,8 @@ class RealtimeConsoleClientTest extends Scope
'required' => true,
]);
+ $attributeKey = $name['body']['key'];
+
$this->assertEquals($name['headers']['status-code'], 201);
$this->assertEquals($name['body']['key'], 'name');
$this->assertEquals($name['body']['type'], 'string');
@@ -81,7 +75,16 @@ class RealtimeConsoleClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(1, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
- $this->assertEquals('database.attributes.create', $response['data']['event']);
+ $this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}.create", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.attributes.*.create", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.attributes.*", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}", $response['data']['events']);
+ $this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}.create", $response['data']['events']);
+ $this->assertContains("collections.*.attributes.*.create", $response['data']['events']);
+ $this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']);
+ $this->assertContains("collections.*.attributes.*", $response['data']['events']);
+ $this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$this->assertEquals('processing', $response['data']['payload']['status']);
@@ -94,12 +97,23 @@ class RealtimeConsoleClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(1, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
- $this->assertEquals('database.attributes.update', $response['data']['event']);
+ $this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}.update", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.attributes.*.update", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.attributes.*", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}", $response['data']['events']);
+ $this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}.update", $response['data']['events']);
+ $this->assertContains("collections.*.attributes.*.update", $response['data']['events']);
+ $this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']);
+ $this->assertContains("collections.*.attributes.*", $response['data']['events']);
+ $this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$this->assertEquals('available', $response['data']['payload']['status']);
$client->close();
+ $data = ['actorsId' => $actorsId];
+
return $data;
}
@@ -108,13 +122,11 @@ class RealtimeConsoleClientTest extends Scope
*/
public function testIndexes(array $data)
{
- $user = $this->getUser();
- $session = $user['session'] ?? '';
$projectId = 'console';
-
+ $actorsId = $data['actorsId'];
$client = $this->getWebsocket(['console'], [
'origin' => 'http://localhost',
- 'cookie' => 'a_session_console='. $this->getRoot()['session'],
+ 'cookie' => 'a_session_console=' . $this->getRoot()['session'],
], $projectId);
$response = json_decode($client->receive(), true);
@@ -130,7 +142,7 @@ class RealtimeConsoleClientTest extends Scope
/**
* Test Indexes
*/
- $index = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/indexes', array_merge([
+ $index = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actorsId . '/indexes', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -142,6 +154,7 @@ class RealtimeConsoleClientTest extends Scope
]);
$this->assertEquals($index['headers']['status-code'], 201);
+ $indexKey = $index['body']['key'];
$response = json_decode($client->receive(), true);
@@ -152,7 +165,16 @@ class RealtimeConsoleClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(1, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
- $this->assertEquals('database.indexes.create', $response['data']['event']);
+ $this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.create", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.indexes.*.create", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.indexes.*", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}", $response['data']['events']);
+ $this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}.create", $response['data']['events']);
+ $this->assertContains("collections.*.indexes.*.create", $response['data']['events']);
+ $this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}", $response['data']['events']);
+ $this->assertContains("collections.*.indexes.*", $response['data']['events']);
+ $this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$this->assertEquals('processing', $response['data']['payload']['status']);
@@ -165,7 +187,16 @@ class RealtimeConsoleClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(1, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
- $this->assertEquals('database.indexes.update', $response['data']['event']);
+ $this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.update", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.indexes.*.update", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.indexes.*", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}", $response['data']['events']);
+ $this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}.update", $response['data']['events']);
+ $this->assertContains("collections.*.indexes.*.update", $response['data']['events']);
+ $this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}", $response['data']['events']);
+ $this->assertContains("collections.*.indexes.*", $response['data']['events']);
+ $this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$this->assertEquals('available', $response['data']['payload']['status']);
@@ -179,13 +210,12 @@ class RealtimeConsoleClientTest extends Scope
*/
public function testDeleteIndex(array $data)
{
- $user = $this->getUser();
- $session = $user['session'] ?? '';
+ $actorsId = $data['actorsId'];
$projectId = 'console';
$client = $this->getWebsocket(['console'], [
'origin' => 'http://localhost',
- 'cookie' => 'a_session_console='. $this->getRoot()['session'],
+ 'cookie' => 'a_session_console=' . $this->getRoot()['session'],
], $projectId);
$response = json_decode($client->receive(), true);
@@ -201,13 +231,13 @@ class RealtimeConsoleClientTest extends Scope
/**
* Test Delete Index
*/
- $attribute = $this->client->call(Client::METHOD_DELETE, '/database/collections/' . $data['actorsId'] . '/indexes/key_name', array_merge([
+ $attribute = $this->client->call(Client::METHOD_DELETE, '/database/collections/' . $actorsId . '/indexes/key_name', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals($attribute['headers']['status-code'], 204);
-
+ $indexKey = 'key_name';
$response = json_decode($client->receive(), true);
$this->assertArrayHasKey('type', $response);
@@ -217,7 +247,16 @@ class RealtimeConsoleClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(1, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
- $this->assertEquals('database.indexes.delete', $response['data']['event']);
+ $this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.delete", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.indexes.*.delete", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.indexes.*", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}", $response['data']['events']);
+ $this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}.delete", $response['data']['events']);
+ $this->assertContains("collections.*.indexes.*.delete", $response['data']['events']);
+ $this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}", $response['data']['events']);
+ $this->assertContains("collections.*.indexes.*", $response['data']['events']);
+ $this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$client->close();
@@ -230,13 +269,12 @@ class RealtimeConsoleClientTest extends Scope
*/
public function testDeleteAttribute(array $data)
{
- $user = $this->getUser();
- $session = $user['session'] ?? '';
+ $actorsId = $data['actorsId'];
$projectId = 'console';
$client = $this->getWebsocket(['console'], [
'origin' => 'http://localhost',
- 'cookie' => 'a_session_console='. $this->getRoot()['session'],
+ 'cookie' => 'a_session_console=' . $this->getRoot()['session'],
], $projectId);
$response = json_decode($client->receive(), true);
@@ -258,7 +296,7 @@ class RealtimeConsoleClientTest extends Scope
], $this->getHeaders()));
$this->assertEquals($attribute['headers']['status-code'], 204);
-
+ $attributeKey = 'name';
$response = json_decode($client->receive(), true);
$this->assertArrayHasKey('type', $response);
@@ -268,9 +306,18 @@ class RealtimeConsoleClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(1, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
- $this->assertEquals('database.attributes.delete', $response['data']['event']);
+ $this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}.delete", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.attributes.*.delete", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.attributes.*", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}", $response['data']['events']);
+ $this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}.delete", $response['data']['events']);
+ $this->assertContains("collections.*.attributes.*.delete", $response['data']['events']);
+ $this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']);
+ $this->assertContains("collections.*.attributes.*", $response['data']['events']);
+ $this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$client->close();
}
-}
\ No newline at end of file
+}
diff --git a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php
index c5155a97a..017792a61 100644
--- a/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php
+++ b/tests/e2e/Services/Realtime/RealtimeCustomClientTest.php
@@ -25,7 +25,7 @@ class RealtimeCustomClientTest extends Scope
$headers = [
'origin' => 'http://localhost',
- 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session
+ 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session
];
$client = $this->getWebsocket(['documents'], $headers);
@@ -240,7 +240,7 @@ class RealtimeCustomClientTest extends Scope
$client = $this->getWebsocket(['account'], [
'origin' => 'http://localhost',
- 'cookie' => 'a_session_'.$projectId.'=' . $session
+ 'cookie' => 'a_session_' . $projectId . '=' . $session
]);
$response = json_decode($client->receive(), true);
@@ -278,7 +278,12 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertContains('account', $response['data']['channels']);
$this->assertContains('account.' . $userId, $response['data']['channels']);
- $this->assertEquals('account.update.name', $response['data']['event']);
+ $this->assertContains("users.{$userId}.update.name", $response['data']['events']);
+ $this->assertContains("users.{$userId}.update", $response['data']['events']);
+ $this->assertContains("users.{$userId}", $response['data']['events']);
+ $this->assertContains("users.*.update.name", $response['data']['events']);
+ $this->assertContains("users.*.update", $response['data']['events']);
+ $this->assertContains("users.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$this->assertEquals($name, $response['data']['payload']['name']);
@@ -291,7 +296,7 @@ class RealtimeCustomClientTest extends Scope
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
- 'cookie' => 'a_session_'.$projectId.'=' . $session,
+ 'cookie' => 'a_session_' . $projectId . '=' . $session,
]), [
'password' => 'new-password',
'oldPassword' => 'password',
@@ -307,7 +312,12 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertContains('account', $response['data']['channels']);
$this->assertContains('account.' . $userId, $response['data']['channels']);
- $this->assertEquals('account.update.password', $response['data']['event']);
+ $this->assertContains("users.{$userId}.update.password", $response['data']['events']);
+ $this->assertContains("users.{$userId}.update", $response['data']['events']);
+ $this->assertContains("users.{$userId}", $response['data']['events']);
+ $this->assertContains("users.*.update.password", $response['data']['events']);
+ $this->assertContains("users.*.update", $response['data']['events']);
+ $this->assertContains("users.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$this->assertEquals($name, $response['data']['payload']['name']);
@@ -319,7 +329,7 @@ class RealtimeCustomClientTest extends Scope
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
- 'cookie' => 'a_session_'.$projectId.'=' . $session,
+ 'cookie' => 'a_session_' . $projectId . '=' . $session,
]), [
'email' => 'torsten@appwrite.io',
'password' => 'new-password',
@@ -335,23 +345,27 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertContains('account', $response['data']['channels']);
$this->assertContains('account.' . $userId, $response['data']['channels']);
- $this->assertEquals('account.update.email', $response['data']['event']);
+ $this->assertContains("users.{$userId}.update.email", $response['data']['events']);
+ $this->assertContains("users.{$userId}.update", $response['data']['events']);
+ $this->assertContains("users.{$userId}", $response['data']['events']);
+ $this->assertContains("users.*.update.email", $response['data']['events']);
+ $this->assertContains("users.*.update", $response['data']['events']);
+ $this->assertContains("users.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
-
$this->assertEquals('torsten@appwrite.io', $response['data']['payload']['email']);
/**
* Test Account Verification Create
*/
- $this->client->call(Client::METHOD_POST, '/account/verification', array_merge([
+ $verification = $this->client->call(Client::METHOD_POST, '/account/verification', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
- 'cookie' => 'a_session_'.$projectId.'=' . $session,
+ 'cookie' => 'a_session_' . $projectId . '=' . $session,
]), [
'url' => 'http://localhost/verification',
]);
-
+ $verificationId = $verification['body']['$id'];
$response = json_decode($client->receive(), true);
$this->assertArrayHasKey('type', $response);
@@ -362,7 +376,16 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertContains('account', $response['data']['channels']);
$this->assertContains('account.' . $userId, $response['data']['channels']);
- $this->assertEquals('account.verification.create', $response['data']['event']);
+ $this->assertContains("users.{$userId}.verification.{$verificationId}.create", $response['data']['events']);
+ $this->assertContains("users.{$userId}.verification.{$verificationId}", $response['data']['events']);
+ $this->assertContains("users.{$userId}.verification.*.create", $response['data']['events']);
+ $this->assertContains("users.{$userId}.verification.*", $response['data']['events']);
+ $this->assertContains("users.{$userId}", $response['data']['events']);
+ $this->assertContains("users.*.verification.{$verificationId}.create", $response['data']['events']);
+ $this->assertContains("users.*.verification.{$verificationId}", $response['data']['events']);
+ $this->assertContains("users.*.verification.*.create", $response['data']['events']);
+ $this->assertContains("users.*.verification.*", $response['data']['events']);
+ $this->assertContains("users.*", $response['data']['events']);
$lastEmail = $this->getLastEmail();
$verification = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
@@ -370,11 +393,11 @@ class RealtimeCustomClientTest extends Scope
/**
* Test Account Verification Complete
*/
- $response = $this->client->call(Client::METHOD_PUT, '/account/verification', array_merge([
+ $verification = $this->client->call(Client::METHOD_PUT, '/account/verification', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
- 'cookie' => 'a_session_'.$projectId.'=' . $session,
+ 'cookie' => 'a_session_' . $projectId . '=' . $session,
]), [
'userId' => $userId,
'secret' => $verification,
@@ -390,8 +413,16 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertContains('account', $response['data']['channels']);
$this->assertContains('account.' . $userId, $response['data']['channels']);
- $this->assertEquals('account.verification.update', $response['data']['event']);
-
+ $this->assertContains("users.{$userId}.verification.{$verificationId}.update", $response['data']['events']);
+ $this->assertContains("users.{$userId}.verification.{$verificationId}", $response['data']['events']);
+ $this->assertContains("users.{$userId}.verification.*.update", $response['data']['events']);
+ $this->assertContains("users.{$userId}.verification.*", $response['data']['events']);
+ $this->assertContains("users.{$userId}", $response['data']['events']);
+ $this->assertContains("users.*.verification.{$verificationId}.update", $response['data']['events']);
+ $this->assertContains("users.*.verification.{$verificationId}", $response['data']['events']);
+ $this->assertContains("users.*.verification.*.update", $response['data']['events']);
+ $this->assertContains("users.*.verification.*", $response['data']['events']);
+ $this->assertContains("users.*", $response['data']['events']);
/**
* Test Acoount Prefs Update
*/
@@ -399,7 +430,7 @@ class RealtimeCustomClientTest extends Scope
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
- 'cookie' => 'a_session_'.$projectId.'=' . $session,
+ 'cookie' => 'a_session_' . $projectId . '=' . $session,
]), [
'prefs' => [
'prefKey1' => 'prefValue1',
@@ -417,7 +448,12 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertContains('account', $response['data']['channels']);
$this->assertContains('account.' . $userId, $response['data']['channels']);
- $this->assertEquals('account.update.prefs', $response['data']['event']);
+ $this->assertContains("users.{$userId}.update.prefs", $response['data']['events']);
+ $this->assertContains("users.{$userId}.update", $response['data']['events']);
+ $this->assertContains("users.{$userId}", $response['data']['events']);
+ $this->assertContains("users.*.update.prefs", $response['data']['events']);
+ $this->assertContains("users.*.update", $response['data']['events']);
+ $this->assertContains("users.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
/**
@@ -432,7 +468,7 @@ class RealtimeCustomClientTest extends Scope
'password' => 'new-password',
]);
- $sessionNew = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$projectId];
+ $sessionNew = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $projectId];
$sessionNewId = $response['body']['$id'];
$response = json_decode($client->receive(), true);
@@ -445,17 +481,26 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertContains('account', $response['data']['channels']);
$this->assertContains('account.' . $userId, $response['data']['channels']);
- $this->assertEquals('account.sessions.create', $response['data']['event']);
+ $this->assertContains("users.{$userId}.sessions.{$sessionNewId}.create", $response['data']['events']);
+ $this->assertContains("users.{$userId}.sessions.{$sessionNewId}", $response['data']['events']);
+ $this->assertContains("users.{$userId}.sessions.*.create", $response['data']['events']);
+ $this->assertContains("users.{$userId}.sessions.*", $response['data']['events']);
+ $this->assertContains("users.{$userId}", $response['data']['events']);
+ $this->assertContains("users.*.sessions.{$sessionNewId}.create", $response['data']['events']);
+ $this->assertContains("users.*.sessions.{$sessionNewId}", $response['data']['events']);
+ $this->assertContains("users.*.sessions.*.create", $response['data']['events']);
+ $this->assertContains("users.*.sessions.*", $response['data']['events']);
+ $this->assertContains("users.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
/**
* Test Account Session Delete
*/
- $this->client->call(Client::METHOD_DELETE, '/account/sessions/'.$sessionNewId, array_merge([
+ $this->client->call(Client::METHOD_DELETE, '/account/sessions/' . $sessionNewId, array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
- 'cookie' => 'a_session_'.$projectId.'=' . $sessionNew,
+ 'cookie' => 'a_session_' . $projectId . '=' . $sessionNew,
]));
$response = json_decode($client->receive(), true);
@@ -468,13 +513,22 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertContains('account', $response['data']['channels']);
$this->assertContains('account.' . $userId, $response['data']['channels']);
- $this->assertEquals('account.sessions.delete', $response['data']['event']);
+ $this->assertContains("users.{$userId}.sessions.{$sessionNewId}.delete", $response['data']['events']);
+ $this->assertContains("users.{$userId}.sessions.{$sessionNewId}", $response['data']['events']);
+ $this->assertContains("users.{$userId}.sessions.*.delete", $response['data']['events']);
+ $this->assertContains("users.{$userId}.sessions.*", $response['data']['events']);
+ $this->assertContains("users.{$userId}", $response['data']['events']);
+ $this->assertContains("users.*.sessions.{$sessionNewId}.delete", $response['data']['events']);
+ $this->assertContains("users.*.sessions.{$sessionNewId}", $response['data']['events']);
+ $this->assertContains("users.*.sessions.*.delete", $response['data']['events']);
+ $this->assertContains("users.*.sessions.*", $response['data']['events']);
+ $this->assertContains("users.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
/**
* Test Account Create Recovery
*/
- $this->client->call(Client::METHOD_POST, '/account/recovery', array_merge([
+ $recovery = $this->client->call(Client::METHOD_POST, '/account/recovery', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
@@ -482,7 +536,7 @@ class RealtimeCustomClientTest extends Scope
'email' => 'torsten@appwrite.io',
'url' => 'http://localhost/recovery',
]);
-
+ $recoveryId = $recovery['body']['$id'];
$response = json_decode($client->receive(), true);
$lastEmail = $this->getLastEmail();
@@ -496,7 +550,16 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertContains('account', $response['data']['channels']);
$this->assertContains('account.' . $userId, $response['data']['channels']);
- $this->assertEquals('account.recovery.create', $response['data']['event']);
+ $this->assertContains("users.{$userId}.recovery.{$recoveryId}.create", $response['data']['events']);
+ $this->assertContains("users.{$userId}.recovery.{$recoveryId}", $response['data']['events']);
+ $this->assertContains("users.{$userId}.recovery.*.create", $response['data']['events']);
+ $this->assertContains("users.{$userId}.recovery.*", $response['data']['events']);
+ $this->assertContains("users.{$userId}", $response['data']['events']);
+ $this->assertContains("users.*.recovery.{$recoveryId}.create", $response['data']['events']);
+ $this->assertContains("users.*.recovery.{$recoveryId}", $response['data']['events']);
+ $this->assertContains("users.*.recovery.*.create", $response['data']['events']);
+ $this->assertContains("users.*.recovery.*", $response['data']['events']);
+ $this->assertContains("users.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$response = $this->client->call(Client::METHOD_PUT, '/account/recovery', array_merge([
@@ -520,7 +583,16 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertContains('account', $response['data']['channels']);
$this->assertContains('account.' . $userId, $response['data']['channels']);
- $this->assertEquals('account.recovery.update', $response['data']['event']);
+ $this->assertContains("users.{$userId}.recovery.{$recoveryId}.update", $response['data']['events']);
+ $this->assertContains("users.{$userId}.recovery.{$recoveryId}", $response['data']['events']);
+ $this->assertContains("users.{$userId}.recovery.*.update", $response['data']['events']);
+ $this->assertContains("users.{$userId}.recovery.*", $response['data']['events']);
+ $this->assertContains("users.{$userId}", $response['data']['events']);
+ $this->assertContains("users.*.recovery.{$recoveryId}.update", $response['data']['events']);
+ $this->assertContains("users.*.recovery.{$recoveryId}", $response['data']['events']);
+ $this->assertContains("users.*.recovery.*.update", $response['data']['events']);
+ $this->assertContains("users.*.recovery.*", $response['data']['events']);
+ $this->assertContains("users.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$client->close();
@@ -534,7 +606,7 @@ class RealtimeCustomClientTest extends Scope
$client = $this->getWebsocket(['documents', 'collections'], [
'origin' => 'http://localhost',
- 'cookie' => 'a_session_'.$projectId.'=' . $session
+ 'cookie' => 'a_session_' . $projectId . '=' . $session
]);
$response = json_decode($client->receive(), true);
@@ -564,9 +636,9 @@ class RealtimeCustomClientTest extends Scope
'permission' => 'document'
]);
- $data = ['actorsId' => $actors['body']['$id']];
+ $actorsId = $actors['body']['$id'];
- $name = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/attributes/string', array_merge([
+ $name = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actorsId . '/attributes/string', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
@@ -587,7 +659,7 @@ class RealtimeCustomClientTest extends Scope
/**
* Test Document Create
*/
- $document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/documents', array_merge([
+ $document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actorsId . '/documents', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -601,6 +673,8 @@ class RealtimeCustomClientTest extends Scope
$response = json_decode($client->receive(), true);
+ $documentId = $document['body']['$id'];
+
$this->assertArrayHasKey('type', $response);
$this->assertArrayHasKey('data', $response);
$this->assertEquals('event', $response['type']);
@@ -608,18 +682,25 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(3, $response['data']['channels']);
$this->assertContains('documents', $response['data']['channels']);
- $this->assertContains('collections.' . $data['actorsId'] . '.documents.' . $document['body']['$id'], $response['data']['channels']);
- $this->assertContains('collections.' . $actors['body']['$id'] . '.documents', $response['data']['channels']);
- $this->assertEquals('database.documents.create', $response['data']['event']);
+ $this->assertContains('collections.' . $actorsId . '.documents.' . $documentId, $response['data']['channels']);
+ $this->assertContains('collections.' . $actorsId . '.documents', $response['data']['channels']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}.create", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.*.create", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.*", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}", $response['data']['events']);
+ $this->assertContains("collections.*.documents.{$documentId}.create", $response['data']['events']);
+ $this->assertContains("collections.*.documents.{$documentId}", $response['data']['events']);
+ $this->assertContains("collections.*.documents.*.create", $response['data']['events']);
+ $this->assertContains("collections.*.documents.*", $response['data']['events']);
+ $this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$this->assertEquals($response['data']['payload']['name'], 'Chris Evans');
- $data['documentId'] = $document['body']['$id'];
-
/**
* Test Document Update
*/
- $document = $this->client->call(Client::METHOD_PATCH, '/database/collections/' . $data['actorsId'] . '/documents/' . $data['documentId'], array_merge([
+ $document = $this->client->call(Client::METHOD_PATCH, '/database/collections/' . $actorsId . '/documents/' . $documentId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -640,9 +721,18 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(3, $response['data']['channels']);
$this->assertContains('documents', $response['data']['channels']);
- $this->assertContains('collections.' . $data['actorsId'] . '.documents.' . $data['documentId'], $response['data']['channels']);
- $this->assertContains('collections.' . $data['actorsId'] . '.documents', $response['data']['channels']);
- $this->assertEquals('database.documents.update', $response['data']['event']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}", $response['data']['channels']);
+ $this->assertContains("collections.{$actorsId}.documents", $response['data']['channels']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}.update", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.*.update", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.*", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}", $response['data']['events']);
+ $this->assertContains("collections.*.documents.{$documentId}.update", $response['data']['events']);
+ $this->assertContains("collections.*.documents.{$documentId}", $response['data']['events']);
+ $this->assertContains("collections.*.documents.*.update", $response['data']['events']);
+ $this->assertContains("collections.*.documents.*", $response['data']['events']);
+ $this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$this->assertEquals($response['data']['payload']['name'], 'Chris Evans 2');
@@ -650,7 +740,7 @@ class RealtimeCustomClientTest extends Scope
/**
* Test Document Delete
*/
- $document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/documents', array_merge([
+ $document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actorsId . '/documents', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -664,7 +754,9 @@ class RealtimeCustomClientTest extends Scope
$client->receive();
- $this->client->call(Client::METHOD_DELETE, '/database/collections/' . $data['actorsId'] . '/documents/' . $document['body']['$id'], array_merge([
+ $documentId = $document['body']['$id'];
+
+ $this->client->call(Client::METHOD_DELETE, '/database/collections/' . $actorsId . '/documents/' . $documentId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -678,9 +770,18 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(3, $response['data']['channels']);
$this->assertContains('documents', $response['data']['channels']);
- $this->assertContains('collections.' . $data['actorsId'] . '.documents.' . $document['body']['$id'], $response['data']['channels']);
- $this->assertContains('collections.' . $data['actorsId'] . '.documents', $response['data']['channels']);
- $this->assertEquals('database.documents.delete', $response['data']['event']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}", $response['data']['channels']);
+ $this->assertContains("collections.{$actorsId}.documents", $response['data']['channels']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}.delete", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.*.delete", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.*", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}", $response['data']['events']);
+ $this->assertContains("collections.*.documents.{$documentId}.delete", $response['data']['events']);
+ $this->assertContains("collections.*.documents.{$documentId}", $response['data']['events']);
+ $this->assertContains("collections.*.documents.*.delete", $response['data']['events']);
+ $this->assertContains("collections.*.documents.*", $response['data']['events']);
+ $this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$this->assertEquals($response['data']['payload']['name'], 'Bradley Cooper');
@@ -695,7 +796,7 @@ class RealtimeCustomClientTest extends Scope
$client = $this->getWebsocket(['documents', 'collections'], [
'origin' => 'http://localhost',
- 'cookie' => 'a_session_'.$projectId.'=' . $session
+ 'cookie' => 'a_session_' . $projectId . '=' . $session
]);
$response = json_decode($client->receive(), true);
@@ -725,9 +826,9 @@ class RealtimeCustomClientTest extends Scope
'permission' => 'collection'
]);
- $data = ['actorsId' => $actors['body']['$id']];
+ $actorsId = $actors['body']['$id'];
- $name = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/attributes/string', array_merge([
+ $name = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actorsId . '/attributes/string', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
@@ -748,7 +849,7 @@ class RealtimeCustomClientTest extends Scope
/**
* Test Document Create
*/
- $document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/documents', array_merge([
+ $document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actorsId . '/documents', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -760,6 +861,8 @@ class RealtimeCustomClientTest extends Scope
'write' => [],
]);
+ $documentId = $document['body']['$id'];
+
$response = json_decode($client->receive(), true);
$this->assertArrayHasKey('type', $response);
@@ -769,18 +872,25 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(3, $response['data']['channels']);
$this->assertContains('documents', $response['data']['channels']);
- $this->assertContains('collections.' . $data['actorsId'] . '.documents.' . $document['body']['$id'], $response['data']['channels']);
- $this->assertContains('collections.' . $actors['body']['$id'] . '.documents', $response['data']['channels']);
- $this->assertEquals('database.documents.create', $response['data']['event']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}", $response['data']['channels']);
+ $this->assertContains("collections.{$actorsId}.documents", $response['data']['channels']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}.create", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.*.create", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.*", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}", $response['data']['events']);
+ $this->assertContains("collections.*.documents.{$documentId}.create", $response['data']['events']);
+ $this->assertContains("collections.*.documents.{$documentId}", $response['data']['events']);
+ $this->assertContains("collections.*.documents.*.create", $response['data']['events']);
+ $this->assertContains("collections.*.documents.*", $response['data']['events']);
+ $this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$this->assertEquals($response['data']['payload']['name'], 'Chris Evans');
- $data['documentId'] = $document['body']['$id'];
-
/**
* Test Document Update
*/
- $document = $this->client->call(Client::METHOD_PATCH, '/database/collections/' . $data['actorsId'] . '/documents/' . $data['documentId'], array_merge([
+ $document = $this->client->call(Client::METHOD_PATCH, '/database/collections/' . $actorsId . '/documents/' . $documentId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -800,9 +910,18 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(3, $response['data']['channels']);
$this->assertContains('documents', $response['data']['channels']);
- $this->assertContains('collections.' . $data['actorsId'] . '.documents.' . $data['documentId'], $response['data']['channels']);
- $this->assertContains('collections.' . $data['actorsId'] . '.documents', $response['data']['channels']);
- $this->assertEquals('database.documents.update', $response['data']['event']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}", $response['data']['channels']);
+ $this->assertContains("collections.{$actorsId}.documents", $response['data']['channels']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}.update", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.*.update", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.*", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}", $response['data']['events']);
+ $this->assertContains("collections.*.documents.{$documentId}.update", $response['data']['events']);
+ $this->assertContains("collections.*.documents.{$documentId}", $response['data']['events']);
+ $this->assertContains("collections.*.documents.*.update", $response['data']['events']);
+ $this->assertContains("collections.*.documents.*", $response['data']['events']);
+ $this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$this->assertEquals($response['data']['payload']['name'], 'Chris Evans 2');
@@ -810,7 +929,7 @@ class RealtimeCustomClientTest extends Scope
/**
* Test Document Delete
*/
- $document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/documents', array_merge([
+ $document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actorsId . '/documents', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -822,9 +941,11 @@ class RealtimeCustomClientTest extends Scope
'write' => [],
]);
+ $documentId = $document['body']['$id'];
+
$client->receive();
- $this->client->call(Client::METHOD_DELETE, '/database/collections/' . $data['actorsId'] . '/documents/' . $document['body']['$id'], array_merge([
+ $this->client->call(Client::METHOD_DELETE, '/database/collections/' . $actorsId . '/documents/' . $documentId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -838,9 +959,18 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(3, $response['data']['channels']);
$this->assertContains('documents', $response['data']['channels']);
- $this->assertContains('collections.' . $data['actorsId'] . '.documents.' . $document['body']['$id'], $response['data']['channels']);
- $this->assertContains('collections.' . $data['actorsId'] . '.documents', $response['data']['channels']);
- $this->assertEquals('database.documents.delete', $response['data']['event']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}", $response['data']['channels']);
+ $this->assertContains("collections.{$actorsId}.documents", $response['data']['channels']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}.delete", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.{$documentId}", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.*.delete", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}.documents.*", $response['data']['events']);
+ $this->assertContains("collections.{$actorsId}", $response['data']['events']);
+ $this->assertContains("collections.*.documents.{$documentId}.delete", $response['data']['events']);
+ $this->assertContains("collections.*.documents.{$documentId}", $response['data']['events']);
+ $this->assertContains("collections.*.documents.*.delete", $response['data']['events']);
+ $this->assertContains("collections.*.documents.*", $response['data']['events']);
+ $this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$this->assertEquals($response['data']['payload']['name'], 'Bradley Cooper');
@@ -855,7 +985,7 @@ class RealtimeCustomClientTest extends Scope
$client = $this->getWebsocket(['files'], [
'origin' => 'http://localhost',
- 'cookie' => 'a_session_'.$projectId.'=' . $session
+ 'cookie' => 'a_session_' . $projectId . '=' . $session
]);
$response = json_decode($client->receive(), true);
@@ -883,11 +1013,12 @@ class RealtimeCustomClientTest extends Scope
'permission' => 'bucket'
]);
- $data = ['bucketId' => $bucket1['body']['$id']];
+ $bucketId = $bucket1['body']['$id'];
+
/**
* Test File Create
*/
- $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([
+ $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -897,6 +1028,8 @@ class RealtimeCustomClientTest extends Scope
'write' => ['role:all'],
]);
+ $fileId = $file['body']['$id'];
+
$response = json_decode($client->receive(), true);
$this->assertArrayHasKey('type', $response);
@@ -906,17 +1039,26 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(3, $response['data']['channels']);
$this->assertContains('files', $response['data']['channels']);
- $this->assertContains('buckets.' . $data['bucketId'] . '.files.' . $file['body']['$id'], $response['data']['channels']);
- $this->assertContains('buckets.' . $data['bucketId'] . '.files', $response['data']['channels']);
- $this->assertEquals('storage.files.create', $response['data']['event']);
+ $this->assertContains("buckets.{$bucketId}.files.{$fileId}", $response['data']['channels']);
+ $this->assertContains("buckets.{$bucketId}.files", $response['data']['channels']);
+ $this->assertContains("buckets.{$bucketId}.files.{$fileId}.create", $response['data']['events']);
+ $this->assertContains("buckets.{$bucketId}.files.{$fileId}", $response['data']['events']);
+ $this->assertContains("buckets.{$bucketId}.files.*.create", $response['data']['events']);
+ $this->assertContains("buckets.{$bucketId}.files.*", $response['data']['events']);
+ $this->assertContains("buckets.{$bucketId}", $response['data']['events']);
+ $this->assertContains("buckets.*.files.{$fileId}.create", $response['data']['events']);
+ $this->assertContains("buckets.*.files.{$fileId}", $response['data']['events']);
+ $this->assertContains("buckets.*.files.*.create", $response['data']['events']);
+ $this->assertContains("buckets.*.files.*", $response['data']['events']);
+ $this->assertContains("buckets.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
- $data['fileId'] = $file['body']['$id'];
+ $fileId = $file['body']['$id'];
/**
* Test File Update
*/
- $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([
+ $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -933,15 +1075,24 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(3, $response['data']['channels']);
$this->assertContains('files', $response['data']['channels']);
- $this->assertContains('buckets.' . $data['bucketId'] . '.files.' . $file['body']['$id'], $response['data']['channels']);
- $this->assertContains('buckets.' . $data['bucketId'] . '.files', $response['data']['channels']);
- $this->assertEquals('storage.files.update', $response['data']['event']);
+ $this->assertContains("buckets.{$bucketId}.files.{$fileId}", $response['data']['channels']);
+ $this->assertContains("buckets.{$bucketId}.files", $response['data']['channels']);
+ $this->assertContains("buckets.{$bucketId}.files.{$fileId}.update", $response['data']['events']);
+ $this->assertContains("buckets.{$bucketId}.files.{$fileId}", $response['data']['events']);
+ $this->assertContains("buckets.{$bucketId}.files.*.update", $response['data']['events']);
+ $this->assertContains("buckets.{$bucketId}.files.*", $response['data']['events']);
+ $this->assertContains("buckets.{$bucketId}", $response['data']['events']);
+ $this->assertContains("buckets.*.files.{$fileId}.update", $response['data']['events']);
+ $this->assertContains("buckets.*.files.{$fileId}", $response['data']['events']);
+ $this->assertContains("buckets.*.files.*.update", $response['data']['events']);
+ $this->assertContains("buckets.*.files.*", $response['data']['events']);
+ $this->assertContains("buckets.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
/**
* Test File Delete
*/
- $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([
+ $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -955,9 +1106,18 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(3, $response['data']['channels']);
$this->assertContains('files', $response['data']['channels']);
- $this->assertContains('buckets.' . $data['bucketId'] . '.files.' . $file['body']['$id'], $response['data']['channels']);
- $this->assertContains('buckets.' . $data['bucketId'] . '.files', $response['data']['channels']);
- $this->assertEquals('storage.files.delete', $response['data']['event']);
+ $this->assertContains("buckets.{$bucketId}.files.{$fileId}", $response['data']['channels']);
+ $this->assertContains("buckets.{$bucketId}.files", $response['data']['channels']);
+ $this->assertContains("buckets.{$bucketId}.files.{$fileId}.delete", $response['data']['events']);
+ $this->assertContains("buckets.{$bucketId}.files.{$fileId}", $response['data']['events']);
+ $this->assertContains("buckets.{$bucketId}.files.*.delete", $response['data']['events']);
+ $this->assertContains("buckets.{$bucketId}.files.*", $response['data']['events']);
+ $this->assertContains("buckets.{$bucketId}", $response['data']['events']);
+ $this->assertContains("buckets.*.files.{$fileId}.delete", $response['data']['events']);
+ $this->assertContains("buckets.*.files.{$fileId}", $response['data']['events']);
+ $this->assertContains("buckets.*.files.*.delete", $response['data']['events']);
+ $this->assertContains("buckets.*.files.*", $response['data']['events']);
+ $this->assertContains("buckets.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$client->close();
@@ -971,7 +1131,7 @@ class RealtimeCustomClientTest extends Scope
$client = $this->getWebsocket(['executions'], [
'origin' => 'http://localhost',
- 'cookie' => 'a_session_'.$projectId.'=' . $session
+ 'cookie' => 'a_session_' . $projectId . '=' . $session
]);
$response = json_decode($client->receive(), true);
@@ -1007,11 +1167,12 @@ class RealtimeCustomClientTest extends Scope
$folder = 'timeout';
$stderr = '';
- $stdout= '';
- $code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz";
- Console::execute('cd '.realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $stdout, $stderr);
-
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/deployments', array_merge([
+ $stdout = '';
+ $code = realpath(__DIR__ . '/../../../resources/functions') . "/{$folder}/code.tar.gz";
+
+ Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/{$folder} && tar --exclude code.tar.gz -czf code.tar.gz .", '', $stdout, $stderr);
+
+ $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
@@ -1028,7 +1189,7 @@ class RealtimeCustomClientTest extends Scope
// Wait for deployment to be built.
sleep(5);
- $response = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/deployments/'.$deploymentId, array_merge([
+ $response = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
@@ -1037,7 +1198,7 @@ class RealtimeCustomClientTest extends Scope
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertNotEmpty($response['body']['$id']);
- $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
+ $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()), []);
@@ -1048,6 +1209,8 @@ class RealtimeCustomClientTest extends Scope
$response = json_decode($client->receive(), true);
$responseUpdate = json_decode($client->receive(), true);
+ $executionId = $execution['body']['$id'];
+
$this->assertArrayHasKey('type', $response);
$this->assertArrayHasKey('data', $response);
$this->assertEquals('event', $response['type']);
@@ -1056,9 +1219,18 @@ class RealtimeCustomClientTest extends Scope
$this->assertCount(4, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
$this->assertContains('executions', $response['data']['channels']);
- $this->assertContains('executions.' . $execution['body']['$id'], $response['data']['channels']);
- $this->assertContains('functions.' . $execution['body']['functionId'], $response['data']['channels']);
- $this->assertEquals('functions.executions.create', $response['data']['event']);
+ $this->assertContains("executions.{$executionId}", $response['data']['channels']);
+ $this->assertContains("functions.{$functionId}", $response['data']['channels']);
+ $this->assertContains("functions.{$functionId}.executions.{$executionId}.create", $response['data']['events']);
+ $this->assertContains("functions.{$functionId}.executions.{$executionId}", $response['data']['events']);
+ $this->assertContains("functions.{$functionId}.executions.*.create", $response['data']['events']);
+ $this->assertContains("functions.{$functionId}.executions.*", $response['data']['events']);
+ $this->assertContains("functions.{$functionId}", $response['data']['events']);
+ $this->assertContains("functions.*.executions.{$executionId}.create", $response['data']['events']);
+ $this->assertContains("functions.*.executions.{$executionId}", $response['data']['events']);
+ $this->assertContains("functions.*.executions.*.create", $response['data']['events']);
+ $this->assertContains("functions.*.executions.*", $response['data']['events']);
+ $this->assertContains("functions.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$this->assertArrayHasKey('type', $responseUpdate);
@@ -1069,15 +1241,24 @@ class RealtimeCustomClientTest extends Scope
$this->assertCount(4, $responseUpdate['data']['channels']);
$this->assertContains('console', $responseUpdate['data']['channels']);
$this->assertContains('executions', $responseUpdate['data']['channels']);
- $this->assertContains('executions.' . $execution['body']['$id'], $responseUpdate['data']['channels']);
- $this->assertContains('functions.' . $execution['body']['functionId'], $responseUpdate['data']['channels']);
- $this->assertEquals('functions.executions.update', $responseUpdate['data']['event']);
+ $this->assertContains("executions.{$executionId}", $responseUpdate['data']['channels']);
+ $this->assertContains("functions.{$functionId}", $responseUpdate['data']['channels']);
+ $this->assertContains("functions.{$functionId}.executions.{$executionId}.update", $responseUpdate['data']['events']);
+ $this->assertContains("functions.{$functionId}.executions.{$executionId}", $responseUpdate['data']['events']);
+ $this->assertContains("functions.{$functionId}.executions.*.update", $responseUpdate['data']['events']);
+ $this->assertContains("functions.{$functionId}.executions.*", $responseUpdate['data']['events']);
+ $this->assertContains("functions.{$functionId}", $responseUpdate['data']['events']);
+ $this->assertContains("functions.*.executions.{$executionId}.update", $responseUpdate['data']['events']);
+ $this->assertContains("functions.*.executions.{$executionId}", $responseUpdate['data']['events']);
+ $this->assertContains("functions.*.executions.*.update", $responseUpdate['data']['events']);
+ $this->assertContains("functions.*.executions.*", $responseUpdate['data']['events']);
+ $this->assertContains("functions.*", $responseUpdate['data']['events']);
$this->assertNotEmpty($responseUpdate['data']['payload']);
$client->close();
// Cleanup : Delete function
- $response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
+ $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
@@ -1094,7 +1275,7 @@ class RealtimeCustomClientTest extends Scope
$client = $this->getWebsocket(['teams'], [
'origin' => 'http://localhost',
- 'cookie' => 'a_session_'.$projectId.'=' . $session
+ 'cookie' => 'a_session_' . $projectId . '=' . $session
]);
$response = json_decode($client->receive(), true);
@@ -1133,14 +1314,17 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(2, $response['data']['channels']);
$this->assertContains('teams', $response['data']['channels']);
- $this->assertContains('teams.' . $teamId, $response['data']['channels']);
- $this->assertEquals('teams.create', $response['data']['event']);
+ $this->assertContains("teams.{$teamId}", $response['data']['channels']);
+ $this->assertContains("teams.{$teamId}.create", $response['data']['events']);
+ $this->assertContains("teams.{$teamId}", $response['data']['events']);
+ $this->assertContains("teams.*.create", $response['data']['events']);
+ $this->assertContains("teams.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
/**
* Test Team Update
*/
- $team = $this->client->call(Client::METHOD_PUT, '/teams/'.$teamId, array_merge([
+ $team = $this->client->call(Client::METHOD_PUT, '/teams/' . $teamId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
], $this->getHeaders()), [
@@ -1159,8 +1343,11 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(2, $response['data']['channels']);
$this->assertContains('teams', $response['data']['channels']);
- $this->assertContains('teams.' . $teamId, $response['data']['channels']);
- $this->assertEquals('teams.update', $response['data']['event']);
+ $this->assertContains("teams.{$teamId}", $response['data']['channels']);
+ $this->assertContains("teams.{$teamId}.update", $response['data']['events']);
+ $this->assertContains("teams.{$teamId}", $response['data']['events']);
+ $this->assertContains("teams.*.update", $response['data']['events']);
+ $this->assertContains("teams.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$client->close();
@@ -1181,7 +1368,7 @@ class RealtimeCustomClientTest extends Scope
$client = $this->getWebsocket(['memberships'], [
'origin' => 'http://localhost',
- 'cookie' => 'a_session_'.$projectId.'='.$session
+ 'cookie' => 'a_session_' . $projectId . '=' . $session
]);
$response = json_decode($client->receive(), true);
@@ -1195,7 +1382,7 @@ class RealtimeCustomClientTest extends Scope
$this->assertNotEmpty($response['data']['user']);
$this->assertEquals($user['$id'], $response['data']['user']['$id']);
- $response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamId.'/memberships', array_merge([
+ $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamId . '/memberships', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -1206,7 +1393,7 @@ class RealtimeCustomClientTest extends Scope
* Test Update Membership
*/
$roles = ['admin', 'editor', 'uncle'];
- $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamId.'/memberships/'.$membershipId, array_merge([
+ $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamId . '/memberships/' . $membershipId, array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -1223,10 +1410,19 @@ class RealtimeCustomClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(2, $response['data']['channels']);
$this->assertContains('memberships', $response['data']['channels']);
- $this->assertContains('memberships.' . $membershipId, $response['data']['channels']);
- $this->assertEquals('teams.memberships.update', $response['data']['event']);
+ $this->assertContains("memberships.{$membershipId}", $response['data']['channels']);
+ $this->assertContains("teams.{$teamId}.memberships.{$membershipId}.update", $response['data']['events']);
+ $this->assertContains("teams.{$teamId}.memberships.{$membershipId}", $response['data']['events']);
+ $this->assertContains("teams.{$teamId}.memberships.*.update", $response['data']['events']);
+ $this->assertContains("teams.{$teamId}.memberships.*", $response['data']['events']);
+ $this->assertContains("teams.{$teamId}", $response['data']['events']);
+ $this->assertContains("teams.*.memberships.{$membershipId}.update", $response['data']['events']);
+ $this->assertContains("teams.*.memberships.{$membershipId}", $response['data']['events']);
+ $this->assertContains("teams.*.memberships.*.update", $response['data']['events']);
+ $this->assertContains("teams.*.memberships.*", $response['data']['events']);
+ $this->assertContains("teams.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
$client->close();
}
-}
\ No newline at end of file
+}
diff --git a/tests/e2e/Services/Webhooks/WebhooksBase.php b/tests/e2e/Services/Webhooks/WebhooksBase.php
index b8ed3b770..fd65b9484 100644
--- a/tests/e2e/Services/Webhooks/WebhooksBase.php
+++ b/tests/e2e/Services/Webhooks/WebhooksBase.php
@@ -23,7 +23,9 @@ trait WebhooksBase
'write' => ['role:all'],
'permission' => 'document',
]);
-
+
+ $actorsId = $actors['body']['$id'];
+
$this->assertEquals($actors['headers']['status-code'], 201);
$this->assertNotEmpty($actors['body']['$id']);
@@ -32,7 +34,10 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'database.collections.create');
+ $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -44,7 +49,7 @@ trait WebhooksBase
$this->assertCount(1, $webhook['data']['$read']);
$this->assertCount(1, $webhook['data']['$write']);
- return array_merge(['actorsId' => $actors['body']['$id']]);
+ return array_merge(['actorsId' => $actorsId]);
}
/**
@@ -52,7 +57,9 @@ trait WebhooksBase
*/
public function testCreateAttributes(array $data): array
{
- $firstName = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/attributes/string', array_merge([
+ $actorsId = $data['actorsId'];
+
+ $firstName = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actorsId . '/attributes/string', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
@@ -62,7 +69,7 @@ trait WebhooksBase
'required' => true,
]);
- $lastName = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/attributes/string', array_merge([
+ $lastName = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actorsId . '/attributes/string', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
@@ -72,7 +79,7 @@ trait WebhooksBase
'required' => true,
]);
- $extra = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/attributes/string', array_merge([
+ $extra = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actorsId . '/attributes/string', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
@@ -82,6 +89,8 @@ trait WebhooksBase
'required' => false,
]);
+ $attributeId = $extra['body']['key'];
+
$this->assertEquals($firstName['headers']['status-code'], 201);
$this->assertEquals($firstName['body']['key'], 'firstName');
$this->assertEquals($lastName['headers']['status-code'], 201);
@@ -97,13 +106,22 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'database.attributes.create');
+ $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.attributes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.attributes.{$actorsId}_{$attributeId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.attributes.{$actorsId}_{$attributeId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.attributes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.attributes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.attributes.{$actorsId}_{$attributeId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.attributes.{$actorsId}_{$attributeId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
$this->assertNotEmpty($webhook['data']['key']);
$this->assertEquals($webhook['data']['key'], 'extra');
-
+
$removed = $this->client->call(Client::METHOD_DELETE, '/database/collections/' . $data['actorsId'] . '/attributes/' . $extra['body']['key'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -117,7 +135,16 @@ trait WebhooksBase
// $this->assertEquals($webhook['method'], 'DELETE');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'database.attributes.delete');
+ $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.attributes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.attributes.{$actorsId}_{$attributeId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.attributes.{$actorsId}_{$attributeId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.attributes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.attributes.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.attributes.{$actorsId}_{$attributeId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.attributes.{$actorsId}_{$attributeId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -132,7 +159,12 @@ trait WebhooksBase
*/
public function testCreateDocument(array $data): array
{
- $document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/documents', array_merge([
+ $actorsId = $data['actorsId'];
+
+ /**
+ * Test for SUCCESS
+ */
+ $document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actorsId . '/documents', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -140,12 +172,13 @@ trait WebhooksBase
'data' => [
'firstName' => 'Chris',
'lastName' => 'Evans',
-
],
'read' => ['role:all'],
'write' => ['role:all'],
]);
+ $documentId = $document['body']['$id'];
+
$this->assertEquals($document['headers']['status-code'], 201);
$this->assertNotEmpty($document['body']['$id']);
@@ -154,7 +187,16 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'database.documents.create');
+ $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.documents.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.documents.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.documents.{$documentId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.documents.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.documents.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.documents.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.documents.{$documentId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -177,7 +219,12 @@ trait WebhooksBase
*/
public function testUpdateDocument(array $data): array
{
- $document = $this->client->call(Client::METHOD_PATCH, '/database/collections/' . $data['actorsId'] . '/documents/'.$data['documentId'], array_merge([
+ $actorsId = $data['actorsId'];
+
+ /**
+ * Test for SUCCESS
+ */
+ $document = $this->client->call(Client::METHOD_PATCH, '/database/collections/' . $actorsId . '/documents/' . $data['documentId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -189,6 +236,8 @@ trait WebhooksBase
'write' => ['role:all'],
]);
+ $documentId = $document['body']['$id'];
+
$this->assertEquals($document['headers']['status-code'], 200);
$this->assertNotEmpty($document['body']['$id']);
@@ -197,7 +246,16 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'database.documents.update');
+ $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.documents.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.documents.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.documents.{$documentId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.documents.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.documents.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.documents.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.documents.{$documentId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -218,7 +276,12 @@ trait WebhooksBase
*/
public function testDeleteDocument(array $data): array
{
- $document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/documents', array_merge([
+ $actorsId = $data['actorsId'];
+
+ /**
+ * Test for SUCCESS
+ */
+ $document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actorsId . '/documents', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -226,16 +289,18 @@ trait WebhooksBase
'data' => [
'firstName' => 'Bradly',
'lastName' => 'Cooper',
-
+
],
'read' => ['role:all'],
'write' => ['role:all'],
]);
+ $documentId = $document['body']['$id'];
+
$this->assertEquals($document['headers']['status-code'], 201);
$this->assertNotEmpty($document['body']['$id']);
- $document = $this->client->call(Client::METHOD_DELETE, '/database/collections/' . $data['actorsId'] . '/documents/' . $document['body']['$id'], array_merge([
+ $document = $this->client->call(Client::METHOD_DELETE, '/database/collections/' . $actorsId . '/documents/' . $document['body']['$id'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -247,7 +312,16 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'database.documents.delete');
+ $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.documents.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.documents.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.documents.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.documents.{$documentId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.documents.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.documents.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.documents.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.documents.{$documentId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -280,7 +354,9 @@ trait WebhooksBase
'read' => ['role:all'],
'write' => ['role:all']
]);
-
+
+ $bucketId = $bucket['body']['$id'];
+
$this->assertEquals($bucket['headers']['status-code'], 201);
$this->assertNotEmpty($bucket['body']['$id']);
@@ -289,7 +365,10 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'storage.buckets.create');
+ $this->assertStringContainsString('buckets.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('buckets.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -299,8 +378,8 @@ trait WebhooksBase
$this->assertEquals(true, $webhook['data']['enabled']);
$this->assertIsArray($webhook['data']['$read']);
$this->assertIsArray($webhook['data']['$write']);
-
- return array_merge(['bucketId' => $bucket['body']['$id']]);
+
+ return array_merge(['bucketId' => $bucketId]);
}
/**
@@ -308,6 +387,8 @@ trait WebhooksBase
*/
public function testUpdateStorageBucket(array $data): array
{
+ $bucketId = $data['bucketId'];
+
/**
* Test for SUCCESS
*/
@@ -320,7 +401,7 @@ trait WebhooksBase
'permission' => 'file',
'enabled' => false,
]);
-
+
$this->assertEquals($bucket['headers']['status-code'], 200);
$this->assertNotEmpty($bucket['body']['$id']);
@@ -329,7 +410,10 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'storage.buckets.update');
+ $this->assertStringContainsString('buckets.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('buckets.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -339,7 +423,7 @@ trait WebhooksBase
$this->assertEquals(false, $webhook['data']['enabled']);
$this->assertIsArray($webhook['data']['$read']);
$this->assertIsArray($webhook['data']['$write']);
-
+
return array_merge(['bucketId' => $bucket['body']['$id']]);
}
@@ -348,6 +432,8 @@ trait WebhooksBase
*/
public function testCreateBucketFile(array $data): array
{
+ $bucketId = $data['bucketId'];
+
//enable bucket
$bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'], array_merge([
'content-type' => 'application/json',
@@ -358,12 +444,12 @@ trait WebhooksBase
'permission' => 'file',
'enabled' => true,
]);
-
+
$this->assertEquals($bucket['headers']['status-code'], 200);
/**
* Test for SUCCESS
*/
- $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'. $data['bucketId'] . '/files', array_merge([
+ $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $data['bucketId'] . '/files', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -374,6 +460,8 @@ trait WebhooksBase
'folderId' => 'xyz',
]);
+ $fileId = $file['body']['$id'];
+
$this->assertEquals($file['headers']['status-code'], 201);
$this->assertNotEmpty($file['body']['$id']);
@@ -382,7 +470,16 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'storage.files.create');
+ $this->assertStringContainsString('buckets.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('buckets.*.files.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('buckets.*.files.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.*.files.{$fileId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.*.files.{$fileId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.files.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.files.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.files.{$fileId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.files.{$fileId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -396,22 +493,23 @@ trait WebhooksBase
$this->assertEquals($webhook['data']['mimeType'], 'image/png');
$this->assertEquals($webhook['data']['sizeOriginal'], 47218);
- /**
- * Test for FAILURE
- */
- $data ['fileId'] = $file['body']['$id'];
+ $data['fileId'] = $fileId;
+
return $data;
}
-
+
/**
* @depends testCreateBucketFile
*/
public function testUpdateBucketFile(array $data): array
{
+ $bucketId = $data['bucketId'];
+ $fileId = $data['fileId'];
+
/**
* Test for SUCCESS
*/
- $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], array_merge([
+ $file = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -427,7 +525,16 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'storage.files.update');
+ $this->assertStringContainsString('buckets.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('buckets.*.files.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('buckets.*.files.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.*.files.{$fileId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.*.files.{$fileId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.files.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.files.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.files.{$fileId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.files.{$fileId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -440,15 +547,18 @@ trait WebhooksBase
$this->assertNotEmpty($webhook['data']['signature']);
$this->assertEquals($webhook['data']['mimeType'], 'image/png');
$this->assertEquals($webhook['data']['sizeOriginal'], 47218);
-
+
return $data;
}
-
+
/**
* @depends testUpdateBucketFile
*/
public function testDeleteBucketFile(array $data): array
{
+ $bucketId = $data['bucketId'];
+ $fileId = $data['fileId'];
+
/**
* Test for SUCCESS
*/
@@ -465,7 +575,16 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'storage.files.delete');
+ $this->assertStringContainsString('buckets.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('buckets.*.files.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('buckets.*.files.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.*.files.{$fileId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.*.files.{$fileId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.files.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.files.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.files.{$fileId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.files.{$fileId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -478,24 +597,25 @@ trait WebhooksBase
$this->assertNotEmpty($webhook['data']['signature']);
$this->assertEquals($webhook['data']['mimeType'], 'image/png');
$this->assertEquals($webhook['data']['sizeOriginal'], 47218);
-
+
return $data;
}
- /**
+ /**
* @depends testDeleteBucketFile
*/
public function testDeleteStorageBucket(array $data)
{
+ $bucketId = $data['bucketId'];
/**
* Test for SUCCESS
*/
- $bucket = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $data['bucketId'] , array_merge([
+ $bucket = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]));
-
+
$this->assertEquals($bucket['headers']['status-code'], 204);
$this->assertEmpty($bucket['body']);
@@ -504,7 +624,10 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'storage.buckets.delete');
+ $this->assertStringContainsString('buckets.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('buckets.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("buckets.{$bucketId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -529,6 +652,8 @@ trait WebhooksBase
'name' => 'Arsenal'
]);
+ $teamId = $team['body']['$id'];
+
$this->assertEquals(201, $team['headers']['status-code']);
$this->assertNotEmpty($team['body']['$id']);
@@ -537,7 +662,10 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'teams.create');
+ $this->assertStringContainsString('teams.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('teams.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -551,7 +679,7 @@ trait WebhooksBase
/**
* Test for FAILURE
*/
- return ['teamId' => $team['body']['$id']];
+ return ['teamId' => $teamId];
}
/**
@@ -559,10 +687,11 @@ trait WebhooksBase
*/
public function testUpdateTeam($data): array
{
+ $teamId = $data['teamId'];
/**
* Test for SUCCESS
*/
- $team = $this->client->call(Client::METHOD_PUT, '/teams/'.$data['teamId'], array_merge([
+ $team = $this->client->call(Client::METHOD_PUT, '/teams/' . $teamId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -577,7 +706,10 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'teams.update');
+ $this->assertStringContainsString('teams.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('teams.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -607,10 +739,12 @@ trait WebhooksBase
'name' => 'Chelsea'
]);
+ $teamId = $team['body']['$id'];
+
$this->assertEquals(201, $team['headers']['status-code']);
$this->assertNotEmpty($team['body']['$id']);
- $team = $this->client->call(Client::METHOD_DELETE, '/teams/'.$team['body']['$id'], array_merge([
+ $team = $this->client->call(Client::METHOD_DELETE, '/teams/' . $team['body']['$id'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -620,7 +754,10 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'teams.delete');
+ $this->assertStringContainsString('teams.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('teams.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -642,13 +779,13 @@ trait WebhooksBase
*/
public function testCreateTeamMembership($data): array
{
- $teamUid = $data['teamId'] ?? '';
- $email = uniqid().'friend@localhost.test';
+ $teamId = $data['teamId'] ?? '';
+ $email = uniqid() . 'friend@localhost.test';
/**
* Test for SUCCESS
*/
- $team = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([
+ $team = $this->client->call(Client::METHOD_POST, '/teams/' . $teamId . '/memberships', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -664,15 +801,23 @@ trait WebhooksBase
$lastEmail = $this->getLastEmail();
$secret = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
- $membershipUid = substr($lastEmail['text'], strpos($lastEmail['text'], '?membershipId=', 0) + 14, 20);
- $userUid = substr($lastEmail['text'], strpos($lastEmail['text'], '&userId=', 0) + 8, 20);
+ $membershipId = $team['body']['$id'];
$webhook = $this->getLastRequest();
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'teams.memberships.create');
+ $this->assertStringContainsString('teams.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('teams.*.memberships.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('teams.*.memberships.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.*.memberships.{$membershipId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.*.memberships.{$membershipId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}.memberships.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}.memberships.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}.memberships.{$membershipId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}.memberships.{$membershipId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -688,25 +833,25 @@ trait WebhooksBase
* Test for FAILURE
*/
return [
- 'teamId' => $teamUid,
+ 'teamId' => $teamId,
'secret' => $secret,
- 'membershipId' => $membershipUid,
+ 'membershipId' => $membershipId,
'userId' => $webhook['data']['userId'],
];
}
/**
- * @depends testCreateTeam
+ * @depends testCreateTeamMembership
*/
- public function testDeleteTeamMembership($data): array
+ public function testDeleteTeamMembership($data): void
{
- $teamUid = $data['teamId'] ?? '';
- $email = uniqid().'friend@localhost.test';
+ $teamId = $data['teamId'] ?? '';
+ $email = uniqid() . 'friend@localhost.test';
/**
* Test for SUCCESS
*/
- $team = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([
+ $team = $this->client->call(Client::METHOD_POST, '/teams/' . $teamId . '/memberships', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -716,10 +861,12 @@ trait WebhooksBase
'url' => 'http://localhost:5000/join-us#title'
]);
+ $membershipId = $team['body']['$id'] ?? '';
+
$this->assertEquals(201, $team['headers']['status-code']);
$this->assertNotEmpty($team['body']['$id']);
-
- $team = $this->client->call(Client::METHOD_DELETE, '/teams/'.$teamUid.'/memberships/'.$team['body']['$id'], array_merge([
+
+ $team = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamId . '/memberships/' . $team['body']['$id'], array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -732,7 +879,16 @@ trait WebhooksBase
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'teams.memberships.delete');
+ $this->assertStringContainsString('teams.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('teams.*.memberships.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('teams.*.memberships.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.*.memberships.{$membershipId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.*.memberships.{$membershipId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}.memberships.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}.memberships.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}.memberships.{$membershipId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamId}.memberships.{$membershipId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -743,10 +899,5 @@ trait WebhooksBase
$this->assertCount(2, $webhook['data']['roles']);
$this->assertIsInt($webhook['data']['joined']);
$this->assertEquals(('server' === $this->getSide()), $webhook['data']['confirm']);
-
- /**
- * Test for FAILURE
- */
- return [];
}
-}
\ No newline at end of file
+}
diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php
index 355c8f585..47eebe4b7 100644
--- a/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php
+++ b/tests/e2e/Services/Webhooks/WebhooksCustomClientTest.php
@@ -13,9 +13,9 @@ class WebhooksCustomClientTest extends Scope
use ProjectCustom;
use SideClient;
- public function testCreateAccount():array
+ public function testCreateAccount(): array
{
- $email = uniqid().'user@localhost.test';
+ $email = uniqid() . 'user@localhost.test';
$password = 'password';
$name = 'User Name';
@@ -43,7 +43,10 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'account.create');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events'],);
+ $this->assertStringContainsString("users.{$id}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -64,9 +67,9 @@ class WebhooksCustomClientTest extends Scope
];
}
- public function testDeleteAccount():array
+ public function testDeleteAccount(): array
{
- $email = uniqid().'user1@localhost.test';
+ $email = uniqid() . 'user1@localhost.test';
$password = 'password';
$name = 'User Name 1';
@@ -95,14 +98,14 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($accountSession['headers']['status-code'], 201);
- $sessionId = $accountSession['body']['$id'];
- $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
+ $id = $account['body']['$id'];
+ $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']];
$account = $this->client->call(Client::METHOD_DELETE, '/account', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
+ 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
]));
$this->assertEquals($account['headers']['status-code'], 204);
@@ -113,7 +116,10 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'account.delete');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -132,8 +138,9 @@ class WebhooksCustomClientTest extends Scope
/**
* @depends testCreateAccount
*/
- public function testCreateAccountSession($data):array
+ public function testCreateAccountSession($data): array
{
+ $id = $data['id'] ?? '';
$email = $data['email'] ?? '';
$password = $data['password'] ?? '';
@@ -152,14 +159,23 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($accountSession['headers']['status-code'], 201);
$sessionId = $accountSession['body']['$id'];
- $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
+ $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']];
$webhook = $this->getLastRequest();
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'account.sessions.create');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.sessions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.sessions.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.sessions.{$sessionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.sessions.{$sessionId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.sessions.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.sessions.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.sessions.{$sessionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.sessions.{$sessionId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -198,8 +214,9 @@ class WebhooksCustomClientTest extends Scope
/**
* @depends testCreateAccount
*/
- public function testDeleteAccountSession($data):array
+ public function testDeleteAccountSession($data): array
{
+ $id = $data['id'] ?? '';
$email = $data['email'] ?? '';
$password = $data['password'] ?? '';
@@ -216,15 +233,15 @@ class WebhooksCustomClientTest extends Scope
]);
$sessionId = $accountSession['body']['$id'];
- $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
+ $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']];
$this->assertEquals($accountSession['headers']['status-code'], 201);
- $accountSession = $this->client->call(Client::METHOD_DELETE, '/account/sessions/'.$sessionId, array_merge([
+ $accountSession = $this->client->call(Client::METHOD_DELETE, '/account/sessions/' . $sessionId, array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
+ 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
]));
$this->assertEquals($accountSession['headers']['status-code'], 204);
@@ -234,7 +251,16 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'account.sessions.delete');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.sessions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.sessions.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.sessions.{$sessionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.sessions.{$sessionId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.sessions.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.sessions.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.sessions.{$sessionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.sessions.{$sessionId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -270,8 +296,9 @@ class WebhooksCustomClientTest extends Scope
/**
* @depends testCreateAccount
*/
- public function testDeleteAccountSessions($data):array
+ public function testDeleteAccountSessions($data): array
{
+ $id = $data['id'] ?? '';
$email = $data['email'] ?? '';
$password = $data['password'] ?? '';
@@ -287,7 +314,8 @@ class WebhooksCustomClientTest extends Scope
'password' => $password,
]);
- $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
+ $sessionId = $accountSession['body']['$id'];
+ $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']];
$this->assertEquals($accountSession['headers']['status-code'], 201);
@@ -295,7 +323,7 @@ class WebhooksCustomClientTest extends Scope
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
+ 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
]));
$this->assertEquals($accountSession['headers']['status-code'], 204);
@@ -305,7 +333,16 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'account.sessions.delete');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.sessions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.sessions.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.sessions.{$sessionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.sessions.{$sessionId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.sessions.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.sessions.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.sessions.{$sessionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.sessions.{$sessionId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -348,7 +385,7 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($accountSession['headers']['status-code'], 201);
$sessionId = $accountSession['body']['$id'];
- $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
+ $session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']];
return array_merge($data, [
'sessionId' => $sessionId,
@@ -370,7 +407,7 @@ class WebhooksCustomClientTest extends Scope
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
+ 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
]), [
'name' => $newName
]);
@@ -383,7 +420,12 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'account.update.name');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.update.name', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.update.name", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -413,7 +455,7 @@ class WebhooksCustomClientTest extends Scope
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
+ 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
]), [
'password' => 'new-password',
'oldPassword' => $password,
@@ -427,7 +469,12 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'account.update.password');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.update.password', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.update.password", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -452,14 +499,14 @@ class WebhooksCustomClientTest extends Scope
{
$id = $data['id'] ?? '';
$email = $data['email'] ?? '';
- $newEmail = uniqid().'new@localhost.test';
+ $newEmail = uniqid() . 'new@localhost.test';
$session = $data['session'] ?? '';
$account = $this->client->call(Client::METHOD_PATCH, '/account/email', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
+ 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
]), [
'email' => $newEmail,
'password' => 'new-password',
@@ -473,7 +520,12 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'account.update.email');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.update.email', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.update.email", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -504,7 +556,7 @@ class WebhooksCustomClientTest extends Scope
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
+ 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
]), [
'prefs' => [
'prefKey1' => 'prefValue1',
@@ -520,7 +572,12 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'account.update.prefs');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.update.prefs', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.update.prefs", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -546,7 +603,6 @@ class WebhooksCustomClientTest extends Scope
{
$id = $data['id'] ?? '';
$email = $data['email'] ?? '';
- $session = $data['session'] ?? '';
$recovery = $this->client->call(Client::METHOD_POST, '/account/recovery', array_merge([
'origin' => 'http://localhost',
@@ -557,6 +613,8 @@ class WebhooksCustomClientTest extends Scope
'url' => 'http://localhost/recovery',
]);
+ $recoveryId = $recovery['body']['$id'];
+
$this->assertEquals(201, $recovery['headers']['status-code']);
$this->assertIsArray($recovery['body']);
@@ -565,18 +623,27 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'account.recovery.create');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.recovery.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.recovery.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.recovery.{$recoveryId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.recovery.{$recoveryId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.recovery.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.recovery.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.recovery.{$recoveryId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.recovery.{$recoveryId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
- $this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id']), true);
+ $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-User-Id'], $id);
$this->assertNotEmpty($webhook['data']['$id']);
$this->assertNotEmpty($webhook['data']['userId']);
$this->assertNotEmpty($webhook['data']['secret']);
$this->assertIsNumeric($webhook['data']['expire']);
$data['secret'] = $webhook['data']['secret'];
-
+
return $data;
}
@@ -602,6 +669,8 @@ class WebhooksCustomClientTest extends Scope
'passwordAgain' => $password,
]);
+ $recoveryId = $recovery['body']['$id'];
+
$this->assertEquals(200, $recovery['headers']['status-code']);
$this->assertIsArray($recovery['body']);
@@ -610,7 +679,16 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'account.recovery.update');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.recovery.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.recovery.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.recovery.{$recoveryId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.recovery.{$recoveryId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.recovery.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.recovery.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.recovery.{$recoveryId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.recovery.{$recoveryId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -638,11 +716,13 @@ class WebhooksCustomClientTest extends Scope
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
+ 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
]), [
'url' => 'http://localhost/verification',
]);
+ $verificationId = $verification['body']['$id'];
+
$this->assertEquals(201, $verification['headers']['status-code']);
$this->assertIsArray($verification['body']);
@@ -651,7 +731,16 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'account.verification.create');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.verification.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.verification.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.verification.{$verificationId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.verification.{$verificationId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.verification.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.verification.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.verification.{$verificationId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.verification.{$verificationId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -680,12 +769,14 @@ class WebhooksCustomClientTest extends Scope
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
- 'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
+ 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
]), [
'userId' => $id,
'secret' => $secret,
]);
+ $verificationId = $verification['body']['$id'];
+
$this->assertEquals(200, $verification['headers']['status-code']);
$this->assertIsArray($verification['body']);
@@ -694,7 +785,16 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'account.verification.update');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.verification.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.verification.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.verification.{$verificationId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.*.verification.{$verificationId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.verification.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.verification.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.verification.{$verificationId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.verification.{$verificationId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -722,7 +822,7 @@ class WebhooksCustomClientTest extends Scope
/**
* Test for SUCCESS
*/
- $team = $this->client->call(Client::METHOD_PATCH, '/teams/'.$teamUid.'/memberships/'.$membershipUid.'/status', array_merge([
+ $team = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -739,7 +839,20 @@ class WebhooksCustomClientTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'teams.memberships.update.status');
+ $this->assertStringContainsString('teams.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('teams.*.memberships.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('teams.*.memberships.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('teams.*.memberships.*.update.status', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.*.memberships.{$membershipUid}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.*.memberships.{$membershipUid}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.*.memberships.{$membershipUid}.update.status", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamUid}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamUid}.memberships.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamUid}.memberships.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamUid}.memberships.*.update.status", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamUid}.memberships.{$membershipUid}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamUid}.memberships.{$membershipUid}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("teams.{$teamUid}.memberships.{$membershipUid}.update.status", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -756,4 +869,4 @@ class WebhooksCustomClientTest extends Scope
*/
return [];
}
-}
\ No newline at end of file
+}
diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php
index b79ae37d7..7c815595f 100644
--- a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php
+++ b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php
@@ -20,10 +20,12 @@ class WebhooksCustomServerTest extends Scope
*/
public function testUpdateCollection($data): array
{
+ $id = $data['actorsId'];
+
/**
* Test for SUCCESS
*/
- $actors = $this->client->call(Client::METHOD_PUT, '/database/collections/'.$data['actorsId'], array_merge([
+ $actors = $this->client->call(Client::METHOD_PUT, '/database/collections/' . $id, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
@@ -31,7 +33,7 @@ class WebhooksCustomServerTest extends Scope
'name' => 'Actors1',
'permission' => 'document',
]);
-
+
$this->assertEquals($actors['headers']['status-code'], 200);
$this->assertNotEmpty($actors['body']['$id']);
@@ -40,7 +42,10 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'database.collections.update');
+ $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$id}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -60,6 +65,8 @@ class WebhooksCustomServerTest extends Scope
*/
public function testCreateDeleteIndexes($data): array
{
+ $actorsId = $data['actorsId'];
+
$index = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/indexes', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -71,6 +78,7 @@ class WebhooksCustomServerTest extends Scope
'orders' => ['ASC', 'ASC'],
]);
+ $indexKey = $index['body']['key'];
$this->assertEquals($index['headers']['status-code'], 201);
$this->assertEquals($index['body']['key'], 'fullname');
@@ -82,7 +90,16 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'database.indexes.create');
+ $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.indexes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.indexes.{$actorsId}_{$indexKey}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.indexes.{$actorsId}_{$indexKey}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.indexes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -101,7 +118,16 @@ class WebhooksCustomServerTest extends Scope
// $this->assertEquals($webhook['method'], 'DELETE');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'database.indexes.delete');
+ $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.indexes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.indexes.{$actorsId}_{$indexKey}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.*.indexes.{$actorsId}_{$indexKey}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.indexes.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -127,10 +153,12 @@ class WebhooksCustomServerTest extends Scope
'permission' => 'document'
]);
+ $id = $actors['body']['$id'];
+
$this->assertEquals($actors['headers']['status-code'], 201);
$this->assertNotEmpty($actors['body']['$id']);
- $actors = $this->client->call(Client::METHOD_DELETE, '/database/collections/'.$actors['body']['$id'], array_merge([
+ $actors = $this->client->call(Client::METHOD_DELETE, '/database/collections/' . $actors['body']['$id'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
@@ -143,7 +171,10 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'database.collections.delete');
+ $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('collections.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("collections.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events'],);
+ $this->assertStringContainsString("collections.{$id}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -158,9 +189,9 @@ class WebhooksCustomServerTest extends Scope
return [];
}
- public function testCreateUser():array
+ public function testCreateUser(): array
{
- $email = uniqid().'user@localhost.test';
+ $email = uniqid() . 'user@localhost.test';
$password = 'password';
$name = 'User Name';
@@ -187,7 +218,10 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'users.create');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events'],);
+ $this->assertStringContainsString("users.{$id}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -206,15 +240,17 @@ class WebhooksCustomServerTest extends Scope
return ['userId' => $user['body']['$id'], 'name' => $user['body']['name'], 'email' => $user['body']['email']];
}
- /**
+ /**
* @depends testCreateUser
*/
- public function testUpdateUserPrefs(array $data):array
+ public function testUpdateUserPrefs(array $data): array
{
+ $id = $data['userId'];
+
/**
* Test for SUCCESS
*/
- $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/prefs', array_merge([
+ $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $id . '/prefs', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -229,7 +265,12 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'users.update.prefs');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.update.prefs', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.update.prefs", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -242,8 +283,10 @@ class WebhooksCustomServerTest extends Scope
/**
* @depends testUpdateUserPrefs
*/
- public function testUpdateUserStatus(array $data):array
+ public function testUpdateUserStatus(array $data): array
{
+ $id = $data['userId'];
+
/**
* Test for SUCCESS
*/
@@ -262,7 +305,12 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'users.update.status');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.update.status', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.update.status", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -277,12 +325,14 @@ class WebhooksCustomServerTest extends Scope
return $data;
}
-
+
/**
* @depends testUpdateUserStatus
*/
- public function testDeleteUser(array $data):array
+ public function testDeleteUser(array $data): array
{
+ $id = $data['userId'];
+
/**
* Test for SUCCESS
*/
@@ -298,7 +348,10 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'users.delete');
+ $this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('users.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("users.{$id}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -314,7 +367,7 @@ class WebhooksCustomServerTest extends Scope
return $data;
}
- public function testCreateFunction():array
+ public function testCreateFunction(): array
{
/**
* Test for SUCCESS
@@ -330,7 +383,7 @@ class WebhooksCustomServerTest extends Scope
'timeout' => 10,
]);
- $functionId = $function['body']['$id'] ?? '';
+ $id = $function['body']['$id'] ?? '';
$this->assertEquals($function['headers']['status-code'], 201);
$this->assertNotEmpty($function['body']['$id']);
@@ -340,7 +393,10 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'functions.create');
+ $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('functions.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -350,19 +406,21 @@ class WebhooksCustomServerTest extends Scope
*/
return [
- 'functionId' => $functionId,
+ 'functionId' => $id,
];
}
/**
* @depends testCreateFunction
*/
- public function testUpdateFunction($data):array
+ public function testUpdateFunction($data): array
{
- /**
- * Test for SUCCESS
- */
- $function = $this->client->call(Client::METHOD_PUT, '/functions/'.$data['functionId'], array_merge([
+ $id = $data['functionId'];
+
+ /**
+ * Test for SUCCESS
+ */
+ $function = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -383,29 +441,32 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'functions.update');
+ $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('functions.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
return $data;
}
-
+
/**
* @depends testUpdateFunction
*/
- public function testCreateDeployment($data):array
+ public function testCreateDeployment($data): array
{
/**
* Test for SUCCESS
*/
$stderr = '';
- $stdout= '';
+ $stdout = '';
$folder = 'timeout';
- $code = realpath(__DIR__ . '/../../../resources/functions'). "/$folder/code.tar.gz";
- Console::execute('cd '.realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $stdout, $stderr);
+ $code = realpath(__DIR__ . '/../../../resources/functions') . "/{$folder}/code.tar.gz";
+ Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/{$folder} && tar --exclude code.tar.gz -czf code.tar.gz .", '', $stdout, $stderr);
- $deployment = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/deployments', array_merge([
+ $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/deployments', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -413,6 +474,7 @@ class WebhooksCustomServerTest extends Scope
'code' => new CURLFile($code, 'application/x-gzip', \basename($code))
]);
+ $id = $data['functionId'] ?? '';
$deploymentId = $deployment['body']['$id'] ?? '';
$this->assertEquals($deployment['headers']['status-code'], 201);
@@ -423,7 +485,12 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'functions.deployments.create');
+ $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('functions.*.deployments.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.*.deployments.{$deploymentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.deployments.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.deployments.{$deploymentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -436,12 +503,15 @@ class WebhooksCustomServerTest extends Scope
/**
* @depends testCreateDeployment
*/
- public function testUpdateDeployment($data):array
+ public function testUpdateDeployment($data): array
{
+ $id = $data['functionId'] ?? '';
+ $deploymentId = $data['deploymentId'] ?? '';
+
/**
* Test for SUCCESS
*/
- $response = $this->client->call(Client::METHOD_PATCH, '/functions/'.$data['functionId'].'/deployments/'.$data['deploymentId'], array_merge([
+ $response = $this->client->call(Client::METHOD_PATCH, '/functions/' . $id . '/deployments/' . $deploymentId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
@@ -457,7 +527,16 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'functions.deployments.update');
+ $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('functions.*.deployments.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('functions.*.deployments.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.*.deployments.{$deploymentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.*.deployments.{$deploymentId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.deployments.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.deployments.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.deployments.{$deploymentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.deployments.{$deploymentId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -472,17 +551,20 @@ class WebhooksCustomServerTest extends Scope
/**
* @depends testUpdateDeployment
*/
- public function testExecutions($data):array
+ public function testExecutions($data): array
{
+ $id = $data['functionId'] ?? '';
+
/**
* Test for SUCCESS
*/
-
- $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/executions', array_merge([
+ $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $id . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
+ $executionId = $execution['body']['$id'] ?? '';
+
$this->assertEquals($execution['headers']['status-code'], 201);
$this->assertNotEmpty($execution['body']['$id']);
@@ -491,12 +573,21 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'functions.executions.create');
+ $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('functions.*.executions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('functions.*.executions.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.*.executions.{$executionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.*.executions.{$executionId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.executions.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.executions.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.executions.{$executionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.executions.{$executionId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
- // wait for timeout function to complete (sleep(5);)
+ // wait for timeout function to complete
sleep(10);
$webhook = $this->getLastRequest();
@@ -504,7 +595,16 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'functions.executions.update');
+ $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('functions.*.executions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('functions.*.executions.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.*.executions.{$executionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.*.executions.{$executionId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.executions.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.executions.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.executions.{$executionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.executions.{$executionId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -519,12 +619,14 @@ class WebhooksCustomServerTest extends Scope
/**
* @depends testExecutions
*/
- public function testDeleteDeployment($data):array
+ public function testDeleteDeployment($data): array
{
+ $id = $data['functionId'] ?? '';
+ $deploymentId = $data['deploymentId'] ?? '';
/**
* Test for SUCCESS
*/
- $deployment = $this->client->call(Client::METHOD_DELETE, '/functions/'.$data['functionId'].'/deployments/'.$data['deploymentId'], array_merge([
+ $deployment = $this->client->call(Client::METHOD_DELETE, '/functions/' . $id . '/deployments/' . $deploymentId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -537,7 +639,16 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'functions.deployments.delete');
+ $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('functions.*.deployments.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('functions.*.deployments.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.*.deployments.{$deploymentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.*.deployments.{$deploymentId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.deployments.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.deployments.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.deployments.{$deploymentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.deployments.{$deploymentId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@@ -552,12 +663,14 @@ class WebhooksCustomServerTest extends Scope
/**
* @depends testDeleteDeployment
*/
- public function testDeleteFunction($data):array
+ public function testDeleteFunction($data): array
{
+ $id = $data['functionId'];
+
/**
* Test for SUCCESS
*/
- $function = $this->client->call(Client::METHOD_DELETE, '/functions/'.$data['functionId'], array_merge([
+ $function = $this->client->call(Client::METHOD_DELETE, '/functions/' . $id, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
@@ -570,7 +683,10 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
- $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'functions.delete');
+ $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString('functions.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
+ $this->assertStringContainsString("functions.{$id}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
diff --git a/tests/e2e/Services/Workers/WebhooksTest.php b/tests/e2e/Services/Workers/WebhooksTest.php
deleted file mode 100644
index f859f9885..000000000
--- a/tests/e2e/Services/Workers/WebhooksTest.php
+++ /dev/null
@@ -1,154 +0,0 @@
-client->call(Client::METHOD_POST, '/teams', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'teamId' => 'unique()',
- 'name' => 'Project Test',
- ]);
-
- $this->assertEquals(201, $team['headers']['status-code']);
- $this->assertEquals('Project Test', $team['body']['name']);
- $this->assertNotEmpty($team['body']['$id']);
-
- $response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'projectId' => 'unique()',
- 'name' => 'Project Test',
- 'teamId' => $team['body']['$id'],
- ]);
-
- $this->assertEquals(201, $response['headers']['status-code']);
- $this->assertNotEmpty($response['body']['$id']);
- $this->assertEquals('Project Test', $response['body']['name']);
- $this->assertEquals($team['body']['$id'], $response['body']['teamId']);
- $this->assertArrayHasKey('platforms', $response['body']);
- $this->assertArrayHasKey('webhooks', $response['body']);
- $this->assertArrayHasKey('keys', $response['body']);
-
- $projectId = $response['body']['$id'];
-
- /**
- * Test for FAILURE
- */
- $response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'projectId' => 'unique()',
- 'name' => '',
- 'teamId' => $team['body']['$id'],
- ]);
-
- $this->assertEquals(400, $response['headers']['status-code']);
-
- $response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'name' => 'Project Test',
- ]);
-
- $this->assertEquals(400, $response['headers']['status-code']);
-
- return ['projectId' => $projectId];
- }
-
- /**
- * @depends testCreateProject
- */
- public function testCreateWebhook($data): array
- {
- $id = (isset($data['projectId'])) ? $data['projectId'] : '';
-
- $response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/webhooks', array_merge([
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $this->getProject()['$id'],
- ], $this->getHeaders()), [
- 'name' => 'Webhook Worker Test',
- 'events' => ['account.create', 'account.update.email'],
- 'url' => 'http://request-catcher:5000/webhook',
- 'security' => true,
- 'httpUser' => 'username',
- 'httpPass' => 'password',
- ]);
-
- $this->assertEquals(201, $response['headers']['status-code']);
- $this->assertNotEmpty($response['body']['$id']);
- $this->assertContains('account.create', $response['body']['events']);
- $this->assertContains('account.update.email', $response['body']['events']);
- $this->assertCount(2, $response['body']['events']);
- $this->assertEquals('http://request-catcher:5000/webhook', $response['body']['url']);
- $this->assertIsBool($response['body']['security']);
- $this->assertEquals(true, $response['body']['security']);
- $this->assertEquals('username', $response['body']['httpUser']);
-
- $data = array_merge($data, ['webhookId' => $response['body']['$id']]);
-
- /**
- * Test for FAILURE
- */
-
- return $data;
- }
-
- /**
- * @depends testCreateWebhook
- */
- public function testCreateAccount($data)
- {
- $projectId = (isset($data['projectId'])) ? $data['projectId'] : '';
- $email = uniqid().'webhook.user@localhost.test';
- $password = 'password';
- $name = 'User Name';
-
- /**
- * Test for SUCCESS
- */
- $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([
- 'origin' => 'http://localhost',
- 'content-type' => 'application/json',
- 'x-appwrite-project' => $projectId,
- ]), [
- 'userId' => 'unique()',
- 'email' => $email,
- 'password' => $password,
- 'name' => $name,
- ]);
-
- $this->assertEquals($response['headers']['status-code'], 201);
-
- $webhook = $this->getLastRequest();
-
- $this->assertNotEmpty($webhook['data']);
- $this->assertNotEmpty($webhook['data']['$id']);
- $this->assertIsBool($webhook['data']['status']);
- $this->assertIsNumeric($webhook['data']['registration']);
- $this->assertEquals($webhook['data']['email'], $email);
- $this->assertEquals($webhook['data']['name'], $name);
- $this->assertIsBool($webhook['data']['emailVerification']);
- $this->assertIsArray($webhook['data']['prefs']);
- }
-}
\ No newline at end of file
diff --git a/tests/unit/Event/EventTest.php b/tests/unit/Event/EventTest.php
index 58d7a1c04..d653541ad 100644
--- a/tests/unit/Event/EventTest.php
+++ b/tests/unit/Event/EventTest.php
@@ -3,6 +3,7 @@
namespace Appwrite\Tests;
use Appwrite\Event\Event;
+use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
use Utopia\App;
@@ -12,7 +13,7 @@ class EventTest extends TestCase
* @var Event
*/
protected $object = null;
-
+
/**
* @var string
*/
@@ -22,8 +23,8 @@ class EventTest extends TestCase
{
$redisHost = App::getEnv('_APP_REDIS_HOST', '');
$redisPort = App::getEnv('_APP_REDIS_PORT', '');
- \Resque::setBackend($redisHost.':'.$redisPort);
-
+ \Resque::setBackend($redisHost . ':' . $redisPort);
+
$this->queue = 'v1-tests' . uniqid();
$this->object = new Event($this->queue, 'TestsV1');
}
@@ -37,9 +38,9 @@ class EventTest extends TestCase
$this->assertEquals($this->queue, $this->object->getQueue());
$this->object->setQueue('demo');
-
+
$this->assertEquals('demo', $this->object->getQueue());
-
+
$this->object->setQueue($this->queue);
}
@@ -48,9 +49,9 @@ class EventTest extends TestCase
$this->assertEquals('TestsV1', $this->object->getClass());
$this->object->setClass('TestsV2');
-
+
$this->assertEquals('TestsV2', $this->object->getClass());
-
+
$this->object->setClass('TestsV1');
}
@@ -58,13 +59,12 @@ class EventTest extends TestCase
{
$this->object
->setParam('eventKey1', 'eventValue1')
- ->setParam('eventKey2', 'eventValue2')
- ;
+ ->setParam('eventKey2', 'eventValue2');
$this->object->trigger();
- $this->assertEquals(null, $this->object->getParam('eventKey1'));
- $this->assertEquals(null, $this->object->getParam('eventKey2'));
+ $this->assertEquals('eventValue1', $this->object->getParam('eventKey1'));
+ $this->assertEquals('eventValue2', $this->object->getParam('eventKey2'));
$this->assertEquals(null, $this->object->getParam('eventKey3'));
$this->assertEquals(\Resque::size($this->queue), 1);
}
@@ -73,8 +73,7 @@ class EventTest extends TestCase
{
$this->object
->setParam('eventKey1', 'eventValue1')
- ->setParam('eventKey2', 'eventValue2')
- ;
+ ->setParam('eventKey2', 'eventValue2');
$this->assertEquals('eventValue1', $this->object->getParam('eventKey1'));
$this->assertEquals('eventValue2', $this->object->getParam('eventKey2'));
@@ -85,4 +84,60 @@ class EventTest extends TestCase
$this->assertEquals(null, $this->object->getParam('eventKey2'));
$this->assertEquals(null, $this->object->getParam('eventKey3'));
}
+
+ public function testGenerateEvents()
+ {
+ $event = Event::generateEvents('users.[userId].create', [
+ 'userId' => 'torsten'
+ ]);
+ $this->assertCount(4, $event);
+ $this->assertContains('users.torsten.create', $event);
+ $this->assertContains('users.torsten', $event);
+ $this->assertContains('users.*.create', $event);
+ $this->assertContains('users.*', $event);
+
+ $event = Event::generateEvents('users.[userId].update.email', [
+ 'userId' => 'torsten'
+ ]);
+ $this->assertCount(6, $event);
+ $this->assertContains('users.torsten.update.email', $event);
+ $this->assertContains('users.torsten.update', $event);
+ $this->assertContains('users.torsten', $event);
+ $this->assertContains('users.*.update.email', $event);
+ $this->assertContains('users.*.update', $event);
+ $this->assertContains('users.*', $event);
+
+ $event = Event::generateEvents('collections.[collectionId].documents.[documentId].create', [
+ 'collectionId' => 'chapters',
+ 'documentId' => 'prolog',
+ ]);
+ $this->assertCount(10, $event);
+
+ $this->assertContains('collections.chapters.documents.prolog.create', $event);
+ $this->assertContains('collections.chapters.documents.prolog', $event);
+ $this->assertContains('collections.chapters.documents.*.create', $event);
+ $this->assertContains('collections.chapters.documents.*', $event);
+ $this->assertContains('collections.chapters', $event);
+ $this->assertContains('collections.*.documents.prolog.create', $event);
+ $this->assertContains('collections.*.documents.prolog', $event);
+ $this->assertContains('collections.*.documents.*.create', $event);
+ $this->assertContains('collections.*.documents.*', $event);
+ $this->assertContains('collections.*', $event);
+
+ try {
+ $event = Event::generateEvents('collections.[collectionId].documents.[documentId].create', [
+ 'collectionId' => 'chapters'
+ ]);
+ $this->fail();
+ } catch (\Throwable $th) {
+ $this->assertInstanceOf(InvalidArgumentException::class, $th, 'An invalid exception was thrown');
+ }
+
+ try {
+ $event = Event::generateEvents('collections.[collectionId].documents.[documentId].create');
+ $this->fail();
+ } catch (\Throwable $th) {
+ $this->assertInstanceOf(InvalidArgumentException::class, $th, 'An invalid exception was thrown');
+ }
+ }
}
diff --git a/tests/unit/Event/Validator/EventValidatorTest.php b/tests/unit/Event/Validator/EventValidatorTest.php
new file mode 100644
index 000000000..e52399959
--- /dev/null
+++ b/tests/unit/Event/Validator/EventValidatorTest.php
@@ -0,0 +1,63 @@
+object = new Event();
+ }
+
+ public function tearDown(): void
+ {
+ }
+
+ public function testValues()
+ {
+ /**
+ * Test for SUCCESS
+ */
+ $this->assertTrue($this->object->isValid('users.*.create'));
+ $this->assertTrue($this->object->isValid('users.torsten.update'));
+ $this->assertTrue($this->object->isValid('users.torsten'));
+ $this->assertTrue($this->object->isValid('users.*.update.email'));
+ $this->assertTrue($this->object->isValid('users.*.update'));
+ $this->assertTrue($this->object->isValid('users.*'));
+ $this->assertTrue($this->object->isValid('collections.chapters.documents.prolog.create'));
+ $this->assertTrue($this->object->isValid('collections.chapters.documents.prolog'));
+ $this->assertTrue($this->object->isValid('collections.chapters.documents.*.create'));
+ $this->assertTrue($this->object->isValid('collections.chapters.documents.*'));
+ $this->assertTrue($this->object->isValid('collections.*.documents.prolog.create'));
+ $this->assertTrue($this->object->isValid('collections.*.documents.prolog'));
+ $this->assertTrue($this->object->isValid('collections.*.documents.*.create'));
+ $this->assertTrue($this->object->isValid('collections.*.documents.*'));
+ $this->assertTrue($this->object->isValid('collections.*'));
+ $this->assertTrue($this->object->isValid('functions.*'));
+ $this->assertTrue($this->object->isValid('buckets.*'));
+ $this->assertTrue($this->object->isValid('teams.*'));
+ $this->assertTrue($this->object->isValid('users.*'));
+ $this->assertTrue($this->object->isValid('teams.*.memberships.*.update.status'));
+
+ /**
+ * Test for FAILURE
+ */
+ $this->assertFalse($this->object->isValid(false));
+ $this->assertFalse($this->object->isValid(null));
+ $this->assertFalse($this->object->isValid(''));
+ $this->assertFalse($this->object->isValid('unknown.*'));
+ $this->assertFalse($this->object->isValid('collections'));
+ $this->assertFalse($this->object->isValid('collections.*.unknown'));
+ $this->assertFalse($this->object->isValid('collections.*.documents.*.unknown'));
+ $this->assertFalse($this->object->isValid('users.torsten.unknown'));
+ $this->assertFalse($this->object->isValid('users.torsten.delete.email'));
+ $this->assertFalse($this->object->isValid('teams.*.memberships.*.update.unknown'));
+ }
+}
diff --git a/tests/unit/Messaging/MessagingTest.php b/tests/unit/Messaging/MessagingTest.php
index a0cad0bae..0d7dd2a2e 100644
--- a/tests/unit/Messaging/MessagingTest.php
+++ b/tests/unit/Messaging/MessagingTest.php
@@ -202,7 +202,7 @@ class MessagingTest extends TestCase
* Test Collection Level Permissions
*/
$result = Realtime::fromPayload(
- event: 'database.documents.create',
+ event: 'collections.collection_id.documents.document_id.create',
payload: new Document([
'$id' => 'test',
'$collection' => 'collection',
@@ -224,7 +224,7 @@ class MessagingTest extends TestCase
* Test Document Level Permissions
*/
$result = Realtime::fromPayload(
- event: 'database.documents.create',
+ event: 'collections.collection_id.documents.document_id.create',
payload: new Document([
'$id' => 'test',
'$collection' => 'collection',
@@ -242,4 +242,51 @@ class MessagingTest extends TestCase
$this->assertContains('role:all', $result['roles']);
$this->assertNotContains('role:admin', $result['roles']);
}
+
+ public function testFromPayloadBucketLevelPermissions(): void
+ {
+ /**
+ * Test Collection Level Permissions
+ */
+ $result = Realtime::fromPayload(
+ event: 'buckets.bucket_id.files.file_id.create',
+ payload: new Document([
+ '$id' => 'test',
+ '$collection' => 'bucket',
+ '$read' => ['role:admin'],
+ '$write' => ['role:admin']
+ ]),
+ bucket: new Document([
+ '$id' => 'bucket',
+ '$read' => ['role:all'],
+ '$write' => ['role:all'],
+ 'permission' => 'bucket'
+ ])
+ );
+
+ $this->assertContains('role:all', $result['roles']);
+ $this->assertNotContains('role:admin', $result['roles']);
+
+ /**
+ * Test Document Level Permissions
+ */
+ $result = Realtime::fromPayload(
+ event: 'buckets.bucket_id.files.file_id.create',
+ payload: new Document([
+ '$id' => 'test',
+ '$collection' => 'bucket',
+ '$read' => ['role:all'],
+ '$write' => ['role:all']
+ ]),
+ bucket: new Document([
+ '$id' => 'bucket',
+ '$read' => ['role:admin'],
+ '$write' => ['role:admin'],
+ 'permission' => 'file'
+ ])
+ );
+
+ $this->assertContains('role:all', $result['roles']);
+ $this->assertNotContains('role:admin', $result['roles']);
+ }
}
diff --git a/tests/unit/Migration/MigrationV13Test.php b/tests/unit/Migration/MigrationV13Test.php
new file mode 100644
index 000000000..3d0b0e297
--- /dev/null
+++ b/tests/unit/Migration/MigrationV13Test.php
@@ -0,0 +1,51 @@
+migration = new V13();
+ $reflector = new ReflectionClass('Appwrite\Migration\Version\V13');
+ $this->method = $reflector->getMethod('fixDocument');
+ $this->method->setAccessible(true);
+ }
+
+ public function testMigrateFunctions()
+ {
+ $document = $this->fixDocument(new Document([
+ '$id' => 'func',
+ '$collection' => 'functions',
+ 'events' => ['account.create', 'users.create']
+ ]));
+
+ $this->assertEquals($document->getAttribute('events'), ['users.*.create']);
+ }
+
+ public function testMigrationWebhooks()
+ {
+ $document = $this->fixDocument(new Document([
+ '$id' => 'webh',
+ '$collection' => 'webhooks',
+ 'events' => ['account.create', 'users.create']
+ ]));
+
+ $this->assertEquals($document->getAttribute('events'), ['users.*.create']);
+ }
+
+ public function testEventsConversion()
+ {
+ $migration = new V13();
+ $events = $migration->migrateEvents($migration->events);
+ foreach ($events as $event) {
+ $this->assertTrue((new Event())->isValid($event), $event);
+ }
+ $this->assertCount(44, $events);
+ }
+}