mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 17:08:45 +00:00
Merge pull request #967 from appwrite/feat-962-pass-data-to-function-execution
Pass custom function $data to execution
This commit is contained in:
commit
c421741386
15 changed files with 379 additions and 37 deletions
|
|
@ -22,6 +22,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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -440,7 +442,7 @@ App::post('/v1/functions/:functionId/tags')
|
|||
->label('sdk.response.model', Response::MODEL_TAG)
|
||||
->param('functionId', '', new UID(), 'Function unique ID.')
|
||||
->param('command', '', new Text('1028'), 'Code execution command.')
|
||||
->param('code', null, new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', false)
|
||||
->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', false)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('projectDB')
|
||||
|
|
@ -679,12 +681,13 @@ 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')
|
||||
->inject('user')
|
||||
->action(function ($functionId, /*$async,*/ $response, $project, $projectDB, $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 */
|
||||
|
|
@ -739,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,7 +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));
|
||||
|
|
@ -196,7 +198,7 @@ class FunctionsV1
|
|||
|
||||
Console::success('Triggered function: '.$event);
|
||||
|
||||
$this->execute('event', $projectId, '', $database, $function, $event, $payload, $userId);
|
||||
$this->execute('event', $projectId, '', $database, $function, $event, $payload, $data, $userId, $jwt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -252,8 +254,7 @@ class FunctionsV1
|
|||
'scheduleOriginal' => $function->getAttribute('schedule', ''),
|
||||
]); // Async task rescheduale
|
||||
|
||||
|
||||
$this->execute($trigger, $projectId, $executionId, $database, $function, $userId);
|
||||
$this->execute($trigger, $projectId, $executionId, $database, $function, /*$event*/'', /*$payload*/'', $data, $userId, $jwt);
|
||||
break;
|
||||
|
||||
case 'http':
|
||||
|
|
@ -265,7 +266,7 @@ class FunctionsV1
|
|||
throw new Exception('Function not found ('.$functionId.')');
|
||||
}
|
||||
|
||||
$this->execute($trigger, $projectId, $executionId, $database, $function, $userId);
|
||||
$this->execute($trigger, $projectId, $executionId, $database, $function, /*$event*/'', /*$payload*/'', $data, $userId, $jwt);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -284,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 = '', string $userId = ''): 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;
|
||||
|
||||
|
|
@ -342,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) {
|
||||
|
|
|
|||
18
phpunit.xml
18
phpunit.xml
|
|
@ -10,7 +10,23 @@
|
|||
>
|
||||
<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',
|
||||
|
|
|
|||
|
|
@ -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', [
|
||||
|
|
@ -124,4 +124,81 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
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 [];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -628,7 +628,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
], $this->getHeaders()), [
|
||||
'tag' => $tagId,
|
||||
]);
|
||||
|
||||
|
||||
$this->assertEquals(200, $tag['headers']['status-code']);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
|
||||
|
|
@ -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']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
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