Merge branch '0.8.x' of github.com:appwrite/appwrite into feat-new-image-features
This commit is contained in:
commit
cd84de8fae
12
CHANGES.md
12
CHANGES.md
|
@ -1,6 +1,15 @@
|
|||
# Version 0.8.0 (Not Released Yet)
|
||||
|
||||
- Anonymous login
|
||||
## Features
|
||||
|
||||
- Added Anonymous Login ([RFC-010](https://github.com/appwrite/rfc/blob/main/010-anonymous-login.md), #914)
|
||||
- Added new Environment Variable to enable or disable Anonymous Login
|
||||
- Added events for functions and executions (#971)
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- Only logged in users can execute functions (for guests, use anonymous login)
|
||||
- Only the user who has triggered the execution get access to the relevant execution logs
|
||||
|
||||
# Version 0.7.2 (Not Released Yet)
|
||||
|
||||
|
@ -31,6 +40,7 @@
|
|||
- Force adding a security email on setup
|
||||
- SMTP is now disabled by default, no dummy SMTP is included in setup
|
||||
- Added a new endpoint that returns the server and SDKs latest versions numbers #941
|
||||
- Custom data strings, userId, and JWT available for cloud functions #967
|
||||
|
||||
## Upgrades
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ After finishing the installation process, you can start writing and editing code
|
|||
|
||||
|
||||
#### Advanced Topics
|
||||
We love to create issues that are good for begginers and label them as `good for begginers` or `hacktoberfest`, but some more advanced topics might require extra knowledge. Below is a list of links you can use to learn more about some of the more advance topics that will help you master the Appwrite codebase.
|
||||
We love to create issues that are good for beginners and label them as `good first issue` or `hacktoberfest`, but some more advanced topics might require extra knowledge. Below is a list of links you can use to learn more about some of the more advance topics that will help you master the Appwrite codebase.
|
||||
|
||||
##### Tools and Libs
|
||||
- [Docker](https://www.docker.com/get-started)
|
||||
|
@ -365,6 +365,7 @@ From time to time, our team will add tutorials that will help contributors find
|
|||
* [Adding Support for a New OAuth2 Provider](./docs/tutorials/add-oauth2-provider.md)
|
||||
* [Appwrite Environment Variables](./docs/tutorials/environment-variables.md)
|
||||
* [Running in Production](./docs/tutorials/running-in-production.md)
|
||||
* [Adding Storage Adapter](./docs/tutorials/add-storage-adapter.md)
|
||||
|
||||
## Other Ways to Help
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ docker run -it --rm ,
|
|||
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.
|
||||
|
||||
|
||||
For advanced production and custom installation, check out our Docker [environment variables](docs/tutorials/environment-variables.md) docs. You can also use our public [docker-compose.yml](https://appwrite.io/docker-compose.yml) file to manually set up an environment.
|
||||
For advanced production and custom installation, check out our Docker [environment variables](https://appwrite.io/docs/environment-variables) docs. You can also use our public [docker-compose.yml](https://gist.github.com/eldadfux/977869ff6bdd7312adfd4e629ee15cc5#file-docker-compose-yml) file to manually set up an environment.
|
||||
|
||||
### Upgrade from an Older Version
|
||||
|
||||
|
|
|
@ -204,7 +204,7 @@ $collections = [
|
|||
'key' => 'email',
|
||||
'type' => Database::SYSTEM_VAR_TYPE_EMAIL,
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
|
@ -222,7 +222,7 @@ $collections = [
|
|||
'key' => 'password',
|
||||
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
|
|
|
@ -97,6 +97,46 @@ return [
|
|||
'model' => Response::MODEL_ANY,
|
||||
'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.tags.create' => [
|
||||
'description' => 'This event triggers when a function tag is created.',
|
||||
'model' => Response::MODEL_TAG,
|
||||
'note' => 'version >= 0.7',
|
||||
],
|
||||
'functions.tags.update' => [
|
||||
'description' => 'This event triggers when a function tag is updated.',
|
||||
'model' => Response::MODEL_FUNCTION,
|
||||
'note' => 'version >= 0.7',
|
||||
],
|
||||
'functions.tags.delete' => [
|
||||
'description' => 'This event triggers when a function tag 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,
|
||||
|
@ -167,4 +207,4 @@ return [
|
|||
'model' => Response::MODEL_MEMBERSHIP,
|
||||
'note' => 'version >= 0.7',
|
||||
],
|
||||
];
|
||||
];
|
||||
|
|
|
@ -32,7 +32,7 @@ return [
|
|||
[
|
||||
'key' => 'flutter',
|
||||
'name' => 'Flutter',
|
||||
'version' => '0.4.0-dev.3',
|
||||
'version' => '0.4.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-flutter',
|
||||
'package' => 'https://pub.dev/packages/appwrite',
|
||||
'enabled' => true,
|
||||
|
|
|
@ -60,8 +60,6 @@ return [
|
|||
'files.read',
|
||||
'locale.read',
|
||||
'avatars.read',
|
||||
'execution.read',
|
||||
'execution.write',
|
||||
],
|
||||
],
|
||||
Auth::USER_ROLE_MEMBER => [
|
||||
|
|
|
@ -118,7 +118,7 @@ return [
|
|||
'default' => 'enabled',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
[
|
||||
|
|
|
@ -109,7 +109,7 @@ App::post('/v1/account')
|
|||
throw new Exception('Account already exists', 409);
|
||||
}
|
||||
|
||||
Authorization::enable();
|
||||
Authorization::reset();
|
||||
|
||||
Authorization::unsetRole('role:'.Auth::USER_ROLE_GUEST);
|
||||
Authorization::setRole('user:'.$user->getId());
|
||||
|
@ -487,7 +487,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
throw new Exception('Account already exists', 409);
|
||||
}
|
||||
|
||||
Authorization::enable();
|
||||
Authorization::reset();
|
||||
|
||||
if (false === $user) {
|
||||
throw new Exception('Failed saving user to DB', 500);
|
||||
|
@ -517,6 +517,15 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
'countryCode' => ($record) ? \strtolower($record['country']['iso_code']) : '--',
|
||||
], $detector->getOS(), $detector->getClient(), $detector->getDevice()));
|
||||
|
||||
$isAnonymousUser = is_null($user->getAttribute('email')) && is_null($user->getAttribute('password'));
|
||||
|
||||
if ($isAnonymousUser) {
|
||||
$user
|
||||
->setAttribute('name', $oauth2->getUserName($accessToken))
|
||||
->setAttribute('email', $oauth2->getUserEmail($accessToken))
|
||||
;
|
||||
}
|
||||
|
||||
$user
|
||||
->setAttribute('oauth2'.\ucfirst($provider), $oauth2ID)
|
||||
->setAttribute('oauth2'.\ucfirst($provider).'AccessToken', $accessToken)
|
||||
|
@ -566,6 +575,130 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
;
|
||||
});
|
||||
|
||||
App::post('/v1/account/sessions/anonymous')
|
||||
->desc('Create Anonymous Session')
|
||||
->groups(['api', 'account'])
|
||||
->label('event', 'account.sessions.create')
|
||||
->label('scope', 'public')
|
||||
->label('sdk.platform', [APP_PLATFORM_CLIENT])
|
||||
->label('sdk.namespace', 'account')
|
||||
->label('sdk.method', 'createAnonymousSession')
|
||||
->label('sdk.description', '/docs/references/account/create-session-anonymous.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_SESSION)
|
||||
->label('abuse-limit', 50)
|
||||
->label('abuse-key', 'ip:{ip}')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('locale')
|
||||
->inject('user')
|
||||
->inject('project')
|
||||
->inject('projectDB')
|
||||
->inject('geodb')
|
||||
->inject('audits')
|
||||
->action(function ($request, $response, $locale, $user, $project, $projectDB, $geodb, $audits) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var Appwrite\Database\Document $user */
|
||||
/** @var Appwrite\Database\Document $project */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
|
||||
if ($user->getId() || 'console' === $project->getId()) {
|
||||
throw new Exception('Failed to create anonymous user.', 401);
|
||||
}
|
||||
|
||||
Authorization::disable();
|
||||
try {
|
||||
$user = $projectDB->createDocument([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_USERS,
|
||||
'$permissions' => [
|
||||
'read' => ['*'],
|
||||
'write' => ['user:{self}']
|
||||
],
|
||||
'email' => null,
|
||||
'emailVerification' => false,
|
||||
'status' => Auth::USER_STATUS_UNACTIVATED,
|
||||
'password' => null,
|
||||
'passwordUpdate' => \time(),
|
||||
'registration' => \time(),
|
||||
'reset' => false,
|
||||
'name' => null
|
||||
]);
|
||||
} catch (Exception $th) {
|
||||
throw new Exception('Failed saving user to DB', 500);
|
||||
}
|
||||
|
||||
Authorization::reset();
|
||||
|
||||
if (false === $user) {
|
||||
throw new Exception('Failed saving user to DB', 500);
|
||||
}
|
||||
|
||||
// Create session token
|
||||
|
||||
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
||||
$record = $geodb->get($request->getIP());
|
||||
$secret = Auth::tokenGenerator();
|
||||
$expiry = \time() + Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||
$session = new Document(array_merge(
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
|
||||
'$permissions' => ['read' => ['user:' . $user['$id']], 'write' => ['user:' . $user['$id']]],
|
||||
'userId' => $user->getId(),
|
||||
'type' => Auth::TOKEN_TYPE_LOGIN,
|
||||
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
|
||||
'expire' => $expiry,
|
||||
'userAgent' => $request->getUserAgent('UNKNOWN'),
|
||||
'ip' => $request->getIP(),
|
||||
'countryCode' => ($record) ? \strtolower($record['country']['iso_code']) : '--',
|
||||
],
|
||||
$detector->getOS(),
|
||||
$detector->getClient(),
|
||||
$detector->getDevice()
|
||||
));
|
||||
|
||||
$user->setAttribute('tokens', $session, Document::SET_TYPE_APPEND);
|
||||
|
||||
Authorization::setRole('user:'.$user->getId());
|
||||
|
||||
$user = $projectDB->updateDocument($user->getArrayCopy());
|
||||
|
||||
if (false === $user) {
|
||||
throw new Exception('Failed saving user to DB', 500);
|
||||
}
|
||||
|
||||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'account.sessions.create')
|
||||
->setParam('resource', 'users/'.$user->getId())
|
||||
;
|
||||
|
||||
if (!Config::getParam('domainVerification')) {
|
||||
$response
|
||||
->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)]))
|
||||
;
|
||||
}
|
||||
|
||||
$response
|
||||
->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), $expiry, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
|
||||
->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), $expiry, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'))
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
;
|
||||
|
||||
$session
|
||||
->setAttribute('current', true)
|
||||
->setAttribute('countryName', (isset($countries[$session->getAttribute('countryCode')])) ? $countries[$session->getAttribute('countryCode')] : $locale->getText('locale.country.unknown'))
|
||||
;
|
||||
|
||||
$response->dynamic($session, Response::MODEL_SESSION);
|
||||
});
|
||||
|
||||
App::post('/v1/account/jwt')
|
||||
->desc('Create Account JWT')
|
||||
->groups(['api', 'account'])
|
||||
|
@ -880,7 +1013,12 @@ App::patch('/v1/account/email')
|
|||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
|
||||
if (!Auth::passwordVerify($password, $user->getAttribute('password'))) { // Double check user password
|
||||
$isAnonymousUser = is_null($user->getAttribute('email')) && is_null($user->getAttribute('password')); // Check if request is from an anonymous account for converting
|
||||
|
||||
if (
|
||||
!$isAnonymousUser &&
|
||||
!Auth::passwordVerify($password, $user->getAttribute('password'))
|
||||
) { // Double check user password
|
||||
throw new Exception('Invalid credentials', 401);
|
||||
}
|
||||
|
||||
|
@ -898,10 +1036,14 @@ App::patch('/v1/account/email')
|
|||
|
||||
// TODO after this user needs to confirm mail again
|
||||
|
||||
$user = $projectDB->updateDocument(\array_merge($user->getArrayCopy(), [
|
||||
'email' => $email,
|
||||
'emailVerification' => false,
|
||||
]));
|
||||
$user = $projectDB->updateDocument(\array_merge(
|
||||
$user->getArrayCopy(),
|
||||
($isAnonymousUser ? [ 'password' => Auth::passwordHash($password) ] : []),
|
||||
[
|
||||
'email' => $email,
|
||||
'emailVerification' => false,
|
||||
]
|
||||
));
|
||||
|
||||
if (false === $user) {
|
||||
throw new Exception('Failed saving user to DB', 500);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Ahc\Jwt\JWT;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Database\Database;
|
||||
use Appwrite\Database\Document;
|
||||
use Appwrite\Database\Validator\Authorization;
|
||||
|
@ -27,6 +29,7 @@ App::post('/v1/functions')
|
|||
->groups(['api', 'functions'])
|
||||
->desc('Create Function')
|
||||
->label('scope', 'functions.write')
|
||||
->label('event', 'functions.create')
|
||||
->label('sdk.platform', [APP_PLATFORM_SERVER])
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'create')
|
||||
|
@ -265,6 +268,7 @@ App::put('/v1/functions/:functionId')
|
|||
->groups(['api', 'functions'])
|
||||
->desc('Update Function')
|
||||
->label('scope', 'functions.write')
|
||||
->label('event', 'functions.update')
|
||||
->label('sdk.platform', [APP_PLATFORM_SERVER])
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'update')
|
||||
|
@ -330,6 +334,7 @@ App::patch('/v1/functions/:functionId/tag')
|
|||
->groups(['api', 'functions'])
|
||||
->desc('Update Function Tag')
|
||||
->label('scope', 'functions.write')
|
||||
->label('event', 'functions.tags.update')
|
||||
->label('sdk.platform', [APP_PLATFORM_SERVER])
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'updateTag')
|
||||
|
@ -387,6 +392,7 @@ App::delete('/v1/functions/:functionId')
|
|||
->groups(['api', 'functions'])
|
||||
->desc('Delete Function')
|
||||
->label('scope', 'functions.write')
|
||||
->label('event', 'functions.delete')
|
||||
->label('sdk.platform', [APP_PLATFORM_SERVER])
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'delete')
|
||||
|
@ -424,6 +430,7 @@ App::post('/v1/functions/:functionId/tags')
|
|||
->groups(['api', 'functions'])
|
||||
->desc('Create Tag')
|
||||
->label('scope', 'functions.write')
|
||||
->label('event', 'functions.tags.create')
|
||||
->label('sdk.platform', [APP_PLATFORM_SERVER])
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'createTag')
|
||||
|
@ -601,6 +608,7 @@ App::delete('/v1/functions/:functionId/tags/:tagId')
|
|||
->groups(['api', 'functions'])
|
||||
->desc('Delete Tag')
|
||||
->label('scope', 'functions.write')
|
||||
->label('event', 'functions.tags.delete')
|
||||
->label('sdk.platform', [APP_PLATFORM_SERVER])
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'deleteTag')
|
||||
|
@ -662,6 +670,7 @@ App::post('/v1/functions/:functionId/executions')
|
|||
->groups(['api', 'functions'])
|
||||
->desc('Create Execution')
|
||||
->label('scope', 'execution.write')
|
||||
->label('event', 'functions.executions.create')
|
||||
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'createExecution')
|
||||
|
@ -672,14 +681,17 @@ App::post('/v1/functions/:functionId/executions')
|
|||
->label('abuse-limit', 60)
|
||||
->label('abuse-time', 60)
|
||||
->param('functionId', '', new UID(), 'Function unique ID.')
|
||||
->param('data', '', new Text(8192), 'String of custom data to send to function.', true)
|
||||
// ->param('async', 1, new Range(0, 1), 'Execute code asynchronously. Pass 1 for true, 0 for false. Default value is 1.', true)
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('projectDB')
|
||||
->action(function ($functionId, /*$async,*/ $response, $project, $projectDB) {
|
||||
->inject('user')
|
||||
->action(function ($functionId, $data, /*$async,*/ $response, $project, $projectDB, $user) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Document $project */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Appwrite\Database\Document $user */
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
|
@ -712,7 +724,7 @@ App::post('/v1/functions/:functionId/executions')
|
|||
$execution = $projectDB->createDocument([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_EXECUTIONS,
|
||||
'$permissions' => [
|
||||
'read' => $function->getPermissions()['execute'] ?? [],
|
||||
'read' => (!empty($user->getId())) ? ['user:' . $user->getId()] : [],
|
||||
'write' => [],
|
||||
],
|
||||
'dateCreated' => time(),
|
||||
|
@ -730,12 +742,36 @@ App::post('/v1/functions/:functionId/executions')
|
|||
if (false === $execution) {
|
||||
throw new Exception('Failed saving execution to DB', 500);
|
||||
}
|
||||
|
||||
|
||||
$jwt = ''; // initialize
|
||||
if (!empty($user->getId())) { // If userId exists, generate a JWT for function
|
||||
|
||||
$tokens = $user->getAttribute('tokens', []);
|
||||
$session = new Document();
|
||||
|
||||
foreach ($tokens as $token) { /** @var Appwrite\Database\Document $token */
|
||||
if ($token->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too
|
||||
$session = $token;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$session->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(),
|
||||
'sessionId' => $session->getId(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Resque::enqueue('v1-functions', 'FunctionsV1', [
|
||||
'projectId' => $project->getId(),
|
||||
'functionId' => $function->getId(),
|
||||
'executionId' => $execution->getId(),
|
||||
'trigger' => 'http',
|
||||
'data' => $data,
|
||||
'userId' => $user->getId(),
|
||||
'jwt' => $jwt,
|
||||
]);
|
||||
|
||||
$response
|
||||
|
|
|
@ -50,24 +50,9 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
|
|||
|
||||
<p class="text-fade margin-bottom-small" data-ls-bind="{{project-function.env|envName}} {{project-function.env|envVersion}}">
|
||||
</p>
|
||||
|
||||
<form data-ls-if="{{project-function.tag}} !== ''" name="functions.createExecution" class="margin-top"
|
||||
data-analytics
|
||||
data-analytics-activity
|
||||
data-analytics-event="submit"
|
||||
data-analytics-category="console"
|
||||
data-analytics-label="Create Function Execution"
|
||||
data-service="functions.createExecution"
|
||||
data-event="submit"
|
||||
data-param-function-id="{{router.params.id}}"
|
||||
data-success="alert,trigger"
|
||||
data-success-param-alert-text="Function executed successfully"
|
||||
data-success-param-trigger-events="functions.createExecution"
|
||||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to execute function"
|
||||
data-failure-param-alert-classname="error">
|
||||
<button style="vertical-align: top;">Execute Now</button> <a data-ls-attrs="href=/console/functions/function/logs?id={{router.params.id}}&project={{router.params.project}}" class="button reverse" style="vertical-align: top;">View Logs</a>
|
||||
</form>
|
||||
<div data-ls-if="{{project-function.tag}} !== ''" class="margin-top">
|
||||
<button data-ls-ui-trigger="execute-now">Execute Now</button> <a data-ls-attrs="href=/console/functions/function/logs?id={{router.params.id}}&project={{router.params.project}}" class="button reverse" style="vertical-align: top;">View Logs</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -575,6 +560,31 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div data-ui-modal class="modal close box sticky-footer" data-button-hide="on" data-open-event="execute-now">
|
||||
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||
<h1 class="margin-bottom">Execute Function</h1>
|
||||
<form data-ls-if="{{project-function.tag}} !== ''" name="functions.createExecution" class="margin-top"
|
||||
data-analytics
|
||||
data-analytics-activity
|
||||
data-analytics-event="submit"
|
||||
data-analytics-category="console"
|
||||
data-analytics-label="Create Function Execution"
|
||||
data-service="functions.createExecution"
|
||||
data-event="submit"
|
||||
data-param-function-id="{{router.params.id}}"
|
||||
data-success="alert,trigger"
|
||||
data-success-param-alert-text="Function executed successfully"
|
||||
data-success-param-trigger-events="functions.createExecution"
|
||||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to execute function"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
<label for="execution-data">Custom Data</label>
|
||||
<textarea id="execution-data" name="data" autocomplete="off" class="margin-bottom" placeholder="Data string (optional)"></textarea>
|
||||
|
||||
<button type="submit" style="vertical-align: top;">Execute Now</button>
|
||||
</form>
|
||||
</div>
|
||||
<div data-ui-modal class="modal close box sticky-footer" data-button-hide="on" data-open-event="deploy-tag">
|
||||
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||
|
||||
|
|
|
@ -148,6 +148,9 @@ class FunctionsV1
|
|||
$event = $this->args['event'] ?? '';
|
||||
$scheduleOriginal = $this->args['scheduleOriginal'] ?? '';
|
||||
$payload = (!empty($this->args['payload'])) ? json_encode($this->args['payload']) : '';
|
||||
$data = $this->args['data'] ?? '';
|
||||
$userId = $this->args['userId'] ?? '';
|
||||
$jwt = $this->args['jwt'] ?? '';
|
||||
|
||||
$database = new Database();
|
||||
$database->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
|
||||
|
@ -195,7 +198,7 @@ class FunctionsV1
|
|||
|
||||
Console::success('Triggered function: '.$event);
|
||||
|
||||
$this->execute('event', $projectId, '', $database, $function, $event, $payload);
|
||||
$this->execute('event', $projectId, '', $database, $function, $event, $payload, $data, $userId, $jwt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -251,8 +254,7 @@ class FunctionsV1
|
|||
'scheduleOriginal' => $function->getAttribute('schedule', ''),
|
||||
]); // Async task rescheduale
|
||||
|
||||
$this->execute($trigger, $projectId, $executionId, $database, $function);
|
||||
|
||||
$this->execute($trigger, $projectId, $executionId, $database, $function, /*$event*/'', /*$payload*/'', $data, $userId, $jwt);
|
||||
break;
|
||||
|
||||
case 'http':
|
||||
|
@ -264,7 +266,7 @@ class FunctionsV1
|
|||
throw new Exception('Function not found ('.$functionId.')');
|
||||
}
|
||||
|
||||
$this->execute($trigger, $projectId, $executionId, $database, $function);
|
||||
$this->execute($trigger, $projectId, $executionId, $database, $function, /*$event*/'', /*$payload*/'', $data, $userId, $jwt);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -283,10 +285,11 @@ class FunctionsV1
|
|||
* @param Database $function
|
||||
* @param string $event
|
||||
* @param string $payload
|
||||
* @param string $data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute(string $trigger, string $projectId, string $executionId, Database $database, Document $function, string $event = '', string $payload = ''): void
|
||||
public function execute(string $trigger, string $projectId, string $executionId, Database $database, Document $function, string $event = '', string $payload = '', string $data = '', string $userId = '', string $jwt = ''): void
|
||||
{
|
||||
global $list;
|
||||
|
||||
|
@ -341,6 +344,10 @@ class FunctionsV1
|
|||
'APPWRITE_FUNCTION_ENV_VERSION' => $environment['version'],
|
||||
'APPWRITE_FUNCTION_EVENT' => $event,
|
||||
'APPWRITE_FUNCTION_EVENT_PAYLOAD' => $payload,
|
||||
'APPWRITE_FUNCTION_DATA' => $data,
|
||||
'APPWRITE_FUNCTION_USER_ID' => $userId,
|
||||
'APPWRITE_FUNCTION_JWT' => $jwt,
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' => $projectId,
|
||||
]);
|
||||
|
||||
\array_walk($vars, function (&$value, $key) {
|
||||
|
@ -469,6 +476,26 @@ class FunctionsV1
|
|||
throw new Exception('Failed saving execution to DB', 500);
|
||||
}
|
||||
|
||||
$executionUpdate = new Event('v1-webhooks', 'WebhooksV1');
|
||||
|
||||
$executionUpdate
|
||||
->setParam('projectId', $projectId)
|
||||
->setParam('userId', $userId)
|
||||
->setParam('event', 'functions.executions.update')
|
||||
->setParam('payload', [
|
||||
'$id' => $execution['$id'],
|
||||
'functionId' => $execution['functionId'],
|
||||
'dateCreated' => $execution['dateCreated'],
|
||||
'trigger' => $execution['trigger'],
|
||||
'status' => $execution['status'],
|
||||
'exitCode' => $execution['exitCode'],
|
||||
'stdout' => $execution['stdout'],
|
||||
'stderr' => $execution['stderr'],
|
||||
'time' => $execution['time']
|
||||
]);
|
||||
|
||||
$executionUpdate->trigger();
|
||||
|
||||
$usage = new Event('v1-usage', 'UsageV1');
|
||||
|
||||
$usage
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
"slickdeals/statsd": "~3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"appwrite/sdk-generator": "0.6.3",
|
||||
"appwrite/sdk-generator": "0.7.0",
|
||||
"phpunit/phpunit": "9.4.2",
|
||||
"swoole/ide-helper": "4.5.5",
|
||||
"vimeo/psalm": "4.1.1"
|
||||
|
|
8
composer.lock
generated
8
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": "402fcc05d9d5ef4c78d71d8bf3d5f87f",
|
||||
"content-hash": "60b57e034676287a703cf42b1de0c60d",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
@ -2350,11 +2350,11 @@
|
|||
},
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "0.6.3",
|
||||
"version": "0.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator",
|
||||
"reference": "583248c57c5bcbd9c74f8312cc7fc3ab6cda51a3"
|
||||
"reference": "12a6a4b723137d5449c84ee2915b1ab3586e2162"
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
|
@ -2384,7 +2384,7 @@
|
|||
}
|
||||
],
|
||||
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
|
||||
"time": "2021-03-07T08:45:05+00:00"
|
||||
"time": "2021-03-23T09:26:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/package-versions-deprecated",
|
||||
|
|
1
docs/references/account/create-session-anonymous.md
Normal file
1
docs/references/account/create-session-anonymous.md
Normal file
|
@ -0,0 +1 @@
|
|||
Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account account, you need to update its [email and password](/docs/client/account#accountUpdateEmail).
|
|
@ -1 +1,2 @@
|
|||
Update currently logged in user account email address. After changing user address, user confirmation status is being reset and a new confirmation mail is sent. For security measures, user password is required to complete this request.
|
||||
Update currently logged in user account email address. After changing user address, user confirmation status is being reset and a new confirmation mail is sent. For security measures, user password is required to complete this request.
|
||||
This endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password.
|
|
@ -1,3 +1,11 @@
|
|||
## 0.4.0
|
||||
|
||||
- Improved code quality
|
||||
- Enabled access to private storage files
|
||||
- Easier integration for preview images with the image widget
|
||||
- Added custom Appwrite exceptions
|
||||
- Breaking: getFilePreview, getFileDownload and getFileView now return Future instead of String
|
||||
|
||||
## 0.4.0-dev.3
|
||||
|
||||
- Added code formatting as part of the CI
|
||||
|
|
|
@ -10,7 +10,7 @@ Adding new features may require various configurations options to be set by the
|
|||
This tutorial will cover, how to properly add a new environment variable in Appwrite.
|
||||
|
||||
### Naming environment varialbe
|
||||
The environment variables in Appwrite are prefixed with `_APP_`. If it belongs to a specific cateogry, the category name is appended as `_APP_REDIS` for the redis category. The available categories are General, Redis, MariaDB, InfluxDB, StatsD, SMTP, Storage and Functions. Finally a properly describing name is given to the variable. For example `_APP_REDIS_HOST` is an environment variable for redis connection host. You can find more information on available categories and existing environment variables in the [environment variables doc](https://appwrite.io/docs/environment-variables).
|
||||
The environment variables in Appwrite are prefixed with `_APP_`. If it belongs to a specific category, the category name is appended as `_APP_REDIS` for the redis category. The available categories are General, Redis, MariaDB, InfluxDB, StatsD, SMTP, Storage and Functions. Finally a properly describing name is given to the variable. For example `_APP_REDIS_HOST` is an environment variable for redis connection host. You can find more information on available categories and existing environment variables in the [environment variables doc](https://appwrite.io/docs/environment-variables).
|
||||
|
||||
### Describe new environment variable
|
||||
First of all, we add the new environment variable to `app/config/variables.php` in the designated category. If none of the categories fit, add it to the General category. Copy the existing variables description to create a new one, so that you will not miss any required fields.
|
||||
|
|
|
@ -37,7 +37,7 @@ In this phase we will add support to the new storage adapter in Appwrite.
|
|||
* Note for this to happen, your PR in the first phase should have been merged and new version of [utopia-php/storage](https://github.com/utopia-php/storage) library released.
|
||||
|
||||
### Upgrade the utopia-php/storage dependency
|
||||
Upgrade the utopia-php/sotrage dependency in `composer.json` file.
|
||||
Upgrade the utopia-php/storage dependency in `composer.json` file.
|
||||
|
||||
### Introduce new environment variables
|
||||
If required for the new adapter, may be for credentials, introduce new environment variables. The storage envorinment variables are prefixed as `_APP_STORAGE_DEVICE`. Please read [Adding Environment Variables]() guidelines in order to properly introduce new environment variables.
|
||||
|
|
18
phpunit.xml
18
phpunit.xml
|
@ -13,7 +13,23 @@
|
|||
</extensions>
|
||||
<testsuites>
|
||||
<testsuite name="Application Test Suite">
|
||||
<directory>./tests/e2e/</directory>
|
||||
<file>./tests/e2e/Client.php</file>
|
||||
<directory>./tests/e2e/General</directory>
|
||||
<directory>./tests/e2e/Scopes</directory>
|
||||
<directory>./tests/e2e/Services/Account</directory>
|
||||
<directory>./tests/e2e/Services/Avatars</directory>
|
||||
<directory>./tests/e2e/Services/Database</directory>
|
||||
<file>./tests/e2e/Services/Functions/FunctionsBase.php</file>
|
||||
<file>./tests/e2e/Services/Functions/FunctionsCustomServerTest.php</file>
|
||||
<file>./tests/e2e/Services/Functions/FunctionsCustomClientTest.php</file>
|
||||
<directory>./tests/e2e/Services/Health</directory>
|
||||
<directory>./tests/e2e/Services/Locale</directory>
|
||||
<directory>./tests/e2e/Services/Projects</directory>
|
||||
<directory>./tests/e2e/Services/Storage</directory>
|
||||
<directory>./tests/e2e/Services/Teams</directory>
|
||||
<directory>./tests/e2e/Services/Users</directory>
|
||||
<directory>./tests/e2e/Services/Webhooks</directory>
|
||||
<directory>./tests/e2e/Services/Workers</directory>
|
||||
<directory>./tests/unit/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
|
5
public/dist/scripts/app-all.js
vendored
5
public/dist/scripts/app-all.js
vendored
|
@ -188,8 +188,9 @@ let path='/functions/{functionId}/executions'.replace(new RegExp('{functionId}',
|
|||
if(limit){payload['limit']=limit;}
|
||||
if(offset){payload['offset']=offset;}
|
||||
if(orderType){payload['orderType']=orderType;}
|
||||
return http.get(path,{'content-type':'application/json',},payload);},createExecution:function(functionId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/executions'.replace(new RegExp('{functionId}','g'),functionId);let payload={};return http.post(path,{'content-type':'application/json',},payload);},getExecution:function(functionId,executionId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
return http.get(path,{'content-type':'application/json',},payload);},createExecution:function(functionId,data){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/executions'.replace(new RegExp('{functionId}','g'),functionId);let payload={};if(data){payload['data']=data;}
|
||||
return http.post(path,{'content-type':'application/json',},payload);},getExecution:function(functionId,executionId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
if(executionId===undefined){throw new Error('Missing required parameter: "executionId"');}
|
||||
let path='/functions/{functionId}/executions/{executionId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{executionId}','g'),executionId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},updateTag:function(functionId,tag){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
if(tag===undefined){throw new Error('Missing required parameter: "tag"');}
|
||||
|
|
5
public/dist/scripts/app-dep.js
vendored
5
public/dist/scripts/app-dep.js
vendored
|
@ -188,8 +188,9 @@ let path='/functions/{functionId}/executions'.replace(new RegExp('{functionId}',
|
|||
if(limit){payload['limit']=limit;}
|
||||
if(offset){payload['offset']=offset;}
|
||||
if(orderType){payload['orderType']=orderType;}
|
||||
return http.get(path,{'content-type':'application/json',},payload);},createExecution:function(functionId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/executions'.replace(new RegExp('{functionId}','g'),functionId);let payload={};return http.post(path,{'content-type':'application/json',},payload);},getExecution:function(functionId,executionId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
return http.get(path,{'content-type':'application/json',},payload);},createExecution:function(functionId,data){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/executions'.replace(new RegExp('{functionId}','g'),functionId);let payload={};if(data){payload['data']=data;}
|
||||
return http.post(path,{'content-type':'application/json',},payload);},getExecution:function(functionId,executionId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
if(executionId===undefined){throw new Error('Missing required parameter: "executionId"');}
|
||||
let path='/functions/{functionId}/executions/{executionId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{executionId}','g'),executionId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},updateTag:function(functionId,tag){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
if(tag===undefined){throw new Error('Missing required parameter: "tag"');}
|
||||
|
|
|
@ -2075,10 +2075,11 @@
|
|||
* function execution process will start asynchronously.
|
||||
*
|
||||
* @param {string} functionId
|
||||
* @param {string} data
|
||||
* @throws {Error}
|
||||
* @return {Promise}
|
||||
*/
|
||||
createExecution: function(functionId) {
|
||||
createExecution: function(functionId, data) {
|
||||
if(functionId === undefined) {
|
||||
throw new Error('Missing required parameter: "functionId"');
|
||||
}
|
||||
|
@ -2087,6 +2088,10 @@
|
|||
|
||||
let payload = {};
|
||||
|
||||
if (data) {
|
||||
payload['data'] = data;
|
||||
}
|
||||
|
||||
return http
|
||||
.post(path, {
|
||||
'content-type': 'application/json',
|
||||
|
|
|
@ -113,6 +113,14 @@ trait ProjectCustom
|
|||
'database.documents.create',
|
||||
'database.documents.update',
|
||||
'database.documents.delete',
|
||||
'functions.create',
|
||||
'functions.update',
|
||||
'functions.delete',
|
||||
'functions.tags.create',
|
||||
'functions.tags.update',
|
||||
'functions.tags.delete',
|
||||
'functions.executions.create',
|
||||
'functions.executions.update',
|
||||
'storage.files.create',
|
||||
'storage.files.update',
|
||||
'storage.files.delete',
|
||||
|
|
|
@ -49,6 +49,39 @@ trait AccountBase
|
|||
|
||||
$this->assertEquals($response['headers']['status-code'], 409);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => '',
|
||||
'password' => '',
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 400);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => '',
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 400);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => '',
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 400);
|
||||
|
||||
return [
|
||||
'id' => $id,
|
||||
'email' => $email,
|
||||
|
@ -372,7 +405,6 @@ trait AccountBase
|
|||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertIsArray($response['body']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertIsNumeric($response['body']['registration']);
|
||||
$this->assertEquals($response['body']['email'], $email);
|
||||
|
@ -440,7 +472,6 @@ trait AccountBase
|
|||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertIsArray($response['body']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertIsNumeric($response['body']['registration']);
|
||||
$this->assertEquals($response['body']['email'], $email);
|
||||
|
@ -507,7 +538,6 @@ trait AccountBase
|
|||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertIsArray($response['body']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertIsNumeric($response['body']['registration']);
|
||||
$this->assertEquals($response['body']['email'], $newEmail);
|
||||
|
@ -565,7 +595,6 @@ trait AccountBase
|
|||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertIsArray($response['body']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertEquals('prefValue1', $response['body']['prefs']['prefKey1']);
|
||||
$this->assertEquals('prefValue2', $response['body']['prefs']['prefKey2']);
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ use Tests\E2E\Client;
|
|||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Utopia\App;
|
||||
|
||||
class AccountCustomClientTest extends Scope
|
||||
{
|
||||
|
@ -226,4 +227,198 @@ class AccountCustomClientTest extends Scope
|
|||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function testCreateAnonymousAccount()
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/anonymous', [
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/anonymous', [
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
return $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateAnonymousAccount
|
||||
*/
|
||||
public function testUpdateAnonymousAccountPassword($session):array
|
||||
{
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/account/password', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
]), [
|
||||
'password' => 'new-password',
|
||||
'oldPassword' => '',
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 400);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testUpdateAnonymousAccountPassword
|
||||
*/
|
||||
public function testUpdateAnonymousAccountEmail($session):array
|
||||
{
|
||||
$email = uniqid().'new@localhost.test';
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$response = $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,
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => '',
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 401);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function testConvertAnonymousAccount():array
|
||||
{
|
||||
$session = $this->testCreateAnonymousAccount();
|
||||
$email = uniqid().'new@localhost.test';
|
||||
$password = 'new-password';
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => $password
|
||||
]);
|
||||
|
||||
$response = $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,
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 400);
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$email = uniqid().'new@localhost.test';
|
||||
|
||||
$response = $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,
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertIsArray($response['body']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertIsNumeric($response['body']['registration']);
|
||||
$this->assertEquals($response['body']['email'], $email);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function testConvertAnonymousAccountOAuth2():array
|
||||
{
|
||||
$session = $this->testCreateAnonymousAccount();
|
||||
$provider = 'mock';
|
||||
$appId = '1';
|
||||
$secret = '123456';
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$this->getProject()['$id'].'/oauth2', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => 'console',
|
||||
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
|
||||
]), [
|
||||
'provider' => $provider,
|
||||
'appId' => $appId,
|
||||
'secret' => $secret,
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/'.$provider, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
]), [
|
||||
'success' => 'http://localhost/v1/mock/tests/general/oauth2/success',
|
||||
'failure' => 'http://localhost/v1/mock/tests/general/oauth2/failure',
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals('success', $response['body']['result']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertEquals($response['body']['name'], 'User Name');
|
||||
$this->assertEquals($response['body']['email'], 'user@localhost.test');
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
|
@ -80,9 +80,9 @@ class FunctionsCustomClientTest extends Scope
|
|||
]);
|
||||
|
||||
$tagId = $tag['body']['$id'] ?? '';
|
||||
|
||||
|
||||
$this->assertEquals(201, $tag['headers']['status-code']);
|
||||
|
||||
|
||||
$function = $this->client->call(Client::METHOD_PATCH, '/functions/'.$function['body']['$id'].'/tag', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
@ -90,7 +90,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
], [
|
||||
'tag' => $tagId,
|
||||
]);
|
||||
|
||||
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/executions', [
|
||||
|
@ -113,6 +113,92 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'async' => 1,
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $execution['headers']['status-code']);
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public function testCreateCustomExecution():array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$apikey = $this->getProject()['apiKey'];
|
||||
|
||||
$function = $this->client->call(Client::METHOD_POST, '/functions', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $apikey,
|
||||
], [
|
||||
'name' => 'Test',
|
||||
'execute' => ['*'],
|
||||
'env' => 'php-7.4',
|
||||
'vars' => [
|
||||
'funcKey1' => 'funcValue1',
|
||||
'funcKey2' => 'funcValue2',
|
||||
'funcKey3' => 'funcValue3',
|
||||
],
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
$functionId = $function['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
|
||||
$tag = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/tags', [
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $apikey,
|
||||
], [
|
||||
'command' => 'php index.php',
|
||||
'code' => new CURLFile(realpath(__DIR__ . '/../../../resources/functions/php-fn.tar.gz'), 'application/x-gzip', 'php-fx.tar.gz'), //different tarball names intentional
|
||||
]);
|
||||
|
||||
$tagId = $tag['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEquals(201, $tag['headers']['status-code']);
|
||||
|
||||
$function = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/tag', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $apikey,
|
||||
], [
|
||||
'tag' => $tagId,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders()), [
|
||||
'data' => 'foobar',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||
|
||||
sleep(10);
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $apikey,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $executions['headers']['status-code']);
|
||||
$this->assertCount(1, $executions['body']['executions']);
|
||||
$this->assertEquals('completed', $executions['body']['executions'][0]['status']);
|
||||
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['stdout']);
|
||||
$this->assertStringContainsString($this->getUser()['$id'], $executions['body']['executions'][0]['stdout']);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -760,4 +760,77 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals($executions['body']['executions'][0]['stdout'], '');
|
||||
$this->assertEquals($executions['body']['executions'][0]['stderr'], '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testTimeout
|
||||
*/
|
||||
public function testCreateCustomExecution()
|
||||
{
|
||||
$name = 'php-8.0';
|
||||
$code = realpath(__DIR__ . '/../../../resources/functions').'/php-fn.tar.gz';
|
||||
$command = 'php index.php';
|
||||
$timeout = 2;
|
||||
|
||||
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Test '.$name,
|
||||
'env' => $name,
|
||||
'vars' => [],
|
||||
'events' => [],
|
||||
'schedule' => '',
|
||||
'timeout' => $timeout,
|
||||
]);
|
||||
|
||||
$functionId = $function['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
|
||||
$tag = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/tags', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'command' => $command,
|
||||
'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
|
||||
]);
|
||||
|
||||
$tagId = $tag['body']['$id'] ?? '';
|
||||
$this->assertEquals(201, $tag['headers']['status-code']);
|
||||
|
||||
$tag = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/tag', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'tag' => $tagId,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $tag['headers']['status-code']);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => 'foobar',
|
||||
]);
|
||||
|
||||
$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([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals($executions['headers']['status-code'], 200);
|
||||
$this->assertEquals($executions['body']['sum'], 1);
|
||||
$this->assertIsArray($executions['body']['executions']);
|
||||
$this->assertCount(1, $executions['body']['executions']);
|
||||
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
||||
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
||||
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['stdout']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Tests\E2E\Services\Webhooks;
|
||||
|
||||
use CURLFile;
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
|
@ -294,4 +295,265 @@ class WebhooksCustomServerTest extends Scope
|
|||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function testCreateFunction():array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Test',
|
||||
'env' => 'php-7.4',
|
||||
'execute' => ['*'],
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
$functionId = $function['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEquals($function['headers']['status-code'], 201);
|
||||
$this->assertNotEmpty($function['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'], 'functions.create');
|
||||
$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']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
return [
|
||||
'functionId' => $functionId,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateFunction
|
||||
*/
|
||||
public function testUpdateFunction($data):array
|
||||
{
|
||||
/**
|
||||
* 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()), [
|
||||
'name' => 'Test',
|
||||
'env' => 'php-7.4',
|
||||
'execute' => ['*'],
|
||||
'vars' => [
|
||||
'key1' => 'value1',
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals($function['headers']['status-code'], 200);
|
||||
$this->assertEquals($function['body']['$id'], $data['functionId']);
|
||||
$this->assertEquals($function['body']['vars'], ['key1' => 'value1']);
|
||||
|
||||
$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'], 'functions.update');
|
||||
$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 testCreateTag($data):array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$tag = $this->client->call(Client::METHOD_POST, '/functions/'.$data['functionId'].'/tags', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'command' => 'php index.php',
|
||||
'code' => new CURLFile(realpath(__DIR__ . '/../../../resources/functions/timeout.tar.gz'), 'application/x-gzip', 'php-fx.tar.gz'),
|
||||
]);
|
||||
|
||||
$tagId = $tag['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEquals($tag['headers']['status-code'], 201);
|
||||
$this->assertNotEmpty($tag['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'], 'functions.tags.create');
|
||||
$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']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
return array_merge($data, ['tagId' => $tagId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTag
|
||||
*/
|
||||
public function testUpdateTag($data):array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/functions/'.$data['functionId'].'/tag', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'tag' => $data['tagId'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertNotEmpty($response['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'], 'functions.tags.update');
|
||||
$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']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testUpdateTag
|
||||
*/
|
||||
public function testExecutions($data):array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$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()), []);
|
||||
|
||||
$this->assertEquals($execution['headers']['status-code'], 201);
|
||||
$this->assertNotEmpty($execution['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'], 'functions.executions.create');
|
||||
$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);)
|
||||
sleep(6);
|
||||
|
||||
$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'], 'functions.executions.update');
|
||||
$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']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testExecutions
|
||||
*/
|
||||
public function testDeleteTag($data):array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$tag = $this->client->call(Client::METHOD_DELETE, '/functions/'.$data['functionId'].'/tags/'.$data['tagId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals($tag['headers']['status-code'], 204);
|
||||
$this->assertEmpty($tag['body']);
|
||||
|
||||
$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'], 'functions.tags.delete');
|
||||
$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']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testDeleteTag
|
||||
*/
|
||||
public function testDeleteFunction($data):array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$function = $this->client->call(Client::METHOD_DELETE, '/functions/'.$data['functionId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $function['headers']['status-code']);
|
||||
$this->assertEmpty($function['body']);
|
||||
|
||||
$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'], 'functions.delete');
|
||||
$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']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
12
tests/resources/functions/package-php-fn.sh
Executable file
12
tests/resources/functions/package-php-fn.sh
Executable file
|
@ -0,0 +1,12 @@
|
|||
|
||||
echo 'PHP Packaging...'
|
||||
|
||||
cp -r $(pwd)/tests/resources/functions/php-fn $(pwd)/tests/resources/functions/packages/php-fn
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/php-fn:/app -w /app composer:2.0 composer install --ignore-platform-reqs
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/php-fn:/app -w /app appwrite/env-php-8.0:1.0.0 tar -zcvf code.tar.gz .
|
||||
|
||||
mv $(pwd)/tests/resources/functions/packages/php-fn/code.tar.gz $(pwd)/tests/resources/functions/php-fn.tar.gz
|
||||
|
||||
rm -r $(pwd)/tests/resources/functions/packages/php-fn
|
BIN
tests/resources/functions/php-fn.tar.gz
Normal file
BIN
tests/resources/functions/php-fn.tar.gz
Normal file
Binary file not shown.
18
tests/resources/functions/php-fn/composer.json
Normal file
18
tests/resources/functions/php-fn/composer.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "appwrite/cloud-function-demo",
|
||||
"description": "Demo cloud function script",
|
||||
"type": "library",
|
||||
"license": "BSD-3-Clause",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Team Appwrite",
|
||||
"email": "team@appwrite.io"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.4.0",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"appwrite/appwrite": "1.1.*"
|
||||
}
|
||||
}
|
64
tests/resources/functions/php-fn/composer.lock
generated
Normal file
64
tests/resources/functions/php-fn/composer.lock
generated
Normal file
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "afdff6a172e6c44aee11f1562175f81a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "appwrite/appwrite",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-for-php.git",
|
||||
"reference": "98b327d3fd18a72f4582019916afd735a0e9e0e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/98b327d3fd18a72f4582019916afd735a0e9e0e7",
|
||||
"reference": "98b327d3fd18a72f4582019916afd735a0e9e0e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"php": ">=7.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "3.7.35"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Appwrite\\": "src/Appwrite"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"description": "Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks",
|
||||
"support": {
|
||||
"email": "team@localhost.test",
|
||||
"issues": "https://github.com/appwrite/sdk-for-php/issues",
|
||||
"source": "https://github.com/appwrite/sdk-for-php/tree/1.1.2",
|
||||
"url": "https://appwrite.io/support"
|
||||
},
|
||||
"time": "2020-08-15T18:24:32+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=7.4.0",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.0.0"
|
||||
}
|
31
tests/resources/functions/php-fn/index.php
Normal file
31
tests/resources/functions/php-fn/index.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
include './vendor/autoload.php';
|
||||
|
||||
use Appwrite\Client;
|
||||
use Appwrite\Services\Storage;
|
||||
|
||||
// $client = new Client();
|
||||
|
||||
// $client
|
||||
// ->setEndpoint($_ENV['APPWRITE_ENDPOINT']) // Your API Endpoint
|
||||
// ->setProject($_ENV['APPWRITE_PROJECT']) // Your project ID
|
||||
// ->setKey($_ENV['APPWRITE_SECRET']) // Your secret API key
|
||||
// ;
|
||||
|
||||
// $storage = new Storage($client);
|
||||
|
||||
// $result = $storage->getFile($_ENV['APPWRITE_FILEID']);
|
||||
|
||||
echo $_ENV['APPWRITE_FUNCTION_ID']."\n";
|
||||
echo $_ENV['APPWRITE_FUNCTION_NAME']."\n";
|
||||
echo $_ENV['APPWRITE_FUNCTION_TAG']."\n";
|
||||
echo $_ENV['APPWRITE_FUNCTION_TRIGGER']."\n";
|
||||
echo $_ENV['APPWRITE_FUNCTION_ENV_NAME']."\n";
|
||||
echo $_ENV['APPWRITE_FUNCTION_ENV_VERSION']."\n";
|
||||
// echo $result['$id'];
|
||||
echo $_ENV['APPWRITE_FUNCTION_EVENT']."\n";
|
||||
echo $_ENV['APPWRITE_FUNCTION_EVENT_PAYLOAD']."\n";
|
||||
echo 'data:'.$_ENV['APPWRITE_FUNCTION_DATA']."\n";
|
||||
echo 'userId:'.$_ENV['APPWRITE_FUNCTION_USER_ID']."\n";
|
||||
echo 'jwt:'.$_ENV['APPWRITE_FUNCTION_JWT']."\n";
|
Loading…
Reference in a new issue