mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge branch '0.7.x' into feat-na-maintenance-task
This commit is contained in:
@@ -27,4 +27,7 @@ _APP_SMTP_PASSWORD=
|
||||
_APP_STORAGE_LIMIT=10000000
|
||||
_APP_FUNCTIONS_TIMEOUT=900
|
||||
_APP_FUNCTIONS_CONTAINERS=10
|
||||
_APP_MAINTENANCE_INTERVAL=86400
|
||||
_APP_FUNCTIONS_CPUS=1
|
||||
_APP_FUNCTIONS_MEMORY=128
|
||||
_APP_FUNCTIONS_MEMORY_SWAP=128
|
||||
_APP_MAINTENANCE_INTERVAL=86400
|
||||
|
||||
+3
-3
@@ -37,6 +37,6 @@ install:
|
||||
script:
|
||||
- docker ps
|
||||
- docker-compose logs appwrite
|
||||
- docker exec appwrite doctor
|
||||
- docker exec appwrite vars
|
||||
- docker exec appwrite test
|
||||
- docker-compose exec appwrite doctor
|
||||
- docker-compose exec appwrite vars
|
||||
- docker-compose exec appwrite test
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
- Added pagination for projects list on the console home page.
|
||||
- Updated storage calculation to match IEC standards
|
||||
- Now using Alpine as base Docker image
|
||||
- Upgraded device detctor to version 3.12.6
|
||||
- Upgraded MariaDB to version 10.5.5
|
||||
- Switch standard ports to 95xx prefix ([#780](https://github.com/appwrite/appwrite/pull/780))
|
||||
- User & Team name max length is now 128 chars and not 100 for better API consistency
|
||||
- Collection name max length is now 128 chars and not 256 for better API consistency
|
||||
- Project name max length is now 128 chars and not 100 for better API consistency
|
||||
@@ -37,6 +40,7 @@
|
||||
- API Key name max length is now 128 chars and not 256 for better API consistency
|
||||
- Task name max length is now 128 chars and not 256 for better API consistency
|
||||
- Platform name max length is now 128 chars and not 256 for better API consistency
|
||||
- Webhooks payloads are now exactly the same as any of the API response objects
|
||||
- Added new locale: Marathi -mr (@spielers)
|
||||
- New and consistent response format for all API object + new response examples in the docs
|
||||
- Removed user roles attribute from user object (can be fetched from /v1/teams/memberships) **
|
||||
@@ -58,6 +62,7 @@
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Fixed a bug that caused blocked users to be able to create sessions ([#777](https://github.com/appwrite/appwrite/pull/781))
|
||||
- Fixed an issue where Special characters in _APP_OPENSSL_KEY_V1_ env caused an error ([#732](https://github.com/appwrite/appwrite/issues/732))
|
||||
- Fixed an issue where Account webhook doesn't trigger through the console ([#493](https://github.com/appwrite/appwrite/issues/493))
|
||||
- Fixed case sensitive country flag code ([#526](https://github.com/appwrite/appwrite/issues/526))
|
||||
|
||||
+12
-1
@@ -145,6 +145,10 @@ Each container in Appwrite is a microservice on its own. Each service is an inde
|
||||
|
||||
Currently, all of the Appwrite microservices are intended to communicate using the TCP protocol over a private network. You should be aware to not expose any of the services to the public-facing network, besides the public port 80 and 443, who, by default, are used to expose the Appwrite HTTP API.
|
||||
|
||||
## Ports
|
||||
|
||||
Appwrite dev version uses ports 80 and 443 as an entry point to the Appwrite API and console. We also expose multiple ports in the range of 9500-9504 for debugging some of the Appwrite containers on dev mode. If you have any conflicts with the ports running on your system, you can easily replace them by editing Appwrite's docker-compose.yml file and executing `docker-compose up -d` command.
|
||||
|
||||
## Technology Stack
|
||||
|
||||
To start helping us to improve the Appwrite server by submitting code, prior knowledge of Appwrite's technology stack can help you with getting started.
|
||||
@@ -224,11 +228,18 @@ bash ./build.sh X.X.X
|
||||
|
||||
Before running the command, make sure you have proper write permissions to the Appwrite docker hub team.
|
||||
|
||||
**Build for multicore**
|
||||
**Build for Multicore**
|
||||
|
||||
```bash
|
||||
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x -t appwrite/appwrite:dev --push .
|
||||
```
|
||||
**Build Functions Envs**
|
||||
|
||||
Build envs for all supported cloud functions (multicore builds)
|
||||
|
||||
```bash
|
||||
bash ./docker/environments/build.sh
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
|
||||
@@ -92,6 +92,9 @@ ENV _APP_SERVER=swoole \
|
||||
_APP_SMTP_PORT=25 \
|
||||
_APP_FUNCTIONS_TIMEOUT=900 \
|
||||
_APP_FUNCTIONS_CONTAINERS=10 \
|
||||
_APP_FUNCTIONS_CPUS=1 \
|
||||
_APP_FUNCTIONS_MEMORY=128 \
|
||||
_APP_FUNCTIONS_MEMORY_SWAP=128 \
|
||||
_APP_SETUP=self-hosted \
|
||||
_APP_VERSION=$VERSION \
|
||||
# 1 Day = 86400 s
|
||||
|
||||
@@ -5,35 +5,49 @@ return [
|
||||
'name' => 'Node.js',
|
||||
'version' => '14.5',
|
||||
'base' => 'node:14.5-alpine',
|
||||
'image' => 'appwrite/env-node:14.5',
|
||||
'image' => 'appwrite/env-node-14.5:1.0.0',
|
||||
'logo' => 'node.png',
|
||||
],
|
||||
'php-7.4' => [
|
||||
'name' => 'PHP',
|
||||
'version' => '7.4',
|
||||
'base' => 'php:7.4-cli-alpine',
|
||||
'image' => 'appwrite/env-php:7.4',
|
||||
'image' => 'appwrite/env-php-7.4:1.0.0',
|
||||
'logo' => 'php.png',
|
||||
],
|
||||
'php-8.0' => [
|
||||
'name' => 'PHP',
|
||||
'version' => '8.0',
|
||||
'base' => 'php:8.0-cli-alpine',
|
||||
'image' => 'appwrite/env-php-8.0:1.0.0',
|
||||
'logo' => 'php.png',
|
||||
],
|
||||
'ruby-2.7' => [
|
||||
'name' => 'Ruby',
|
||||
'version' => '2.7',
|
||||
'base' => 'ruby:2.7-alpine',
|
||||
'image' => 'appwrite/env-ruby:2.7',
|
||||
'image' => 'appwrite/env-ruby-2.7:1.0.2',
|
||||
'logo' => 'ruby.png',
|
||||
],
|
||||
'python-3.8' => [
|
||||
'name' => 'Python',
|
||||
'version' => '3.8',
|
||||
'base' => 'python:3.8-alpine',
|
||||
'image' => 'appwrite/env-python:3.8',
|
||||
'image' => 'appwrite/env-python-3.8:1.0.0',
|
||||
'logo' => 'python.png',
|
||||
],
|
||||
'deno-1.2' => [
|
||||
'name' => 'Deno',
|
||||
'version' => '1.2',
|
||||
'base' => 'hayd/deno:alpine-1.2.0',
|
||||
'image' => 'appwrite/env-deno:1.2',
|
||||
'image' => 'appwrite/env-deno-1.2:1.0.0',
|
||||
'logo' => 'deno.png',
|
||||
],
|
||||
'deno-1.5' => [
|
||||
'name' => 'Deno',
|
||||
'version' => '1.5',
|
||||
'base' => 'hayd/deno:alpine-1.5.0',
|
||||
'image' => 'appwrite/env-deno-1.5:1.0.0',
|
||||
'logo' => 'deno.png',
|
||||
],
|
||||
// 'dart-2.8' => [
|
||||
|
||||
@@ -151,6 +151,24 @@ return [
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_CPUS',
|
||||
'default' => '1',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_MEMORY',
|
||||
'default' => '128',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_MEMORY_SWAP',
|
||||
'default' => '128',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_INTERVAL',
|
||||
'default' => '86400',
|
||||
|
||||
@@ -179,6 +179,10 @@ App::post('/v1/account/sessions')
|
||||
throw new Exception('Invalid credentials', 401); // Wrong password or username
|
||||
}
|
||||
|
||||
if (Auth::USER_STATUS_BLOCKED == $profile->getAttribute('status')) { // Account is blocked
|
||||
throw new Exception('Invalid credentials. User is blocked', 401); // User is in status blocked
|
||||
}
|
||||
|
||||
$dd = new DeviceDetector($request->getUserAgent('UNKNOWN'));
|
||||
|
||||
$dd->parse();
|
||||
@@ -524,6 +528,10 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
}
|
||||
}
|
||||
|
||||
if (Auth::USER_STATUS_BLOCKED == $user->getAttribute('status')) { // Account is blocked
|
||||
throw new Exception('Invalid credentials. User is blocked', 401); // User is in status blocked
|
||||
}
|
||||
|
||||
// Create session token, verify user account and update OAuth2 ID and Access Token
|
||||
|
||||
$dd = new DeviceDetector($request->getUserAgent('UNKNOWN'));
|
||||
@@ -1263,6 +1271,10 @@ App::post('/v1/account/recovery')
|
||||
throw new Exception('User not found', 404); // TODO maybe hide this
|
||||
}
|
||||
|
||||
if (Auth::USER_STATUS_BLOCKED == $profile->getAttribute('status')) { // Account is blocked
|
||||
throw new Exception('Invalid credentials. User is blocked', 401); // User is in status blocked
|
||||
}
|
||||
|
||||
$secret = Auth::tokenGenerator();
|
||||
$recovery = new Document([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
|
||||
|
||||
@@ -667,7 +667,6 @@ App::post('/v1/functions/:functionId/executions')
|
||||
throw new Exception('Failed saving execution to DB', 500);
|
||||
}
|
||||
|
||||
// Issue a TLS certificate when domain is verified
|
||||
Resque::enqueue('v1-functions', 'FunctionsV1', [
|
||||
'projectId' => $project->getId(),
|
||||
'functionId' => $function->getId(),
|
||||
|
||||
@@ -202,6 +202,7 @@ App::get('/v1/projects/:projectId/usage')
|
||||
|
||||
$requests = [];
|
||||
$network = [];
|
||||
$functions = [];
|
||||
|
||||
if ($client) {
|
||||
$start = $period[$range]['start']->format(DateTime::RFC3339);
|
||||
@@ -229,6 +230,17 @@ App::get('/v1/projects/:projectId/usage')
|
||||
'date' => \strtotime($point['time']),
|
||||
];
|
||||
}
|
||||
|
||||
// Functions
|
||||
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_executions_all" WHERE time > \''.$start.'\' AND time < \''.$end.'\' AND "metric_type"=\'counter\' AND "project"=\''.$project->getId().'\' GROUP BY time('.$period[$range]['group'].') FILL(null)');
|
||||
$points = $result->getPoints();
|
||||
|
||||
foreach ($points as $point) {
|
||||
$functions[] = [
|
||||
'value' => (!empty($point['value'])) ? $point['value'] : 0,
|
||||
'date' => \strtotime($point['time']),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Users
|
||||
@@ -286,6 +298,12 @@ App::get('/v1/projects/:projectId/usage')
|
||||
return $item['value'];
|
||||
}, $network)),
|
||||
],
|
||||
'functions' => [
|
||||
'data' => $functions,
|
||||
'total' => \array_sum(\array_map(function ($item) {
|
||||
return $item['value'];
|
||||
}, $functions)),
|
||||
],
|
||||
'collections' => [
|
||||
'data' => $collections,
|
||||
'total' => $collectionsTotal,
|
||||
|
||||
@@ -490,7 +490,6 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
'teamId='.$teamId,
|
||||
],
|
||||
]);
|
||||
|
||||
$users = [];
|
||||
|
||||
foreach ($memberships as $membership) {
|
||||
|
||||
@@ -33,6 +33,8 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
/** @var Appwrite\Event\Event $deletes */
|
||||
/** @var Appwrite\Event\Event $functions */
|
||||
|
||||
/** @var bool $mode */
|
||||
/** @var array $clients */
|
||||
|
||||
@@ -220,11 +222,15 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
|
||||
/*
|
||||
* Background Jobs
|
||||
*/
|
||||
|
||||
$events
|
||||
->setParam('projectId', $project->getId())
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', $route->getLabel('event', ''))
|
||||
->setParam('payload', [])
|
||||
->setParam('functionId', null)
|
||||
->setParam('executionId', null)
|
||||
->setParam('trigger', 'event')
|
||||
;
|
||||
|
||||
$audits
|
||||
@@ -250,6 +256,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
|
||||
$deletes
|
||||
->setParam('projectId', $project->getId())
|
||||
;
|
||||
|
||||
}, ['utopia', 'request', 'response', 'console', 'project', 'user', 'locale', 'events', 'audits', 'usage', 'deletes', 'clients']);
|
||||
|
||||
App::shutdown(function ($utopia, $request, $response, $project, $events, $audits, $usage, $deletes, $mode) {
|
||||
@@ -261,6 +268,7 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
/** @var Appwrite\Event\Event $deletes */
|
||||
/** @var Appwrite\Event\Event $functions */
|
||||
/** @var bool $mode */
|
||||
|
||||
if (!empty($events->getParam('event'))) {
|
||||
@@ -268,12 +276,15 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
||||
$events->setParam('payload', $response->getPayload());
|
||||
}
|
||||
|
||||
$events
|
||||
$webhooks = clone $events;
|
||||
$functions = clone $events;
|
||||
|
||||
$webhooks
|
||||
->setQueue('v1-webhooks')
|
||||
->setClass('WebhooksV1')
|
||||
->trigger();
|
||||
|
||||
$events
|
||||
$functions
|
||||
->setQueue('v1-functions')
|
||||
->setClass('FunctionsV1')
|
||||
->trigger();
|
||||
@@ -299,6 +310,7 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
||||
->trigger()
|
||||
;
|
||||
}
|
||||
|
||||
}, ['utopia', 'request', 'response', 'project', 'events', 'audits', 'usage', 'deletes', 'mode']);
|
||||
|
||||
App::options(function ($request, $response) {
|
||||
@@ -377,7 +389,7 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project) {
|
||||
->addHeader('Pragma', 'no-cache')
|
||||
->setStatusCode($code)
|
||||
;
|
||||
|
||||
|
||||
if ($template) {
|
||||
$comp = new View($template);
|
||||
|
||||
|
||||
+1
-1
@@ -43,4 +43,4 @@ $preloader
|
||||
->paths(realpath(__DIR__ . '/../app/config'))
|
||||
->paths(realpath(__DIR__ . '/../app/controllers'))
|
||||
->paths(realpath(__DIR__ . '/../src'))
|
||||
->load();
|
||||
->load();
|
||||
|
||||
@@ -85,11 +85,11 @@ $graph = $this->getParam('graph', false);
|
||||
<div class="value margin-bottom-small"><span class="sum" data-ls-bind="{{usage.network.total|humanFileSize}}" data-default="0">0</span></div>
|
||||
<div class="metric margin-bottom-small">Bandwidth</div>
|
||||
|
||||
<!-- <div class="margin-top-large value small">
|
||||
<div class="margin-top-large value small">
|
||||
<b class="text-size-small sum small" data-ls-bind="{{usage.functions.total|statsTotal}}" data-default="0"></b>
|
||||
<br />
|
||||
<b>Func. Executions</b>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -81,6 +81,9 @@ services:
|
||||
- _APP_STORAGE_LIMIT
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_CONTAINERS
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
|
||||
appwrite-worker-usage:
|
||||
image: appwrite/appwrite:<?php echo $version."\n"; ?>
|
||||
@@ -220,8 +223,8 @@ services:
|
||||
- mariadb
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /tmp:/tmp:rw
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- /tmp:/tmp:rw
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_REDIS_HOST
|
||||
@@ -233,6 +236,9 @@ services:
|
||||
- _APP_DB_PASS
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_CONTAINERS
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
|
||||
appwrite-worker-mails:
|
||||
image: appwrite/appwrite:<?php echo $version."\n"; ?>
|
||||
|
||||
+294
-107
@@ -4,9 +4,12 @@ ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
use Appwrite\Database\Database;
|
||||
use Appwrite\Database\Document;
|
||||
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
|
||||
use Appwrite\Database\Adapter\Redis as RedisAdapter;
|
||||
use Appwrite\Database\Validator\Authorization;
|
||||
use Appwrite\Event\Event;
|
||||
use Swoole\Runtime;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
@@ -15,19 +18,26 @@ require_once __DIR__.'/../init.php';
|
||||
|
||||
\cli_set_process_title('Functions V1 Worker');
|
||||
|
||||
Runtime::setHookFlags(SWOOLE_HOOK_ALL);
|
||||
|
||||
Console::success(APP_NAME.' functions worker v1 has started');
|
||||
|
||||
$environments = Config::getParam('environments');
|
||||
|
||||
/**
|
||||
* Warmup Docker Images
|
||||
*/
|
||||
$warmupStart = \microtime(true);
|
||||
|
||||
Co\run(function() use ($environments) {
|
||||
foreach($environments as $environment) { // Warmup: make sure images are ready to run fast 🚀
|
||||
Co\run(function() use ($environments) { // Warmup: make sure images are ready to run fast 🚀
|
||||
Swoole\Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
|
||||
|
||||
foreach($environments as $environment) {
|
||||
go(function() use ($environment) {
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
Console::info('Warming up '.$environment['name'].' environment');
|
||||
Console::info('Warming up '.$environment['name'].' environment...');
|
||||
|
||||
Console::execute('docker pull '.$environment['image'], '', $stdout, $stderr);
|
||||
|
||||
@@ -47,6 +57,62 @@ $warmupTime = $warmupEnd - $warmupStart;
|
||||
|
||||
Console::success('Finished warmup in '.$warmupTime.' seconds');
|
||||
|
||||
/**
|
||||
* List function servers
|
||||
*/
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
$exitCode = Console::execute('docker ps --all --format "name={{.Names}}&status={{.Status}}&labels={{.Labels}}" --filter label=appwrite-type=function'
|
||||
, '', $stdout, $stderr, 30);
|
||||
|
||||
$executionStart = \microtime(true);
|
||||
|
||||
$exitCode = Console::execute('docker ps --all --format "name={{.Names}}&status={{.Status}}&labels={{.Labels}}" --filter label=appwrite-type=function'
|
||||
, '', $stdout, $stderr, 30);
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
|
||||
$list = [];
|
||||
$stdout = \explode("\n", $stdout);
|
||||
|
||||
\array_map(function($value) use (&$list) {
|
||||
$container = [];
|
||||
|
||||
\parse_str($value, $container);
|
||||
|
||||
if(isset($container['name'])) {
|
||||
// $labels = [];
|
||||
// $temp = explode(',', $container['labels'] ?? []);
|
||||
|
||||
// foreach($temp as &$label) {
|
||||
// $label = explode('=', $label);
|
||||
// $labels[$label[0] || 0] = $label[1] || '';
|
||||
// }
|
||||
|
||||
$container = [
|
||||
'name' => $container['name'],
|
||||
'online' => (\substr($container['status'], 0, 2) === 'Up'),
|
||||
'status' => $container['status'],
|
||||
'labels' => $container['labels'],
|
||||
];
|
||||
|
||||
\array_map(function($value) use (&$container) {
|
||||
$value = \explode('=', $value);
|
||||
|
||||
if(isset($value[0]) && isset($value[1])) {
|
||||
$container[$value[0]] = $value[1];
|
||||
}
|
||||
}, \explode(',', $container['labels']));
|
||||
|
||||
$list[$container['name']] = $container;
|
||||
}
|
||||
}, $stdout);
|
||||
|
||||
var_dump(json_encode($list));
|
||||
|
||||
Console::info(count($list)." functions listed in " . ($executionEnd - $executionStart) . " seconds with exit code {$exitCode}");
|
||||
|
||||
/*
|
||||
* 1. Get Original Task
|
||||
* 2. Check for updates
|
||||
@@ -69,8 +135,8 @@ Console::success('Finished warmup in '.$warmupTime.' seconds');
|
||||
* + pass one-time api key
|
||||
* 4. Update execution status - DONE
|
||||
* 5. Update execution stdout & stderr - DONE
|
||||
* 6. Trigger audit log
|
||||
* 7. Trigger usage log
|
||||
* 6. Trigger audit log - DONE
|
||||
* 7. Trigger usage log - DONE
|
||||
*/
|
||||
|
||||
//TODO aviod scheduled execution if delay is bigger than X offest
|
||||
@@ -88,46 +154,141 @@ Console::success('Finished warmup in '.$warmupTime.' seconds');
|
||||
/**
|
||||
* Get Usage Stats
|
||||
* -> Network (docker stats --no-stream --format="{{.NetIO}}" appwrite)
|
||||
* -> CPU Time
|
||||
* -> Invoctions (+1)
|
||||
* Report to usage worker
|
||||
* -> CPU Time - DONE
|
||||
* -> Invoctions (+1) - DONE
|
||||
*/
|
||||
|
||||
// Double-check Cleanup
|
||||
|
||||
class FunctionsV1
|
||||
{
|
||||
public $args = [];
|
||||
|
||||
public $allowed = [];
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
}
|
||||
|
||||
public function perform()
|
||||
{
|
||||
global $environments, $register;
|
||||
global $register;
|
||||
|
||||
$projectId = $this->args['projectId'];
|
||||
$functionId = $this->args['functionId'];
|
||||
$functionTag = $this->args['functionTag'];
|
||||
$executionId = $this->args['executionId'];
|
||||
$functionTrigger = $this->args['functionTrigger'];
|
||||
$projectId = $this->args['projectId'] ?? '';
|
||||
$functionId = $this->args['functionId'] ?? '';
|
||||
$executionId = $this->args['executionId'] ?? '';
|
||||
$trigger = $this->args['trigger'] ?? '';
|
||||
$event = $this->args['event'] ?? '';
|
||||
$payload = (!empty($this->args['payload'])) ? json_encode($this->args['payload']) : '';
|
||||
|
||||
$projectDB = new Database();
|
||||
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
|
||||
$projectDB->setNamespace('app_'.$projectId);
|
||||
$projectDB->setMocks(Config::getParam('collections', []));
|
||||
$database = new Database();
|
||||
$database->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
|
||||
$database->setNamespace('app_'.$projectId);
|
||||
$database->setMocks(Config::getParam('collections', []));
|
||||
|
||||
Authorization::disable();
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
Authorization::reset();
|
||||
switch ($trigger) {
|
||||
case 'event':
|
||||
$limit = 30;
|
||||
$sum = 30;
|
||||
$offset = 0;
|
||||
$functions = []; /** @var Document[] $functions */
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
throw new Exception('Function not found', 404);
|
||||
while ($sum >= $limit) {
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$functions = $database->getCollection([
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'orderField' => 'name',
|
||||
'orderType' => 'ASC',
|
||||
'orderCast' => 'string',
|
||||
'filters' => [
|
||||
'$collection='.Database::SYSTEM_COLLECTION_FUNCTIONS,
|
||||
],
|
||||
]);
|
||||
|
||||
Authorization::reset();
|
||||
|
||||
$sum = \count($functions);
|
||||
$offset = $offset + $limit;
|
||||
|
||||
Console::log('Fetched '.$sum.' functions...');
|
||||
|
||||
foreach($functions as $function) {
|
||||
$events = $function->getAttribute('events', []);
|
||||
$tag = $function->getAttribute('tag', []);
|
||||
|
||||
Console::success('Itterating function: '.$function->getAttribute('name'));
|
||||
|
||||
if(!\in_array($event, $events) || empty($tag)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Console::success('Triggered function: '.$event);
|
||||
|
||||
Swoole\Coroutine\run(function () use ($projectId, $database, $function, $event, $payload) {
|
||||
$this->execute('event', $projectId, '', $database, $function, $event, $payload);
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'schedule':
|
||||
/*
|
||||
* 1. Get Original Task
|
||||
* 2. Check for updates
|
||||
* If has updates skip task and don't reschedule
|
||||
* If status not equal to play skip task
|
||||
* 3. Check next run date, update task and add new job at the given date
|
||||
* 4. Execute task (set optional timeout)
|
||||
* 5. Update task response to log
|
||||
* On success reset error count
|
||||
* On failure add error count
|
||||
* If error count bigger than allowed change status to pause
|
||||
*/
|
||||
|
||||
break;
|
||||
|
||||
case 'http':
|
||||
Authorization::disable();
|
||||
$function = $database->getDocument($functionId);
|
||||
Authorization::reset();
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
throw new Exception('Function not found ('.$functionId.')');
|
||||
}
|
||||
|
||||
Swoole\Coroutine\run(function () use ($trigger, $projectId, $executionId, $database, $function) {
|
||||
$this->execute($trigger, $projectId, $executionId, $database, $function);
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute function tag
|
||||
*
|
||||
* @param string $trigger
|
||||
* @param string $projectId
|
||||
* @param string $executionId
|
||||
* @param Database $database
|
||||
* @param Database $function
|
||||
* @param string $event
|
||||
* @param string $payload
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute(string $trigger, string $projectId, string $executionId, Database $database, Document $function, string $event = '', string $payload = ''): void
|
||||
{
|
||||
global $register, $list;
|
||||
|
||||
$environments = Config::getParam('environments');
|
||||
|
||||
Authorization::disable();
|
||||
$tag = $projectDB->getDocument($functionTag);
|
||||
$tag = $database->getDocument($function->getAttribute('tag', ''));
|
||||
Authorization::reset();
|
||||
|
||||
if($tag->getAttribute('functionId') !== $function->getId()) {
|
||||
@@ -136,27 +297,24 @@ class FunctionsV1
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$execution = $projectDB->getDocument($executionId);
|
||||
$execution = (!empty($executionId)) ? $database->getDocument($executionId) : $database->createDocument([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_EXECUTIONS,
|
||||
'$permissions' => [
|
||||
'read' => [],
|
||||
'write' => [],
|
||||
],
|
||||
'dateCreated' => time(),
|
||||
'functionId' => $function->getId(),
|
||||
'trigger' => $trigger, // http / schedule / event
|
||||
'status' => 'processing', // waiting / processing / completed / failed
|
||||
'exitCode' => 0,
|
||||
'stdout' => '',
|
||||
'stderr' => '',
|
||||
'time' => 0,
|
||||
]);
|
||||
|
||||
if (empty($execution->getId()) || Database::SYSTEM_COLLECTION_EXECUTIONS != $execution->getCollection()) {
|
||||
$execution = $projectDB->createDocument([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_EXECUTIONS,
|
||||
'$permissions' => [
|
||||
'read' => [],
|
||||
'write' => [],
|
||||
],
|
||||
'dateCreated' => \time(),
|
||||
'functionId' => $function->getId(),
|
||||
'status' => 'processing', // waiting / processing / completed / failed
|
||||
'exitCode' => 0,
|
||||
'stdout' => '',
|
||||
'stderr' => '',
|
||||
'time' => 0,
|
||||
]);
|
||||
|
||||
if (false === $execution) {
|
||||
throw new Exception('Failed saving execution to DB', 500);
|
||||
}
|
||||
if(false === $execution) {
|
||||
throw new Exception('Failed to create execution');
|
||||
}
|
||||
|
||||
Authorization::reset();
|
||||
@@ -170,27 +328,30 @@ class FunctionsV1
|
||||
}
|
||||
|
||||
$vars = \array_merge($function->getAttribute('vars', []), [
|
||||
'APPWRITE_FUNCTION_ID' => $functionId,
|
||||
'APPWRITE_FUNCTION_ID' => $function->getId(),
|
||||
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
|
||||
'APPWRITE_FUNCTION_TAG' => $functionTag,
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $functionTrigger,
|
||||
'APPWRITE_FUNCTION_TAG' => $tag->getId(),
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $trigger,
|
||||
'APPWRITE_FUNCTION_ENV_NAME' => $environment['name'],
|
||||
'APPWRITE_FUNCTION_ENV_VERSION' => $environment['version'],
|
||||
'APPWRITE_FUNCTION_EVENT' => $event,
|
||||
'APPWRITE_FUNCTION_EVENT_PAYLOAD' => $payload,
|
||||
]);
|
||||
|
||||
\array_walk($vars, function (&$value, $key) {
|
||||
$value = (empty($value)) ? 'null' : $value;
|
||||
$key = $this->filterEnvKey($key);
|
||||
$value = \escapeshellarg((empty($value)) ? 'null' : $value);
|
||||
$value = "\t\t\t--env {$key}={$value} \\";
|
||||
});
|
||||
|
||||
$tagPath = $tag->getAttribute('codePath', '');
|
||||
$tagPath = $tag->getAttribute('path', '');
|
||||
$tagPathTarget = '/tmp/project-'.$projectId.'/'.$tag->getId().'/code.tar.gz';
|
||||
$tagPathTargetDir = \pathinfo($tagPathTarget, PATHINFO_DIRNAME);
|
||||
$container = 'appwrite-function-'.$tag->getId();
|
||||
$command = \escapeshellcmd($tag->getAttribute('command', ''));
|
||||
|
||||
if(!\is_readable($tagPath)) {
|
||||
throw new Exception('Code is not readable: '.$tag->getAttribute('codePath', ''));
|
||||
throw new Exception('Code is not readable: '.$tag->getAttribute('path', ''));
|
||||
}
|
||||
|
||||
if (!\file_exists($tagPathTargetDir)) {
|
||||
@@ -205,47 +366,7 @@ class FunctionsV1
|
||||
}
|
||||
}
|
||||
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
$executionStart = \microtime(true);
|
||||
|
||||
$exitCode = Console::execute('docker ps --all --format "name={{.Names}}&status={{.Status}}&labels={{.Labels}}" --filter label=appwrite-type=function'
|
||||
, '', $stdout, $stderr, 30);
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
|
||||
$list = [];
|
||||
$stdout = \explode("\n", $stdout);
|
||||
|
||||
\array_map(function($value) use (&$list) {
|
||||
$container = [];
|
||||
|
||||
\parse_str($value, $container);
|
||||
|
||||
if(isset($container['name'])) {
|
||||
$container = [
|
||||
'name' => $container['name'],
|
||||
'online' => (\substr($container['status'], 0, 2) === 'Up'),
|
||||
'status' => $container['status'],
|
||||
'labels' => $container['labels'],
|
||||
];
|
||||
|
||||
\array_map(function($value) use (&$container) {
|
||||
$value = \explode('=', $value);
|
||||
|
||||
if(isset($value[0]) && isset($value[1])) {
|
||||
$container[$value[0]] = $value[1];
|
||||
}
|
||||
}, \explode(',', $container['labels']));
|
||||
|
||||
$list[$container['name']] = $container;
|
||||
}
|
||||
}, $stdout);
|
||||
|
||||
Console::info("Functions listed in " . ($executionEnd - $executionStart) . " seconds with exit code {$exitCode}");
|
||||
|
||||
if(isset($list[$container]) && !$list[$container]['online']) {
|
||||
if(isset($list[$container]) && !$list[$container]['online']) { // Remove conatiner if not online
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
@@ -261,17 +382,17 @@ class FunctionsV1
|
||||
$stderr = '';
|
||||
|
||||
$executionStart = \microtime(true);
|
||||
|
||||
$executionTime = \time();
|
||||
|
||||
$exitCode = Console::execute("docker run \
|
||||
-d \
|
||||
--entrypoint=\"\" \
|
||||
--cpus=4 \
|
||||
--memory=128m \
|
||||
--memory-swap=128m \
|
||||
--rm \
|
||||
--cpus=".App::getEnv('_APP_FUNCTIONS_CPUS', '1')." \
|
||||
--memory=".App::getEnv('_APP_FUNCTIONS_MEMORY', '128')."m \
|
||||
--memory-swap=".App::getEnv('_APP_FUNCTIONS_MEMORY_SWAP', '128')."m \
|
||||
--name={$container} \
|
||||
--label appwrite-type=function \
|
||||
--label appwrite-created=".\time()." \
|
||||
--label appwrite-created=".$executionTime." \
|
||||
--volume {$tagPathTargetDir}:/tmp:rw \
|
||||
--workdir /usr/local/src \
|
||||
".\implode("\n", $vars)."
|
||||
@@ -284,7 +405,17 @@ class FunctionsV1
|
||||
if($exitCode !== 0) {
|
||||
throw new Exception('Failed to create function environment: '.$stderr);
|
||||
}
|
||||
|
||||
|
||||
$list[$container] = [
|
||||
'name' => $container,
|
||||
'online' => true,
|
||||
'status' => 'Up',
|
||||
'labels' => [
|
||||
'appwrite-type' => 'function',
|
||||
'appwrite-created' => $executionTime,
|
||||
],
|
||||
];
|
||||
|
||||
Console::info("Function created in " . ($executionEnd - $executionStart) . " seconds with exit code {$exitCode}");
|
||||
}
|
||||
else {
|
||||
@@ -296,22 +427,27 @@ class FunctionsV1
|
||||
|
||||
$executionStart = \microtime(true);
|
||||
|
||||
$exitCode = Console::execute("docker exec {$container} {$command}"
|
||||
$exitCode = Console::execute("docker exec \
|
||||
".\implode("\n", $vars)."
|
||||
{$container} \
|
||||
{$command}"
|
||||
, '', $stdout, $stderr, $function->getAttribute('timeout', (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)));
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
$executionTime = ($executionEnd - $executionStart);
|
||||
$functionStatus = ($exitCode === 0) ? 'completed' : 'failed';
|
||||
|
||||
Console::info("Function executed in " . ($executionEnd - $executionStart) . " seconds with exit code {$exitCode}");
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$execution = $projectDB->updateDocument(array_merge($execution->getArrayCopy(), [
|
||||
$execution = $database->updateDocument(array_merge($execution->getArrayCopy(), [
|
||||
'tagId' => $tag->getId(),
|
||||
'status' => ($exitCode === 0) ? 'completed' : 'failed',
|
||||
'status' => $functionStatus,
|
||||
'exitCode' => $exitCode,
|
||||
'stdout' => mb_substr($stdout, -4000), // log last 4000 chars output
|
||||
'stderr' => mb_substr($stderr, -4000), // log last 4000 chars output
|
||||
'time' => ($executionEnd - $executionStart),
|
||||
'stdout' => \mb_substr($stdout, -4000), // log last 4000 chars output
|
||||
'stderr' => \mb_substr($stderr, -4000), // log last 4000 chars output
|
||||
'time' => $executionTime,
|
||||
]));
|
||||
|
||||
Authorization::reset();
|
||||
@@ -320,6 +456,32 @@ class FunctionsV1
|
||||
throw new Exception('Failed saving execution to DB', 500);
|
||||
}
|
||||
|
||||
$usage = new Event('v1-usage', 'UsageV1');
|
||||
|
||||
$usage
|
||||
->setParam('projectId', $projectId)
|
||||
->setParam('functionId', $function->getId())
|
||||
->setParam('functionExecution', 1)
|
||||
->setParam('functionStatus', $functionStatus)
|
||||
->setParam('functionExecutionTime', $executionTime * 1000) // ms
|
||||
->setParam('networkRequestSize', 0)
|
||||
->setParam('networkResponseSize', 0)
|
||||
;
|
||||
|
||||
$usage->trigger();
|
||||
|
||||
$this->cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup any hanging containers above the allowed max containers.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup(): void
|
||||
{
|
||||
global $list;
|
||||
|
||||
Console::success(count($list).' running containers counted');
|
||||
|
||||
$max = (int) App::getEnv('_APP_FUNCTIONS_CONTAINERS');
|
||||
@@ -332,7 +494,7 @@ class FunctionsV1
|
||||
foreach($list as $env) {
|
||||
$sorted[] = [
|
||||
'name' => $env['name'],
|
||||
'created' => (int)$env['appwrite-created']
|
||||
'created' => (int)($env['appwrite-created'] ?? 0)
|
||||
];
|
||||
}
|
||||
|
||||
@@ -354,6 +516,31 @@ class FunctionsV1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter ENV vars
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function filterEnvKey(string $string): string
|
||||
{
|
||||
if(empty($this->allowed)) {
|
||||
$this->allowed = array_fill_keys(\str_split('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_'), true);
|
||||
}
|
||||
|
||||
$string = \str_split($string);
|
||||
$output = '';
|
||||
|
||||
foreach ($string as $char) {
|
||||
if(\array_key_exists($char, $this->allowed)) {
|
||||
$output .= $char;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
}
|
||||
|
||||
+14
-8
@@ -27,17 +27,19 @@ class UsageV1
|
||||
$statsd = $register->get('statsd', true);
|
||||
|
||||
$projectId = $this->args['projectId'];
|
||||
$httpMethod = $this->args['httpMethod'];
|
||||
$httpRequest = $this->args['httpRequest'];
|
||||
|
||||
|
||||
$storage = $this->args['storage'];
|
||||
|
||||
$networkRequestSize = $this->args['networkRequestSize'];
|
||||
$networkResponseSize = $this->args['networkResponseSize'];
|
||||
|
||||
$storage = $this->args['storage'];
|
||||
$httpMethod = $this->args['httpMethod'];
|
||||
$httpRequest = $this->args['httpRequest'];
|
||||
|
||||
$functionId = $this->args['functionId'];
|
||||
$functionExecution = $this->args['functionExecution'];
|
||||
$functionExecutionTime = $this->args['functionExecutionTime'];
|
||||
$functionId = $this->args['functionId'];
|
||||
$functionStatus = $this->args['functionStatus'];
|
||||
|
||||
$tags = ",project={$projectId},version=".App::getEnv('_APP_VERSION', 'UNKNOWN').'';
|
||||
|
||||
@@ -49,14 +51,18 @@ class UsageV1
|
||||
}
|
||||
|
||||
if($functionExecution >= 1) {
|
||||
$statsd->increment('executions.all'.$tags.',functionId='.$functionId);
|
||||
$statsd->increment('executions.all'.$tags.',functionId='.$functionId.',functionStatus='.$functionStatus);
|
||||
var_dump($tags.',functionId='.$functionId.',functionStatus='.$functionStatus);
|
||||
$statsd->count('executions.time'.$tags.',functionId='.$functionId, $functionExecutionTime);
|
||||
}
|
||||
|
||||
$statsd->count('network.all'.$tags, $networkRequestSize + $networkResponseSize);
|
||||
$statsd->count('network.inbound'.$tags, $networkRequestSize);
|
||||
$statsd->count('network.outbound'.$tags, $networkResponseSize);
|
||||
$statsd->count('storage.all'.$tags, $storage);
|
||||
$statsd->count('network.all'.$tags, $networkRequestSize + $networkResponseSize);
|
||||
|
||||
if($storage >= 1) {
|
||||
$statsd->count('storage.all'.$tags, $storage);
|
||||
}
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
|
||||
Generated
+3
-3
@@ -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": "ec0368f495f4b9126f378e0057679100",
|
||||
"content-hash": "aa1bf812ee6a45af12cdfbbfb7229471",
|
||||
"packages": [
|
||||
{
|
||||
"name": "appwrite/php-clamav",
|
||||
@@ -1315,9 +1315,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/cli/issues",
|
||||
"source": "https://github.com/utopia-php/cli/tree/0.7.2"
|
||||
"source": "https://github.com/utopia-php/cli/tree/0.7.3"
|
||||
},
|
||||
"time": "2020-10-23T13:34:41+00:00"
|
||||
"time": "2020-11-02T07:50:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/config",
|
||||
|
||||
+44
-14
@@ -55,7 +55,6 @@ services:
|
||||
- traefik.http.routers.appwrite-secure.rule=PathPrefix(`/`)
|
||||
- traefik.http.routers.appwrite-secure.tls=true
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- appwrite-cache:/storage/cache:rw
|
||||
- appwrite-config:/storage/config:rw
|
||||
@@ -102,6 +101,9 @@ services:
|
||||
- _APP_STORAGE_LIMIT
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_CONTAINERS
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
|
||||
appwrite-worker-usage:
|
||||
entrypoint: worker-usage
|
||||
@@ -111,6 +113,9 @@ services:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- telegraf
|
||||
@@ -129,6 +134,9 @@ services:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
@@ -150,6 +158,9 @@ services:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
@@ -173,6 +184,9 @@ services:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
@@ -195,12 +209,15 @@ services:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
volumes:
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- appwrite-cache:/storage/cache:rw
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_REDIS_HOST
|
||||
@@ -219,12 +236,14 @@ services:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
volumes:
|
||||
- appwrite-config:/storage/config:rw
|
||||
- appwrite-certificates:/storage/certificates:rw
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
@@ -244,13 +263,15 @@ services:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- /tmp:/tmp:rw
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /tmp:/tmp:rw
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_REDIS_HOST
|
||||
@@ -262,6 +283,9 @@ services:
|
||||
- _APP_DB_PASS
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_CONTAINERS
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
|
||||
appwrite-worker-mails:
|
||||
entrypoint: worker-mails
|
||||
@@ -271,6 +295,9 @@ services:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- maildev
|
||||
@@ -316,6 +343,9 @@ services:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
environment:
|
||||
@@ -332,7 +362,7 @@ services:
|
||||
volumes:
|
||||
- appwrite-mariadb:/var/lib/mysql:rw
|
||||
ports:
|
||||
- "3306:3306"
|
||||
- "9502:3306"
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=password
|
||||
- MYSQL_DATABASE=${_APP_DB_SCHEMA}
|
||||
@@ -392,7 +422,7 @@ services:
|
||||
container_name: appwrite-maildev
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '1080:80'
|
||||
- '9503:80'
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
@@ -401,7 +431,7 @@ services:
|
||||
container_name: appwrite-request-catcher
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '5000:5000'
|
||||
- '9504:5000'
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
|
||||
@@ -2,4 +2,12 @@
|
||||
|
||||
Docker based enviornments for Appwrite Functions. You can use this Docker images to locally tests your functions by executing them on your local desktop or server.
|
||||
|
||||
All the supported enviornments are based on Docker Alpine images.
|
||||
All the supported enviornments are based on Docker Alpine images.
|
||||
|
||||
## Build
|
||||
|
||||
Build envs for all supported cloud functions (multicore builds)
|
||||
|
||||
```bash
|
||||
bash ./docker/environments/build.sh
|
||||
```
|
||||
@@ -0,0 +1,22 @@
|
||||
echo 'Starting build...'
|
||||
|
||||
echo 'Deno 1.2...'
|
||||
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-deno-1.2:1.0.0 ./docker/environments/deno-1.2/ --push
|
||||
|
||||
echo 'Deno 1.5...'
|
||||
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-deno-1.5:1.0.0 ./docker/environments/deno-1.5/ --push
|
||||
|
||||
echo 'Node 14.5...'
|
||||
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le -t appwrite/env-node-14.5:1.0.0 ./docker/environments/node-14.5/ --push
|
||||
|
||||
echo 'PHP 7.4...'
|
||||
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-php-7.4:1.0.0 ./docker/environments/php-7.4/ --push
|
||||
|
||||
echo 'PHP 8.0...'
|
||||
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-php-8.0:1.0.0 ./docker/environments/php-8.0/ --push
|
||||
|
||||
echo 'Python 3.8...'
|
||||
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-python-3.8:1.0.0 ./docker/environments/python-3.8/ --push
|
||||
|
||||
echo 'Ruby 2.7...'
|
||||
docker buildx build --platform linux/amd64,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-ruby-2.7:1.0.2 ./docker/environments/ruby-2.7/ --push
|
||||
@@ -1,7 +0,0 @@
|
||||
echo 'Starting Deno 1.2 build...'
|
||||
|
||||
docker build --tag appwrite/env-deno:1.2 .
|
||||
|
||||
echo 'Pushing Deno 1.2 build to registry...'
|
||||
|
||||
docker push appwrite/env-deno:1.2
|
||||
@@ -0,0 +1,11 @@
|
||||
FROM hayd/deno:alpine-1.5.0
|
||||
|
||||
LABEL maintainer="team@appwrite.io"
|
||||
|
||||
RUN apk add tar
|
||||
|
||||
RUN mkdir /usr/local/src
|
||||
|
||||
WORKDIR /usr/local/src/
|
||||
|
||||
ENV DENO_DIR=/usr/local/src/.appwrite
|
||||
@@ -1,7 +0,0 @@
|
||||
echo 'Starting Node 14.5 build...'
|
||||
|
||||
docker build --tag appwrite/env-node:14.5 .
|
||||
|
||||
echo 'Pushing Node 14.5 build to registry...'
|
||||
|
||||
docker push appwrite/env-node:14.5
|
||||
@@ -1,7 +0,0 @@
|
||||
echo 'Starting PHP 7.4 build...'
|
||||
|
||||
docker build --tag appwrite/env-php:7.4 .
|
||||
|
||||
echo 'Pushing PHP 7.4 build to registry...'
|
||||
|
||||
docker push appwrite/env-php:7.4
|
||||
@@ -0,0 +1,9 @@
|
||||
FROM php:8.0-cli-alpine
|
||||
|
||||
LABEL maintainer="team@appwrite.io"
|
||||
|
||||
RUN apk add tar
|
||||
|
||||
RUN mkdir /usr/local/src
|
||||
|
||||
WORKDIR /usr/local/src/
|
||||
@@ -8,4 +8,4 @@ RUN mkdir /usr/local/src
|
||||
|
||||
WORKDIR /usr/local/src/
|
||||
|
||||
ENV PIP_TARGET=/usr/local/src/.appwrite
|
||||
ENV PYTHONPATH "${PYTHONPATH}:/usr/local/src/.appwrite"
|
||||
@@ -1,7 +0,0 @@
|
||||
echo 'Starting Python 3.8 build...'
|
||||
|
||||
docker build --tag appwrite/env-python:3.8 .
|
||||
|
||||
echo 'Pushing Python 3.8 build to registry...'
|
||||
|
||||
docker push appwrite/env-python:3.8
|
||||
@@ -8,5 +8,5 @@ RUN mkdir /usr/local/src
|
||||
|
||||
WORKDIR /usr/local/src/
|
||||
|
||||
ENV GEM_PATH=/usr/local/src/.appwrite/2.1.0
|
||||
ENV GEM_PATH=/usr/local/src/.appwrite
|
||||
ENV GEM_SPEC_CACHE=/usr/local/src/.appwrite/specs
|
||||
@@ -1,7 +0,0 @@
|
||||
echo 'Starting Ruby 2.7 build...'
|
||||
|
||||
docker build --tag appwrite/env-ruby:2.7 .
|
||||
|
||||
echo 'Pushing Ruby 2.7 build to registry...'
|
||||
|
||||
docker push appwrite/env-ruby:2.7
|
||||
@@ -0,0 +1,15 @@
|
||||
let sdk = new Appwrite();
|
||||
|
||||
sdk
|
||||
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
|
||||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
|
||||
;
|
||||
|
||||
let promise = sdk.functions.getUsage('[FUNCTION_ID]');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
}, function (error) {
|
||||
console.log(error); // Failure
|
||||
});
|
||||
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"36": "360 Phone Browser",
|
||||
"3B": "360 Browser",
|
||||
"AA": "Avant Browser",
|
||||
"AB": "ABrowse",
|
||||
"AG": "ANTGalio",
|
||||
"AM": "Amaya",
|
||||
"AO": "Amigo",
|
||||
"AN": "Android Browser",
|
||||
"AR": "Arora",
|
||||
"AV": "Amiga Voyager",
|
||||
"AW": "Amiga Aweb",
|
||||
"BB": "BlackBerry Browser",
|
||||
"BD": "Baidu Browser",
|
||||
"BS": "Baidu Spark",
|
||||
"BE": "Beonex",
|
||||
"BJ": "Bunjalloo",
|
||||
"BX": "BrowseX",
|
||||
"CA": "Camino",
|
||||
"CC": "Coc Coc",
|
||||
"CD": "Comodo Dragon",
|
||||
"CX": "Charon",
|
||||
"CF": "Chrome Frame",
|
||||
"CH": "Chrome",
|
||||
"CI": "Chrome Mobile iOS",
|
||||
"CK": "Conkeror",
|
||||
"CM": "Chrome Mobile",
|
||||
"CN": "CoolNovo",
|
||||
"CO": "CometBird",
|
||||
"CP": "ChromePlus",
|
||||
"CR": "Chromium",
|
||||
"CS": "Cheshire",
|
||||
"DE": "Deepnet Explorer",
|
||||
"DF": "Dolphin",
|
||||
"DI": "Dillo",
|
||||
"EL": "Elinks",
|
||||
"EP": "Epiphany",
|
||||
"ES": "Espial TV Browser",
|
||||
"FB": "Firebird",
|
||||
"FD": "Fluid",
|
||||
"FE": "Fennec",
|
||||
"FF": "Firefox",
|
||||
"FL": "Flock",
|
||||
"FN": "Fireweb Navigator",
|
||||
"GA": "Galeon",
|
||||
"GE": "Google Earth",
|
||||
"HJ": "HotJava",
|
||||
"IA": "Iceape",
|
||||
"IB": "IBrowse",
|
||||
"IC": "iCab",
|
||||
"ID": "IceDragon",
|
||||
"IW": "Iceweasel",
|
||||
"IE": "Internet Explorer",
|
||||
"IM": "IE Mobile",
|
||||
"IR": "Iron",
|
||||
"JS": "Jasmine",
|
||||
"KI": "Kindle Browser",
|
||||
"KM": "K-meleon",
|
||||
"KO": "Konqueror",
|
||||
"KP": "Kapiko",
|
||||
"KY": "Kylo",
|
||||
"KZ": "Kazehakase",
|
||||
"LB": "Liebao",
|
||||
"LI": "Links",
|
||||
"LS": "Lunascape",
|
||||
"LX": "Lynx",
|
||||
"MB": "MicroB",
|
||||
"MC": "NCSA Mosaic",
|
||||
"ME": "Mercury",
|
||||
"MF": "Mobile Safari",
|
||||
"MI": "Midori",
|
||||
"MU": "MIUI Browser",
|
||||
"MS": "Mobile Silk",
|
||||
"MX": "Maxthon",
|
||||
"NB": "Nokia Browser",
|
||||
"NO": "Nokia OSS Browser",
|
||||
"NV": "Nokia Ovi Browser",
|
||||
"NF": "NetFront",
|
||||
"NL": "NetFront Life",
|
||||
"NP": "NetPositive",
|
||||
"NS": "Netscape",
|
||||
"OB": "Obigo",
|
||||
"OD": "Odyssey Web Browser",
|
||||
"OF": "Off By One",
|
||||
"OE": "ONE Browser",
|
||||
"OI": "Opera Mini",
|
||||
"OM": "Opera Mobile",
|
||||
"OP": "Opera",
|
||||
"ON": "Opera Next",
|
||||
"OR": "Oregano",
|
||||
"OV": "Openwave Mobile Browser",
|
||||
"OW": "OmniWeb",
|
||||
"PL": "Palm Blazer",
|
||||
"PM": "Pale Moon",
|
||||
"PR": "Palm Pre",
|
||||
"PU": "Puffin",
|
||||
"PW": "Palm WebPro",
|
||||
"PX": "Phoenix",
|
||||
"PO": "Polaris",
|
||||
"PS": "Microsoft Edge",
|
||||
"QQ": "QQ Browser",
|
||||
"RK": "Rekonq",
|
||||
"RM": "RockMelt",
|
||||
"SA": "Sailfish Browser",
|
||||
"SC": "SEMC-Browser",
|
||||
"SE": "Sogou Explorer",
|
||||
"SF": "Safari",
|
||||
"SH": "Shiira",
|
||||
"SL": "Sleipnir",
|
||||
"SM": "SeaMonkey",
|
||||
"SN": "Snowshoe",
|
||||
"SR": "Sunrise",
|
||||
"SX": "Swiftfox",
|
||||
"TZ": "Tizen Browser",
|
||||
"UC": "UC Browser",
|
||||
"VI": "Vivaldi",
|
||||
"WE": "WebPositive",
|
||||
"WO": "wOSBrowser",
|
||||
"WT": "WeTab Browser",
|
||||
"YA": "Yandex Browser",
|
||||
"XI": "Xiino"
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"AIX": "AIX",
|
||||
"AND": "Android",
|
||||
"AMG": "AmigaOS",
|
||||
"ATV": "Apple TV",
|
||||
"ARL": "Arch Linux",
|
||||
"BTR": "BackTrack",
|
||||
"SBA": "Bada",
|
||||
"BEO": "BeOS",
|
||||
"BLB": "BlackBerry OS",
|
||||
"QNX": "BlackBerry Tablet OS",
|
||||
"BMP": "Brew",
|
||||
"CES": "CentOS",
|
||||
"COS": "Chrome OS",
|
||||
"CYN": "CyanogenMod",
|
||||
"DEB": "Debian",
|
||||
"DFB": "DragonFly",
|
||||
"FED": "Fedora",
|
||||
"FOS": "Firefox OS",
|
||||
"BSD": "FreeBSD",
|
||||
"GNT": "Gentoo",
|
||||
"GTV": "Google TV",
|
||||
"HPX": "HP-UX",
|
||||
"HAI": "Haiku OS",
|
||||
"IRI": "IRIX",
|
||||
"INF": "Inferno",
|
||||
"KNO": "Knoppix",
|
||||
"KBT": "Kubuntu",
|
||||
"LIN": "GNU\/Linux",
|
||||
"LBT": "Lubuntu",
|
||||
"VLN": "VectorLinux",
|
||||
"MAC": "Mac",
|
||||
"MAE": "Maemo",
|
||||
"MDR": "Mandriva",
|
||||
"SMG": "MeeGo",
|
||||
"MCD": "MocorDroid",
|
||||
"MIN": "Mint",
|
||||
"MLD": "MildWild",
|
||||
"MOR": "MorphOS",
|
||||
"NBS": "NetBSD",
|
||||
"MTK": "MTK \/ Nucleus",
|
||||
"WII": "Nintendo",
|
||||
"NDS": "Nintendo Mobile",
|
||||
"OS2": "OS\/2",
|
||||
"T64": "OSF1",
|
||||
"OBS": "OpenBSD",
|
||||
"PSP": "PlayStation Portable",
|
||||
"PS3": "PlayStation",
|
||||
"RHT": "Red Hat",
|
||||
"ROS": "RISC OS",
|
||||
"RZD": "RazoDroiD",
|
||||
"SAB": "Sabayon",
|
||||
"SSE": "SUSE",
|
||||
"SAF": "Sailfish OS",
|
||||
"SLW": "Slackware",
|
||||
"SOS": "Solaris",
|
||||
"SYL": "Syllable",
|
||||
"SYM": "Symbian",
|
||||
"SYS": "Symbian OS",
|
||||
"S40": "Symbian OS Series 40",
|
||||
"S60": "Symbian OS Series 60",
|
||||
"SY3": "Symbian^3",
|
||||
"TDX": "ThreadX",
|
||||
"TIZ": "Tizen",
|
||||
"UBT": "Ubuntu",
|
||||
"WTV": "WebTV",
|
||||
"WIN": "Windows",
|
||||
"WCE": "Windows CE",
|
||||
"WMO": "Windows Mobile",
|
||||
"WPH": "Windows Phone",
|
||||
"WRT": "Windows RT",
|
||||
"XBX": "Xbox",
|
||||
"XBT": "Xubuntu",
|
||||
"YNS": "YunOs",
|
||||
"IOS": "iOS",
|
||||
"POS": "palmOS",
|
||||
"WOS": "webOS"
|
||||
}
|
||||
Vendored
+40
-19
@@ -205,7 +205,9 @@ return http.post(path,{'content-type':'multipart/form-data',},payload);},getTag:
|
||||
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"');}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},deleteTag:function(functionId,tagId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"');}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);}};let health={get:function(){let path='/health';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getAntiVirus:function(){let path='/health/anti-virus';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCache:function(){let path='/health/cache';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getDB:function(){let path='/health/db';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueCertificates:function(){let path='/health/queue/certificates';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueFunctions:function(){let path='/health/queue/functions';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueLogs:function(){let path='/health/queue/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueTasks:function(){let path='/health/queue/tasks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueUsage:function(){let path='/health/queue/usage';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueWebhooks:function(){let path='/health/queue/webhooks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getStorageLocal:function(){let path='/health/storage/local';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getTime:function(){let path='/health/time';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getLanguages:function(){let path='/locale/languages';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(search='',limit=25,offset=0,orderType='ASC'){let path='/projects';let payload={};if(search){payload['search']=search;}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getUsage:function(functionId,range='last30'){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/usage'.replace(new RegExp('{functionId}','g'),functionId);let payload={};if(range){payload['range']=range;}
|
||||
return http.get(path,{'content-type':'application/json',},payload);}};let health={get:function(){let path='/health';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getAntiVirus:function(){let path='/health/anti-virus';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCache:function(){let path='/health/cache';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getDB:function(){let path='/health/db';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueCertificates:function(){let path='/health/queue/certificates';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueFunctions:function(){let path='/health/queue/functions';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueLogs:function(){let path='/health/queue/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueTasks:function(){let path='/health/queue/tasks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueUsage:function(){let path='/health/queue/usage';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueWebhooks:function(){let path='/health/queue/webhooks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getStorageLocal:function(){let path='/health/storage/local';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getTime:function(){let path='/health/time';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getLanguages:function(){let path='/locale/languages';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(search='',limit=25,offset=0,orderType='ASC'){let path='/projects';let payload={};if(search){payload['search']=search;}
|
||||
if(limit){payload['limit']=limit;}
|
||||
if(offset){payload['offset']=offset;}
|
||||
if(orderType){payload['orderType']=orderType;}
|
||||
@@ -1959,7 +1961,8 @@ if(service.instance){return service.instance;}
|
||||
let instance=(typeof service.object==='function')?this.resolve(service.object):service.object;let skip=false;if(service.watch&&name!=='window'&&name!=='document'&&name!=='element'&&typeof instance==='object'&&instance!==null){let handler={name:service.name,watch:function(){},get:function(target,key){if(key==="__name"){return this.name;}
|
||||
if(key==="__watch"){return this.watch;}
|
||||
if(key==="__proxy"){return true;}
|
||||
if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)}else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;}
|
||||
if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)}
|
||||
else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;}
|
||||
if(key==="__watch"){return this.watch=value;}
|
||||
target[key]=value;let path=receiver.__name+'.'+key;document.dispatchEvent(new CustomEvent(path+'.changed'));if(skip){return true;}
|
||||
skip=true;container.set('$prop',key,true);container.set('$value',value,true);container.resolve(this.watch);container.set('$key',null,true);container.set('$value',null,true);skip=false;return true;},};instance=new Proxy(instance,handler);}
|
||||
@@ -1976,7 +1979,8 @@ object[shift].unshift(value);break;case'splice':if(!Array.isArray(object[shift])
|
||||
object[shift].splice(value,1);break;default:object[shift]=value;}
|
||||
return true;}
|
||||
if(!object){return null;}
|
||||
if(!shift){result=object;}else{return object[shift];}
|
||||
if(!shift){result=object;}
|
||||
else{return object[shift];}
|
||||
return result;};let bind=function(element,path,callback){let event=container.scope(path)+'.changed';let service=event.split('.').slice(0,1).pop();let debug=element.getAttribute('data-debug')||false;listeners[service]=listeners[service]||{};listeners[service][event]=true;let printer=(function(x){return function(){if(!document.body.contains(element)){element=null;document.removeEventListener(event,printer,false);return false;}
|
||||
let oldNamespaces=namespaces;namespaces=x;callback();namespaces=oldNamespaces;}}(Object.assign({},namespaces)));document.addEventListener(event,printer);};let addNamespace=function(key,scope){namespaces[key]=scope;return this;}
|
||||
let removeNamespace=function(key){delete namespaces[key];return this;}
|
||||
@@ -1987,9 +1991,10 @@ if(typeof url!=='string'){throw new Error('var url must be of type string');}
|
||||
if(typeof headers!=='object'){throw new Error('var headers must be of type object');}
|
||||
if(typeof url!=='string'){throw new Error('var url must be of type string');}
|
||||
for(i=0;i<globalParams.length;i++){url=addParam(url,globalParams[i].key,globalParams[i].value);}
|
||||
return new Promise(function(resolve,reject){let xmlhttp=new XMLHttpRequest();xmlhttp.open(method,url,true);xmlhttp.setRequestHeader('Ajax','1');for(i=0;i<globalHeaders.length;i++){xmlhttp.setRequestHeader(globalHeaders[i].key,globalHeaders[i].value);}
|
||||
return new Promise(function(resolve,reject){let xmlhttp=new XMLHttpRequest();xmlhttp.open(method,url,true);for(i=0;i<globalHeaders.length;i++){xmlhttp.setRequestHeader(globalHeaders[i].key,globalHeaders[i].value);}
|
||||
for(let key in headers){if(headers.hasOwnProperty(key)){xmlhttp.setRequestHeader(key,headers[key]);}}
|
||||
xmlhttp.onload=function(){if(4===xmlhttp.readyState&&200===xmlhttp.status){resolve(xmlhttp.response);}else{document.dispatchEvent(new CustomEvent('http-'+method.toLowerCase()+'-'+xmlhttp.status));reject(new Error(xmlhttp.statusText));}};if(progress){xmlhttp.addEventListener('progress',progress);xmlhttp.upload.addEventListener('progress',progress,false);}
|
||||
xmlhttp.onload=function(){if(4===xmlhttp.readyState&&200===xmlhttp.status){resolve(xmlhttp.response);}
|
||||
else{document.dispatchEvent(new CustomEvent('http-'+method.toLowerCase()+'-'+xmlhttp.status));reject(new Error(xmlhttp.statusText));}};if(progress){xmlhttp.addEventListener('progress',progress);xmlhttp.upload.addEventListener('progress',progress,false);}
|
||||
xmlhttp.onerror=function(){reject(new Error("Network Error"));};xmlhttp.send(payload);})};return{'get':function(url){return request('GET',url,{},'')},'post':function(url,headers,payload){return request('POST',url,headers,payload)},'put':function(url,headers,payload){return request('PUT',url,headers,payload)},'patch':function(url,headers,payload){return request('PATCH',url,headers,payload)},'delete':function(url){return request('DELETE',url,{},'')},'addGlobalParam':function(key,value){globalParams.push({key:key,value:value});},'addGlobalHeader':function(key,value){globalHeaders.push({key:key,value:value});}}},true,false);window.ls.container.set('cookie',function(document){function get(name){let value="; "+document.cookie,parts=value.split("; "+name+"=");if(parts.length===2){return parts.pop().split(";").shift();}
|
||||
return null;}
|
||||
function set(name,value,days){let date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));let expires=(0<days)?'expires='+date.toUTCString():'expires=0';document.cookie=name+"="+value+";"+expires+";path=/";return this;}
|
||||
@@ -2012,22 +2017,30 @@ object[prop]=defaults[prop];}
|
||||
if(!object.selector){throw new Error('View component is missing a selector attribute');}
|
||||
stock[object.selector]=object;return this;},render:function(element,callback){parse(element,false,callback);element.dispatchEvent(new window.Event('rendered',{bubbles:false}));}}},true,false);window.ls.container.set('router',function(window){let getJsonFromUrl=function(URL){let query;if(URL){let pos=location.search.indexOf('?');if(pos===-1)return[];query=location.search.substr(pos+1);}else{query=location.search.substr(1);}
|
||||
let result={};query.split('&').forEach(function(part){if(!part){return;}
|
||||
part=part.split('+').join(' ');let eq=part.indexOf('=');let key=eq>-1?part.substr(0,eq):part;let val=eq>-1?decodeURIComponent(part.substr(eq+1)):'';let from=key.indexOf('[');if(from===-1){result[decodeURIComponent(key)]=val;}else{let to=key.indexOf(']');let index=decodeURIComponent(key.substring(from+1,to));key=decodeURIComponent(key.substring(0,from));if(!result[key]){result[key]=[];}
|
||||
if(!index){result[key].push(val);}else{result[key][index]=val;}}});return result;};let states=[];let params=getJsonFromUrl(window.location.search);let hash=window.location.hash;let current=null;let previous=null;let getPrevious=()=>previous;let getCurrent=()=>current;let setPrevious=(value)=>{previous=value;return this;};let setCurrent=(value)=>{current=value;return this;};let setParam=function(key,value){params[key]=value;return this;};let getParam=function(key,def){if(key in params){return params[key];}
|
||||
part=part.split('+').join(' ');let eq=part.indexOf('=');let key=eq>-1?part.substr(0,eq):part;let val=eq>-1?decodeURIComponent(part.substr(eq+1)):'';let from=key.indexOf('[');if(from===-1){result[decodeURIComponent(key)]=val;}
|
||||
else{let to=key.indexOf(']');let index=decodeURIComponent(key.substring(from+1,to));key=decodeURIComponent(key.substring(0,from));if(!result[key]){result[key]=[];}
|
||||
if(!index){result[key].push(val);}
|
||||
else{result[key][index]=val;}}});return result;};let states=[];let params=getJsonFromUrl(window.location.search);let hash=window.location.hash;let current=null;let previous=null;let getPrevious=()=>previous;let getCurrent=()=>current;let setPrevious=(value)=>{previous=value;return this;};let setCurrent=(value)=>{current=value;return this;};let setParam=function(key,value){params[key]=value;return this;};let getParam=function(key,def){if(key in params){return params[key];}
|
||||
return def;};let getParams=function(){return params;};let getURL=function(){return window.location.href;};let add=function(path,view){if(typeof path!=='string'){throw new Error('path must be of type string');}
|
||||
if(typeof view!=='object'){throw new Error('view must be of type object');}
|
||||
states[states.length++]={path:path,view:view};return this;};let match=function(location){let url=location.pathname;states.sort(function(a,b){return b.path.length-a.path.length;});states.sort(function(a,b){let n=b.path.split('/').length-a.path.split('/').length;if(n!==0){return n;}
|
||||
return b.path.length-a.path.length;});for(let i=0;i<states.length;i++){let value=states[i];value.path=(value.path.substring(0,1)!=='/')?location.pathname+value.path:value.path;let match=new RegExp("^"+value.path.replace(/:[^\s/]+/g,'([\\w-]+)')+"$");let found=url.match(match);if(found){previous=current;current=value;return value;}}
|
||||
return null};let change=function(URL,replace){if(!replace){window.history.pushState({},'',URL);}else{window.history.replaceState({},'',URL);}
|
||||
return null};let change=function(URL,replace){if(!replace){window.history.pushState({},'',URL);}
|
||||
else{window.history.replaceState({},'',URL);}
|
||||
window.dispatchEvent(new PopStateEvent('popstate',{}));return this;};let reload=function(){return change(window.location.href);};return{setParam:setParam,getParam:getParam,getParams:getParams,getURL:getURL,add:add,change:change,reload:reload,match:match,getCurrent:getCurrent,setCurrent:setCurrent,getPrevious:getPrevious,setPrevious:setPrevious,params:params,hash:hash,reset:function(){this.params=getJsonFromUrl(window.location.search);this.hash=window.location.hash;}};},true,true);window.ls.container.set('expression',function(container,filter){let paths=[];return{regex:/(\{{.*?\}})/gi,parse:function(string,def,cast=false){def=def||'';paths=[];return string.replace(this.regex,match=>{let reference=match.substring(2,match.length-2).replace('[\'','.').replace('\']','').trim();reference=reference.split('|');let path=container.scope((reference[0]||''));let result=container.path(path);path=container.scope(path);if(!paths.includes(path)){paths.push(path);}
|
||||
if(reference.length>=2){for(let i=1;i<reference.length;i++){result=filter.apply(reference[i],result);}}
|
||||
if(null===result||undefined===result){result=def;}else if(typeof result==='object'){result=JSON.stringify(result,null,4);}else if(((typeof result==='object')||(typeof result==='string'))&&cast){result='\''+result+'\'';}
|
||||
if(null===result||undefined===result){result=def;}
|
||||
else if(typeof result==='object'){result=JSON.stringify(result,null,4);}
|
||||
else if(((typeof result==='object')||(typeof result==='string'))&&cast){result='\''+result+'\'';}
|
||||
return result;}).replace(/\\{/g,"{").replace(/\\}/g,"}");},getPaths:()=>paths,}},true,false);window.ls.container.set('filter',function(container){let filters={};let add=function(name,callback){filters[name]=callback;return this;};let apply=function(name,value){container.set('$value',value,true,false);return container.resolve(filters[name]);};add('uppercase',($value)=>{if(typeof $value!=='string'){return $value;}
|
||||
return $value.toUpperCase();});add('lowercase',($value)=>{if(typeof $value!=='string'){return $value;}
|
||||
return $value.toLowerCase();});return{add:add,apply:apply}},true,false);window.ls.container.get('filter').add('escape',value=>{if(typeof value!=='string'){return value;}
|
||||
return value.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\"/g,'"').replace(/\'/g,''').replace(/\//g,'/');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false).set('document',window.document,true,false).set('element',window.document,true,false);window.ls.run=function(window){try{this.view.render(window.document);}catch(error){let handler=window.ls.container.resolve(this.error);handler(error);}};window.ls.error=()=>{return error=>{console.error('ls-error',error.message,error.stack,error.toString());}};window.ls.router=window.ls.container.get('router');window.ls.view=window.ls.container.get('view');window.ls.filter=window.ls.container.get('filter');window.ls.container.get('view').add({selector:'data-ls-router',repeat:false,controller:function(element,window,document,view,router){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},};let init=function(route){let count=parseInt(element.getAttribute('data-ls-scope-count')||0);element.setAttribute('data-ls-scope-count',count+1);window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
|
||||
return value.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\"/g,'"').replace(/\'/g,''').replace(/\//g,'/');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false).set('document',window.document,true,false).set('element',window.document,true,false);window.ls.run=function(window){try{this.view.render(window.document);}
|
||||
catch(error){let handler=window.ls.container.resolve(this.error);handler(error);}};window.ls.error=()=>{return error=>{console.error('ls-error',error.message,error.stack,error.toString());}};window.ls.router=window.ls.container.get('router');window.ls.view=window.ls.container.get('view');window.ls.filter=window.ls.container.get('filter');window.ls.container.get('view').add({selector:'data-ls-router',controller:function(element,window,document,view,router){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},};let init=function(route){let count=parseInt(element.getAttribute('data-ls-scope-count')||0);element.setAttribute('data-ls-scope-count',count+1);window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
|
||||
router.reset();if(null===route){return;}
|
||||
scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===router.getPrevious()){scope.template='';document.dispatchEvent(new CustomEvent('state-changed'));}else if(count===1){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}else if(null!==router.getPrevious()){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}};let findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}
|
||||
scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===router.getPrevious()){scope.template='';document.dispatchEvent(new CustomEvent('state-changed'));}
|
||||
else if(count===1){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}
|
||||
else if(null!==router.getPrevious()){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}};let findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}
|
||||
while(el=el.parentNode){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}}
|
||||
return null;};element.removeAttribute('data-ls-router');element.setAttribute('data-ls-scope','');element.setAttribute('data-ls-scope-count',1);view.add(scope);document.addEventListener('click',function(event){let target=findParent('a',event.target);if(!target){return false;}
|
||||
if(!target.href){return false;}
|
||||
@@ -2041,32 +2054,40 @@ window.history.pushState({},'Unknown',target.href);}
|
||||
init(route);return true;});window.addEventListener('popstate',function(){init(router.match(window.location));});window.addEventListener('hashchange',function(){init(router.match(window.location));});init(router.match(window.location));}});window.ls.container.get('view').add({selector:'data-ls-attrs',controller:function(element,expression,container){let attrs=element.getAttribute('data-ls-attrs').trim().split(',');let paths=[];let debug=element.getAttribute('data-debug')||false;let check=()=>{container.set('element',element,true,false);if(debug){console.info('debug-ls-attrs attributes:',attrs);}
|
||||
for(let i=0;i<attrs.length;i++){let attr=attrs[i];let key=expression.parse((attr.substring(0,attr.indexOf('='))||attr));paths=paths.concat(expression.getPaths());let value='';if(attr.indexOf('=')>-1){value=expression.parse(attr.substring(attr.indexOf('=')+1))||'';paths=paths.concat(expression.getPaths());}
|
||||
if(!key){return null;}
|
||||
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-bind',controller:function(element,expression,container){let debug=element.getAttribute('data-debug')||false;let echo=function(value,bind=true){if(element.tagName==='INPUT'||element.tagName==='SELECT'||element.tagName==='BUTTON'||element.tagName==='TEXTAREA'){let type=element.getAttribute('type');if('radio'===type){if(value.toString()===element.value){element.setAttribute('checked','checked');}else{element.removeAttribute('checked');}
|
||||
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-bind',controller:function(element,expression,container){let debug=element.getAttribute('data-debug')||false;let echo=function(value,bind=true){if(element.tagName==='INPUT'||element.tagName==='SELECT'||element.tagName==='BUTTON'||element.tagName==='TEXTAREA'){let type=element.getAttribute('type');if('radio'===type){if(value.toString()===element.value){element.setAttribute('checked','checked');}
|
||||
else{element.removeAttribute('checked');}
|
||||
if(bind){element.addEventListener('change',()=>{for(let i=0;i<paths.length;i++){if(element.checked){value=element.value;}
|
||||
container.path(paths[i],value);}});}
|
||||
return;}
|
||||
if('checkbox'===type){if(typeof value==='boolean'||value==='true'||value==='false'){if(value===true||value==='true'){element.setAttribute('checked','checked');element.checked=true;}else{element.removeAttribute('checked');element.checked=false;}}else{try{value=JSON.parse(value);element.checked=(Array.isArray(value)&&(value.indexOf(element.value)>-1));value=element.value;}catch{return null;}}
|
||||
if('checkbox'===type){if(typeof value==='boolean'||value==='true'||value==='false'){if(value===true||value==='true'){element.setAttribute('checked','checked');element.checked=true;}
|
||||
else{element.removeAttribute('checked');element.checked=false;}}
|
||||
else{try{value=JSON.parse(value);element.checked=(Array.isArray(value)&&(value.indexOf(element.value)>-1));value=element.value;}
|
||||
catch{return null;}}
|
||||
if(bind){element.addEventListener('change',()=>{for(let i=0;i<paths.length;i++){let value=container.path(paths[i]);let index=value.indexOf(element.value);if(element.checked&&index<0){value.push(element.value);}
|
||||
if(!element.checked&&index>-1){value.splice(index,1);}
|
||||
container.path(paths[i],value);}});}
|
||||
return;}
|
||||
if(element.value!==value){element.value=value;element.dispatchEvent(new Event('change'));}
|
||||
if(bind){element.addEventListener('input',sync);element.addEventListener('change',sync);}}else{if(element.textContent!=value){element.innerHTML=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
if(bind){element.addEventListener('input',sync);element.addEventListener('change',sync);}}
|
||||
else{if(element.innerHTML!=value){element.innerHTML=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
for(let i=0;i<paths.length;i++){if('{{'+paths[i]+'}}'!==parsedSyntax){if(debug){console.info('debug-ls-bind','sync-skipped-path',paths[i]);console.info('debug-ls-bind','sync-skipped-syntax',syntax);console.info('debug-ls-bind','sync-skipped-syntax-parsed',parsedSyntax);}
|
||||
continue;}
|
||||
if(debug){console.info('debug-ls-bind','sync-loop-path',paths[i]);console.info('debug-ls-bind','sync-loop-syntax',parsedSyntax);}
|
||||
container.path(paths[i],element.value);}}})();let syntax=element.getAttribute('data-ls-bind');let parsedSyntax=container.scope(syntax);let unsync=(!!element.getAttribute('data-unsync'))||false;let result=expression.parse(syntax);let paths=expression.getPaths();echo(result,!unsync);element.addEventListener('looped',function(){echo(expression.parse(parsedSyntax),false);});for(let i=0;i<paths.length;i++){let path=paths[i].split('.');if(debug){console.info('debug-ls-bind','bind-path',path);console.info('debug-ls-bind','bind-syntax',syntax);}
|
||||
while(path.length){container.bind(element,path.join('.'),()=>{echo(expression.parse(parsedSyntax),false);});path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-if',controller:function(element,expression,container,view){let result='';let syntax=element.getAttribute('data-ls-if')||'';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=()=>{if(debug){console.info('debug-ls-if',expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true));}
|
||||
try{result=(eval(expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true)));}catch(error){throw new Error('Failed to evaluate expression "'+syntax+' (resulted with: "'+result+'")": '+error);}
|
||||
try{result=(eval(expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true)));}
|
||||
catch(error){throw new Error('Failed to evaluate expression "'+syntax+' (resulted with: "'+result+'")": '+error);}
|
||||
if(debug){console.info('debug-ls-if result:',result);}
|
||||
paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility='hidden';element.style.display='none';}else{element.style.removeProperty('display');element.style.removeProperty('visibility');}
|
||||
if(prv===true&&element.$lsSkip===false){view.render(element)}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-loop',template:false,repeat:false,nested:false,controller:function(element,view,container,window,expression){let expr=expression.parse(element.getAttribute('data-ls-loop'));let as=element.getAttribute('data-ls-as');let key=element.getAttribute('data-ls-key')||'$index';let limit=parseInt(expression.parse(element.getAttribute('data-limit')||'')||-1);let debug=element.getAttribute('data-debug')||false;let echo=function(){let array=container.path(expr);let counter=0;array=(!array)?[]:array;let watch=!!(array&&array.__proxy);while(element.hasChildNodes()){element.removeChild(element.lastChild);element.lastChild=null;}
|
||||
paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility='hidden';element.style.display='none';}
|
||||
else{element.style.removeProperty('display');element.style.removeProperty('visibility');}
|
||||
if(prv===true&&element.$lsSkip===false){view.render(element)}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-loop',template:false,nested:false,controller:function(element,view,container,window,expression){let expr=expression.parse(element.getAttribute('data-ls-loop'));let as=element.getAttribute('data-ls-as');let key=element.getAttribute('data-ls-key')||'$index';let limit=parseInt(expression.parse(element.getAttribute('data-limit')||'')||-1);let debug=element.getAttribute('data-debug')||false;let echo=function(){let array=container.path(expr);let counter=0;array=(!array)?[]:array;let watch=!!(array&&array.__proxy);while(element.hasChildNodes()){element.removeChild(element.lastChild);element.lastChild=null;}
|
||||
if(array instanceof Array&&typeof array!=='object'){throw new Error('Reference value must be array or object. '+(typeof array)+' given');}
|
||||
let children=[];element.$lsSkip=true;element.style.visibility=(0===array.length)?'hidden':'visible';for(let prop in array){if(counter==limit){break;}
|
||||
let children=[];element.$lsSkip=true;for(let prop in array){if(counter==limit){break;}
|
||||
counter++;if(!array.hasOwnProperty(prop)){continue;}
|
||||
children[prop]=template.cloneNode(true);element.appendChild(children[prop]);(index=>{let context=expr+'.'+index;container.addNamespace(as,context);if(debug){console.info('debug-ls-loop','index',index);console.info('debug-ls-loop','context',context);console.info('debug-ls-loop','context-path',container.path(context).name);console.info('debug-ls-loop','namespaces',container.namespaces);}
|
||||
container.set(as,container.path(context),true,watch);container.set(key,index,true,false);view.render(children[prop]);container.removeNamespace(as);})(prop);}
|
||||
element.dispatchEvent(new Event('looped'));};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr+'.length',echo);let path=(expr+'.length').split('.');while(path.length){container.bind(element,path.join('.'),echo);path.pop();}}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,repeat:false,controller:function(element,view,http,expression,document,container){let template=element.getAttribute('data-ls-template')||'';let type=element.getAttribute('data-type')||'url';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(init=false){let source=expression.parse(template);paths=expression.getPaths();element.innerHTML='';if('script'===type){let inlineTemplate=document.getElementById(source);if(inlineTemplate&&inlineTemplate.innerHTML){element.innerHTML=inlineTemplate.innerHTML;element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}else{if(debug){console.error('Missing template "'+source+'"');}}
|
||||
element.dispatchEvent(new Event('looped'));};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr+'.length',echo);let path=(expr+'.length').split('.');while(path.length){container.bind(element,path.join('.'),echo);path.pop();}}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,controller:function(element,view,http,expression,document,container){let template=element.getAttribute('data-ls-template')||'';let type=element.getAttribute('data-type')||'url';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(init=false){let source=expression.parse(template);paths=expression.getPaths();element.innerHTML='';if('script'===type){let inlineTemplate=document.getElementById(source);if(inlineTemplate&&inlineTemplate.innerHTML){element.innerHTML=inlineTemplate.innerHTML;element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}
|
||||
else{if(debug){console.error('Missing template "'+source+'"');}}
|
||||
if(!init){view.render(element);}
|
||||
return;}
|
||||
http.get(source).then(function(element){return function(data){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}}(element),function(){throw new Error('Failed loading template');});};check(true);for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.error=function(){return function(error){window.console.error(error);if(window.location.pathname!=='/console'){window.location='/console';}};};window.addEventListener("error",function(event){console.error("ERROR-EVENT:",event.error.message,event.error.stack);});document.addEventListener("account.deleteSession",function(){window.location="/auth/signin";});document.addEventListener("account.create",function(){let container=window.ls.container;let form=container.get('serviceForm');let sdk=container.get('console');let promise=sdk.account.createSession(form.email,form.password);container.set("serviceForm",{},true,true);promise.then(function(){window.location='/console';},function(error){window.location='/auth/signup?failure=1';});});(function(window){"use strict";window.ls.container.set('alerts',function(window){return{list:[],ids:0,counter:0,max:5,add:function(message,time){var scope=this;message.id=scope.ids++;message.remove=function(){scope.remove(message.id);};scope.counter++;scope.list.unshift(message);if(scope.counter>scope.max){scope.list.pop();scope.counter--;}
|
||||
|
||||
Vendored
+3
-1
@@ -205,7 +205,9 @@ return http.post(path,{'content-type':'multipart/form-data',},payload);},getTag:
|
||||
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"');}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},deleteTag:function(functionId,tagId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"');}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);}};let health={get:function(){let path='/health';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getAntiVirus:function(){let path='/health/anti-virus';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCache:function(){let path='/health/cache';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getDB:function(){let path='/health/db';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueCertificates:function(){let path='/health/queue/certificates';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueFunctions:function(){let path='/health/queue/functions';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueLogs:function(){let path='/health/queue/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueTasks:function(){let path='/health/queue/tasks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueUsage:function(){let path='/health/queue/usage';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueWebhooks:function(){let path='/health/queue/webhooks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getStorageLocal:function(){let path='/health/storage/local';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getTime:function(){let path='/health/time';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getLanguages:function(){let path='/locale/languages';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(search='',limit=25,offset=0,orderType='ASC'){let path='/projects';let payload={};if(search){payload['search']=search;}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getUsage:function(functionId,range='last30'){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/usage'.replace(new RegExp('{functionId}','g'),functionId);let payload={};if(range){payload['range']=range;}
|
||||
return http.get(path,{'content-type':'application/json',},payload);}};let health={get:function(){let path='/health';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getAntiVirus:function(){let path='/health/anti-virus';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCache:function(){let path='/health/cache';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getDB:function(){let path='/health/db';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueCertificates:function(){let path='/health/queue/certificates';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueFunctions:function(){let path='/health/queue/functions';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueLogs:function(){let path='/health/queue/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueTasks:function(){let path='/health/queue/tasks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueUsage:function(){let path='/health/queue/usage';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueWebhooks:function(){let path='/health/queue/webhooks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getStorageLocal:function(){let path='/health/storage/local';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getTime:function(){let path='/health/time';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getLanguages:function(){let path='/locale/languages';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(search='',limit=25,offset=0,orderType='ASC'){let path='/projects';let payload={};if(search){payload['search']=search;}
|
||||
if(limit){payload['limit']=limit;}
|
||||
if(offset){payload['offset']=offset;}
|
||||
if(orderType){payload['orderType']=orderType;}
|
||||
|
||||
Vendored
+37
-18
@@ -8,7 +8,8 @@ if(service.instance){return service.instance;}
|
||||
let instance=(typeof service.object==='function')?this.resolve(service.object):service.object;let skip=false;if(service.watch&&name!=='window'&&name!=='document'&&name!=='element'&&typeof instance==='object'&&instance!==null){let handler={name:service.name,watch:function(){},get:function(target,key){if(key==="__name"){return this.name;}
|
||||
if(key==="__watch"){return this.watch;}
|
||||
if(key==="__proxy"){return true;}
|
||||
if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)}else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;}
|
||||
if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)}
|
||||
else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;}
|
||||
if(key==="__watch"){return this.watch=value;}
|
||||
target[key]=value;let path=receiver.__name+'.'+key;document.dispatchEvent(new CustomEvent(path+'.changed'));if(skip){return true;}
|
||||
skip=true;container.set('$prop',key,true);container.set('$value',value,true);container.resolve(this.watch);container.set('$key',null,true);container.set('$value',null,true);skip=false;return true;},};instance=new Proxy(instance,handler);}
|
||||
@@ -25,7 +26,8 @@ object[shift].unshift(value);break;case'splice':if(!Array.isArray(object[shift])
|
||||
object[shift].splice(value,1);break;default:object[shift]=value;}
|
||||
return true;}
|
||||
if(!object){return null;}
|
||||
if(!shift){result=object;}else{return object[shift];}
|
||||
if(!shift){result=object;}
|
||||
else{return object[shift];}
|
||||
return result;};let bind=function(element,path,callback){let event=container.scope(path)+'.changed';let service=event.split('.').slice(0,1).pop();let debug=element.getAttribute('data-debug')||false;listeners[service]=listeners[service]||{};listeners[service][event]=true;let printer=(function(x){return function(){if(!document.body.contains(element)){element=null;document.removeEventListener(event,printer,false);return false;}
|
||||
let oldNamespaces=namespaces;namespaces=x;callback();namespaces=oldNamespaces;}}(Object.assign({},namespaces)));document.addEventListener(event,printer);};let addNamespace=function(key,scope){namespaces[key]=scope;return this;}
|
||||
let removeNamespace=function(key){delete namespaces[key];return this;}
|
||||
@@ -36,9 +38,10 @@ if(typeof url!=='string'){throw new Error('var url must be of type string');}
|
||||
if(typeof headers!=='object'){throw new Error('var headers must be of type object');}
|
||||
if(typeof url!=='string'){throw new Error('var url must be of type string');}
|
||||
for(i=0;i<globalParams.length;i++){url=addParam(url,globalParams[i].key,globalParams[i].value);}
|
||||
return new Promise(function(resolve,reject){let xmlhttp=new XMLHttpRequest();xmlhttp.open(method,url,true);xmlhttp.setRequestHeader('Ajax','1');for(i=0;i<globalHeaders.length;i++){xmlhttp.setRequestHeader(globalHeaders[i].key,globalHeaders[i].value);}
|
||||
return new Promise(function(resolve,reject){let xmlhttp=new XMLHttpRequest();xmlhttp.open(method,url,true);for(i=0;i<globalHeaders.length;i++){xmlhttp.setRequestHeader(globalHeaders[i].key,globalHeaders[i].value);}
|
||||
for(let key in headers){if(headers.hasOwnProperty(key)){xmlhttp.setRequestHeader(key,headers[key]);}}
|
||||
xmlhttp.onload=function(){if(4===xmlhttp.readyState&&200===xmlhttp.status){resolve(xmlhttp.response);}else{document.dispatchEvent(new CustomEvent('http-'+method.toLowerCase()+'-'+xmlhttp.status));reject(new Error(xmlhttp.statusText));}};if(progress){xmlhttp.addEventListener('progress',progress);xmlhttp.upload.addEventListener('progress',progress,false);}
|
||||
xmlhttp.onload=function(){if(4===xmlhttp.readyState&&200===xmlhttp.status){resolve(xmlhttp.response);}
|
||||
else{document.dispatchEvent(new CustomEvent('http-'+method.toLowerCase()+'-'+xmlhttp.status));reject(new Error(xmlhttp.statusText));}};if(progress){xmlhttp.addEventListener('progress',progress);xmlhttp.upload.addEventListener('progress',progress,false);}
|
||||
xmlhttp.onerror=function(){reject(new Error("Network Error"));};xmlhttp.send(payload);})};return{'get':function(url){return request('GET',url,{},'')},'post':function(url,headers,payload){return request('POST',url,headers,payload)},'put':function(url,headers,payload){return request('PUT',url,headers,payload)},'patch':function(url,headers,payload){return request('PATCH',url,headers,payload)},'delete':function(url){return request('DELETE',url,{},'')},'addGlobalParam':function(key,value){globalParams.push({key:key,value:value});},'addGlobalHeader':function(key,value){globalHeaders.push({key:key,value:value});}}},true,false);window.ls.container.set('cookie',function(document){function get(name){let value="; "+document.cookie,parts=value.split("; "+name+"=");if(parts.length===2){return parts.pop().split(";").shift();}
|
||||
return null;}
|
||||
function set(name,value,days){let date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));let expires=(0<days)?'expires='+date.toUTCString():'expires=0';document.cookie=name+"="+value+";"+expires+";path=/";return this;}
|
||||
@@ -61,22 +64,30 @@ object[prop]=defaults[prop];}
|
||||
if(!object.selector){throw new Error('View component is missing a selector attribute');}
|
||||
stock[object.selector]=object;return this;},render:function(element,callback){parse(element,false,callback);element.dispatchEvent(new window.Event('rendered',{bubbles:false}));}}},true,false);window.ls.container.set('router',function(window){let getJsonFromUrl=function(URL){let query;if(URL){let pos=location.search.indexOf('?');if(pos===-1)return[];query=location.search.substr(pos+1);}else{query=location.search.substr(1);}
|
||||
let result={};query.split('&').forEach(function(part){if(!part){return;}
|
||||
part=part.split('+').join(' ');let eq=part.indexOf('=');let key=eq>-1?part.substr(0,eq):part;let val=eq>-1?decodeURIComponent(part.substr(eq+1)):'';let from=key.indexOf('[');if(from===-1){result[decodeURIComponent(key)]=val;}else{let to=key.indexOf(']');let index=decodeURIComponent(key.substring(from+1,to));key=decodeURIComponent(key.substring(0,from));if(!result[key]){result[key]=[];}
|
||||
if(!index){result[key].push(val);}else{result[key][index]=val;}}});return result;};let states=[];let params=getJsonFromUrl(window.location.search);let hash=window.location.hash;let current=null;let previous=null;let getPrevious=()=>previous;let getCurrent=()=>current;let setPrevious=(value)=>{previous=value;return this;};let setCurrent=(value)=>{current=value;return this;};let setParam=function(key,value){params[key]=value;return this;};let getParam=function(key,def){if(key in params){return params[key];}
|
||||
part=part.split('+').join(' ');let eq=part.indexOf('=');let key=eq>-1?part.substr(0,eq):part;let val=eq>-1?decodeURIComponent(part.substr(eq+1)):'';let from=key.indexOf('[');if(from===-1){result[decodeURIComponent(key)]=val;}
|
||||
else{let to=key.indexOf(']');let index=decodeURIComponent(key.substring(from+1,to));key=decodeURIComponent(key.substring(0,from));if(!result[key]){result[key]=[];}
|
||||
if(!index){result[key].push(val);}
|
||||
else{result[key][index]=val;}}});return result;};let states=[];let params=getJsonFromUrl(window.location.search);let hash=window.location.hash;let current=null;let previous=null;let getPrevious=()=>previous;let getCurrent=()=>current;let setPrevious=(value)=>{previous=value;return this;};let setCurrent=(value)=>{current=value;return this;};let setParam=function(key,value){params[key]=value;return this;};let getParam=function(key,def){if(key in params){return params[key];}
|
||||
return def;};let getParams=function(){return params;};let getURL=function(){return window.location.href;};let add=function(path,view){if(typeof path!=='string'){throw new Error('path must be of type string');}
|
||||
if(typeof view!=='object'){throw new Error('view must be of type object');}
|
||||
states[states.length++]={path:path,view:view};return this;};let match=function(location){let url=location.pathname;states.sort(function(a,b){return b.path.length-a.path.length;});states.sort(function(a,b){let n=b.path.split('/').length-a.path.split('/').length;if(n!==0){return n;}
|
||||
return b.path.length-a.path.length;});for(let i=0;i<states.length;i++){let value=states[i];value.path=(value.path.substring(0,1)!=='/')?location.pathname+value.path:value.path;let match=new RegExp("^"+value.path.replace(/:[^\s/]+/g,'([\\w-]+)')+"$");let found=url.match(match);if(found){previous=current;current=value;return value;}}
|
||||
return null};let change=function(URL,replace){if(!replace){window.history.pushState({},'',URL);}else{window.history.replaceState({},'',URL);}
|
||||
return null};let change=function(URL,replace){if(!replace){window.history.pushState({},'',URL);}
|
||||
else{window.history.replaceState({},'',URL);}
|
||||
window.dispatchEvent(new PopStateEvent('popstate',{}));return this;};let reload=function(){return change(window.location.href);};return{setParam:setParam,getParam:getParam,getParams:getParams,getURL:getURL,add:add,change:change,reload:reload,match:match,getCurrent:getCurrent,setCurrent:setCurrent,getPrevious:getPrevious,setPrevious:setPrevious,params:params,hash:hash,reset:function(){this.params=getJsonFromUrl(window.location.search);this.hash=window.location.hash;}};},true,true);window.ls.container.set('expression',function(container,filter){let paths=[];return{regex:/(\{{.*?\}})/gi,parse:function(string,def,cast=false){def=def||'';paths=[];return string.replace(this.regex,match=>{let reference=match.substring(2,match.length-2).replace('[\'','.').replace('\']','').trim();reference=reference.split('|');let path=container.scope((reference[0]||''));let result=container.path(path);path=container.scope(path);if(!paths.includes(path)){paths.push(path);}
|
||||
if(reference.length>=2){for(let i=1;i<reference.length;i++){result=filter.apply(reference[i],result);}}
|
||||
if(null===result||undefined===result){result=def;}else if(typeof result==='object'){result=JSON.stringify(result,null,4);}else if(((typeof result==='object')||(typeof result==='string'))&&cast){result='\''+result+'\'';}
|
||||
if(null===result||undefined===result){result=def;}
|
||||
else if(typeof result==='object'){result=JSON.stringify(result,null,4);}
|
||||
else if(((typeof result==='object')||(typeof result==='string'))&&cast){result='\''+result+'\'';}
|
||||
return result;}).replace(/\\{/g,"{").replace(/\\}/g,"}");},getPaths:()=>paths,}},true,false);window.ls.container.set('filter',function(container){let filters={};let add=function(name,callback){filters[name]=callback;return this;};let apply=function(name,value){container.set('$value',value,true,false);return container.resolve(filters[name]);};add('uppercase',($value)=>{if(typeof $value!=='string'){return $value;}
|
||||
return $value.toUpperCase();});add('lowercase',($value)=>{if(typeof $value!=='string'){return $value;}
|
||||
return $value.toLowerCase();});return{add:add,apply:apply}},true,false);window.ls.container.get('filter').add('escape',value=>{if(typeof value!=='string'){return value;}
|
||||
return value.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\"/g,'"').replace(/\'/g,''').replace(/\//g,'/');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false).set('document',window.document,true,false).set('element',window.document,true,false);window.ls.run=function(window){try{this.view.render(window.document);}catch(error){let handler=window.ls.container.resolve(this.error);handler(error);}};window.ls.error=()=>{return error=>{console.error('ls-error',error.message,error.stack,error.toString());}};window.ls.router=window.ls.container.get('router');window.ls.view=window.ls.container.get('view');window.ls.filter=window.ls.container.get('filter');window.ls.container.get('view').add({selector:'data-ls-router',repeat:false,controller:function(element,window,document,view,router){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},};let init=function(route){let count=parseInt(element.getAttribute('data-ls-scope-count')||0);element.setAttribute('data-ls-scope-count',count+1);window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
|
||||
return value.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\"/g,'"').replace(/\'/g,''').replace(/\//g,'/');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false).set('document',window.document,true,false).set('element',window.document,true,false);window.ls.run=function(window){try{this.view.render(window.document);}
|
||||
catch(error){let handler=window.ls.container.resolve(this.error);handler(error);}};window.ls.error=()=>{return error=>{console.error('ls-error',error.message,error.stack,error.toString());}};window.ls.router=window.ls.container.get('router');window.ls.view=window.ls.container.get('view');window.ls.filter=window.ls.container.get('filter');window.ls.container.get('view').add({selector:'data-ls-router',controller:function(element,window,document,view,router){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},};let init=function(route){let count=parseInt(element.getAttribute('data-ls-scope-count')||0);element.setAttribute('data-ls-scope-count',count+1);window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
|
||||
router.reset();if(null===route){return;}
|
||||
scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===router.getPrevious()){scope.template='';document.dispatchEvent(new CustomEvent('state-changed'));}else if(count===1){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}else if(null!==router.getPrevious()){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}};let findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}
|
||||
scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===router.getPrevious()){scope.template='';document.dispatchEvent(new CustomEvent('state-changed'));}
|
||||
else if(count===1){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}
|
||||
else if(null!==router.getPrevious()){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}};let findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}
|
||||
while(el=el.parentNode){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}}
|
||||
return null;};element.removeAttribute('data-ls-router');element.setAttribute('data-ls-scope','');element.setAttribute('data-ls-scope-count',1);view.add(scope);document.addEventListener('click',function(event){let target=findParent('a',event.target);if(!target){return false;}
|
||||
if(!target.href){return false;}
|
||||
@@ -90,32 +101,40 @@ window.history.pushState({},'Unknown',target.href);}
|
||||
init(route);return true;});window.addEventListener('popstate',function(){init(router.match(window.location));});window.addEventListener('hashchange',function(){init(router.match(window.location));});init(router.match(window.location));}});window.ls.container.get('view').add({selector:'data-ls-attrs',controller:function(element,expression,container){let attrs=element.getAttribute('data-ls-attrs').trim().split(',');let paths=[];let debug=element.getAttribute('data-debug')||false;let check=()=>{container.set('element',element,true,false);if(debug){console.info('debug-ls-attrs attributes:',attrs);}
|
||||
for(let i=0;i<attrs.length;i++){let attr=attrs[i];let key=expression.parse((attr.substring(0,attr.indexOf('='))||attr));paths=paths.concat(expression.getPaths());let value='';if(attr.indexOf('=')>-1){value=expression.parse(attr.substring(attr.indexOf('=')+1))||'';paths=paths.concat(expression.getPaths());}
|
||||
if(!key){return null;}
|
||||
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-bind',controller:function(element,expression,container){let debug=element.getAttribute('data-debug')||false;let echo=function(value,bind=true){if(element.tagName==='INPUT'||element.tagName==='SELECT'||element.tagName==='BUTTON'||element.tagName==='TEXTAREA'){let type=element.getAttribute('type');if('radio'===type){if(value.toString()===element.value){element.setAttribute('checked','checked');}else{element.removeAttribute('checked');}
|
||||
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-bind',controller:function(element,expression,container){let debug=element.getAttribute('data-debug')||false;let echo=function(value,bind=true){if(element.tagName==='INPUT'||element.tagName==='SELECT'||element.tagName==='BUTTON'||element.tagName==='TEXTAREA'){let type=element.getAttribute('type');if('radio'===type){if(value.toString()===element.value){element.setAttribute('checked','checked');}
|
||||
else{element.removeAttribute('checked');}
|
||||
if(bind){element.addEventListener('change',()=>{for(let i=0;i<paths.length;i++){if(element.checked){value=element.value;}
|
||||
container.path(paths[i],value);}});}
|
||||
return;}
|
||||
if('checkbox'===type){if(typeof value==='boolean'||value==='true'||value==='false'){if(value===true||value==='true'){element.setAttribute('checked','checked');element.checked=true;}else{element.removeAttribute('checked');element.checked=false;}}else{try{value=JSON.parse(value);element.checked=(Array.isArray(value)&&(value.indexOf(element.value)>-1));value=element.value;}catch{return null;}}
|
||||
if('checkbox'===type){if(typeof value==='boolean'||value==='true'||value==='false'){if(value===true||value==='true'){element.setAttribute('checked','checked');element.checked=true;}
|
||||
else{element.removeAttribute('checked');element.checked=false;}}
|
||||
else{try{value=JSON.parse(value);element.checked=(Array.isArray(value)&&(value.indexOf(element.value)>-1));value=element.value;}
|
||||
catch{return null;}}
|
||||
if(bind){element.addEventListener('change',()=>{for(let i=0;i<paths.length;i++){let value=container.path(paths[i]);let index=value.indexOf(element.value);if(element.checked&&index<0){value.push(element.value);}
|
||||
if(!element.checked&&index>-1){value.splice(index,1);}
|
||||
container.path(paths[i],value);}});}
|
||||
return;}
|
||||
if(element.value!==value){element.value=value;element.dispatchEvent(new Event('change'));}
|
||||
if(bind){element.addEventListener('input',sync);element.addEventListener('change',sync);}}else{if(element.textContent!=value){element.innerHTML=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
if(bind){element.addEventListener('input',sync);element.addEventListener('change',sync);}}
|
||||
else{if(element.innerHTML!=value){element.innerHTML=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
for(let i=0;i<paths.length;i++){if('{{'+paths[i]+'}}'!==parsedSyntax){if(debug){console.info('debug-ls-bind','sync-skipped-path',paths[i]);console.info('debug-ls-bind','sync-skipped-syntax',syntax);console.info('debug-ls-bind','sync-skipped-syntax-parsed',parsedSyntax);}
|
||||
continue;}
|
||||
if(debug){console.info('debug-ls-bind','sync-loop-path',paths[i]);console.info('debug-ls-bind','sync-loop-syntax',parsedSyntax);}
|
||||
container.path(paths[i],element.value);}}})();let syntax=element.getAttribute('data-ls-bind');let parsedSyntax=container.scope(syntax);let unsync=(!!element.getAttribute('data-unsync'))||false;let result=expression.parse(syntax);let paths=expression.getPaths();echo(result,!unsync);element.addEventListener('looped',function(){echo(expression.parse(parsedSyntax),false);});for(let i=0;i<paths.length;i++){let path=paths[i].split('.');if(debug){console.info('debug-ls-bind','bind-path',path);console.info('debug-ls-bind','bind-syntax',syntax);}
|
||||
while(path.length){container.bind(element,path.join('.'),()=>{echo(expression.parse(parsedSyntax),false);});path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-if',controller:function(element,expression,container,view){let result='';let syntax=element.getAttribute('data-ls-if')||'';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=()=>{if(debug){console.info('debug-ls-if',expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true));}
|
||||
try{result=(eval(expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true)));}catch(error){throw new Error('Failed to evaluate expression "'+syntax+' (resulted with: "'+result+'")": '+error);}
|
||||
try{result=(eval(expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true)));}
|
||||
catch(error){throw new Error('Failed to evaluate expression "'+syntax+' (resulted with: "'+result+'")": '+error);}
|
||||
if(debug){console.info('debug-ls-if result:',result);}
|
||||
paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility='hidden';element.style.display='none';}else{element.style.removeProperty('display');element.style.removeProperty('visibility');}
|
||||
if(prv===true&&element.$lsSkip===false){view.render(element)}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-loop',template:false,repeat:false,nested:false,controller:function(element,view,container,window,expression){let expr=expression.parse(element.getAttribute('data-ls-loop'));let as=element.getAttribute('data-ls-as');let key=element.getAttribute('data-ls-key')||'$index';let limit=parseInt(expression.parse(element.getAttribute('data-limit')||'')||-1);let debug=element.getAttribute('data-debug')||false;let echo=function(){let array=container.path(expr);let counter=0;array=(!array)?[]:array;let watch=!!(array&&array.__proxy);while(element.hasChildNodes()){element.removeChild(element.lastChild);element.lastChild=null;}
|
||||
paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility='hidden';element.style.display='none';}
|
||||
else{element.style.removeProperty('display');element.style.removeProperty('visibility');}
|
||||
if(prv===true&&element.$lsSkip===false){view.render(element)}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-loop',template:false,nested:false,controller:function(element,view,container,window,expression){let expr=expression.parse(element.getAttribute('data-ls-loop'));let as=element.getAttribute('data-ls-as');let key=element.getAttribute('data-ls-key')||'$index';let limit=parseInt(expression.parse(element.getAttribute('data-limit')||'')||-1);let debug=element.getAttribute('data-debug')||false;let echo=function(){let array=container.path(expr);let counter=0;array=(!array)?[]:array;let watch=!!(array&&array.__proxy);while(element.hasChildNodes()){element.removeChild(element.lastChild);element.lastChild=null;}
|
||||
if(array instanceof Array&&typeof array!=='object'){throw new Error('Reference value must be array or object. '+(typeof array)+' given');}
|
||||
let children=[];element.$lsSkip=true;element.style.visibility=(0===array.length)?'hidden':'visible';for(let prop in array){if(counter==limit){break;}
|
||||
let children=[];element.$lsSkip=true;for(let prop in array){if(counter==limit){break;}
|
||||
counter++;if(!array.hasOwnProperty(prop)){continue;}
|
||||
children[prop]=template.cloneNode(true);element.appendChild(children[prop]);(index=>{let context=expr+'.'+index;container.addNamespace(as,context);if(debug){console.info('debug-ls-loop','index',index);console.info('debug-ls-loop','context',context);console.info('debug-ls-loop','context-path',container.path(context).name);console.info('debug-ls-loop','namespaces',container.namespaces);}
|
||||
container.set(as,container.path(context),true,watch);container.set(key,index,true,false);view.render(children[prop]);container.removeNamespace(as);})(prop);}
|
||||
element.dispatchEvent(new Event('looped'));};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr+'.length',echo);let path=(expr+'.length').split('.');while(path.length){container.bind(element,path.join('.'),echo);path.pop();}}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,repeat:false,controller:function(element,view,http,expression,document,container){let template=element.getAttribute('data-ls-template')||'';let type=element.getAttribute('data-type')||'url';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(init=false){let source=expression.parse(template);paths=expression.getPaths();element.innerHTML='';if('script'===type){let inlineTemplate=document.getElementById(source);if(inlineTemplate&&inlineTemplate.innerHTML){element.innerHTML=inlineTemplate.innerHTML;element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}else{if(debug){console.error('Missing template "'+source+'"');}}
|
||||
element.dispatchEvent(new Event('looped'));};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr+'.length',echo);let path=(expr+'.length').split('.');while(path.length){container.bind(element,path.join('.'),echo);path.pop();}}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,controller:function(element,view,http,expression,document,container){let template=element.getAttribute('data-ls-template')||'';let type=element.getAttribute('data-type')||'url';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(init=false){let source=expression.parse(template);paths=expression.getPaths();element.innerHTML='';if('script'===type){let inlineTemplate=document.getElementById(source);if(inlineTemplate&&inlineTemplate.innerHTML){element.innerHTML=inlineTemplate.innerHTML;element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}
|
||||
else{if(debug){console.error('Missing template "'+source+'"');}}
|
||||
if(!init){view.render(element);}
|
||||
return;}
|
||||
http.get(source).then(function(element){return function(data){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}}(element),function(){throw new Error('Failed loading template');});};check(true);for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.error=function(){return function(error){window.console.error(error);if(window.location.pathname!=='/console'){window.location='/console';}};};window.addEventListener("error",function(event){console.error("ERROR-EVENT:",event.error.message,event.error.stack);});document.addEventListener("account.deleteSession",function(){window.location="/auth/signin";});document.addEventListener("account.create",function(){let container=window.ls.container;let form=container.get('serviceForm');let sdk=container.get('console');let promise=sdk.account.createSession(form.email,form.password);container.set("serviceForm",{},true,true);promise.then(function(){window.location='/console';},function(error){window.location='/auth/signup?failure=1';});});(function(window){"use strict";window.ls.container.set('alerts',function(window){return{list:[],ids:0,counter:0,max:5,add:function(message,time){var scope=this;message.id=scope.ids++;message.remove=function(){scope.remove(message.id);};scope.counter++;scope.list.unshift(message);if(scope.counter>scope.max){scope.list.pop();scope.counter--;}
|
||||
|
||||
@@ -2238,6 +2238,34 @@
|
||||
.delete(path, {
|
||||
'content-type': 'application/json',
|
||||
}, payload);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get Function Usage
|
||||
*
|
||||
*
|
||||
* @param {string} functionId
|
||||
* @param {string} range
|
||||
* @throws {Error}
|
||||
* @return {Promise}
|
||||
*/
|
||||
getUsage: function(functionId, range = 'last30') {
|
||||
if(functionId === undefined) {
|
||||
throw new Error('Missing required parameter: "functionId"');
|
||||
}
|
||||
|
||||
let path = '/functions/{functionId}/usage'.replace(new RegExp('{functionId}', 'g'), functionId);
|
||||
|
||||
let payload = {};
|
||||
|
||||
if(range) {
|
||||
payload['range'] = range;
|
||||
}
|
||||
|
||||
return http
|
||||
.get(path, {
|
||||
'content-type': 'application/json',
|
||||
}, payload);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,4 +48,4 @@
|
||||
|
||||
}
|
||||
});
|
||||
})(window);
|
||||
})(window);
|
||||
|
||||
@@ -49,4 +49,83 @@ class AccountCustomClientTest extends Scope
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function testBlockedAccount():array
|
||||
{
|
||||
$email = uniqid().'user@localhost.test';
|
||||
$password = 'password';
|
||||
$name = 'User Name (blocked)';
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$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,
|
||||
'name' => $name,
|
||||
]);
|
||||
|
||||
$id = $response['body']['$id'];
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
|
||||
$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);
|
||||
|
||||
$sessionId = $response['body']['$id'];
|
||||
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
|
||||
|
||||
$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);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/users/' . $id . '/status', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'status' => 2,
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
|
||||
$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'], 401);
|
||||
|
||||
$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'], 401);
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideServer;
|
||||
use Utopia\CLI\Console;
|
||||
|
||||
class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
@@ -183,7 +184,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'command' => 'php function.php',
|
||||
'code' => new CURLFile(realpath(__DIR__ . '/../../../resources/functions/php-fx.tar.gz'), 'application/x-gzip', 'php-fx.tar.gz'),
|
||||
'code' => new CURLFile(realpath(__DIR__ . '/../../../resources/functions/php.tar.gz'), 'application/x-gzip', 'php-fx.tar.gz'),
|
||||
]);
|
||||
|
||||
$tagId = $tag['body']['$id'] ?? '';
|
||||
@@ -192,7 +193,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertNotEmpty($tag['body']['$id']);
|
||||
$this->assertIsInt($tag['body']['dateCreated']);
|
||||
$this->assertEquals('php function.php', $tag['body']['command']);
|
||||
$this->assertEquals(751, $tag['body']['size']);
|
||||
$this->assertGreaterThan(10000, $tag['body']['size']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
@@ -264,7 +265,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
$this->assertEquals(751, $function['body']['size']);
|
||||
$this->assertGreaterThan(10000, $function['body']['size']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
@@ -279,7 +280,6 @@ class FunctionsCustomServerTest extends Scope
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testUpdateTag
|
||||
*/
|
||||
@@ -337,10 +337,11 @@ class FunctionsCustomServerTest extends Scope
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
sleep(10);
|
||||
|
||||
return array_merge($data, ['executionId' => $executionId]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testCreateExecution
|
||||
*/
|
||||
@@ -451,4 +452,254 @@ class FunctionsCustomServerTest extends Scope
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function testENVS():array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$file = $this->client->call(Client::METHOD_POST, '/storage/files', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
|
||||
'read' => ['*'],
|
||||
'write' => ['*'],
|
||||
'folderId' => 'xyz',
|
||||
]);
|
||||
|
||||
$this->assertEquals($file['headers']['status-code'], 201);
|
||||
$this->assertNotEmpty($file['body']['$id']);
|
||||
|
||||
$fileId = $file['body']['$id'] ?? '';
|
||||
|
||||
$functions = realpath(__DIR__ . '/../../../resources/functions');
|
||||
|
||||
/**
|
||||
* Command for rebuilding code packages:
|
||||
* bash tests/resources/functions/package-*.sh
|
||||
*/
|
||||
$envs = [
|
||||
[
|
||||
'language' => 'PHP',
|
||||
'version' => '7.4',
|
||||
'name' => 'php-7.4',
|
||||
'code' => $functions.'/php.tar.gz',
|
||||
'command' => 'php index.php',
|
||||
'timeout' => 15,
|
||||
],
|
||||
[
|
||||
'language' => 'PHP',
|
||||
'version' => '8.0',
|
||||
'name' => 'php-8.0',
|
||||
'code' => $functions.'/php.tar.gz',
|
||||
'command' => 'php index.php',
|
||||
'timeout' => 15,
|
||||
],
|
||||
[
|
||||
'language' => 'Python',
|
||||
'version' => '3.8',
|
||||
'name' => 'python-3.8',
|
||||
'code' => $functions.'/python.tar.gz',
|
||||
'command' => 'python main.py',
|
||||
'timeout' => 15,
|
||||
],
|
||||
[
|
||||
'language' => 'Node.js',
|
||||
'version' => '14.5',
|
||||
'name' => 'node-14',
|
||||
'code' => $functions.'/node.tar.gz',
|
||||
'command' => 'node index.js',
|
||||
'timeout' => 15,
|
||||
],
|
||||
[
|
||||
'language' => 'Ruby',
|
||||
'version' => '2.7',
|
||||
'name' => 'ruby-2.7',
|
||||
'code' => $functions.'/ruby.tar.gz',
|
||||
'command' => 'ruby app.rb',
|
||||
'timeout' => 15,
|
||||
],
|
||||
[
|
||||
'language' => 'Deno',
|
||||
'version' => '1.5',
|
||||
'name' => 'deno-1.5',
|
||||
'code' => $functions.'/deno.tar.gz',
|
||||
'command' => 'deno run --allow-env index.ts',
|
||||
'timeout' => 15,
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($envs as $key => $env) {
|
||||
$language = $env['language'] ?? '';
|
||||
$version = $env['version'] ?? '';
|
||||
$name = $env['name'] ?? '';
|
||||
$code = $env['code'] ?? '';
|
||||
$command = $env['command'] ?? '';
|
||||
$timeout = $env['timeout'] ?? 15;
|
||||
|
||||
$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' => [
|
||||
'APPWRITE_ENDPOINT' => 'http://appwrite.test/v1',
|
||||
'APPWRITE_PROJECT' => $this->getProject()['$id'],
|
||||
'APPWRITE_SECRET' => $this->getProject()['apiKey'],
|
||||
'APPWRITE_FILEID' => $fileId,
|
||||
],
|
||||
'events' => [],
|
||||
'schedule' => '',
|
||||
'timeout' => $timeout,
|
||||
]);
|
||||
|
||||
// var_dump('http://'.gethostbyname(trim(`hostname`)).'/v1');
|
||||
|
||||
$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()), [
|
||||
'async' => 1,
|
||||
]);
|
||||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||
|
||||
sleep(15);
|
||||
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
if($executions['body']['executions'][0]['status'] === 'failed') {
|
||||
var_dump($executions['body']['executions'][0]);
|
||||
}
|
||||
|
||||
$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->assertEquals($executions['body']['executions'][0]['status'], 'completed');
|
||||
$this->assertEquals($executions['body']['executions'][0]['exitCode'], 0);
|
||||
|
||||
$stdout = explode("\n", $executions['body']['executions'][0]['stdout']);
|
||||
|
||||
$this->assertEquals($stdout[0], $functionId);
|
||||
$this->assertEquals($stdout[1], 'Test '.$name);
|
||||
$this->assertEquals($stdout[2], $tagId);
|
||||
$this->assertEquals($stdout[3], 'http');
|
||||
$this->assertEquals($stdout[4], $language);
|
||||
$this->assertEquals($stdout[5], $version);
|
||||
// $this->assertEquals($stdout[6], $fileId);
|
||||
}
|
||||
|
||||
return [
|
||||
'functionId' => $functionId,
|
||||
];
|
||||
}
|
||||
/**
|
||||
* @depends testENVS
|
||||
*/
|
||||
public function testTimeout()
|
||||
{
|
||||
$name = 'php-8.0';
|
||||
$code = realpath(__DIR__ . '/../../../resources/functions').'/timeout.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()), [
|
||||
'async' => 1,
|
||||
]);
|
||||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||
|
||||
sleep(15);
|
||||
|
||||
$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->assertEquals($executions['body']['executions'][0]['status'], 'failed');
|
||||
$this->assertEquals($executions['body']['executions'][0]['exitCode'], 1);
|
||||
$this->assertGreaterThan(2, $executions['body']['executions'][0]['time']);
|
||||
$this->assertLessThan(3, $executions['body']['executions'][0]['time']);
|
||||
$this->assertEquals($executions['body']['executions'][0]['stdout'], '');
|
||||
$this->assertEquals($executions['body']['executions'][0]['stderr'], '');
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,9 @@ services:
|
||||
- _APP_STORAGE_LIMIT
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_CONTAINERS
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
|
||||
appwrite-worker-usage:
|
||||
entrypoint: worker-usage
|
||||
@@ -239,6 +242,9 @@ services:
|
||||
- _APP_DB_PASS
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_CONTAINERS
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
|
||||
appwrite-worker-mails:
|
||||
entrypoint: worker-mails
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
import * as sdk from "https://deno.land/x/appwrite/mod.ts";
|
||||
|
||||
let client = new sdk.Client();
|
||||
|
||||
client
|
||||
.setEndpoint(Deno.env.get("APPWRITE_ENDPOINT") || '') // Your API Endpoint
|
||||
.setProject(Deno.env.get("APPWRITE_PROJECT") || '') // Your project ID
|
||||
.setKey(Deno.env.get("APPWRITE_SECRET") || '') // Your secret API key
|
||||
;
|
||||
|
||||
let storage = new sdk.Storage(client);
|
||||
|
||||
// let result = storage.getFile(Deno.env.get("APPWRITE_FILEID"));
|
||||
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_ID") || '');
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_NAME") || '');
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_TAG") || '');
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_TRIGGER") || '');
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_ENV_NAME") || '');
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_ENV_VERSION") || '');
|
||||
// console.log(result['$id']"));
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_EVENT") || '');
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_EVENT_PAYLOAD") || '');
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
const sdk = require('node-appwrite');
|
||||
|
||||
let client = new sdk.Client();
|
||||
|
||||
client
|
||||
.setEndpoint(process.env.APPWRITE_ENDPOINT) // Your API Endpoint
|
||||
.setProject(process.env.APPWRITE_PROJECT) // Your project ID
|
||||
.setKey(process.env.APPWRITE_SECRET) // Your secret API key
|
||||
;
|
||||
|
||||
let storage = new sdk.Storage(client);
|
||||
|
||||
// let result = storage.getFile(process.env.APPWRITE_FILEID);
|
||||
|
||||
console.log(process.env.APPWRITE_FUNCTION_ID);
|
||||
console.log(process.env.APPWRITE_FUNCTION_NAME);
|
||||
console.log(process.env.APPWRITE_FUNCTION_TAG);
|
||||
console.log(process.env.APPWRITE_FUNCTION_TRIGGER);
|
||||
console.log(process.env.APPWRITE_FUNCTION_ENV_NAME);
|
||||
console.log(process.env.APPWRITE_FUNCTION_ENV_VERSION);
|
||||
// console.log(result['$id']);
|
||||
console.log(process.env.APPWRITE_FUNCTION_EVENT);
|
||||
console.log(process.env.APPWRITE_FUNCTION_EVENT_PAYLOAD);
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
{
|
||||
"name": "appwrite-cloud-function-demo",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"asn1": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
|
||||
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
|
||||
"requires": {
|
||||
"safer-buffer": "~2.1.0"
|
||||
}
|
||||
},
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
|
||||
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
|
||||
},
|
||||
"bcrypt-pbkdf": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
||||
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
|
||||
"requires": {
|
||||
"tweetnacl": "^0.14.3"
|
||||
}
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"requires": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"dashdash": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"ecc-jsbn": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
|
||||
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
|
||||
"requires": {
|
||||
"jsbn": "~0.1.0",
|
||||
"safer-buffer": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
||||
},
|
||||
"extsprintf": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
|
||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
|
||||
},
|
||||
"forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
||||
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.6",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"getpass": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
||||
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"har-schema": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "5.1.5",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
|
||||
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
|
||||
"requires": {
|
||||
"ajv": "^6.12.3",
|
||||
"har-schema": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"jsprim": "^1.2.2",
|
||||
"sshpk": "^1.7.0"
|
||||
}
|
||||
},
|
||||
"is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
|
||||
},
|
||||
"isstream": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
|
||||
},
|
||||
"jsbn": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
|
||||
},
|
||||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||
},
|
||||
"json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
|
||||
},
|
||||
"jsprim": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
|
||||
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
"extsprintf": "1.3.0",
|
||||
"json-schema": "0.2.3",
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.20",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.44.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
|
||||
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.27",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
|
||||
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
|
||||
"requires": {
|
||||
"mime-db": "1.44.0"
|
||||
}
|
||||
},
|
||||
"node-appwrite": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-1.1.0.tgz",
|
||||
"integrity": "sha512-ZLOsxmsGry4ZRT63QRbNgUxhYiUzJlQntQL2nKAy6PBL1S/hMCChKrdLIdJv3ytGxPrrIWiDWxXivMeUeCW5KA==",
|
||||
"requires": {
|
||||
"request": "^2.88.0",
|
||||
"request-promise-native": "^1.0.7"
|
||||
}
|
||||
},
|
||||
"oauth-sign": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
|
||||
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
|
||||
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
|
||||
},
|
||||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
},
|
||||
"request": {
|
||||
"version": "2.88.2",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
|
||||
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
|
||||
"requires": {
|
||||
"aws-sign2": "~0.7.0",
|
||||
"aws4": "^1.8.0",
|
||||
"caseless": "~0.12.0",
|
||||
"combined-stream": "~1.0.6",
|
||||
"extend": "~3.0.2",
|
||||
"forever-agent": "~0.6.1",
|
||||
"form-data": "~2.3.2",
|
||||
"har-validator": "~5.1.3",
|
||||
"http-signature": "~1.2.0",
|
||||
"is-typedarray": "~1.0.0",
|
||||
"isstream": "~0.1.2",
|
||||
"json-stringify-safe": "~5.0.1",
|
||||
"mime-types": "~2.1.19",
|
||||
"oauth-sign": "~0.9.0",
|
||||
"performance-now": "^2.1.0",
|
||||
"qs": "~6.5.2",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"tough-cookie": "~2.5.0",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"uuid": "^3.3.2"
|
||||
}
|
||||
},
|
||||
"request-promise-core": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz",
|
||||
"integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==",
|
||||
"requires": {
|
||||
"lodash": "^4.17.19"
|
||||
}
|
||||
},
|
||||
"request-promise-native": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz",
|
||||
"integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==",
|
||||
"requires": {
|
||||
"request-promise-core": "1.1.4",
|
||||
"stealthy-require": "^1.1.1",
|
||||
"tough-cookie": "^2.3.3"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"sshpk": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
|
||||
"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
|
||||
"requires": {
|
||||
"asn1": "~0.2.3",
|
||||
"assert-plus": "^1.0.0",
|
||||
"bcrypt-pbkdf": "^1.0.0",
|
||||
"dashdash": "^1.12.0",
|
||||
"ecc-jsbn": "~0.1.1",
|
||||
"getpass": "^0.1.1",
|
||||
"jsbn": "~0.1.0",
|
||||
"safer-buffer": "^2.0.2",
|
||||
"tweetnacl": "~0.14.0"
|
||||
}
|
||||
},
|
||||
"stealthy-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
|
||||
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
|
||||
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
|
||||
"requires": {
|
||||
"psl": "^1.1.28",
|
||||
"punycode": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
|
||||
"integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||
},
|
||||
"verror": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
"extsprintf": "^1.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "appwrite-cloud-function-demo",
|
||||
"version": "0.1.0",
|
||||
"license": "BSD-3-Clause",
|
||||
"repository": "public",
|
||||
"dependencies": {
|
||||
"node-appwrite": "1.1.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
echo 'Deno Packaging...'
|
||||
|
||||
cp -r $(pwd)/tests/resources/functions/deno $(pwd)/tests/resources/functions/packages/deno
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/deno:/app -w /app appwrite/env-deno-1.5:1.0.0 ls
|
||||
docker run --rm --env DENO_DIR=./.appwrite -v $(pwd)/tests/resources/functions/packages/deno:/app -w /app appwrite/env-deno-1.5:1.0.0 deno cache index.ts
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/deno:/app -w /app appwrite/env-deno-1.5:1.0.0 tar -zcvf code.tar.gz .
|
||||
|
||||
mv $(pwd)/tests/resources/functions/packages/deno/code.tar.gz $(pwd)/tests/resources/functions/deno.tar.gz
|
||||
|
||||
rm -r $(pwd)/tests/resources/functions/packages/deno
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
echo 'Node Packaging...'
|
||||
|
||||
cp -r $(pwd)/tests/resources/functions/node $(pwd)/tests/resources/functions/packages/node
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/node:/app -w /app appwrite/env-node-14.5:1.0.0 npm install
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/node:/app -w /app appwrite/env-node-14.5:1.0.0 tar -zcvf code.tar.gz .
|
||||
|
||||
mv $(pwd)/tests/resources/functions/packages/node/code.tar.gz $(pwd)/tests/resources/functions/node.tar.gz
|
||||
|
||||
rm -r $(pwd)/tests/resources/functions/packages/node
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
echo 'PHP Packaging...'
|
||||
|
||||
cp -r $(pwd)/tests/resources/functions/php $(pwd)/tests/resources/functions/packages/php
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/php:/app -w /app composer:2.0 composer install --ignore-platform-reqs
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/php:/app -w /app appwrite/env-php-8.0:1.0.0 tar -zcvf code.tar.gz .
|
||||
|
||||
mv $(pwd)/tests/resources/functions/packages/php/code.tar.gz $(pwd)/tests/resources/functions/php.tar.gz
|
||||
|
||||
rm -r $(pwd)/tests/resources/functions/packages/php
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
echo 'Python Packaging...'
|
||||
|
||||
cp -r $(pwd)/tests/resources/functions/python $(pwd)/tests/resources/functions/packages/python
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/python:/app -w /app --env PIP_TARGET=./.appwrite appwrite/env-python-3.8:1.0.0 pip install -r ./requirements.txt --upgrade --ignore-installed
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/python:/app -w /app appwrite/env-python-3.8:1.0.0 tar -zcvf code.tar.gz .
|
||||
|
||||
mv $(pwd)/tests/resources/functions/packages/python/code.tar.gz $(pwd)/tests/resources/functions/python.tar.gz
|
||||
|
||||
rm -r $(pwd)/tests/resources/functions/packages/python
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
echo 'Ruby Packaging...'
|
||||
|
||||
cp -r $(pwd)/tests/resources/functions/ruby $(pwd)/tests/resources/functions/packages/ruby
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/ruby:/app -w /app --env GEM_HOME=./.appwrite appwrite/env-ruby-2.7:1.0.2 bundle install
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/ruby:/app -w /app appwrite/env-ruby-2.7:1.0.2 tar -zcvf code.tar.gz .
|
||||
|
||||
mv $(pwd)/tests/resources/functions/packages/ruby/code.tar.gz $(pwd)/tests/resources/functions/ruby.tar.gz
|
||||
|
||||
rm -r $(pwd)/tests/resources/functions/packages/ruby
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
echo 'Timeout Packaging...'
|
||||
|
||||
cp -r $(pwd)/tests/resources/functions/timeout $(pwd)/tests/resources/functions/packages/timeout
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/timeout:/app -w /app appwrite/env-php-8.0:1.0.0 tar -zcvf code.tar.gz .
|
||||
|
||||
mv $(pwd)/tests/resources/functions/packages/timeout/code.tar.gz $(pwd)/tests/resources/functions/timeout.tar.gz
|
||||
|
||||
rm -r $(pwd)/tests/resources/functions/packages/timeout
|
||||
Binary file not shown.
Binary file not shown.
@@ -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
@@ -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"
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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";
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
import json
|
||||
import os
|
||||
from appwrite.client import Client
|
||||
from appwrite.services.storage import Storage
|
||||
|
||||
# Setup appwrite client
|
||||
client = Client()
|
||||
client.set_endpoint(os.environ["APPWRITE_ENDPOINT"]) # PRIVATE IP OF YOUR APPWRITE CONTAINER
|
||||
client.set_project(os.environ["APPWRITE_PROJECT"]) # YOUR PROJECT ID
|
||||
client.set_key(os.environ["APPWRITE_SECRET"])
|
||||
|
||||
storage = Storage(client)
|
||||
# result = storage.get_file(os.environ["APPWRITE_FILEID"])
|
||||
|
||||
print(os.environ["APPWRITE_FUNCTION_ID"])
|
||||
print(os.environ["APPWRITE_FUNCTION_NAME"])
|
||||
print(os.environ["APPWRITE_FUNCTION_TAG"])
|
||||
print(os.environ["APPWRITE_FUNCTION_TRIGGER"])
|
||||
print(os.environ["APPWRITE_FUNCTION_ENV_NAME"])
|
||||
print(os.environ["APPWRITE_FUNCTION_ENV_VERSION"])
|
||||
# print(result["$id"])
|
||||
print(os.environ["APPWRITE_FUNCTION_EVENT"])
|
||||
print(os.environ["APPWRITE_FUNCTION_EVENT_PAYLOAD"])
|
||||
@@ -0,0 +1 @@
|
||||
appwrite
|
||||
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
ruby "~> 2.7.0"
|
||||
|
||||
gem 'appwrite', '~> 1.0', '>= 1.0.11'
|
||||
@@ -0,0 +1,16 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
appwrite (1.0.11)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
appwrite (~> 1.0, >= 1.0.11)
|
||||
|
||||
RUBY VERSION
|
||||
ruby 2.7.2p137
|
||||
|
||||
BUNDLED WITH
|
||||
2.1.4
|
||||
@@ -0,0 +1,23 @@
|
||||
require 'appwrite'
|
||||
|
||||
client = Appwrite::Client.new()
|
||||
|
||||
client
|
||||
.set_endpoint(ENV["APPWRITE_ENDPOINT"]) # Your API Endpoint
|
||||
.set_project(ENV["APPWRITE_PROJECT"]) # Your project ID
|
||||
.set_key(ENV["APPWRITE_SECRET"]) # Your secret API key
|
||||
;
|
||||
|
||||
storage = Appwrite::Storage.new(client);
|
||||
|
||||
# result = storage.get_file(ENV["APPWRITE_FILEID"]);
|
||||
|
||||
puts ENV["APPWRITE_FUNCTION_ID"]
|
||||
puts ENV["APPWRITE_FUNCTION_NAME"]
|
||||
puts ENV["APPWRITE_FUNCTION_TAG"]
|
||||
puts ENV["APPWRITE_FUNCTION_TRIGGER"]
|
||||
puts ENV["APPWRITE_FUNCTION_ENV_NAME"]
|
||||
puts ENV["APPWRITE_FUNCTION_ENV_VERSION"]
|
||||
# puts result["$id"]
|
||||
puts ENV["APPWRITE_FUNCTION_EVENT"]
|
||||
puts ENV["APPWRITE_FUNCTION_EVENT_PAYLOAD"]
|
||||
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
sleep(10);
|
||||
Reference in New Issue
Block a user