mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 17:08:45 +00:00
Merge branch 'refs/heads/1.6.x' into refactor-changing-function-sdk-types
# Conflicts: # app/config/specs/open-api3-latest-client.json # app/config/specs/open-api3-latest-console.json # app/config/specs/open-api3-latest-server.json # app/config/specs/swagger2-latest-client.json # app/config/specs/swagger2-latest-console.json # app/config/specs/swagger2-latest-server.json
This commit is contained in:
commit
2de3803796
28 changed files with 620 additions and 199 deletions
|
|
@ -553,6 +553,12 @@ To run end-2-end tests for a specific service use:
|
|||
docker compose exec appwrite test /usr/src/code/tests/e2e/Services/[ServiceName]
|
||||
```
|
||||
|
||||
To run one specific test:
|
||||
|
||||
```bash
|
||||
docker compose exec appwrite vendor/bin/phpunit --filter [FunctionName]
|
||||
```
|
||||
|
||||
## Benchmarking
|
||||
|
||||
You can use WRK Docker image to benchmark the server performance. Benchmarking is extremely useful when you want to compare how the server behaves before and after a change has been applied. Replace [APPWRITE_HOSTNAME_OR_IP] with your Appwrite server hostname or IP. Note that localhost is not accessible from inside the WRK container.
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \
|
|||
--no-plugins --no-scripts --prefer-dist \
|
||||
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
|
||||
|
||||
FROM appwrite/base:0.9.1 as final
|
||||
FROM appwrite/base:0.9.2 as final
|
||||
|
||||
LABEL maintainer="team@appwrite.io"
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,6 @@ const TEMPLATE_RUNTIMES = [
|
|||
'name' => 'node',
|
||||
'versions' => ['21.0', '20.0', '19.0', '18.0', '16.0', '14.5']
|
||||
],
|
||||
'PHP' => [
|
||||
'name' => 'php',
|
||||
'versions' => ['8.3', '8.2', '8.1', '8.0']
|
||||
],
|
||||
'RUBY' => [
|
||||
'name' => 'ruby',
|
||||
'versions' => ['3.3', '3.2', '3.1', '3.0']
|
||||
],
|
||||
'PYTHON' => [
|
||||
'name' => 'python',
|
||||
'versions' => ['3.12', '3.11', '3.10', '3.9', '3.8']
|
||||
|
|
@ -21,14 +13,22 @@ const TEMPLATE_RUNTIMES = [
|
|||
'name' => 'dart',
|
||||
'versions' => ['3.3', '3.1', '3.0', '2.19', '2.18', '2.17', '2.16', '2.16']
|
||||
],
|
||||
'GO' => [
|
||||
'name' => 'go',
|
||||
'versions' => ['1.22']
|
||||
],
|
||||
'PHP' => [
|
||||
'name' => 'php',
|
||||
'versions' => ['8.3', '8.2', '8.1', '8.0']
|
||||
],
|
||||
'BUN' => [
|
||||
'name' => 'bun',
|
||||
'versions' => ['1.0']
|
||||
],
|
||||
'GO' => [
|
||||
'name' => 'go',
|
||||
'versions' => ['1.22']
|
||||
]
|
||||
'RUBY' => [
|
||||
'name' => 'ruby',
|
||||
'versions' => ['3.3', '3.2', '3.1', '3.0']
|
||||
],
|
||||
];
|
||||
|
||||
function getRuntimes($runtime, $commands, $entrypoint, $providerRootDirectory, $versionsDenyList = [])
|
||||
|
|
@ -59,13 +59,6 @@ return [
|
|||
'useCases' => ['starter'],
|
||||
'runtimes' => [
|
||||
...getRuntimes(TEMPLATE_RUNTIMES['NODE'], 'npm install', 'src/main.js', 'node/starter'),
|
||||
...getRuntimes(
|
||||
TEMPLATE_RUNTIMES['PHP'],
|
||||
'composer install',
|
||||
'src/index.php',
|
||||
'php/starter'
|
||||
),
|
||||
...getRuntimes(TEMPLATE_RUNTIMES['RUBY'], 'bundle install', 'lib/main.rb', 'ruby/starter'),
|
||||
...getRuntimes(
|
||||
TEMPLATE_RUNTIMES['PYTHON'],
|
||||
'pip install -r requirements.txt',
|
||||
|
|
@ -73,14 +66,21 @@ return [
|
|||
'python/starter'
|
||||
),
|
||||
...getRuntimes(TEMPLATE_RUNTIMES['DART'], 'dart pub get', 'lib/main.dart', 'dart/starter'),
|
||||
...getRuntimes(TEMPLATE_RUNTIMES['GO'], '', 'main.go', 'go/starter'),
|
||||
...getRuntimes(
|
||||
TEMPLATE_RUNTIMES['PHP'],
|
||||
'composer install',
|
||||
'src/index.php',
|
||||
'php/starter'
|
||||
),
|
||||
...getRuntimes(TEMPLATE_RUNTIMES['BUN'], 'bun install', 'src/main.ts', 'bun/starter'),
|
||||
...getRuntimes(TEMPLATE_RUNTIMES['GO'], '', 'main.go', 'go/starter')
|
||||
...getRuntimes(TEMPLATE_RUNTIMES['RUBY'], 'bundle install', 'lib/main.rb', 'ruby/starter'),
|
||||
],
|
||||
'instructions' => 'For documentation and instructions check out <a target="_blank" rel="noopener noreferrer" class="link" href="https://github.com/appwrite/templates/tree/main/node/starter">file</a>.',
|
||||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [],
|
||||
'scopes' => ["users.read"]
|
||||
],
|
||||
|
|
@ -106,7 +106,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'UPSTASH_URL',
|
||||
|
|
@ -149,7 +149,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'REDIS_HOST',
|
||||
|
|
@ -191,7 +191,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'NEO4J_URI',
|
||||
|
|
@ -242,7 +242,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'MONGO_URI',
|
||||
|
|
@ -278,7 +278,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'PGHOST',
|
||||
|
|
@ -362,7 +362,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'OPENAI_API_KEY',
|
||||
|
|
@ -416,7 +416,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'DISCORD_PUBLIC_KEY',
|
||||
|
|
@ -466,7 +466,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'PERSPECTIVE_API_KEY',
|
||||
|
|
@ -513,7 +513,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'PANGEA_REDACT_TOKEN',
|
||||
|
|
@ -542,7 +542,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => []
|
||||
],
|
||||
[
|
||||
|
|
@ -568,7 +568,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'GITHUB_TOKEN',
|
||||
|
|
@ -610,7 +610,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'APPWRITE_DATABASE_ID',
|
||||
|
|
@ -673,7 +673,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'APPWRITE_DATABASE_ID',
|
||||
|
|
@ -766,7 +766,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'APPWRITE_DATABASE_ID',
|
||||
|
|
@ -836,6 +836,12 @@ return [
|
|||
'src/main.py',
|
||||
'python/whatsapp_with_vonage'
|
||||
),
|
||||
...getRuntimes(
|
||||
TEMPLATE_RUNTIMES['DART'],
|
||||
'dart pub get',
|
||||
'lib/main.dart',
|
||||
'dart/whatsapp-with-vonage'
|
||||
),
|
||||
...getRuntimes(
|
||||
TEMPLATE_RUNTIMES['PHP'],
|
||||
'composer install',
|
||||
|
|
@ -843,10 +849,10 @@ return [
|
|||
'php/whatsapp-with-vonage'
|
||||
),
|
||||
...getRuntimes(
|
||||
TEMPLATE_RUNTIMES['DART'],
|
||||
'dart pub get',
|
||||
'lib/main.dart',
|
||||
'dart/whatsapp-with-vonage'
|
||||
TEMPLATE_RUNTIMES['BUN'],
|
||||
'bun install',
|
||||
'src/main.ts',
|
||||
'bun/whatsapp-with-vonage'
|
||||
),
|
||||
...getRuntimes(
|
||||
TEMPLATE_RUNTIMES['RUBY'],
|
||||
|
|
@ -854,18 +860,12 @@ return [
|
|||
'lib/main.rb',
|
||||
'ruby/whatsapp-with-vonage'
|
||||
),
|
||||
...getRuntimes(
|
||||
TEMPLATE_RUNTIMES['BUN'],
|
||||
'bun install',
|
||||
'src/main.ts',
|
||||
'bun/whatsapp-with-vonage'
|
||||
)
|
||||
],
|
||||
'instructions' => 'For documentation and instructions check out <a target="_blank" rel="noopener noreferrer" class="link" href="https://github.com/appwrite/templates/tree/main/node/whatsapp-with-vonage">file</a>.',
|
||||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'VONAGE_API_KEY',
|
||||
|
|
@ -920,7 +920,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'FCM_PROJECT_ID',
|
||||
|
|
@ -987,7 +987,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'SMTP_HOST',
|
||||
|
|
@ -1057,7 +1057,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'STRIPE_SECRET_KEY',
|
||||
|
|
@ -1098,7 +1098,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'STRIPE_SECRET_KEY',
|
||||
|
|
@ -1155,7 +1155,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'HUGGINGFACE_ACCESS_TOKEN',
|
||||
|
|
@ -1188,7 +1188,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'HUGGINGFACE_ACCESS_TOKEN',
|
||||
|
|
@ -1221,7 +1221,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'APPWRITE_DATABASE_ID',
|
||||
|
|
@ -1279,7 +1279,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'APPWRITE_DATABASE_ID',
|
||||
|
|
@ -1337,7 +1337,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'APPWRITE_DATABASE_ID',
|
||||
|
|
@ -1395,7 +1395,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'APPWRITE_DATABASE_ID',
|
||||
|
|
@ -1453,7 +1453,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'REPLICATE_API_KEY',
|
||||
|
|
@ -1487,7 +1487,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'TOGETHER_API_KEY',
|
||||
|
|
@ -1529,7 +1529,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'PERPLEXITY_API_KEY',
|
||||
|
|
@ -1569,7 +1569,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'REPLICATE_API_KEY',
|
||||
|
|
@ -1603,7 +1603,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'OPENAI_API_KEY',
|
||||
|
|
@ -1666,7 +1666,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'OPENAI_API_KEY',
|
||||
|
|
@ -1729,7 +1729,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'ELEVENLABS_API_KEY',
|
||||
|
|
@ -1784,7 +1784,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'LMNT_API_KEY',
|
||||
|
|
@ -1825,7 +1825,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'ANYSCALE_API_KEY',
|
||||
|
|
@ -1865,7 +1865,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'APPWRITE_BUCKET_ID',
|
||||
|
|
@ -1907,7 +1907,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'FAL_API_KEY',
|
||||
|
|
@ -1941,7 +1941,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'LEMON_SQUEEZY_API_KEY',
|
||||
|
|
@ -1996,7 +1996,7 @@ return [
|
|||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerBranch' => 'main',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'APPWRITE_DATABASE_ID',
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -165,7 +165,7 @@ App::post('/v1/functions')
|
|||
->param('templateRepository', '', new Text(128, 0), 'Repository name of the template.', true)
|
||||
->param('templateOwner', '', new Text(128, 0), 'The name of the owner of the template.', true)
|
||||
->param('templateRootDirectory', '', new Text(128, 0), 'Path to function code in the template repo.', true)
|
||||
->param('templateBranch', '', new Text(128, 0), 'Production branch for the repo linked to the function template.', true)
|
||||
->param('templateVersion', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
|
@ -175,7 +175,7 @@ App::post('/v1/functions')
|
|||
->inject('queueForBuilds')
|
||||
->inject('dbForConsole')
|
||||
->inject('gitHub')
|
||||
->action(function (string $functionId, string $name, string $runtime, array $execute, array $events, string $schedule, int $timeout, bool $enabled, bool $logging, string $entrypoint, string $commands, array $scopes, string $installationId, string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, string $templateRepository, string $templateOwner, string $templateRootDirectory, string $templateBranch, Request $request, Response $response, Database $dbForProject, Document $project, Document $user, Event $queueForEvents, Build $queueForBuilds, Database $dbForConsole, GitHub $github) use ($redeployVcs) {
|
||||
->action(function (string $functionId, string $name, string $runtime, array $execute, array $events, string $schedule, int $timeout, bool $enabled, bool $logging, string $entrypoint, string $commands, array $scopes, string $installationId, string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, string $templateRepository, string $templateOwner, string $templateRootDirectory, string $templateVersion, Request $request, Response $response, Database $dbForProject, Document $project, Document $user, Event $queueForEvents, Build $queueForBuilds, Database $dbForConsole, GitHub $github) use ($redeployVcs) {
|
||||
$functionId = ($functionId == 'unique()') ? ID::unique() : $functionId;
|
||||
|
||||
$allowList = \array_filter(\explode(',', System::getEnv('_APP_FUNCTIONS_RUNTIMES', '')));
|
||||
|
|
@ -190,12 +190,12 @@ App::post('/v1/functions')
|
|||
!empty($templateRepository)
|
||||
&& !empty($templateOwner)
|
||||
&& !empty($templateRootDirectory)
|
||||
&& !empty($templateBranch)
|
||||
&& !empty($templateVersion)
|
||||
) {
|
||||
$template->setAttribute('repositoryName', $templateRepository)
|
||||
->setAttribute('ownerName', $templateOwner)
|
||||
->setAttribute('rootDirectory', $templateRootDirectory)
|
||||
->setAttribute('branch', $templateBranch);
|
||||
->setAttribute('version', $templateVersion);
|
||||
}
|
||||
|
||||
$installation = $dbForConsole->getDocument('installations', $installationId);
|
||||
|
|
@ -284,9 +284,34 @@ App::post('/v1/functions')
|
|||
|
||||
$function = $dbForProject->updateDocument('functions', $function->getId(), $function);
|
||||
|
||||
// Redeploy vcs logic
|
||||
if (!empty($providerRepositoryId)) {
|
||||
// Deploy VCS
|
||||
$redeployVcs($request, $function, $project, $installation, $dbForProject, $queueForBuilds, $template, $github);
|
||||
} elseif(!$template->isEmpty()) {
|
||||
// Deploy non-VCS from template
|
||||
$deploymentId = ID::unique();
|
||||
$deployment = $dbForProject->createDocument('deployments', new Document([
|
||||
'$id' => $deploymentId,
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'resourceId' => $function->getId(),
|
||||
'resourceInternalId' => $function->getInternalId(),
|
||||
'resourceType' => 'functions',
|
||||
'entrypoint' => $function->getAttribute('entrypoint', ''),
|
||||
'commands' => $function->getAttribute('commands', ''),
|
||||
'type' => 'manual',
|
||||
'search' => implode(' ', [$deploymentId, $function->getAttribute('entrypoint', '')]),
|
||||
'activate' => true,
|
||||
]));
|
||||
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($function)
|
||||
->setDeployment($deployment)
|
||||
->setTemplate($template);
|
||||
}
|
||||
|
||||
$functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
|
||||
|
|
@ -861,7 +886,7 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId/download')
|
|||
->groups(['api', 'functions'])
|
||||
->desc('Download deployment')
|
||||
->label('scope', 'functions.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'getDeploymentDownload')
|
||||
->label('sdk.description', '/docs/references/functions/get-deployment-download.md')
|
||||
|
|
@ -1080,9 +1105,9 @@ App::post('/v1/functions/:functionId/deployments')
|
|||
->inject('deviceForFunctions')
|
||||
->inject('deviceForLocal')
|
||||
->inject('queueForBuilds')
|
||||
->action(function (string $functionId, ?string $entrypoint, ?string $commands, mixed $code, bool $activate, Request $request, Response $response, Database $dbForProject, Event $queueForEvents, Document $project, Device $deviceForFunctions, Device $deviceForLocal, Build $queueForBuilds) {
|
||||
->action(function (string $functionId, ?string $entrypoint, ?string $commands, mixed $code, mixed $activate, Request $request, Response $response, Database $dbForProject, Event $queueForEvents, Document $project, Device $deviceForFunctions, Device $deviceForLocal, Build $queueForBuilds) {
|
||||
|
||||
$activate = filter_var($activate, FILTER_VALIDATE_BOOLEAN);
|
||||
$activate = \strval($activate) === 'true' || \strval($activate) === '1';
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
|
|
@ -1180,7 +1205,6 @@ App::post('/v1/functions/:functionId/deployments')
|
|||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed moving file');
|
||||
}
|
||||
|
||||
$activate = (bool) filter_var($activate, FILTER_VALIDATE_BOOLEAN);
|
||||
$type = $request->getHeader('x-sdk-language') === 'cli' ? 'cli' : 'manual';
|
||||
|
||||
if ($chunksUploaded === $chunks) {
|
||||
|
|
@ -1619,8 +1643,8 @@ App::post('/v1/functions/:functionId/executions')
|
|||
->param('async', false, new Boolean(), 'Execute code in the background. Default value is false.', true)
|
||||
->param('path', '/', new Text(2048), 'HTTP path of execution. Path can include query params. Default value is /', true)
|
||||
->param('method', 'POST', new Whitelist(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], true), 'HTTP method of execution. Default value is GET.', true)
|
||||
->param('headers', [], new AnyOf([new Text(65535), new Assoc()], AnyOf::TYPE_MIXED), 'HTTP headers of execution. Defaults to empty.', true)
|
||||
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
||||
->param('headers', [], new AnyOf([new Assoc(), new Text(65535)], AnyOf::TYPE_MIXED), 'HTTP headers of execution. Defaults to empty.', true)
|
||||
->param('scheduledAt', null, new DatetimeValidator(true, DateTimeValidator::PRECISION_MINUTES, 60), 'Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.', true)
|
||||
->inject('response')
|
||||
->inject('request')
|
||||
->inject('project')
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use Appwrite\Utopia\Database\Validator\Queries\Projects;
|
|||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\Abuse\Adapters\Database as AbuseDatabase;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Cache\Cache;
|
||||
|
|
@ -209,7 +209,7 @@ App::post('/v1/projects')
|
|||
$audit = new Audit($dbForProject);
|
||||
$audit->setup();
|
||||
|
||||
$abuse = new TimeLimit('', 0, 1, $dbForProject);
|
||||
$abuse = new AbuseDatabase('', 0, 1, $dbForProject);
|
||||
$abuse->setup();
|
||||
|
||||
/** @var array $collections */
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use Appwrite\Event\Mail;
|
|||
use Appwrite\Event\Messaging;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Platform\Workers\Deletes;
|
||||
use Appwrite\Template\Template;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Memberships;
|
||||
|
|
@ -338,10 +339,12 @@ App::delete('/v1/teams/:teamId')
|
|||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->inject('response')
|
||||
->inject('getProjectDB')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForDeletes')
|
||||
->action(function (string $teamId, Response $response, Database $dbForProject, Event $queueForEvents, Delete $queueForDeletes) {
|
||||
->inject('queueForEvents')
|
||||
->inject('project')
|
||||
->action(function (string $teamId, Response $response, callable $getProjectDB, Database $dbForProject, Delete $queueForDeletes, Event $queueForEvents, Document $project) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
|
|
@ -353,9 +356,14 @@ App::delete('/v1/teams/:teamId')
|
|||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove team from DB');
|
||||
}
|
||||
|
||||
$queueForDeletes
|
||||
->setType(DELETE_TYPE_DOCUMENT)
|
||||
->setDocument($team);
|
||||
$deletes = new Deletes();
|
||||
$deletes->deleteMemberships($getProjectDB, $team, $project);
|
||||
|
||||
if ($project->getId() === 'console') {
|
||||
$queueForDeletes
|
||||
->setType(DELETE_TYPE_TEAM_PROJECTS)
|
||||
->setDocument($team);
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
->setParam('teamId', $team->getId())
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use Appwrite\Messaging\Adapter\Realtime;
|
|||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\Abuse\Adapters\Database as AbuseDatabase;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Adapter\Filesystem;
|
||||
use Utopia\Cache\Cache;
|
||||
|
|
@ -380,7 +380,7 @@ App::init()
|
|||
foreach ($abuseKeyLabel as $abuseKey) {
|
||||
$start = $request->getContentRangeStart();
|
||||
$end = $request->getContentRangeEnd();
|
||||
$timeLimit = new TimeLimit($abuseKey, $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), $dbForProject);
|
||||
$timeLimit = new AbuseDatabase($abuseKey, $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), $dbForProject);
|
||||
$timeLimit
|
||||
->setParam('{projectId}', $project->getId())
|
||||
->setParam('{userId}', $user->getId())
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use Swoole\Http\Request as SwooleRequest;
|
|||
use Swoole\Http\Response as SwooleResponse;
|
||||
use Swoole\Http\Server;
|
||||
use Swoole\Process;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\Abuse\Adapters\Database as AbuseDatabase;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\CLI\Console;
|
||||
|
|
@ -101,8 +101,8 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
|
|||
$audit->setup();
|
||||
}
|
||||
|
||||
if ($dbForConsole->getCollection(TimeLimit::COLLECTION)->isEmpty()) {
|
||||
$adapter = new TimeLimit("", 0, 1, $dbForConsole);
|
||||
if ($dbForConsole->getCollection(AbuseDatabase::COLLECTION)->isEmpty()) {
|
||||
$adapter = new AbuseDatabase("", 0, 1, $dbForConsole);
|
||||
$adapter->setup();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ const DELETE_TYPE_PROJECTS = 'projects';
|
|||
const DELETE_TYPE_FUNCTIONS = 'functions';
|
||||
const DELETE_TYPE_DEPLOYMENTS = 'deployments';
|
||||
const DELETE_TYPE_USERS = 'users';
|
||||
const DELETE_TYPE_TEAMS = 'teams';
|
||||
const DELETE_TYPE_TEAM_PROJECTS = 'teams_projects';
|
||||
const DELETE_TYPE_EXECUTIONS = 'executions';
|
||||
const DELETE_TYPE_AUDIT = 'audit';
|
||||
const DELETE_TYPE_ABUSE = 'abuse';
|
||||
|
|
@ -750,7 +750,7 @@ $register->set('logger', function () {
|
|||
|
||||
$providerName = $loggingProvider->getScheme();
|
||||
$providerConfig = match ($providerName) {
|
||||
'sentry' => ['key' => $loggingProvider->getPassword(), 'projectId' => $loggingProvider->getUser() ?? '', 'host' => $loggingProvider->getHost()],
|
||||
'sentry' => ['key' => $loggingProvider->getPassword(), 'projectId' => $loggingProvider->getUser() ?? '', 'host' => 'https://' . $loggingProvider->getHost()],
|
||||
'logowl' => ['ticket' => $loggingProvider->getUser() ?? '', 'host' => $loggingProvider->getHost()],
|
||||
default => ['key' => $loggingProvider->getHost()],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use Swoole\Runtime;
|
|||
use Swoole\Table;
|
||||
use Swoole\Timer;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\Abuse\Adapters\Database as AbuseDatabase;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Adapter\Sharding;
|
||||
use Utopia\Cache\Cache;
|
||||
|
|
@ -463,7 +463,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
|||
*
|
||||
* Abuse limits are connecting 128 times per minute and ip address.
|
||||
*/
|
||||
$timeLimit = new TimeLimit('url:{url},ip:{ip}', 128, 60, $dbForProject);
|
||||
$timeLimit = new AbuseDatabase('url:{url},ip:{ip}', 128, 60, $dbForProject);
|
||||
$timeLimit
|
||||
->setParam('{ip}', $request->getIP())
|
||||
->setParam('{url}', $request->getURI());
|
||||
|
|
@ -563,7 +563,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
|||
*
|
||||
* Abuse limits are sending 32 times per minute and connection.
|
||||
*/
|
||||
$timeLimit = new TimeLimit('url:{url},connection:{connection}', 32, 60, $database);
|
||||
$timeLimit = new AbuseDatabase('url:{url},connection:{connection}', 32, 60, $database);
|
||||
|
||||
$timeLimit
|
||||
->setParam('{connection}', $connection)
|
||||
|
|
|
|||
|
|
@ -44,13 +44,13 @@
|
|||
"ext-sockets": "*",
|
||||
"appwrite/php-runtimes": "0.14.*",
|
||||
"appwrite/php-clamav": "2.0.*",
|
||||
"utopia-php/abuse": "0.38.*",
|
||||
"utopia-php/abuse": "0.40.*",
|
||||
"utopia-php/analytics": "0.10.*",
|
||||
"utopia-php/audit": "0.40.*",
|
||||
"utopia-php/audit": "0.41.*",
|
||||
"utopia-php/cache": "0.10.*",
|
||||
"utopia-php/cli": "0.15.*",
|
||||
"utopia-php/config": "0.2.*",
|
||||
"utopia-php/database": "0.50.*",
|
||||
"utopia-php/database": "0.51.*",
|
||||
"utopia-php/domains": "0.5.*",
|
||||
"utopia-php/dsn": "0.2.1",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
|
|
|
|||
68
composer.lock
generated
68
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "340aae0879435fc71eac688d47033eb4",
|
||||
"content-hash": "cd0323e7303780f34b2f775a526de516",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
|
@ -1429,26 +1429,28 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/abuse",
|
||||
"version": "0.38.0",
|
||||
"version": "0.40.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/abuse.git",
|
||||
"reference": "b7be9086c9d9b4561d810cbd42fdda798742f56c"
|
||||
"reference": "69748a6741a9e44f0c9e430f3c2bd2b8a677c048"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/b7be9086c9d9b4561d810cbd42fdda798742f56c",
|
||||
"reference": "b7be9086c9d9b4561d810cbd42fdda798742f56c",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/69748a6741a9e44f0c9e430f3c2bd2b8a677c048",
|
||||
"reference": "69748a6741a9e44f0c9e430f3c2bd2b8a677c048",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-pdo": "*",
|
||||
"ext-redis": "*",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": "0.50.*"
|
||||
"utopia-php/database": "0.51.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.5.*",
|
||||
"phpbench/phpbench": "^1.2",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpunit/phpunit": "^9.4"
|
||||
},
|
||||
|
|
@ -1472,9 +1474,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/abuse/issues",
|
||||
"source": "https://github.com/utopia-php/abuse/tree/0.38.0"
|
||||
"source": "https://github.com/utopia-php/abuse/tree/0.40.0"
|
||||
},
|
||||
"time": "2024-06-24T00:52:02+00:00"
|
||||
"time": "2024-08-16T06:08:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/analytics",
|
||||
|
|
@ -1524,21 +1526,21 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/audit",
|
||||
"version": "0.40.0",
|
||||
"version": "0.41.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/audit.git",
|
||||
"reference": "735ae211ce5fee5b52b736731571b4030b1d7cdc"
|
||||
"reference": "77f1d0a95ea791e38a38a8bc1b7728ffcedcd2d1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/735ae211ce5fee5b52b736731571b4030b1d7cdc",
|
||||
"reference": "735ae211ce5fee5b52b736731571b4030b1d7cdc",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/77f1d0a95ea791e38a38a8bc1b7728ffcedcd2d1",
|
||||
"reference": "77f1d0a95ea791e38a38a8bc1b7728ffcedcd2d1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": "0.50.*"
|
||||
"utopia-php/database": "0.51.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.5.*",
|
||||
|
|
@ -1565,9 +1567,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/audit/issues",
|
||||
"source": "https://github.com/utopia-php/audit/tree/0.40.0"
|
||||
"source": "https://github.com/utopia-php/audit/tree/0.41.0"
|
||||
},
|
||||
"time": "2024-06-24T00:52:17+00:00"
|
||||
"time": "2024-08-16T06:08:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/cache",
|
||||
|
|
@ -1721,16 +1723,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "0.50.4",
|
||||
"version": "0.51.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "fd3b856be77bd643bc8a9e3572ee11e4185b9230"
|
||||
"reference": "845783a54cced784e00db084a29486fdb96d3d58"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/fd3b856be77bd643bc8a9e3572ee11e4185b9230",
|
||||
"reference": "fd3b856be77bd643bc8a9e3572ee11e4185b9230",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/845783a54cced784e00db084a29486fdb96d3d58",
|
||||
"reference": "845783a54cced784e00db084a29486fdb96d3d58",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -1771,9 +1773,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.50.4"
|
||||
"source": "https://github.com/utopia-php/database/tree/0.51.1"
|
||||
},
|
||||
"time": "2024-08-13T03:18:26+00:00"
|
||||
"time": "2024-08-16T10:54:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
|
|
@ -1923,16 +1925,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/framework",
|
||||
"version": "0.33.7",
|
||||
"version": "0.33.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/http.git",
|
||||
"reference": "78d293d99a262bd63ece750bbf989c7e0643b825"
|
||||
"reference": "a7f577540a25cb90896fef2b64767bf8d700f3c5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/http/zipball/78d293d99a262bd63ece750bbf989c7e0643b825",
|
||||
"reference": "78d293d99a262bd63ece750bbf989c7e0643b825",
|
||||
"url": "https://api.github.com/repos/utopia-php/http/zipball/a7f577540a25cb90896fef2b64767bf8d700f3c5",
|
||||
"reference": "a7f577540a25cb90896fef2b64767bf8d700f3c5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -1962,9 +1964,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/http/issues",
|
||||
"source": "https://github.com/utopia-php/http/tree/0.33.7"
|
||||
"source": "https://github.com/utopia-php/http/tree/0.33.8"
|
||||
},
|
||||
"time": "2024-08-01T14:01:04+00:00"
|
||||
"time": "2024-08-15T14:10:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/image",
|
||||
|
|
@ -2759,16 +2761,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/vcs",
|
||||
"version": "0.8.1",
|
||||
"version": "0.8.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/vcs.git",
|
||||
"reference": "3084aa93d24ed1e70f01e75f4318fc0d07f12596"
|
||||
"reference": "eb9b7eade1a46a4f660e0d5a6304f7fa26ec9d18"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/3084aa93d24ed1e70f01e75f4318fc0d07f12596",
|
||||
"reference": "3084aa93d24ed1e70f01e75f4318fc0d07f12596",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/eb9b7eade1a46a4f660e0d5a6304f7fa26ec9d18",
|
||||
"reference": "eb9b7eade1a46a4f660e0d5a6304f7fa26ec9d18",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2802,9 +2804,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/vcs/issues",
|
||||
"source": "https://github.com/utopia-php/vcs/tree/0.8.1"
|
||||
"source": "https://github.com/utopia-php/vcs/tree/0.8.2"
|
||||
},
|
||||
"time": "2024-07-29T20:49:09+00:00"
|
||||
"time": "2024-08-13T14:36:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/websocket",
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ services:
|
|||
appwrite-console:
|
||||
<<: *x-logging
|
||||
container_name: appwrite-console
|
||||
image: appwrite/console:5.0.0-rc14
|
||||
image: appwrite/console:5.0.0-rc15
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="true"
|
||||
stopOnFailure="false"
|
||||
>
|
||||
<extensions>
|
||||
<extension class="Appwrite\Tests\TestHook" />
|
||||
|
|
|
|||
|
|
@ -207,7 +207,65 @@ class Builds extends Action
|
|||
}
|
||||
|
||||
try {
|
||||
if ($isNewBuild && $isVcsEnabled) {
|
||||
if($isNewBuild && !$isVcsEnabled) {
|
||||
// Non-vcs+Template
|
||||
|
||||
$templateRepositoryName = $template->getAttribute('repositoryName', '');
|
||||
$templateOwnerName = $template->getAttribute('ownerName', '');
|
||||
$templateVersion = $template->getAttribute('version', '');
|
||||
|
||||
$templateRootDirectory = $template->getAttribute('rootDirectory', '');
|
||||
$templateRootDirectory = \rtrim($templateRootDirectory, '/');
|
||||
$templateRootDirectory = \ltrim($templateRootDirectory, '.');
|
||||
$templateRootDirectory = \ltrim($templateRootDirectory, '/');
|
||||
|
||||
if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateVersion)) {
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
// Clone template repo
|
||||
$tmpTemplateDirectory = '/tmp/builds/' . $buildId . '-template';
|
||||
$gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateVersion, GitHub::CLONE_TYPE_TAG, $tmpTemplateDirectory, $templateRootDirectory);
|
||||
$exit = Console::execute($gitCloneCommandForTemplate, '', $stdout, $stderr);
|
||||
|
||||
if ($exit !== 0) {
|
||||
throw new \Exception('Unable to clone code repository: ' . $stderr);
|
||||
}
|
||||
|
||||
// Ensure directories
|
||||
Console::execute('mkdir -p ' . \escapeshellarg($tmpTemplateDirectory . '/' . $templateRootDirectory), '', $stdout, $stderr);
|
||||
|
||||
$tmpPathFile = $tmpTemplateDirectory . '/code.tar.gz';
|
||||
|
||||
$localDevice = new Local();
|
||||
|
||||
if (substr($tmpTemplateDirectory, -1) !== '/') {
|
||||
$tmpTemplateDirectory .= '/';
|
||||
}
|
||||
|
||||
$directorySize = $localDevice->getDirectorySize($tmpTemplateDirectory);
|
||||
$functionsSizeLimit = (int)System::getEnv('_APP_FUNCTIONS_SIZE_LIMIT', '30000000');
|
||||
if ($directorySize > $functionsSizeLimit) {
|
||||
throw new \Exception('Repository directory size should be less than ' . number_format($functionsSizeLimit / 1048576, 2) . ' MBs.');
|
||||
}
|
||||
|
||||
$tarParamDirectory = \escapeshellarg('/tmp/builds/' . $buildId . '-template' . (empty($templateRootDirectory) ? '' : '/' . $templateRootDirectory));
|
||||
Console::execute('tar --exclude code.tar.gz -czf ' . \escapeshellarg($tmpPathFile) . ' -C ' . \escapeshellcmd($tarParamDirectory) . ' .', '', $stdout, $stderr); // TODO: Replace escapeshellcmd with escapeshellarg if we find a way that doesnt break syntax
|
||||
|
||||
$source = $deviceForFunctions->getPath($deployment->getId() . '.' . \pathinfo('code.tar.gz', PATHINFO_EXTENSION));
|
||||
$result = $localDevice->transfer($tmpPathFile, $source, $deviceForFunctions);
|
||||
|
||||
if (!$result) {
|
||||
throw new \Exception("Unable to move file");
|
||||
}
|
||||
|
||||
Console::execute('rm -rf ' . \escapeshellarg($tmpTemplateDirectory), '', $stdout, $stderr);
|
||||
|
||||
$build = $dbForProject->updateDocument('builds', $build->getId(), $build->setAttribute('source', $source));
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment->setAttribute('path', $source));
|
||||
}
|
||||
} elseif ($isNewBuild && $isVcsEnabled) {
|
||||
// VCS and VCS+Temaplte
|
||||
$tmpDirectory = '/tmp/builds/' . $buildId . '/code';
|
||||
$rootDirectory = $function->getAttribute('providerRootDirectory', '');
|
||||
$rootDirectory = \rtrim($rootDirectory, '/');
|
||||
|
|
@ -233,7 +291,8 @@ class Builds extends Action
|
|||
$gitCloneCommand = $github->generateCloneCommand($cloneOwner, $cloneRepository, $cloneVersion, $cloneType, $tmpDirectory, $rootDirectory);
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
Console::execute('mkdir -p /tmp/builds/' . \escapeshellcmd($buildId), '', $stdout, $stderr);
|
||||
|
||||
Console::execute('mkdir -p ' . \escapeshellarg('/tmp/builds/' . $buildId), '', $stdout, $stderr);
|
||||
|
||||
if ($dbForProject->getDocument('builds', $buildId)->getAttribute('status') === 'canceled') {
|
||||
Console::info('Build has been canceled');
|
||||
|
|
@ -263,23 +322,18 @@ class Builds extends Action
|
|||
// Build from template
|
||||
$templateRepositoryName = $template->getAttribute('repositoryName', '');
|
||||
$templateOwnerName = $template->getAttribute('ownerName', '');
|
||||
$templateBranch = $template->getAttribute('branch', '');
|
||||
$templateVersion = $template->getAttribute('version', '');
|
||||
|
||||
$templateRootDirectory = $template->getAttribute('rootDirectory', '');
|
||||
$templateRootDirectory = \rtrim($templateRootDirectory, '/');
|
||||
$templateRootDirectory = \ltrim($templateRootDirectory, '.');
|
||||
$templateRootDirectory = \ltrim($templateRootDirectory, '/');
|
||||
|
||||
if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateBranch)) {
|
||||
if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateVersion)) {
|
||||
// Clone template repo
|
||||
$tmpTemplateDirectory = '/tmp/builds/' . \escapeshellcmd($buildId) . '/template';
|
||||
$tmpTemplateDirectory = '/tmp/builds/' . $buildId . '/template';
|
||||
|
||||
$cloneType = GitHub::CLONE_TYPE_BRANCH;
|
||||
if(\str_starts_with($templateBranch, '0.1.')) { // Temporary fix for 1.5. In future versions this only support tag names
|
||||
$cloneType = GitHub::CLONE_TYPE_TAG;
|
||||
}
|
||||
|
||||
$gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateBranch, $cloneType, $tmpTemplateDirectory, $templateRootDirectory);
|
||||
$gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateVersion, GitHub::CLONE_TYPE_TAG, $tmpTemplateDirectory, $templateRootDirectory);
|
||||
$exit = Console::execute($gitCloneCommandForTemplate, '', $stdout, $stderr);
|
||||
|
||||
if ($exit !== 0) {
|
||||
|
|
@ -287,20 +341,20 @@ class Builds extends Action
|
|||
}
|
||||
|
||||
// Ensure directories
|
||||
Console::execute('mkdir -p ' . $tmpTemplateDirectory . '/' . $templateRootDirectory, '', $stdout, $stderr);
|
||||
Console::execute('mkdir -p ' . $tmpDirectory . '/' . $rootDirectory, '', $stdout, $stderr);
|
||||
Console::execute('mkdir -p ' . \escapeshellarg($tmpTemplateDirectory . '/' . $templateRootDirectory), '', $stdout, $stderr);
|
||||
Console::execute('mkdir -p ' . \escapeshellarg($tmpDirectory . '/' . $rootDirectory), '', $stdout, $stderr);
|
||||
|
||||
// Merge template into user repo
|
||||
Console::execute('rsync -av --exclude \'.git\' ' . $tmpTemplateDirectory . '/' . $templateRootDirectory . '/ ' . $tmpDirectory . '/' . $rootDirectory, '', $stdout, $stderr);
|
||||
Console::execute('rsync -av --exclude \'.git\' ' . \escapeshellarg($tmpTemplateDirectory . '/' . $templateRootDirectory . '/') . ' ' . \escapeshellarg($tmpDirectory . '/' . $rootDirectory), '', $stdout, $stderr);
|
||||
|
||||
// Commit and push
|
||||
$exit = Console::execute('git config --global user.email "team@appwrite.io" && git config --global user.name "Appwrite" && cd ' . $tmpDirectory . ' && git add . && git commit -m "Create \'' . \escapeshellcmd($function->getAttribute('name', '')) . '\' function" && git push origin ' . \escapeshellcmd($branchName), '', $stdout, $stderr);
|
||||
$exit = Console::execute('git config --global user.email "team@appwrite.io" && git config --global user.name "Appwrite" && cd ' . \escapeshellarg($tmpDirectory) . ' && git add . && git commit -m "Create ' . \escapeshellarg($function->getAttribute('name', '')) . ' function" && git push origin ' . \escapeshellarg($branchName), '', $stdout, $stderr);
|
||||
|
||||
if ($exit !== 0) {
|
||||
throw new \Exception('Unable to push code repository: ' . $stderr);
|
||||
}
|
||||
|
||||
$exit = Console::execute('cd ' . $tmpDirectory . ' && git rev-parse HEAD', '', $stdout, $stderr);
|
||||
$exit = Console::execute('cd ' . \escapeshellarg($tmpDirectory) . ' && git rev-parse HEAD', '', $stdout, $stderr);
|
||||
|
||||
if ($exit !== 0) {
|
||||
throw new \Exception('Unable to get vcs commit SHA: ' . $stderr);
|
||||
|
|
@ -334,7 +388,7 @@ class Builds extends Action
|
|||
);
|
||||
}
|
||||
|
||||
$tmpPath = '/tmp/builds/' . \escapeshellcmd($buildId);
|
||||
$tmpPath = '/tmp/builds/' . $buildId;
|
||||
$tmpPathFile = $tmpPath . '/code.tar.gz';
|
||||
$localDevice = new Local();
|
||||
|
||||
|
|
@ -348,21 +402,17 @@ class Builds extends Action
|
|||
throw new \Exception('Repository directory size should be less than ' . number_format($functionsSizeLimit / 1048576, 2) . ' MBs.');
|
||||
}
|
||||
|
||||
Console::execute('tar --exclude code.tar.gz -czf ' . $tmpPathFile . ' -C /tmp/builds/' . \escapeshellcmd($buildId) . '/code' . (empty($rootDirectory) ? '' : '/' . $rootDirectory) . ' .', '', $stdout, $stderr);
|
||||
$tarParamDirectory = '/tmp/builds/' . $buildId . '/code' . (empty($rootDirectory) ? '' : '/' . $rootDirectory);
|
||||
Console::execute('tar --exclude code.tar.gz -czf ' . \escapeshellarg($tmpPathFile) . ' -C ' . \escapeshellcmd($tarParamDirectory) . ' .', '', $stdout, $stderr); // TODO: Replace escapeshellcmd with escapeshellarg if we find a way that doesnt break syntax
|
||||
|
||||
$path = $deviceForFunctions->getPath($deployment->getId() . '.' . \pathinfo('code.tar.gz', PATHINFO_EXTENSION));
|
||||
$result = $localDevice->transfer($tmpPathFile, $path, $deviceForFunctions);
|
||||
$source = $deviceForFunctions->getPath($deployment->getId() . '.' . \pathinfo('code.tar.gz', PATHINFO_EXTENSION));
|
||||
$result = $localDevice->transfer($tmpPathFile, $source, $deviceForFunctions);
|
||||
|
||||
if (!$result) {
|
||||
throw new \Exception("Unable to move file");
|
||||
}
|
||||
|
||||
$deployment->setAttribute('path', $path);
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
|
||||
|
||||
Console::execute('rm -rf ' . $tmpPath, '', $stdout, $stderr);
|
||||
|
||||
$source = $path;
|
||||
Console::execute('rm -rf ' . \escapeshellarg($tmpPath), '', $stdout, $stderr);
|
||||
|
||||
$build = $dbForProject->updateDocument('builds', $build->getId(), $build->setAttribute('source', $source));
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment->setAttribute('path', $source));
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use Appwrite\Extend\Exception;
|
|||
use Executor\Executor;
|
||||
use Throwable;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\Abuse\Adapters\Database as AbuseDatabase;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Cache\Adapter\Filesystem;
|
||||
use Utopia\Cache\Cache;
|
||||
|
|
@ -95,12 +95,6 @@ class Deletes extends Action
|
|||
case DELETE_TYPE_USERS:
|
||||
$this->deleteUser($getProjectDB, $document, $project);
|
||||
break;
|
||||
case DELETE_TYPE_TEAMS:
|
||||
$this->deleteMemberships($getProjectDB, $document, $project);
|
||||
if ($project->getId() === 'console') {
|
||||
$this->deleteProjectsByTeam($dbForConsole, $getProjectDB, $deviceForFiles, $deviceForFunctions, $deviceForBuilds, $deviceForCache, $document);
|
||||
}
|
||||
break;
|
||||
case DELETE_TYPE_BUCKETS:
|
||||
$this->deleteBucket($getProjectDB, $deviceForFiles, $document, $project);
|
||||
break;
|
||||
|
|
@ -115,6 +109,9 @@ class Deletes extends Action
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case DELETE_TYPE_TEAM_PROJECTS:
|
||||
$this->deleteProjectsByTeam($dbForConsole, $getProjectDB, $document);
|
||||
break;
|
||||
case DELETE_TYPE_EXECUTIONS:
|
||||
$this->deleteExecutionLogs($project, $getProjectDB, $executionRetention);
|
||||
break;
|
||||
|
|
@ -419,7 +416,7 @@ class Deletes extends Action
|
|||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
private function deleteMemberships(callable $getProjectDB, Document $document, Document $project): void
|
||||
public function deleteMemberships(callable $getProjectDB, Document $document, Document $project): void
|
||||
{
|
||||
$dbForProject = $getProjectDB($project);
|
||||
$teamInternalId = $document->getInternalId();
|
||||
|
|
@ -447,14 +444,21 @@ class Deletes extends Action
|
|||
* @throws Conflict
|
||||
* @throws Restricted
|
||||
* @throws Structure
|
||||
* @throws Exception
|
||||
*/
|
||||
private function deleteProjectsByTeam(Database $dbForConsole, callable $getProjectDB, Device $deviceForFiles, Device $deviceForFunctions, Device $deviceForBuilds, Device $deviceForCache, Document $document): void
|
||||
private function deleteProjectsByTeam(Database $dbForConsole, callable $getProjectDB, Document $document): void
|
||||
{
|
||||
|
||||
$projects = $dbForConsole->find('projects', [
|
||||
Query::equal('teamInternalId', [$document->getInternalId()])
|
||||
]);
|
||||
|
||||
foreach ($projects as $project) {
|
||||
$deviceForFiles = getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId());
|
||||
$deviceForFunctions = getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
|
||||
$deviceForBuilds = getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId());
|
||||
$deviceForCache = getDevice(APP_STORAGE_CACHE . '/app-' . $project->getId());
|
||||
|
||||
$this->deleteProject($dbForConsole, $getProjectDB, $deviceForFiles, $deviceForFunctions, $deviceForBuilds, $deviceForCache, $project);
|
||||
$dbForConsole->deleteDocument('projects', $project->getId());
|
||||
}
|
||||
|
|
@ -489,7 +493,7 @@ class Deletes extends Action
|
|||
$projectCollectionIds = [
|
||||
...\array_keys(Config::getParam('collections', [])['projects']),
|
||||
Audit::COLLECTION,
|
||||
TimeLimit::COLLECTION,
|
||||
AbuseDatabase::COLLECTION,
|
||||
];
|
||||
|
||||
$limit = \count($projectCollectionIds) + 25;
|
||||
|
|
@ -682,7 +686,7 @@ class Deletes extends Action
|
|||
{
|
||||
$projectId = $project->getId();
|
||||
$dbForProject = $getProjectDB($project);
|
||||
$timeLimit = new TimeLimit("", 0, 1, $dbForProject);
|
||||
$timeLimit = new AbuseDatabase("", 0, 1, $dbForProject);
|
||||
$abuse = new Abuse($timeLimit);
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -286,7 +286,13 @@ class Swagger2 extends Format
|
|||
$validator = $validator->getValidator();
|
||||
}
|
||||
|
||||
switch ((!empty($validator)) ? \get_class($validator) : '') {
|
||||
$validatorClass = (!empty($validator)) ? \get_class($validator) : '';
|
||||
if($validatorClass === 'Utopia\Validator\AnyOf') {
|
||||
$validator = $param['validator']->getValidators()[0];
|
||||
$validatorClass = \get_class($validator);
|
||||
}
|
||||
|
||||
switch ($validatorClass) {
|
||||
case 'Utopia\Validator\Text':
|
||||
case 'Utopia\Database\Validator\UID':
|
||||
$node['type'] = $validator->getType();
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ class V18 extends Filter
|
|||
case 'account.deleteMfaAuthenticator':
|
||||
unset($content['otp']);
|
||||
break;
|
||||
|
||||
case 'functions.create':
|
||||
$content['templateVersion'] = $content['templateBranch'];
|
||||
unset($content['templateBranch']);
|
||||
break;
|
||||
}
|
||||
|
||||
return $content;
|
||||
|
|
|
|||
|
|
@ -98,9 +98,9 @@ class TemplateFunction extends Model
|
|||
'default' => '',
|
||||
'example' => 'appwrite',
|
||||
])
|
||||
->addRule('providerBranch', [
|
||||
->addRule('providerVersion', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'VCS (Version Control System) branch name',
|
||||
'description' => 'VCS (Version Control System) branch version (tag).',
|
||||
'default' => '',
|
||||
'example' => 'main',
|
||||
])
|
||||
|
|
|
|||
|
|
@ -219,7 +219,8 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
// Schedule execution for the future
|
||||
\date_default_timezone_set('UTC');
|
||||
$futureTime = (new \DateTime())->add(new \DateInterval('PT10S'));
|
||||
$futureTime = (new \DateTime())->add(new \DateInterval('PT2M'));
|
||||
$futureTime->setTime($futureTime->format('H'), $futureTime->format('i'), 0, 0);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -236,7 +237,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
$executionId = $execution['body']['$id'];
|
||||
|
||||
sleep(10);
|
||||
sleep(60 + 60 + 15); // up to 1 minute round up, 1 minute schedule postpone, 15s cold start safety
|
||||
|
||||
$start = \microtime(true);
|
||||
while (true) {
|
||||
|
|
@ -250,8 +251,8 @@ class FunctionsCustomClientTest extends Scope
|
|||
break;
|
||||
}
|
||||
|
||||
if (\microtime(true) - $start > 5) {
|
||||
$this->fail('Execution did not complete within 5 seconds of schedule');
|
||||
if (\microtime(true) - $start > 10) {
|
||||
$this->fail('Scheduled execution did not complete with status ' . $execution['body']['status'] . ': ' . \json_encode($execution));
|
||||
}
|
||||
|
||||
usleep(500000); // 0.5 seconds
|
||||
|
|
@ -267,7 +268,6 @@ class FunctionsCustomClientTest extends Scope
|
|||
/* Test for FAILURE */
|
||||
|
||||
// Schedule synchronous execution
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
|
@ -278,6 +278,41 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
$this->assertEquals(400, $execution['headers']['status-code']);
|
||||
|
||||
// Execution with seconds precision
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'async' => true,
|
||||
'scheduledAt' => (new \DateTime("2100-12-08 16:12:02"))->format(\DateTime::ATOM)
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $execution['headers']['status-code']);
|
||||
|
||||
// Execution with milliseconds precision
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'async' => true,
|
||||
'scheduledAt' => (new \DateTime("2100-12-08 16:12:02.255"))->format(\DateTime::ATOM)
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $execution['headers']['status-code']);
|
||||
|
||||
// Execution too soon
|
||||
$futureTime = (new \DateTime())->add(new \DateInterval('PT1M'));
|
||||
$futureTime->setTime($futureTime->format('H'), $futureTime->format('i'), 0, 0);
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $function['body']['$id'] . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'async' => true,
|
||||
'scheduledAt' => $futureTime->format(\DateTime::ATOM),
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $execution['headers']['status-code']);
|
||||
|
||||
// Cleanup : Delete function
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $function['body']['$id'], [
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -848,6 +883,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
$this->assertEquals(200, $templates['headers']['status-code']);
|
||||
$this->assertGreaterThan(0, $templates['body']['total']);
|
||||
$this->assertIsArray($templates['body']['templates']);
|
||||
|
||||
$this->assertArrayHasKey('runtimes', $templates['body']['templates'][0]);
|
||||
$this->assertArrayHasKey('useCases', $templates['body']['templates'][0]);
|
||||
for ($i = 0; $i < 25; $i++) {
|
||||
|
|
|
|||
|
|
@ -439,6 +439,135 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals('cli', $functionDetails['body']['type']);
|
||||
}
|
||||
|
||||
public function testCreateDeploymentFromTemplate()
|
||||
{
|
||||
$runtimeName = 'php-8.0';
|
||||
|
||||
// Fetch starter template (used to create function later)
|
||||
$template = $this->client->call(Client::METHOD_GET, '/functions/templates/starter', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $template['headers']['status-code']);
|
||||
|
||||
$entrypoint = null;
|
||||
$rootDirectory = null;
|
||||
$commands = null;
|
||||
foreach($template['body']['runtimes'] as $runtime) {
|
||||
if($runtime["name"] !== $runtimeName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$entrypoint = $runtime["entrypoint"];
|
||||
$rootDirectory = $runtime["providerRootDirectory"];
|
||||
$commands = $runtime["commands"];
|
||||
break;
|
||||
}
|
||||
|
||||
$this->assertNotNull($entrypoint);
|
||||
|
||||
/**
|
||||
* If below test ever starts failing, it means temaplate used in
|
||||
* this test now has some variables. This test currently doesnt test variables.
|
||||
* Remove bellow assertion and update test to crete variable,
|
||||
* and ensure variable works as expected in execution.
|
||||
*/
|
||||
$this->assertEmpty($template['body']['variables']);
|
||||
|
||||
// Create function using settings from template.
|
||||
// Deployment is automatically created from template inside endpoint
|
||||
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $this->getHeaders()), [
|
||||
'functionId' => ID::unique(),
|
||||
'name' => $template['body']['name'],
|
||||
'runtime' => $runtimeName,
|
||||
'execute' => $template['body']['permissions'],
|
||||
'entrypoint' => $entrypoint,
|
||||
'events' => $template['body']['events'],
|
||||
'schedule' => $template['body']['cron'],
|
||||
'timeout' => $template['body']['timeout'],
|
||||
'commands' => $commands,
|
||||
'scopes' => $template['body']['scopes'],
|
||||
'templateRepository' => $template['body']['providerRepositoryId'],
|
||||
'templateOwner' => $template['body']['providerOwner'],
|
||||
'templateRootDirectory' => $rootDirectory,
|
||||
'templateVersion' => $template['body']['providerVersion'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
$this->assertNotEmpty($function['body']['$id']);
|
||||
|
||||
$functionId = $function['body']['$id'];
|
||||
|
||||
// List deployments so we can await deployment build
|
||||
$deployments = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], []);
|
||||
|
||||
$this->assertEquals(200, $deployments['headers']['status-code']);
|
||||
$this->assertEquals(1, $deployments['body']['total']);
|
||||
$this->assertNotEmpty($deployments['body']['deployments'][0]['$id']);
|
||||
|
||||
$deploymentId = $deployments['body']['deployments'][0]['$id'];
|
||||
|
||||
// Wait for deployment build to finish
|
||||
// Deployment is automatically activated
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
|
||||
|
||||
$function = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
$this->assertEquals($deploymentId, $function['body']['deployment']);
|
||||
|
||||
// Execute function to ensure starter code is used
|
||||
// Also tests if dynamic keys works as expected
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'path' => '/ping'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||
$this->assertEquals("completed", $execution['body']['status']);
|
||||
$this->assertEquals(200, $execution['body']['responseStatusCode']);
|
||||
$this->assertEquals("Pong", $execution['body']['responseBody']);
|
||||
$this->assertEmpty($execution['body']['errors']);
|
||||
|
||||
// Get users to ensure execution logged correct total users
|
||||
$users = $this->client->call(Client::METHOD_GET, '/users', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(200, $users['headers']['status-code']);
|
||||
$this->assertIsInt($users['body']['total']);
|
||||
|
||||
$totalusers = $users['body']['total'];
|
||||
|
||||
$this->assertStringContainsString("Total users: " . $totalusers, $execution['body']['logs']);
|
||||
|
||||
// Cleanup : Delete function
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], []);
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testUpdate
|
||||
*/
|
||||
|
|
@ -468,6 +597,37 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
$this->awaitDeploymentIsBuilt($data['functionId'], $deploymentId);
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/deployments', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
|
||||
'activate' => 'false'
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
$this->assertNotEmpty($deployment['body']['$id']);
|
||||
|
||||
$deploymentIdInactive = $deployment['body']['$id'];
|
||||
|
||||
$this->awaitDeploymentIsBuilt($data['functionId'], $deploymentIdInactive);
|
||||
|
||||
$function = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
$this->assertEquals($deploymentId, $function['body']['deployment']);
|
||||
$this->assertNotEquals($deploymentIdInactive, $function['body']['deployment']);
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/deployments/' . $deploymentIdInactive, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(204, $deployment['headers']['status-code']);
|
||||
|
||||
return array_merge($data, ['deploymentId' => $deploymentId]);
|
||||
}
|
||||
|
||||
|
|
@ -1126,14 +1286,15 @@ class FunctionsCustomServerTest extends Scope
|
|||
*/
|
||||
public function testDeleteScheduledExecution($data): array
|
||||
{
|
||||
$futureTime = (new \DateTime())->add(new \DateInterval('PT10H'))->format('Y-m-d H:i:s');
|
||||
$futureTime = (new \DateTime())->add(new \DateInterval('PT10H'));
|
||||
$futureTime->setTime($futureTime->format('H'), $futureTime->format('i'), 0, 0);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'async' => true,
|
||||
'scheduledAt' => $futureTime,
|
||||
'scheduledAt' => $futureTime->format('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
|
|
@ -1268,7 +1429,11 @@ class FunctionsCustomServerTest extends Scope
|
|||
$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->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::equal('trigger', ['http'])->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals($executions['headers']['status-code'], 200);
|
||||
$this->assertEquals($executions['body']['total'], 1);
|
||||
|
|
@ -1284,17 +1449,39 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals($executions['body']['executions'][0]['logs'], '');
|
||||
$this->assertStringContainsString('timed out', $executions['body']['executions'][0]['errors']);
|
||||
|
||||
sleep(75); // Wait for scheduled execution to be created and time out
|
||||
$start = \microtime(true);
|
||||
while (true) {
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::equal('trigger', ['schedule'])->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$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(200, $executions['headers']['status-code']);
|
||||
|
||||
if (\count($executions['body']['executions']) > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 0s would mean instant execution
|
||||
// +60 seconds, maximum possible waiting time before next minute
|
||||
// +10 seconds, maximum update interval time
|
||||
// +60 seconds, possible overlap between update and schedule tick
|
||||
// +10 seconds, maximum execution time including cold-start
|
||||
// Result: We allow maximum
|
||||
if (\microtime(true) - $start > 140) {
|
||||
$this->fail('Execution did not create within 140 seconds of schedule: ' . \json_encode($executions));
|
||||
}
|
||||
|
||||
usleep(1000000); // 1 second
|
||||
}
|
||||
|
||||
$this->assertEquals(200, $executions['headers']['status-code']);
|
||||
$this->assertCount(2, $executions['body']['executions']);
|
||||
$this->assertIsArray($executions['body']['executions']);
|
||||
$this->assertEquals($executions['body']['executions'][1]['trigger'], 'schedule');
|
||||
$this->assertGreaterThanOrEqual(1, \count($executions['body']['executions']));
|
||||
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'schedule');
|
||||
|
||||
// Cleanup : Delete function
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
|
||||
|
|
|
|||
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
namespace Tests\E2E\Services\Teams;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideServer;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
|
||||
class TeamsCustomServerTest extends Scope
|
||||
{
|
||||
|
|
@ -12,4 +15,96 @@ class TeamsCustomServerTest extends Scope
|
|||
use TeamsBaseServer;
|
||||
use ProjectCustom;
|
||||
use SideServer;
|
||||
|
||||
public function testMembershipDeletedWhenTeamDeleted(): array
|
||||
{
|
||||
/* 1. Create Team */
|
||||
$response = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'teamId' => ID::unique(),
|
||||
'name' => 'Demo'
|
||||
]);
|
||||
|
||||
$teamUid = $response['body']['$id'];
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertEquals('Demo', $response['body']['name']);
|
||||
$this->assertGreaterThan(-1, $response['body']['total']);
|
||||
$this->assertIsInt($response['body']['total']);
|
||||
$this->assertArrayHasKey('prefs', $response['body']);
|
||||
$dateValidator = new DatetimeValidator();
|
||||
$this->assertEquals(true, $dateValidator->isValid($response['body']['$createdAt']));
|
||||
|
||||
/* 2. Create user. */
|
||||
$email = uniqid() . 'friend@localhost.test';
|
||||
$name = 'Friend User';
|
||||
$password = 'password';
|
||||
$userId = ID::unique();
|
||||
|
||||
// Create a user account before we create a invite so we can check if the user has permissions when it shouldn't
|
||||
$user = $this->client->call(Client::METHOD_POST, '/account', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'userId' => $userId,
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
'name' => $name,
|
||||
], false);
|
||||
|
||||
$this->assertEquals(201, $user['headers']['status-code']);
|
||||
|
||||
/* 3. Add membership to user. */
|
||||
$response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'userId' => $userId,
|
||||
'roles' => ['admin', 'editor'],
|
||||
'url' => 'http://localhost:5000/join-us#title'
|
||||
]);
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
/* 4. Ensure user is a member. */
|
||||
$response = $this->client->call(Client::METHOD_GET, '/users/' . $userId . '/memberships', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals($teamUid, $response['body']['memberships'][0]['teamId']);
|
||||
|
||||
/* 5. Delete Team */
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
$this->assertEmpty($response['body']);
|
||||
|
||||
/* 6. Ensure Team got deleted */
|
||||
$response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
/* 7. Ensure memberships got removed from the user. */
|
||||
$response = $this->client->call(Client::METHOD_GET, '/users/' . $userId . '/memberships', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEmpty($response['body']['memberships']);
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue