Merge branch '0.14.x' of https://github.com/appwrite/appwrite into feat-use-build-timeout
This commit is contained in:
commit
6c9e17ec74
|
@ -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 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.',
|
||||
]
|
||||
]
|
||||
];
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -969,7 +1006,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)
|
||||
|
@ -999,7 +1036,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);
|
||||
|
@ -1049,7 +1086,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);
|
||||
|
@ -1072,7 +1109,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')
|
||||
|
@ -1085,10 +1122,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);
|
||||
|
@ -1101,7 +1140,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);
|
||||
|
@ -1111,13 +1150,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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Utopia\App;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Storage\Device\DOSpaces;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Storage\Device\Local;
|
||||
use Utopia\Storage\Device\S3;
|
||||
use Utopia\Storage\Storage;
|
||||
|
||||
App::init(function ($utopia, $request, $response, $project, $user, $events, $audits, $usage, $deletes, $database, $dbForProject, $mode) {
|
||||
App::init(function ($utopia, $request, $response, $project, $user, $events, $audits, $mails, $usage, $deletes, $database, $dbForProject, $mode) {
|
||||
/** @var Utopia\App $utopia */
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
|
@ -21,7 +18,8 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud
|
|||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Registry\Registry $register */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Audit $audits */
|
||||
/** @var Appwrite\Event\Mail $mails */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var Appwrite\Event\Event $deletes */
|
||||
/** @var Appwrite\Event\Event $database */
|
||||
|
@ -88,27 +86,23 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud
|
|||
* Background Jobs
|
||||
*/
|
||||
$events
|
||||
->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');
|
||||
}, ['utopia', 'request', 'response', 'project', 'events', 'audits', 'usage', 'deletes', 'database', 'mode', 'dbForProject'], 'api');
|
|
@ -165,7 +165,7 @@ App::get('/console/webhooks')
|
|||
$page
|
||||
->setParam('events', Config::getParam('events', []))
|
||||
;
|
||||
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Webhooks')
|
||||
->setParam('body', $page);
|
||||
|
|
14
app/init.php
14
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']);
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
]);
|
||||
});
|
||||
(new Certificate())
|
||||
->setDomain(new Document([
|
||||
'domain' => $domain
|
||||
]))
|
||||
->setSkipRenewCheck(true)
|
||||
->trigger();
|
||||
});
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
require_once __DIR__.'/../init.php';
|
||||
require_once __DIR__ . '/../init.php';
|
||||
|
||||
Console::title('Audits V1 Worker');
|
||||
Console::success(APP_NAME . ' audits worker v1 has started');
|
||||
|
||||
class AuditsV1 extends Worker
|
||||
{
|
||||
public function getName(): string {
|
||||
public function getName(): string
|
||||
{
|
||||
return "audits";
|
||||
}
|
||||
|
||||
|
@ -21,30 +24,39 @@ class AuditsV1 extends Worker
|
|||
|
||||
public function run(): void
|
||||
{
|
||||
$projectId = $this->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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Appwrite\Utopia\Response\Model\Deployment;
|
||||
use Cron\CronExpression;
|
||||
use Executor\Executor;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
@ -11,43 +13,41 @@ use Utopia\Storage\Storage;
|
|||
use Utopia\Database\Document;
|
||||
use Utopia\Config\Config;
|
||||
|
||||
require_once __DIR__.'/../init.php';
|
||||
require_once __DIR__ . '/../init.php';
|
||||
|
||||
// Disable Auth since we already validate it in the API
|
||||
Authorization::disable();
|
||||
|
||||
Console::title('Builds V1 Worker');
|
||||
Console::success(APP_NAME.' build worker v1 has started');
|
||||
Console::success(APP_NAME . ' build worker v1 has started');
|
||||
|
||||
// TODO: Executor should return appropriate response codes.
|
||||
class BuildsV1 extends Worker
|
||||
{
|
||||
/**
|
||||
* @var Executor
|
||||
*/
|
||||
private $executor = null;
|
||||
{
|
||||
private ?Executor $executor = null;
|
||||
|
||||
public function getName(): string
|
||||
public function getName(): string
|
||||
{
|
||||
return "builds";
|
||||
}
|
||||
|
||||
public function init(): void {
|
||||
public function init(): void
|
||||
{
|
||||
$this->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
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Utopia\CLI\Console;
|
||||
|
@ -20,12 +21,11 @@ class DatabaseV1 extends Worker
|
|||
public function run(): void
|
||||
{
|
||||
Authorization::disable();
|
||||
$projectId = $this->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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Func;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Appwrite\Stats\Stats;
|
||||
use Appwrite\Utopia\Response\Model\Execution;
|
||||
use Cron\CronExpression;
|
||||
use Executor\Executor;
|
||||
use Swoole\Runtime;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
|
@ -15,23 +15,19 @@ use Utopia\Database\Database;
|
|||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
require_once __DIR__.'/../init.php';
|
||||
require_once __DIR__ . '/../init.php';
|
||||
|
||||
Console::title('Functions V1 Worker');
|
||||
Console::success(APP_NAME . ' functions worker v1 has started');
|
||||
|
||||
class FunctionsV1 extends Worker
|
||||
{
|
||||
/**
|
||||
* @var Executor
|
||||
*/
|
||||
private $executor = null;
|
||||
|
||||
private ?Executor $executor = null;
|
||||
public array $args = [];
|
||||
|
||||
public array $allowed = [];
|
||||
|
||||
public function getName(): string {
|
||||
public function getName(): string
|
||||
{
|
||||
return "functions";
|
||||
}
|
||||
|
||||
|
@ -42,65 +38,87 @@ class FunctionsV1 extends Worker
|
|||
|
||||
public function run(): void
|
||||
{
|
||||
$projectId = $this->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,47 +288,65 @@ 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) {
|
||||
$endtime = \microtime(true);
|
||||
$time = $endtime - $execution->getAttribute('dateCreated');
|
||||
$execution->setAttribute('time', $time);
|
||||
$execution->setAttribute('status', 'failed');
|
||||
$execution->setAttribute('statusCode', $th->getCode());
|
||||
$execution->setAttribute('stderr', $th->getMessage());
|
||||
$execution
|
||||
->setAttribute('time', $time)
|
||||
->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']
|
||||
);
|
||||
|
@ -352,7 +357,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', ''))
|
||||
|
@ -360,7 +365,6 @@ class FunctionsV1 extends Worker
|
|||
->setParam('networkRequestSize', 0)
|
||||
->setParam('networkResponseSize', 0)
|
||||
->submit();
|
||||
$usage->submit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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 = [];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.*",
|
||||
|
|
16
composer.lock
generated
16
composer.lock
generated
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
<directory>./tests/e2e/Services/Storage</directory>
|
||||
<directory>./tests/e2e/Services/Teams</directory>
|
||||
<directory>./tests/e2e/Services/Users</directory>
|
||||
<directory>./tests/e2e/Services/Workers</directory>
|
||||
<directory>./tests/e2e/Services/Webhooks</directory>
|
||||
<file>./tests/e2e/Services/Functions/FunctionsBase.php</file>
|
||||
<file>./tests/e2e/Services/Functions/FunctionsCustomServerTest.php</file>
|
||||
|
|
4
public/dist/scripts/app-all.js
vendored
4
public/dist/scripts/app-all.js
vendored
|
@ -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<events.length;y++){if(events[y]==="init"){element.addEventListener("rendered",function(){apply(form.toJson(element));},{once:true});}else{}
|
||||
element.setAttribute("data-event","none");}
|
||||
break;default:break;}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-forms-headers",controller:function(element){let key=document.createElement("input");let value=document.createElement("input");let wrap=document.createElement("div");let cell1=document.createElement("div");let cell2=document.createElement("div");key.type="text";key.className="margin-bottom-no";key.placeholder="Key";value.type="text";value.className="margin-bottom-no";value.placeholder="Value";wrap.className="row thin margin-bottom-small";cell1.className="col span-6";cell2.className="col span-6";element.parentNode.insertBefore(wrap,element);cell1.appendChild(key);cell2.appendChild(value);wrap.appendChild(cell1);wrap.appendChild(cell2);key.addEventListener("input",function(){syncA();});value.addEventListener("input",function(){syncA();});element.addEventListener("change",function(){syncB();});let syncA=function(){element.value=key.value.toLowerCase()+":"+value.value.toLowerCase();};let syncB=function(){let split=element.value.toLowerCase().split(":");key.value=split[0]||"";value.value=split[1]||"";key.value=key.value.trim();value.value=value.value.trim();};syncB();}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-forms-key-value",controller:function(element){let key=document.createElement("input");let value=document.createElement("input");let wrap=document.createElement("div");let cell1=document.createElement("div");let cell2=document.createElement("div");key.type="text";key.className="margin-bottom-no";key.placeholder="Key";key.required=true;value.type="text";value.className="margin-bottom-no";value.placeholder="Value";value.required=true;wrap.className="row thin margin-bottom-small";cell1.className="col span-6";cell2.className="col span-6";element.parentNode.insertBefore(wrap,element);cell1.appendChild(key);cell2.appendChild(value);wrap.appendChild(cell1);wrap.appendChild(cell2);key.addEventListener("input",function(){syncA();});value.addEventListener("input",function(){syncA();});element.addEventListener("change",function(){syncB();});let syncA=function(){element.name=key.value;element.value=value.value;};let syncB=function(){key.value=element.name||"";value.value=element.value||"";};syncB();}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-move-down",controller:function(element){Array.prototype.slice.call(element.querySelectorAll("[data-move-down]")).map(function(obj){obj.addEventListener("click",function(){if(element.nextElementSibling){console.log('down',element.offsetHeight);element.parentNode.insertBefore(element.nextElementSibling,element);element.scrollIntoView({block:'center'});}});});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-move-up",controller:function(element){Array.prototype.slice.call(element.querySelectorAll("[data-move-up]")).map(function(obj){obj.addEventListener("click",function(){if(element.previousElementSibling){console.log('up',element);element.parentNode.insertBefore(element,element.previousElementSibling);element.scrollIntoView({block:'center'});}});});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-nav",repeat:false,controller:function(element,view,container,document){let titles=document.querySelectorAll('[data-forms-nav-anchor]');let links=element.querySelectorAll('[data-forms-nav-link]');let minLink=null;let check=function(){let minDistance=null;let minElement=null;for(let i=0;i<titles.length;++i){let title=titles[i];let distance=title.getBoundingClientRect().top;console.log(i);if((minDistance===null||minDistance>=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);}
|
||||
|
|
4
public/dist/scripts/app.js
vendored
4
public/dist/scripts/app.js
vendored
|
@ -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<events.length;y++){if(events[y]==="init"){element.addEventListener("rendered",function(){apply(form.toJson(element));},{once:true});}else{}
|
||||
element.setAttribute("data-event","none");}
|
||||
break;default:break;}}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-forms-headers",controller:function(element){let key=document.createElement("input");let value=document.createElement("input");let wrap=document.createElement("div");let cell1=document.createElement("div");let cell2=document.createElement("div");key.type="text";key.className="margin-bottom-no";key.placeholder="Key";value.type="text";value.className="margin-bottom-no";value.placeholder="Value";wrap.className="row thin margin-bottom-small";cell1.className="col span-6";cell2.className="col span-6";element.parentNode.insertBefore(wrap,element);cell1.appendChild(key);cell2.appendChild(value);wrap.appendChild(cell1);wrap.appendChild(cell2);key.addEventListener("input",function(){syncA();});value.addEventListener("input",function(){syncA();});element.addEventListener("change",function(){syncB();});let syncA=function(){element.value=key.value.toLowerCase()+":"+value.value.toLowerCase();};let syncB=function(){let split=element.value.toLowerCase().split(":");key.value=split[0]||"";value.value=split[1]||"";key.value=key.value.trim();value.value=value.value.trim();};syncB();}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-forms-key-value",controller:function(element){let key=document.createElement("input");let value=document.createElement("input");let wrap=document.createElement("div");let cell1=document.createElement("div");let cell2=document.createElement("div");key.type="text";key.className="margin-bottom-no";key.placeholder="Key";key.required=true;value.type="text";value.className="margin-bottom-no";value.placeholder="Value";value.required=true;wrap.className="row thin margin-bottom-small";cell1.className="col span-6";cell2.className="col span-6";element.parentNode.insertBefore(wrap,element);cell1.appendChild(key);cell2.appendChild(value);wrap.appendChild(cell1);wrap.appendChild(cell2);key.addEventListener("input",function(){syncA();});value.addEventListener("input",function(){syncA();});element.addEventListener("change",function(){syncB();});let syncA=function(){element.name=key.value;element.value=value.value;};let syncB=function(){key.value=element.name||"";value.value=element.value||"";};syncB();}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-move-down",controller:function(element){Array.prototype.slice.call(element.querySelectorAll("[data-move-down]")).map(function(obj){obj.addEventListener("click",function(){if(element.nextElementSibling){console.log('down',element.offsetHeight);element.parentNode.insertBefore(element.nextElementSibling,element);element.scrollIntoView({block:'center'});}});});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-move-up",controller:function(element){Array.prototype.slice.call(element.querySelectorAll("[data-move-up]")).map(function(obj){obj.addEventListener("click",function(){if(element.previousElementSibling){console.log('up',element);element.parentNode.insertBefore(element,element.previousElementSibling);element.scrollIntoView({block:'center'});}});});}});})(window);(function(window){"use strict";window.ls.container.get("view").add({selector:"data-forms-nav",repeat:false,controller:function(element,view,container,document){let titles=document.querySelectorAll('[data-forms-nav-anchor]');let links=element.querySelectorAll('[data-forms-nav-link]');let minLink=null;let check=function(){let minDistance=null;let minElement=null;for(let i=0;i<titles.length;++i){let title=titles[i];let distance=title.getBoundingClientRect().top;console.log(i);if((minDistance===null||minDistance>=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);}
|
||||
|
|
130
src/Appwrite/Event/Audit.php
Normal file
130
src/Appwrite/Event/Audit.php
Normal file
|
@ -0,0 +1,130 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Event;
|
||||
|
||||
use Resque;
|
||||
|
||||
class Audit extends Event
|
||||
{
|
||||
protected string $resource = '';
|
||||
protected string $mode = '';
|
||||
protected string $userAgent = '';
|
||||
protected string $ip = '';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(Event::AUDITS_QUEUE_NAME, Event::AUDITS_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set resource for this audit event.
|
||||
*
|
||||
* @param string $resource
|
||||
* @return self
|
||||
*/
|
||||
public function setResource(string $resource): self
|
||||
{
|
||||
$this->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())
|
||||
]);
|
||||
}
|
||||
}
|
103
src/Appwrite/Event/Build.php
Normal file
103
src/Appwrite/Event/Build.php
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Event;
|
||||
|
||||
use Resque;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Build extends Event
|
||||
{
|
||||
protected string $type = '';
|
||||
protected ?Document $resource = null;
|
||||
protected ?Document $deployment = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(Event::BUILDS_QUEUE_NAME, Event::BUILDS_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets resource document for the build event.
|
||||
*
|
||||
* @param Document $resource
|
||||
* @return self
|
||||
*/
|
||||
public function setResource(Document $resource): self
|
||||
{
|
||||
$this->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
|
||||
]);
|
||||
}
|
||||
}
|
79
src/Appwrite/Event/Certificate.php
Normal file
79
src/Appwrite/Event/Certificate.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Event;
|
||||
|
||||
use Resque;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Certificate extends Event
|
||||
{
|
||||
protected bool $skipRenewCheck = false;
|
||||
protected ?Document $domain = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(Event::CERTIFICATES_QUEUE_NAME, Event::CERTIFICATES_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set domain for this certificates event.
|
||||
*
|
||||
* @param Document $domain
|
||||
* @return self
|
||||
*/
|
||||
public function setDomain(Document $domain): self
|
||||
{
|
||||
$this->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
|
||||
]);
|
||||
}
|
||||
}
|
103
src/Appwrite/Event/Database.php
Normal file
103
src/Appwrite/Event/Database.php
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Event;
|
||||
|
||||
use Resque;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Database extends Event
|
||||
{
|
||||
protected string $type = '';
|
||||
protected ?Document $collection = null;
|
||||
protected ?Document $document = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(Event::DATABASE_QUEUE_NAME, Event::DATABASE_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type for this database event (use the constants starting with DATABASE_TYPE_*).
|
||||
*
|
||||
* @param string $type
|
||||
* @return self
|
||||
*/
|
||||
public function setType(string $type): self
|
||||
{
|
||||
$this->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())
|
||||
]);
|
||||
}
|
||||
}
|
123
src/Appwrite/Event/Delete.php
Normal file
123
src/Appwrite/Event/Delete.php
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Event;
|
||||
|
||||
use Resque;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Delete extends Event
|
||||
{
|
||||
protected string $type = '';
|
||||
protected ?int $timestamp = null;
|
||||
protected ?int $timestamp1d = null;
|
||||
protected ?int $timestamp30m = null;
|
||||
protected ?Document $document = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(Event::DELETE_QUEUE_NAME, Event::DELETE_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type for the delete event (use the constants starting with DELETE_TYPE_*).
|
||||
*
|
||||
* @param string $type
|
||||
* @return self
|
||||
*/
|
||||
public function setType(string $type): self
|
||||
{
|
||||
$this->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
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
178
src/Appwrite/Event/Func.php
Normal file
178
src/Appwrite/Event/Func.php
Normal file
|
@ -0,0 +1,178 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Event;
|
||||
|
||||
use DateTime;
|
||||
use Resque;
|
||||
use ResqueScheduler;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Func extends Event
|
||||
{
|
||||
protected string $jwt = '';
|
||||
protected string $type = '';
|
||||
protected string $data = '';
|
||||
protected ?Document $function = null;
|
||||
protected ?Document $execution = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(Event::FUNCTIONS_QUEUE_NAME, Event::FUNCTIONS_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets function document for the function event.
|
||||
*
|
||||
* @param Document $function
|
||||
* @return self
|
||||
*/
|
||||
public function setFunction(Document $function): self
|
||||
{
|
||||
$this->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
|
||||
]);
|
||||
}
|
||||
}
|
181
src/Appwrite/Event/Mail.php
Normal file
181
src/Appwrite/Event/Mail.php
Normal file
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Event;
|
||||
|
||||
use Resque;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Mail extends Event
|
||||
{
|
||||
protected string $recipient = '';
|
||||
protected string $url = '';
|
||||
protected string $type = '';
|
||||
protected string $name = '';
|
||||
protected string $locale = '';
|
||||
protected ?Document $team = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(Event::MAILS_QUEUE_NAME, Event::MAILS_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets team for the mail event.
|
||||
*
|
||||
* @param Document $team
|
||||
* @return self
|
||||
*/
|
||||
public function setTeam(Document $team): self
|
||||
{
|
||||
$this->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())
|
||||
]);
|
||||
}
|
||||
}
|
127
src/Appwrite/Event/Validator/Event.php
Normal file
127
src/Appwrite/Event/Validator/Event.php
Normal file
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Event\Validator;
|
||||
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Validator;
|
||||
|
||||
class Event extends Validator
|
||||
{
|
||||
/**
|
||||
* Get Description.
|
||||
*
|
||||
* Returns validator description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Event is not valid.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Is valid.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($value): bool
|
||||
{
|
||||
$events = Config::getParam('events', []);
|
||||
$parts = \explode('.', $value);
|
||||
$count = \count($parts);
|
||||
|
||||
if ($count < 2 || $count > 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ abstract class Migration
|
|||
'0.13.2' => 'V12',
|
||||
'0.13.3' => 'V12',
|
||||
'0.13.4' => 'V12',
|
||||
'0.14.0' => 'V13',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
215
src/Appwrite/Migration/Version/V13.php
Normal file
215
src/Appwrite/Migration/Version/V13.php
Normal file
|
@ -0,0 +1,215 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Migration\Version;
|
||||
|
||||
use Appwrite\Event\Validator\Event;
|
||||
use Appwrite\Migration\Migration;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class V13 extends Migration
|
||||
{
|
||||
public array $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.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.email',
|
||||
'users.update.name',
|
||||
'users.update.password',
|
||||
'users.update.status',
|
||||
'users.sessions.delete',
|
||||
'users.delete',
|
||||
'teams.create',
|
||||
'teams.update',
|
||||
'teams.delete',
|
||||
'teams.memberships.create',
|
||||
'teams.memberships.update',
|
||||
'teams.memberships.update.status',
|
||||
'teams.memberships.delete'
|
||||
];
|
||||
|
||||
public function execute(): void
|
||||
{
|
||||
Console::log('Migrating project: ' . $this->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)));
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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']);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(10);
|
||||
|
||||
$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'], 'An internal curl error has occurred within the executor! Error Msg: Operation 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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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']);
|
||||
|
|
|
@ -1,154 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Workers;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectConsole;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Tests\E2E\Scopes\SideServer;
|
||||
|
||||
class WebhooksTest extends Scope
|
||||
{
|
||||
use ProjectConsole;
|
||||
use SideClient;
|
||||
|
||||
public function testCreateProject(): array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$team = $this->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']);
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
63
tests/unit/Event/Validator/EventValidatorTest.php
Normal file
63
tests/unit/Event/Validator/EventValidatorTest.php
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Tests;
|
||||
|
||||
use Appwrite\Event\Validator\Event;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Utopia\Config\Config;
|
||||
|
||||
class EventValidatorTest extends TestCase
|
||||
{
|
||||
protected ?Event $object = null;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
Config::load('events', __DIR__.'/../../../../app/config/events.php');
|
||||
$this->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'));
|
||||
}
|
||||
}
|
|
@ -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']);
|
||||
}
|
||||
}
|
||||
|
|
51
tests/unit/Migration/MigrationV13Test.php
Normal file
51
tests/unit/Migration/MigrationV13Test.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Tests;
|
||||
|
||||
use Appwrite\Event\Validator\Event;
|
||||
use ReflectionClass;
|
||||
use Appwrite\Migration\Version\V13;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class MigrationV13Test extends MigrationTest
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue