Merge branch 'main' into feat-improve-migration-validations

This commit is contained in:
Bradley Schofield
2023-11-02 10:48:38 +00:00
207 changed files with 59824 additions and 3538 deletions
+1 -1
View File
@@ -91,7 +91,7 @@ _APP_GRAPHQL_MAX_DEPTH=3
_APP_DOCKER_HUB_USERNAME=
_APP_DOCKER_HUB_PASSWORD=
_APP_VCS_GITHUB_APP_NAME=
_APP_VCS_GITHUB_PRIVATE_KEY=""
_APP_VCS_GITHUB_PRIVATE_KEY=disabled
_APP_VCS_GITHUB_APP_ID=
_APP_VCS_GITHUB_CLIENT_ID=
_APP_VCS_GITHUB_CLIENT_SECRET=
-1
View File
@@ -16,7 +16,6 @@ jobs:
with:
fetch-depth: 2
submodules: recursive
ref: cl-1.4.x
- name: Login to Docker Hub
uses: docker/login-action@v2
+104 -42
View File
@@ -4,57 +4,119 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
IMAGE: appwrite-dev
CACHE_KEY: appwrite-dev-${{ github.event.pull_request.head.sha }}
on: [pull_request]
jobs:
tests:
name: Unit & E2E
setup:
name: Setup & Build Appwrite Image
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build Appwrite
uses: docker/build-push-action@v3
with:
context: .
push: false
tags: ${{ env.IMAGE }}
load: true
cache-from: type=gha
cache-to: type=gha,mode=max
outputs: type=docker,dest=/tmp/${{ env.IMAGE }}.tar
build-args: |
DEBUG=false
TESTING=true
VERSION=dev
- name: Cache Docker Image
uses: actions/cache@v3
with:
key: ${{ env.CACHE_KEY }}
path: /tmp/${{ env.IMAGE }}.tar
unit_test:
name: Unit Test
runs-on: ubuntu-latest
needs: setup
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# Fetch submodules
submodules: recursive
- name: checkout
uses: actions/checkout@v2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
- name: Load Cache
uses: actions/cache@v3
with:
key: ${{ env.CACHE_KEY }}
path: /tmp/${{ env.IMAGE }}.tar
fail-on-cache-miss: true
# This is a separate action that sets up buildx runner
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Load and Start Appwrite
run: |
docker load --input /tmp/${{ env.IMAGE }}.tar
docker compose up -d
sleep 10
- name: Build Appwrite
uses: docker/build-push-action@v3
with:
context: .
push: false
tags: appwrite-dev
load: true
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
DEBUG=false
TESTING=true
VERSION=dev
- name: Doctor
run: docker compose exec -T appwrite doctor
- name: Start Appwrite
run: |
docker compose up -d
sleep 30
- name: Environment Variables
run: docker compose exec -T appwrite vars
- name: Doctor
run: |
docker compose logs appwrite
docker compose exec -T appwrite doctor
- name: Run Unit Tests
run: docker compose exec appwrite test /usr/src/code/tests/unit
- name: Environment Variables
run: docker compose exec -T appwrite vars
e2e_test:
name: E2E Test
runs-on: ubuntu-latest
needs: setup
strategy:
fail-fast: false
matrix:
service:
[
Account,
Avatars,
Console,
Databases,
Functions,
GraphQL,
Health,
Locale,
Projects,
Realtime,
Storage,
Teams,
Users,
Webhooks,
VCS,
]
- name: Run Tests
run: docker compose exec -T appwrite test --debug
steps:
- name: checkout
uses: actions/checkout@v3
- name: Load Cache
uses: actions/cache@v3
with:
key: ${{ env.CACHE_KEY }}
path: /tmp/${{ env.IMAGE }}.tar
fail-on-cache-miss: true
- name: Load and Start Appwrite
run: |
docker load --input /tmp/${{ env.IMAGE }}.tar
docker compose up -d
sleep 10
- name: Run ${{matrix.service}} Tests
run: docker compose exec -T appwrite test /usr/src/code/tests/e2e/Services/${{matrix.service}} --debug
+1 -1
View File
@@ -1,4 +1,4 @@
[submodule "app/console"]
path = app/console
url = https://github.com/appwrite/console
branch = 3.2.1
branch = 3.2.5
+1 -1
View File
@@ -8,7 +8,7 @@ tasks:
command: |
docker run --rm --interactive --tty \
--volume $PWD:/app \
composer update \
composer install \
--ignore-platform-reqs \
--optimize-autoloader \
--no-plugins \
+55
View File
@@ -1,3 +1,58 @@
# Version 1.4.9
## Bug fixes
* Fix 400 error on function domain execution in [#7059](https://github.com/appwrite/appwrite/pull/7059)
# Version 1.4.8
## Notable changes
* Fix certificate emails and add support for variables in email template subject in [#6495](https://github.com/appwrite/appwrite/)pull/6495
* Bump console to version 3.2.5 in [#7027](https://github.com/appwrite/appwrite/pull/7027)
* Bump utopia database and storage versions in [#7002](https://github.com/appwrite/appwrite/pull/7002)
## Bug fixes
* Fixes cookie headers not being passed properly by router in [#7024](https://github.com/appwrite/appwrite/pull/7024)
* Fix permission problem in deletes worker in [#7013](https://github.com/appwrite/appwrite/pull/7013)
## Miscellaneous
* Improve error handling in the realtime service in [#6998](https://github.com/appwrite/appwrite/pull/6998)
* Update the error code for unsupported protocol in [#7006](https://github.com/appwrite/appwrite/pull/7006)
* Improve CI tests by executing them in parallel in [#6198](https://github.com/appwrite/appwrite/pull/6198)
* Update README.md to add links to orchestration tools in [#7011](https://github.com/appwrite/appwrite/pull/7011)
* Update gitpod setup to install instead of update dependencies in [#6938](https://github.com/appwrite/appwrite/pull/6938)
* Remove analytics from install script in [#7017](https://github.com/appwrite/appwrite/pull/7017)
* Improve database logging in [#7003](https://github.com/appwrite/appwrite/pull/7003)
* Add VCS tests in [#6894](https://github.com/appwrite/appwrite/pull/6894)
* Improve error messages in [#6487](https://github.com/appwrite/appwrite/pull/6487)
* Add command to delete orphaned projects in [#7015](https://github.com/appwrite/appwrite/pull/7015)
# Version 1.4.7
## Fixes
- Fix missing body in async function execution in [#6988](https://github.com/appwrite/appwrite/pull/6988)
# Version 1.4.6
## Changes
- Bump console to version 3.2.3 in [#6947](https://github.com/appwrite/appwrite/pull/6947)
- New health endpoints in [#6319](https://github.com/appwrite/appwrite/pull/6319)
- 30 second sync executions timeout in [#6370](https://github.com/appwrite/appwrite/pull/6370)
- Feat db per worker in [#6888](https://github.com/appwrite/appwrite/pull/6888)
- Feat: Dart 3.1 support in [#6936](https://github.com/appwrite/appwrite/pull/6936)
- chore: remove resque library and update health check endpoints in [#6946](https://github.com/appwrite/appwrite/pull/6946)
- Refactor workers in [#6928](https://github.com/appwrite/appwrite/pull/6928)
## Fixes
- Fix realtime deletes in [#6897](https://github.com/appwrite/appwrite/pull/6897)
- Update teamInternalId when updating project team in [#6898](https://github.com/appwrite/appwrite/pull/6898)
- Fix: spanish translations (emails) in [#5290](https://github.com/appwrite/appwrite/pull/5290)
- chore: fix spec links in [#6434](https://github.com/appwrite/appwrite/pull/6434)
- Delegate custom deletes in [#6934](https://github.com/appwrite/appwrite/pull/6934)
# Version 1.4.5
## Changes
+2 -4
View File
@@ -89,7 +89,7 @@ $ git push origin [name_of_your_new_branch]
To set up a working **development environment**, just fork the project git repository and install the backend and frontend dependencies using the proper package manager and create run the docker-compose stack.
> If you just want to install Appwrite for day-to-day use and not as a contributor, you can reference the [installation guide](https://github.com/appwrite/appwrite#installation), the [getting started guide](https://appwrite.io/docs/getting-started-for-web), or the main [README](README.md) file.
> If you just want to install Appwrite for day-to-day use and not as a contributor, you can reference the [installation guide](https://github.com/appwrite/appwrite#installation), the [getting started guide](https://appwrite.io/docs/quick-starts), or the main [README](README.md) file.
```bash
git clone git@github.com:[YOUR_FORK_HERE]/appwrite.git
@@ -206,7 +206,6 @@ Appwrite's current structure is a combination of both [Monolithic](https://en.wi
│ ├── Network
│ ├── OpenSSL
│ ├── Promises
│ ├── Resque
│ ├── Specification
│ ├── Task
│ ├── Template
@@ -251,7 +250,6 @@ Appwrite stack is a combination of a variety of open-source technologies and too
- Imagemagick - for manipulating and managing image media files.
- Webp - for better compression of images on supporting clients.
- SMTP - for sending email messages and alerts.
- Resque - for managing data queues and scheduled tasks over a Redis server.
## Package Managers
@@ -456,7 +454,7 @@ From time to time, our team will add tutorials that will help contributors find
- [Adding Support for a New OAuth2 Provider](./docs/tutorials/add-oauth2-provider.md)
- [Appwrite Environment Variables](./docs/tutorials/add-environment-variable.md)
- [Running in Production](https://appwrite.io/docs/production)
- [Running in Production](https://appwrite.io/docs/advanced/self-hosting/production)
- [Adding Storage Adapter](./docs/tutorials/add-storage-adapter.md)
## Other Ways to Help
+1
View File
@@ -101,6 +101,7 @@ RUN chmod +x /usr/local/bin/hamster && \
chmod +x /usr/local/bin/volume-sync && \
chmod +x /usr/local/bin/patch-delete-schedule-updated-at-attribute && \
chmod +x /usr/local/bin/patch-delete-project-collections && \
chmod +x /usr/local/bin/delete-orphaned-projects && \
chmod +x /usr/local/bin/clear-card-cache && \
chmod +x /usr/local/bin/calc-users-stats && \
chmod +x /usr/local/bin/calc-tier-stats
+3 -3
View File
@@ -66,7 +66,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:1.4.5
appwrite/appwrite:1.4.9
```
### Windows
@@ -78,7 +78,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^
appwrite/appwrite:1.4.5
appwrite/appwrite:1.4.9
```
#### PowerShell
@@ -88,7 +88,7 @@ docker run -it --rm `
--volume /var/run/docker.sock:/var/run/docker.sock `
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
--entrypoint="install" `
appwrite/appwrite:1.4.5
appwrite/appwrite:1.4.9
```
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
+4 -4
View File
@@ -65,7 +65,7 @@ Table of Contents:
## Installation
Appwrite is designed to run in a containerized environment. Running your server is as easy as running one command from your terminal. You can either run Appwrite on your localhost using docker-compose or on any other container orchestration tool, such as Kubernetes, Docker Swarm, or Rancher.
Appwrite is designed to run in a containerized environment. Running your server is as easy as running one command from your terminal. You can either run Appwrite on your localhost using docker-compose or on any other container orchestration tool, such as [Kubernetes](https://kubernetes.io/docs/home/), [Docker Swarm](https://docs.docker.com/engine/swarm/), or [Rancher](https://rancher.com/docs/).
The easiest way to start running your Appwrite server is by running our docker-compose file. Before running the installation command, make sure you have [Docker](https://www.docker.com/products/docker-desktop) installed on your machine:
@@ -76,7 +76,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:1.4.5
appwrite/appwrite:1.4.9
```
### Windows
@@ -88,7 +88,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^
appwrite/appwrite:1.4.5
appwrite/appwrite:1.4.9
```
#### PowerShell
@@ -98,7 +98,7 @@ docker run -it --rm `
--volume /var/run/docker.sock:/var/run/docker.sock `
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
--entrypoint="install" `
appwrite/appwrite:1.4.5
appwrite/appwrite:1.4.9
```
Once the Docker installation is complete, go to http://localhost to access the Appwrite console from your browser. Please note that on non-Linux native hosts, the server might take a few minutes to start after completing the installation.
+24 -8
View File
@@ -3,6 +3,8 @@
require_once __DIR__ . '/init.php';
require_once __DIR__ . '/controllers/general.php';
use Appwrite\Event\Delete;
use Appwrite\Event\Certificate;
use Appwrite\Event\Func;
use Appwrite\Platform\Appwrite;
use Utopia\CLI\CLI;
@@ -17,6 +19,7 @@ use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Logger\Log;
use Utopia\Pools\Group;
use Utopia\Queue\Connection;
use Utopia\Registry\Registry;
Authorization::disable();
@@ -58,7 +61,11 @@ CLI::setResource('dbForConsole', function ($pools, $cache) {
->getResource();
$dbForConsole = new Database($dbAdapter, $cache);
$dbForConsole->setNamespace('_console');
$dbForConsole
->setNamespace('_console')
->setMetadata('host', \gethostname())
->setMetadata('project', 'console');
// Ensure tables exist
$collections = Config::getParam('collections', [])['console'];
@@ -86,7 +93,7 @@ CLI::setResource('dbForConsole', function ($pools, $cache) {
CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole, $cache) {
$databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools
$getProjectDB = function (Document $project) use ($pools, $dbForConsole, $cache, &$databases) {
return function (Document $project) use ($pools, $dbForConsole, $cache, &$databases) {
if ($project->isEmpty() || $project->getId() === 'console') {
return $dbForConsole;
}
@@ -108,12 +115,13 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
$databases[$databaseName] = $database;
$database->setNamespace('_' . $project->getInternalId());
$database
->setNamespace('_' . $project->getInternalId())
->setMetadata('host', \gethostname())
->setMetadata('project', $project->getId());
return $database;
};
return $getProjectDB;
}, ['pools', 'dbForConsole', 'cache']);
CLI::setResource('influxdb', function (Registry $register) {
@@ -140,10 +148,18 @@ CLI::setResource('influxdb', function (Registry $register) {
return $database;
}, ['register']);
CLI::setResource('queueForFunctions', function (Group $pools) {
return new Func($pools->get('queue')->pop()->getResource());
CLI::setResource('queue', function (Group $pools) {
return $pools->get('queue')->pop()->getResource();
}, ['pools']);
CLI::setResource('queueForFunctions', function (Connection $queue) {
return new Func($queue);
}, ['queue']);
CLI::setResource('queueForDeletes', function (Connection $queue) {
return new Delete($queue);
}, ['queue']);
CLI::setResource('queueForCertificates', function (Connection $queue) {
return new Certificate($queue);
}, ['queue']);
CLI::setResource('logError', function (Registry $register) {
return function (Throwable $error, string $namespace, string $action) use ($register) {
$logger = $register->get('logger');
+29 -8
View File
@@ -86,7 +86,7 @@ return [
Exception::GENERAL_PROTOCOL_UNSUPPORTED => [
'name' => Exception::GENERAL_PROTOCOL_UNSUPPORTED,
'description' => 'The request cannot be fulfilled with the current protocol. Please check the value of the _APP_OPTIONS_FORCE_HTTPS environment variable.',
'code' => 500,
'code' => 426,
],
Exception::GENERAL_CODES_DISABLED => [
'name' => Exception::GENERAL_CODES_DISABLED,
@@ -355,7 +355,7 @@ return [
],
Exception::STORAGE_BUCKET_ALREADY_EXISTS => [
'name' => Exception::STORAGE_BUCKET_ALREADY_EXISTS,
'description' => 'A storage bucket with the requested ID already exists. Try again with a different ID or use "unique()" to generate a unique ID.',
'description' => 'A storage bucket with the requested ID already exists. Try again with a different ID or use ID.unique() to generate a unique ID.',
'code' => 409,
],
Exception::STORAGE_BUCKET_NOT_FOUND => [
@@ -460,12 +460,16 @@ return [
'description' => 'Database not found',
'code' => 404
],
Exception::DATABASE_ALREADY_EXISTS => [
'name' => Exception::DATABASE_ALREADY_EXISTS,
'description' => 'Database already exists',
'code' => 409
],
Exception::DATABASE_TIMEOUT => [
'name' => Exception::DATABASE_TIMEOUT,
'description' => 'Database timed out. Try adjusting your queries or adding an index.',
'code' => 408
],
/** Collections */
Exception::COLLECTION_NOT_FOUND => [
@@ -475,7 +479,7 @@ return [
],
Exception::COLLECTION_ALREADY_EXISTS => [
'name' => Exception::COLLECTION_ALREADY_EXISTS,
'description' => 'A collection with the requested ID already exists. Try again with a different ID or use "unique()" to generate a unique ID.',
'description' => 'A collection with the requested ID already exists. Try again with a different ID or use ID.unique() to generate a unique ID.',
'code' => 409,
],
Exception::COLLECTION_LIMIT_EXCEEDED => [
@@ -507,7 +511,7 @@ return [
],
Exception::DOCUMENT_ALREADY_EXISTS => [
'name' => Exception::DOCUMENT_ALREADY_EXISTS,
'description' => 'Document with the requested ID already exists. Try again with a different ID or use "unique()" to generate a unique ID.',
'description' => 'Document with the requested ID already exists. Try again with a different ID or use ID.unique() to generate a unique ID.',
'code' => 409,
],
Exception::DOCUMENT_UPDATE_CONFLICT => [
@@ -549,7 +553,7 @@ return [
],
Exception::ATTRIBUTE_ALREADY_EXISTS => [
'name' => Exception::ATTRIBUTE_ALREADY_EXISTS,
'description' => 'Attribute with the requested ID already exists. Try again with a different ID or use "unique()" to generate a unique ID.',
'description' => 'Attribute with the requested key already exists. Attribute keys must be unique, try again with a different key.',
'code' => 409,
],
Exception::ATTRIBUTE_LIMIT_EXCEEDED => [
@@ -581,7 +585,7 @@ return [
],
Exception::INDEX_ALREADY_EXISTS => [
'name' => Exception::INDEX_ALREADY_EXISTS,
'description' => 'Index with the requested ID already exists. Try again with a different ID or use "unique()" to generate a unique ID.',
'description' => 'Index with the requested key already exists. Try again with a different key.',
'code' => 409,
],
Exception::INDEX_INVALID => [
@@ -598,7 +602,7 @@ return [
],
Exception::PROJECT_ALREADY_EXISTS => [
'name' => Exception::PROJECT_ALREADY_EXISTS,
'description' => 'Project with the requested ID already exists. Try again with a different ID or use "unique()" to generate a unique ID.',
'description' => 'Project with the requested ID already exists. Try again with a different ID or use ID.unique() to generate a unique ID.',
'code' => 409,
],
Exception::PROJECT_UNKNOWN => [
@@ -728,6 +732,23 @@ return [
'description' => 'Migration is already in progress. You can check the status of the migration in your Appwrite Console\'s "Settings" > "Migrations".',
'code' => 409,
],
/** Realtime */
Exception::REALTIME_MESSAGE_FORMAT_INVALID => [
'name' => Exception::REALTIME_MESSAGE_FORMAT_INVALID,
'description' => 'Message format is not valid.',
'code' => 1003,
],
Exception::REALTIME_POLICY_VIOLATION => [
'name' => Exception::REALTIME_POLICY_VIOLATION,
'description' => 'Policy violation.',
'code' => 1008,
],
Exception::REALTIME_TOO_MANY_MESSAGES => [
'name' => Exception::REALTIME_TOO_MANY_MESSAGES,
'description' => 'Too many messages.',
'code' => 1013,
],
Exception::MIGRATION_PROVIDER_ERROR => [
'name' => Exception::MIGRATION_PROVIDER_ERROR,
'description' => 'An error occurred on the provider\'s side. Please try again later.',
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
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
+105 -117
View File
@@ -76,8 +76,9 @@ App::post('/v1/account')
->inject('user')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, string $email, string $password, string $name, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents) {
$email = \strtolower($email);
if ('console' === $project->getId()) {
$whitelistEmails = $project->getAttribute('authWhitelistEmails');
@@ -156,7 +157,7 @@ App::post('/v1/account')
Authorization::setRole(Role::user($user->getId())->toString());
Authorization::setRole(Role::users()->toString());
$events->setParam('userId', $user->getId());
$queueForEvents->setParam('userId', $user->getId());
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -193,8 +194,8 @@ App::post('/v1/account/sessions/email')
->inject('project')
->inject('locale')
->inject('geodb')
->inject('events')
->action(function (string $email, string $password, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $events) {
->inject('queueForEvents')
->action(function (string $email, string $password, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents) {
$email = \strtolower($email);
$protocol = $request->getProtocol();
@@ -276,7 +277,7 @@ App::post('/v1/account/sessions/email')
->setAttribute('expire', $expire)
;
$events
$queueForEvents
->setParam('userId', $user->getId())
->setParam('sessionId', $session->getId())
;
@@ -440,8 +441,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
->inject('user')
->inject('dbForProject')
->inject('geodb')
->inject('events')
->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Event $events) use ($oauthDefaultSuccess) {
->inject('queueForEvents')
->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Event $queueForEvents) use ($oauthDefaultSuccess) {
$protocol = $request->getProtocol();
$callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
@@ -758,7 +759,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$session->setAttribute('expire', $expire);
$events
$queueForEvents
->setParam('userId', $user->getId())
->setParam('sessionId', $session->getId())
->setPayload($response->output($session, Response::MODEL_SESSION))
@@ -897,9 +898,9 @@ App::post('/v1/account/sessions/magic-url')
->inject('project')
->inject('dbForProject')
->inject('locale')
->inject('events')
->inject('mails')
->action(function (string $userId, string $email, string $url, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $events, Mail $mails) {
->inject('queueForEvents')
->inject('queueForMails')
->action(function (string $userId, string $email, string $url, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails) {
if (empty(App::getEnv('_APP_SMTP_HOST'))) {
throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP disabled');
@@ -999,7 +1000,12 @@ App::post('/v1/account/sessions/magic-url')
$customTemplate = $project->getAttribute('templates', [])['email.magicSession-' . $locale->default] ?? [];
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
$message->setParam('{{body}}', $body);
$message
->setParam('{{body}}', $body)
->setParam('{{hello}}', $locale->getText("emails.magicSession.hello"))
->setParam('{{footer}}', $locale->getText("emails.magicSession.footer"))
->setParam('{{thanks}}', $locale->getText("emails.magicSession.thanks"))
->setParam('{{signature}}', $locale->getText("emails.magicSession.signature"));
$body = $message->render();
$smtp = $project->getAttribute('smtp', []);
@@ -1020,7 +1026,7 @@ App::post('/v1/account/sessions/magic-url')
$replyTo = $smtp['replyTo'];
}
$mails
$queueForMails
->setSmtpHost($smtp['host'] ?? '')
->setSmtpPort($smtp['port'] ?? '')
->setSmtpUsername($smtp['username'] ?? '')
@@ -1042,23 +1048,14 @@ App::post('/v1/account/sessions/magic-url')
$subject = $customTemplate['subject'] ?? $subject;
}
$mails
$queueForMails
->setSmtpReplyTo($replyTo)
->setSmtpSenderEmail($senderEmail)
->setSmtpSenderName($senderName);
}
$emailVariables = [
'subject' => $subject,
'hello' => $locale->getText("emails.magicSession.hello"),
'body' => $body,
'footer' => $locale->getText("emails.magicSession.footer"),
'thanks' => $locale->getText("emails.magicSession.thanks"),
'signature' => $locale->getText("emails.magicSession.signature"),
'direction' => $locale->getText('settings.direction'),
'bg-body' => '#f7f7f7',
'bg-content' => '#ffffff',
'text-content' => '#000000',
/* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */
'user' => '',
'team' => '',
@@ -1066,14 +1063,14 @@ App::post('/v1/account/sessions/magic-url')
'redirect' => $url
];
$mails
$queueForMails
->setSubject($subject)
->setBody($body)
->setVariables($emailVariables)
->setRecipient($email)
->trigger();
$events->setPayload(
$queueForEvents->setPayload(
$response->output(
$token->setAttribute('secret', $loginSecret),
Response::MODEL_TOKEN
@@ -1117,8 +1114,8 @@ App::put('/v1/account/sessions/magic-url')
->inject('project')
->inject('locale')
->inject('geodb')
->inject('events')
->action(function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents) {
/** @var Utopia\Database\Document $user */
@@ -1186,7 +1183,7 @@ App::put('/v1/account/sessions/magic-url')
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed saving user to DB');
}
$events
$queueForEvents
->setParam('userId', $user->getId())
->setParam('sessionId', $session->getId());
@@ -1235,10 +1232,10 @@ App::post('/v1/account/sessions/phone')
->inject('user')
->inject('project')
->inject('dbForProject')
->inject('events')
->inject('messaging')
->inject('queueForEvents')
->inject('queueForMessaging')
->inject('locale')
->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $events, EventPhone $messaging, Locale $locale) {
->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents, EventPhone $queueForMessaging, Locale $locale) {
if (empty(App::getEnv('_APP_SMS_PROVIDER'))) {
throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured');
@@ -1326,12 +1323,12 @@ App::post('/v1/account/sessions/phone')
$message = $message->setParam('{{token}}', $secret);
$message = $message->render();
$messaging
$queueForMessaging
->setRecipient($phone)
->setMessage($message)
->trigger();
$events->setPayload(
$queueForEvents->setPayload(
$response->output(
$token->setAttribute('secret', $secret),
Response::MODEL_TOKEN
@@ -1370,8 +1367,8 @@ App::put('/v1/account/sessions/phone')
->inject('project')
->inject('locale')
->inject('geodb')
->inject('events')
->action(function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents) {
$userFromRequest = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId));
@@ -1435,7 +1432,7 @@ App::put('/v1/account/sessions/phone')
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed saving user to DB');
}
$events
$queueForEvents
->setParam('userId', $user->getId())
->setParam('sessionId', $session->getId())
;
@@ -1490,8 +1487,8 @@ App::post('/v1/account/sessions/anonymous')
->inject('project')
->inject('dbForProject')
->inject('geodb')
->inject('events')
->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Event $events) {
->inject('queueForEvents')
->action(function (Request $request, Response $response, Locale $locale, Document $user, Document $project, Database $dbForProject, Reader $geodb, Event $queueForEvents) {
$protocol = $request->getProtocol();
@@ -1574,7 +1571,7 @@ App::post('/v1/account/sessions/anonymous')
$dbForProject->deleteCachedDocument('users', $user->getId());
$events
$queueForEvents
->setParam('userId', $user->getId())
->setParam('sessionId', $session->getId())
;
@@ -1858,14 +1855,14 @@ App::patch('/v1/account/name')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (string $name, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $name, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
$user->setAttribute('name', $name);
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
$events->setParam('userId', $user->getId());
$queueForEvents->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_ACCOUNT);
});
@@ -1895,8 +1892,8 @@ App::patch('/v1/account/password')
->inject('user')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $password, string $oldPassword, ?\DateTime $requestTimestamp, Response $response, Document $user, Document $project, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $password, string $oldPassword, ?\DateTime $requestTimestamp, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents) {
// Check old password only if its an existing user.
if (!empty($user->getAttribute('passwordUpdate')) && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password
@@ -1932,7 +1929,7 @@ App::patch('/v1/account/password')
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
$events->setParam('userId', $user->getId());
$queueForEvents->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_ACCOUNT);
});
@@ -1960,8 +1957,8 @@ App::patch('/v1/account/email')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (string $email, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $email, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
// passwordUpdate will be empty if the user has never set a password
$passwordUpdate = $user->getAttribute('passwordUpdate');
@@ -2002,7 +1999,7 @@ App::patch('/v1/account/email')
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
}
$events->setParam('userId', $user->getId());
$queueForEvents->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_ACCOUNT);
});
@@ -2030,8 +2027,8 @@ App::patch('/v1/account/phone')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (string $phone, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $phone, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
// passwordUpdate will be empty if the user has never set a password
$passwordUpdate = $user->getAttribute('passwordUpdate');
@@ -2061,7 +2058,7 @@ App::patch('/v1/account/phone')
throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS);
}
$events->setParam('userId', $user->getId());
$queueForEvents->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_ACCOUNT);
});
@@ -2088,14 +2085,14 @@ App::patch('/v1/account/prefs')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (array $prefs, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (array $prefs, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
$user->setAttribute('prefs', $prefs);
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
$events->setParam('userId', $user->getId());
$queueForEvents->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_ACCOUNT);
});
@@ -2120,14 +2117,14 @@ App::patch('/v1/account/status')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
$user->setAttribute('status', false);
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
$events
$queueForEvents
->setParam('userId', $user->getId())
->setPayload($response->output($user, Response::MODEL_ACCOUNT));
@@ -2166,9 +2163,9 @@ App::delete('/v1/account/sessions/:sessionId')
->inject('user')
->inject('dbForProject')
->inject('locale')
->inject('events')
->inject('queueForEvents')
->inject('project')
->action(function (?string $sessionId, ?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events, Document $project) {
->action(function (?string $sessionId, ?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Document $project) {
$protocol = $request->getProtocol();
$authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
@@ -2208,7 +2205,7 @@ App::delete('/v1/account/sessions/:sessionId')
$dbForProject->deleteCachedDocument('users', $user->getId());
$events
$queueForEvents
->setParam('userId', $user->getId())
->setParam('sessionId', $session->getId())
->setPayload($response->output($session, Response::MODEL_SESSION))
@@ -2244,8 +2241,8 @@ App::patch('/v1/account/sessions/:sessionId')
->inject('dbForProject')
->inject('project')
->inject('locale')
->inject('events')
->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Event $events) {
->inject('queueForEvents')
->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Event $queueForEvents) {
$authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
$sessionId = ($sessionId === 'current')
? Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret, $authDuration)
@@ -2293,7 +2290,7 @@ App::patch('/v1/account/sessions/:sessionId')
$session->setAttribute('expire', DateTime::formatTz(DateTime::addSeconds(new \DateTime($session->getCreatedAt()), $authDuration)));
$events
$queueForEvents
->setParam('userId', $user->getId())
->setParam('sessionId', $session->getId())
->setPayload($response->output($session, Response::MODEL_SESSION))
@@ -2326,8 +2323,8 @@ App::delete('/v1/account/sessions')
->inject('user')
->inject('dbForProject')
->inject('locale')
->inject('events')
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events) {
->inject('queueForEvents')
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $queueForEvents) {
$protocol = $request->getProtocol();
$sessions = $user->getAttribute('sessions', []);
@@ -2354,13 +2351,13 @@ App::delete('/v1/account/sessions')
->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'));
// Use current session for events.
$events->setPayload($response->output($session, Response::MODEL_SESSION));
$queueForEvents->setPayload($response->output($session, Response::MODEL_SESSION));
}
}
$dbForProject->deleteCachedDocument('users', $user->getId());
$events
$queueForEvents
->setParam('userId', $user->getId())
->setParam('sessionId', $session->getId());
@@ -2393,9 +2390,9 @@ App::post('/v1/account/recovery')
->inject('dbForProject')
->inject('project')
->inject('locale')
->inject('mails')
->inject('events')
->action(function (string $email, string $url, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Mail $mails, Event $events) {
->inject('queueForMails')
->inject('queueForEvents')
->action(function (string $email, string $url, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Locale $locale, Mail $queueForMails, Event $queueForEvents) {
if (empty(App::getEnv('_APP_SMTP_HOST'))) {
throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled');
@@ -2456,7 +2453,12 @@ App::post('/v1/account/recovery')
$customTemplate = $project->getAttribute('templates', [])['email.recovery-' . $locale->default] ?? [];
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
$message->setParam('{{body}}', $body);
$message
->setParam('{{body}}', $body)
->setParam('{{hello}}', $locale->getText("emails.recovery.hello"))
->setParam('{{footer}}', $locale->getText("emails.recovery.footer"))
->setParam('{{thanks}}', $locale->getText("emails.recovery.thanks"))
->setParam('{{signature}}', $locale->getText("emails.recovery.signature"));
$body = $message->render();
$smtp = $project->getAttribute('smtp', []);
@@ -2477,7 +2479,7 @@ App::post('/v1/account/recovery')
$replyTo = $smtp['replyTo'];
}
$mails
$queueForMails
->setSmtpHost($smtp['host'] ?? '')
->setSmtpPort($smtp['port'] ?? '')
->setSmtpUsername($smtp['username'] ?? '')
@@ -2499,23 +2501,14 @@ App::post('/v1/account/recovery')
$subject = $customTemplate['subject'] ?? $subject;
}
$mails
$queueForMails
->setSmtpReplyTo($replyTo)
->setSmtpSenderEmail($senderEmail)
->setSmtpSenderName($senderName);
}
$emailVariables = [
'subject' => $subject,
'hello' => $locale->getText("emails.recovery.hello"),
'body' => $body,
'footer' => $locale->getText("emails.recovery.footer"),
'thanks' => $locale->getText("emails.recovery.thanks"),
'signature' => $locale->getText("emails.recovery.signature"),
'direction' => $locale->getText('settings.direction'),
'bg-body' => '#f7f7f7',
'bg-content' => '#ffffff',
'text-content' => '#000000',
/* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */
'user' => $profile->getAttribute('name'),
'team' => '',
@@ -2523,8 +2516,7 @@ App::post('/v1/account/recovery')
'redirect' => $url
];
$mails
$queueForMails
->setRecipient($profile->getAttribute('email', ''))
->setName($profile->getAttribute('name'))
->setBody($body)
@@ -2532,7 +2524,7 @@ App::post('/v1/account/recovery')
->setSubject($subject)
->trigger();
$events
$queueForEvents
->setParam('userId', $profile->getId())
->setParam('tokenId', $recovery->getId())
->setUser($profile)
@@ -2576,8 +2568,8 @@ App::put('/v1/account/recovery')
->inject('user')
->inject('dbForProject')
->inject('project')
->inject('events')
->action(function (string $userId, string $secret, string $password, string $passwordAgain, Response $response, Document $user, Database $dbForProject, Document $project, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, string $secret, string $password, string $passwordAgain, Response $response, Document $user, Database $dbForProject, Document $project, Event $queueForEvents) {
if ($password !== $passwordAgain) {
throw new Exception(Exception::USER_PASSWORD_MISMATCH);
}
@@ -2630,7 +2622,7 @@ App::put('/v1/account/recovery')
$dbForProject->deleteDocument('tokens', $recovery);
$dbForProject->deleteCachedDocument('users', $profile->getId());
$events
$queueForEvents
->setParam('userId', $profile->getId())
->setParam('tokenId', $recoveryDocument->getId())
;
@@ -2662,9 +2654,9 @@ App::post('/v1/account/verification')
->inject('user')
->inject('dbForProject')
->inject('locale')
->inject('events')
->inject('mails')
->action(function (string $url, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Event $events, Mail $mails) {
->inject('queueForEvents')
->inject('queueForMails')
->action(function (string $url, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails) {
if (empty(App::getEnv('_APP_SMTP_HOST'))) {
throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled');
@@ -2708,7 +2700,12 @@ App::post('/v1/account/verification')
$customTemplate = $project->getAttribute('templates', [])['email.verification-' . $locale->default] ?? [];
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
$message->setParam('{{body}}', $body);
$message
->setParam('{{body}}', $body)
->setParam('{{hello}}', $locale->getText("emails.verification.hello"))
->setParam('{{footer}}', $locale->getText("emails.verification.footer"))
->setParam('{{thanks}}', $locale->getText("emails.verification.thanks"))
->setParam('{{signature}}', $locale->getText("emails.verification.signature"));
$body = $message->render();
$smtp = $project->getAttribute('smtp', []);
@@ -2729,7 +2726,7 @@ App::post('/v1/account/verification')
$replyTo = $smtp['replyTo'];
}
$mails
$queueForMails
->setSmtpHost($smtp['host'] ?? '')
->setSmtpPort($smtp['port'] ?? '')
->setSmtpUsername($smtp['username'] ?? '')
@@ -2751,23 +2748,14 @@ App::post('/v1/account/verification')
$subject = $customTemplate['subject'] ?? $subject;
}
$mails
$queueForMails
->setSmtpReplyTo($replyTo)
->setSmtpSenderEmail($senderEmail)
->setSmtpSenderName($senderName);
}
$emailVariables = [
'subject' => $subject,
'hello' => $locale->getText("emails.verification.hello"),
'body' => $body,
'footer' => $locale->getText("emails.verification.footer"),
'thanks' => $locale->getText("emails.verification.thanks"),
'signature' => $locale->getText("emails.verification.signature"),
'direction' => $locale->getText('settings.direction'),
'bg-body' => '#f7f7f7',
'bg-content' => '#ffffff',
'text-content' => '#000000',
/* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */
'user' => $user->getAttribute('name'),
'team' => '',
@@ -2775,7 +2763,7 @@ App::post('/v1/account/verification')
'redirect' => $url
];
$mails
$queueForMails
->setSubject($subject)
->setBody($body)
->setVariables($emailVariables)
@@ -2783,7 +2771,7 @@ App::post('/v1/account/verification')
->setName($user->getAttribute('name') ?? '')
->trigger();
$events
$queueForEvents
->setParam('userId', $user->getId())
->setParam('tokenId', $verification->getId())
->setPayload($response->output(
@@ -2821,8 +2809,8 @@ App::put('/v1/account/verification')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
$profile = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId));
@@ -2852,7 +2840,7 @@ App::put('/v1/account/verification')
$dbForProject->deleteDocument('tokens', $verification);
$dbForProject->deleteCachedDocument('users', $profile->getId());
$events
$queueForEvents
->setParam('userId', $userId)
->setParam('tokenId', $verificationDocument->getId())
;
@@ -2881,11 +2869,11 @@ App::post('/v1/account/verification/phone')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->inject('messaging')
->inject('queueForEvents')
->inject('queueForMessaging')
->inject('project')
->inject('locale')
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $events, EventPhone $messaging, Document $project, Locale $locale) {
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, EventPhone $queueForMessaging, Document $project, Locale $locale) {
if (empty(App::getEnv('_APP_SMS_PROVIDER'))) {
throw new Exception(Exception::GENERAL_PHONE_DISABLED);
@@ -2933,13 +2921,13 @@ App::post('/v1/account/verification/phone')
$message = $message->setParam('{{token}}', $secret);
$message = $message->render();
$messaging
$queueForMessaging
->setRecipient($user->getAttribute('phone'))
->setMessage($message)
->trigger()
;
$events
$queueForEvents
->setParam('userId', $user->getId())
->setParam('tokenId', $verification->getId())
->setPayload($response->output(
@@ -2978,8 +2966,8 @@ App::put('/v1/account/verification/phone')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, string $secret, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
$profile = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId));
@@ -3007,7 +2995,7 @@ App::put('/v1/account/verification/phone')
$dbForProject->deleteDocument('tokens', $verification);
$dbForProject->deleteCachedDocument('users', $profile->getId());
$events
$queueForEvents
->setParam('userId', $user->getId())
->setParam('tokenId', $verificationDocument->getId())
;
+172 -142
View File
@@ -12,21 +12,23 @@ use Appwrite\Utopia\Database\Validator\Queries\Attributes;
use Appwrite\Utopia\Database\Validator\Queries\Collections;
use Appwrite\Utopia\Database\Validator\Queries\Databases;
use Appwrite\Utopia\Database\Validator\Queries\Indexes;
use Appwrite\Utopia\Request;
use Appwrite\Utopia\Response;
use MaxMind\Db\Reader;
use Utopia\App;
use Utopia\Audit\Audit;
use Utopia\Config\Config;
use Utopia\Database\Adapter\MariaDB;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Exception\Authorization as AuthorizationException;
use Utopia\Database\Exception\Conflict as ConflictException;
use Utopia\Database\Exception\Duplicate as DuplicateException;
use Utopia\Database\Exception\Limit as LimitException;
use Utopia\Database\Exception\Query as QueryException;
use Utopia\Database\Exception\Restricted as RestrictedException;
use Utopia\Database\Exception\Structure as StructureException;
use Utopia\Database\Exception\Query as QueryException;
use Utopia\Database\Exception\Timeout as TimeoutException;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
@@ -37,8 +39,6 @@ use Utopia\Database\Validator\Index as IndexValidator;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\Permissions;
use Utopia\Database\Validator\Queries;
use Utopia\Database\Validator\Queries\Document as DocumentQueriesValidator;
use Utopia\Database\Validator\Queries\Documents;
use Utopia\Database\Validator\Query\Limit;
use Utopia\Database\Validator\Query\Offset;
use Utopia\Database\Validator\Structure;
@@ -57,13 +57,26 @@ use Utopia\Validator\URL;
use Utopia\Validator\WhiteList;
/**
* Create attribute of varying type
*
* * Create attribute of varying type
*
* @param string $databaseId
* @param string $collectionId
* @param Document $attribute
* @param Response $response
* @param Database $dbForProject
* @param EventDatabase $queueForDatabase
* @param Event $queueForEvents
* @return Document Newly created attribute document
* @throws AuthorizationException
* @throws Exception
* @throws LimitException
* @throws RestrictedException
* @throws StructureException
* @throws \Utopia\Database\Exception
* @throws ConflictException
* @throws Exception
*/
function createAttribute(string $databaseId, string $collectionId, Document $attribute, Response $response, Database $dbForProject, EventDatabase $database, Event $events): Document
function createAttribute(string $databaseId, string $collectionId, Document $attribute, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): Document
{
$key = $attribute->getAttribute('key');
$type = $attribute->getAttribute('type', '');
@@ -193,13 +206,13 @@ function createAttribute(string $databaseId, string $collectionId, Document $att
$dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId());
}
$database
$queueForDatabase
->setType(DATABASE_TYPE_CREATE_ATTRIBUTE)
->setDatabase($db)
->setCollection($collection)
->setDocument($attribute);
$events
$queueForEvents
->setContext('collection', $collection)
->setContext('database', $db)
->setParam('databaseId', $databaseId)
@@ -216,7 +229,7 @@ function updateAttribute(
string $collectionId,
string $key,
Database $dbForProject,
Event $events,
Event $queueForEvents,
string $type,
string $filter = null,
string|bool|int|float $default = null,
@@ -360,7 +373,7 @@ function updateAttribute(
$attribute = $dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key, $attribute);
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collection->getId());
$events
$queueForEvents
->setContext('collection', $collection)
->setContext('database', $db)
->setParam('databaseId', $databaseId)
@@ -370,6 +383,18 @@ function updateAttribute(
return $attribute;
}
App::init()
->groups(['api', 'database'])
->inject('request')
->inject('dbForProject')
->action(function (Request $request, Database $dbForProject) {
$timeout = \intval($request->getHeader('x-appwrite-timeout'));
if (!empty($timeout) && App::isDevelopment()) {
$dbForProject->setTimeout($timeout);
}
});
App::post('/v1/databases')
->desc('Create database')
->groups(['api', 'database'])
@@ -390,8 +415,8 @@ App::post('/v1/databases')
->param('enabled', true, new Boolean(), 'Is the database enabled? When set to \'disabled\', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.', true)
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $queueForEvents) {
$databaseId = $databaseId == 'unique()' ? ID::unique() : $databaseId;
@@ -440,7 +465,7 @@ App::post('/v1/databases')
throw new Exception(Exception::DATABASE_ALREADY_EXISTS);
}
$events->setParam('databaseId', $database->getId());
$queueForEvents->setParam('databaseId', $database->getId());
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -627,8 +652,8 @@ App::put('/v1/databases/:databaseId')
->param('enabled', true, new Boolean(), 'Is database enabled? When set to \'disabled\', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.', true)
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $queueForEvents) {
$database = $dbForProject->getDocument('databases', $databaseId);
@@ -647,7 +672,7 @@ App::put('/v1/databases/:databaseId')
throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, 'Bad structure. ' . $exception->getMessage());
}
$events->setParam('databaseId', $database->getId());
$queueForEvents->setParam('databaseId', $database->getId());
$response->dynamic($database, Response::MODEL_DATABASE);
});
@@ -669,9 +694,9 @@ App::delete('/v1/databases/:databaseId')
->param('databaseId', '', new UID(), 'Database ID.')
->inject('response')
->inject('dbForProject')
->inject('events')
->inject('deletes')
->action(function (string $databaseId, Response $response, Database $dbForProject, Event $events, Delete $deletes) {
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (string $databaseId, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
$database = $dbForProject->getDocument('databases', $databaseId);
@@ -686,11 +711,11 @@ App::delete('/v1/databases/:databaseId')
$dbForProject->deleteCachedDocument('databases', $database->getId());
$dbForProject->deleteCachedCollection('databases_' . $database->getInternalId());
$deletes
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($database);
$queueForDatabase
->setType(DATABASE_TYPE_DELETE_DATABASE)
->setDatabase($database);
$events
$queueForEvents
->setParam('databaseId', $database->getId())
->setPayload($response->output($database, Response::MODEL_DATABASE));
@@ -722,8 +747,8 @@ App::post('/v1/databases/:databaseId/collections')
->inject('response')
->inject('dbForProject')
->inject('mode')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $events) {
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $queueForEvents) {
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
@@ -756,7 +781,7 @@ App::post('/v1/databases/:databaseId/collections')
throw new Exception(Exception::COLLECTION_LIMIT_EXCEEDED);
}
$events
$queueForEvents
->setContext('database', $database)
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId());
@@ -983,8 +1008,8 @@ App::put('/v1/databases/:databaseId/collections/:collectionId')
->inject('response')
->inject('dbForProject')
->inject('mode')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $events) {
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $queueForEvents) {
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
@@ -1019,7 +1044,7 @@ App::put('/v1/databases/:databaseId/collections/:collectionId')
throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, 'Bad structure. ' . $exception->getMessage());
}
$events
$queueForEvents
->setContext('database', $database)
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId());
@@ -1047,10 +1072,10 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId')
->param('collectionId', '', new UID(), 'Collection ID.')
->inject('response')
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->inject('mode')
->inject('events')
->inject('deletes')
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, string $mode, Event $events, Delete $deletes) {
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, string $mode) {
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
@@ -1070,11 +1095,12 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId')
$dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId());
$deletes
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($collection);
$queueForDatabase
->setType(DATABASE_TYPE_DELETE_COLLECTION)
->setDatabase($database)
->setCollection($collection);
$events
$queueForEvents
->setContext('database', $database)
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId())
@@ -1110,9 +1136,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string
->param('encrypt', false, new Boolean(), 'Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.', true)
->inject('response')
->inject('dbForProject')
->inject('database')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, bool $encrypt, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, bool $encrypt, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
// Ensure attribute default is within required size
$validator = new Text($size, 0);
@@ -1134,7 +1160,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string
'default' => $default,
'array' => $array,
'filters' => $filters,
]), $response, $dbForProject, $database, $events);
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
@@ -1166,9 +1192,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email'
->param('array', false, new Boolean(), 'Is attribute an array?', true)
->inject('response')
->inject('dbForProject')
->inject('database')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
$attribute = createAttribute($databaseId, $collectionId, new Document([
'key' => $key,
@@ -1178,7 +1204,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email'
'default' => $default,
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_EMAIL,
]), $response, $dbForProject, $database, $events);
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
@@ -1211,10 +1237,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum')
->param('array', false, new Boolean(), 'Is attribute an array?', true)
->inject('response')
->inject('dbForProject')
->inject('database')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, array $elements, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, array $elements, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
// use length of longest string as attribute size
$size = 0;
foreach ($elements as $element) {
@@ -1238,7 +1263,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum')
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_ENUM,
'formatOptions' => ['elements' => $elements],
]), $response, $dbForProject, $database, $events);
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
@@ -1270,9 +1295,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip')
->param('array', false, new Boolean(), 'Is attribute an array?', true)
->inject('response')
->inject('dbForProject')
->inject('database')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
$attribute = createAttribute($databaseId, $collectionId, new Document([
'key' => $key,
@@ -1282,7 +1307,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip')
'default' => $default,
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_IP,
]), $response, $dbForProject, $database, $events);
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
@@ -1314,9 +1339,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url')
->param('array', false, new Boolean(), 'Is attribute an array?', true)
->inject('response')
->inject('dbForProject')
->inject('database')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
$attribute = createAttribute($databaseId, $collectionId, new Document([
'key' => $key,
@@ -1326,7 +1351,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url')
'default' => $default,
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_URL,
]), $response, $dbForProject, $database, $events);
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
@@ -1360,9 +1385,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege
->param('array', false, new Boolean(), 'Is attribute an array?', true)
->inject('response')
->inject('dbForProject')
->inject('database')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, bool $array, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
// Ensure attribute default is within range
$min = (is_null($min)) ? PHP_INT_MIN : \intval($min);
@@ -1392,7 +1417,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege
'min' => $min,
'max' => $max,
],
]), $response, $dbForProject, $database, $events);
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$formatOptions = $attribute->getAttribute('formatOptions', []);
@@ -1433,9 +1458,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float'
->param('array', false, new Boolean(), 'Is attribute an array?', true)
->inject('response')
->inject('dbForProject')
->inject('database')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, bool $array, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
// Ensure attribute default is within range
$min = (is_null($min)) ? -PHP_FLOAT_MAX : \floatval($min);
@@ -1468,7 +1493,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float'
'min' => $min,
'max' => $max,
],
]), $response, $dbForProject, $database, $events);
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$formatOptions = $attribute->getAttribute('formatOptions', []);
@@ -1507,9 +1532,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea
->param('array', false, new Boolean(), 'Is attribute an array?', true)
->inject('response')
->inject('dbForProject')
->inject('database')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, bool $array, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
$attribute = createAttribute($databaseId, $collectionId, new Document([
'key' => $key,
@@ -1518,7 +1543,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea
'required' => $required,
'default' => $default,
'array' => $array,
]), $response, $dbForProject, $database, $events);
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
@@ -1550,9 +1575,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti
->param('array', false, new Boolean(), 'Is attribute an array?', true)
->inject('response')
->inject('dbForProject')
->inject('database')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
$filters[] = 'datetime';
@@ -1564,7 +1589,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti
'default' => $default,
'array' => $array,
'filters' => $filters,
]), $response, $dbForProject, $database, $events);
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
@@ -1598,8 +1623,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/relati
->param('onDelete', Database::RELATION_MUTATE_RESTRICT, new WhiteList([Database::RELATION_MUTATE_CASCADE, Database::RELATION_MUTATE_RESTRICT, Database::RELATION_MUTATE_SET_NULL], true), 'Constraints option', true)
->inject('response')
->inject('dbForProject')
->inject('database')
->inject('events')
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (
string $databaseId,
string $collectionId,
@@ -1611,8 +1636,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/relati
string $onDelete,
Response $response,
Database $dbForProject,
EventDatabase $database,
Event $events
EventDatabase $queueForDatabase,
Event $queueForEvents
) {
$key ??= $relatedCollectionId;
$twoWayKey ??= $collectionId;
@@ -1638,8 +1663,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/relati
]),
$response,
$dbForProject,
$database,
$events
$queueForDatabase,
$queueForEvents
);
$options = $attribute->getAttribute('options', []);
@@ -1827,15 +1852,15 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/strin
->param('default', null, new Nullable(new Text(0, 0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $queueForEvents) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
queueForEvents: $queueForEvents,
type: Database::VAR_STRING,
default: $default,
required: $required
@@ -1868,14 +1893,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/email
->param('default', null, new Nullable(new Email()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $queueForEvents) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
queueForEvents: $queueForEvents,
type: Database::VAR_STRING,
filter: APP_DATABASE_ATTRIBUTE_EMAIL,
default: $default,
@@ -1910,14 +1935,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/enum/
->param('default', null, new Nullable(new Text(0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?array $elements, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?array $elements, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $queueForEvents) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
queueForEvents: $queueForEvents,
type: Database::VAR_STRING,
filter: APP_DATABASE_ATTRIBUTE_ENUM,
default: $default,
@@ -1952,14 +1977,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/ip/:k
->param('default', null, new Nullable(new IP()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $queueForEvents) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
queueForEvents: $queueForEvents,
type: Database::VAR_STRING,
filter: APP_DATABASE_ATTRIBUTE_IP,
default: $default,
@@ -1993,14 +2018,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/url/:
->param('default', null, new Nullable(new URL()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $queueForEvents) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
queueForEvents: $queueForEvents,
type: Database::VAR_STRING,
filter: APP_DATABASE_ATTRIBUTE_URL,
default: $default,
@@ -2036,14 +2061,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/integ
->param('default', null, new Nullable(new Integer()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, Response $response, Database $dbForProject, Event $queueForEvents) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
queueForEvents: $queueForEvents,
type: Database::VAR_INTEGER,
default: $default,
required: $required,
@@ -2087,14 +2112,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/float
->param('default', null, new Nullable(new FloatValidator()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, Response $response, Database $dbForProject, Event $queueForEvents) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
queueForEvents: $queueForEvents,
type: Database::VAR_FLOAT,
default: $default,
required: $required,
@@ -2136,14 +2161,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/boole
->param('default', null, new Nullable(new Boolean()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, Response $response, Database $dbForProject, Event $queueForEvents) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
queueForEvents: $queueForEvents,
type: Database::VAR_BOOLEAN,
default: $default,
required: $required
@@ -2176,14 +2201,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/datet
->param('default', null, new Nullable(new DatetimeValidator()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $queueForEvents) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
queueForEvents: $queueForEvents,
type: Database::VAR_DATETIME,
default: $default,
required: $required
@@ -2215,7 +2240,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/
->param('onDelete', null, new WhiteList([Database::RELATION_MUTATE_CASCADE, Database::RELATION_MUTATE_RESTRICT, Database::RELATION_MUTATE_SET_NULL], true), 'Constraints option', true)
->inject('response')
->inject('dbForProject')
->inject('events')
->inject('queueForEvents')
->action(function (
string $databaseId,
string $collectionId,
@@ -2223,14 +2248,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/
?string $onDelete,
Response $response,
Database $dbForProject,
Event $events
Event $queueForEvents
) {
$attribute = updateAttribute(
$databaseId,
$collectionId,
$key,
$dbForProject,
$events,
$queueForEvents,
type: Database::VAR_RELATIONSHIP,
required: false,
options: [
@@ -2254,7 +2279,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
->desc('Delete attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].delete')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.delete')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('usage.metric', 'collections.{scope}.requests.update')
@@ -2270,9 +2295,9 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
->param('key', '', new Key(), 'Attribute Key.')
->inject('response')
->inject('dbForProject')
->inject('database')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
$db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
@@ -2323,7 +2348,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
}
}
$database
$queueForDatabase
->setType(DATABASE_TYPE_DELETE_ATTRIBUTE)
->setCollection($collection)
->setDatabase($db)
@@ -2349,7 +2374,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
default => Response::MODEL_ATTRIBUTE,
};
$events
$queueForEvents
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId())
->setParam('attributeId', $attribute->getId())
@@ -2385,9 +2410,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true)
->inject('response')
->inject('dbForProject')
->inject('database')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
$db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
@@ -2489,8 +2514,11 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
'orders' => $orders,
]);
$validator = new IndexValidator($dbForProject->getAdapter()->getMaxIndexLength());
if (!$validator->isValid($collection->setAttribute('indexes', $index, Document::SET_TYPE_APPEND))) {
$validator = new IndexValidator(
$collection->getAttribute('attributes'),
$dbForProject->getAdapter()->getMaxIndexLength()
);
if (!$validator->isValid($index)) {
throw new Exception(Exception::INDEX_INVALID, $validator->getDescription());
}
@@ -2502,13 +2530,13 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId);
$database
$queueForDatabase
->setType(DATABASE_TYPE_CREATE_INDEX)
->setDatabase($db)
->setCollection($collection)
->setDocument($index);
$events
$queueForEvents
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId())
->setParam('indexId', $index->getId())
@@ -2631,7 +2659,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
->desc('Delete index')
->groups(['api', 'database'])
->label('scope', 'collections.write')
->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].delete')
->label('event', 'databases.[databaseId].collections.[collectionId].indexes.[indexId].update')
->label('audits.event', 'index.delete')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('usage.metric', 'collections.{scope}.requests.update')
@@ -2647,9 +2675,9 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
->param('key', '', new Key(), 'Index Key.')
->inject('response')
->inject('dbForProject')
->inject('database')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
->inject('queueForDatabase')
->inject('queueForEvents')
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
$db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
@@ -2675,13 +2703,13 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId);
$database
$queueForDatabase
->setType(DATABASE_TYPE_DELETE_INDEX)
->setDatabase($db)
->setCollection($collection)
->setDocument($index);
$events
$queueForEvents
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId())
->setParam('indexId', $index->getId())
@@ -2722,9 +2750,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
->inject('response')
->inject('dbForProject')
->inject('user')
->inject('events')
->inject('queueForEvents')
->inject('mode')
->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $events, string $mode) {
->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, string $mode) {
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
@@ -2920,12 +2948,13 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
$processDocument($collection, $document);
$events
$queueForEvents
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId())
->setParam('documentId', $document->getId())
->setContext('collection', $collection)
->setContext('database', $database);
->setContext('database', $database)
;
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -3285,9 +3314,9 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
->inject('requestTimestamp')
->inject('response')
->inject('dbForProject')
->inject('events')
->inject('queueForEvents')
->inject('mode')
->action(function (string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events, string $mode) {
->action(function (string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $queueForEvents, string $mode) {
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
@@ -3474,12 +3503,13 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$processDocument($collection, $document);
$events
$queueForEvents
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId())
->setParam('documentId', $document->getId())
->setContext('collection', $collection)
->setContext('database', $database);
->setContext('database', $database)
;
$response->dynamic($document, Response::MODEL_DOCUMENT);
});
@@ -3511,10 +3541,10 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
->inject('requestTimestamp')
->inject('response')
->inject('dbForProject')
->inject('events')
->inject('deletes')
->inject('queueForDeletes')
->inject('queueForEvents')
->inject('mode')
->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events, Delete $deletes, string $mode) {
->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Delete $queueForDeletes, Event $queueForEvents, string $mode) {
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
@@ -3585,11 +3615,11 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
$processDocument($collection, $document);
$deletes
$queueForDeletes
->setType(DELETE_TYPE_AUDIT)
->setDocument($document);
$events
$queueForEvents
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId())
->setParam('documentId', $document->getId())
+55 -44
View File
@@ -6,7 +6,6 @@ use Appwrite\Event\Build;
use Appwrite\Event\Delete;
use Appwrite\Event\Event;
use Appwrite\Event\Func;
use Appwrite\Event\Usage;
use Appwrite\Event\Validator\FunctionEvent;
use Appwrite\Utopia\Response\Model\Rule;
use Appwrite\Extend\Exception;
@@ -47,10 +46,11 @@ use Utopia\Validator\Boolean;
use Utopia\Database\Exception\Duplicate as DuplicateException;
use MaxMind\Db\Reader;
use Utopia\VCS\Adapter\Git\GitHub;
use Utopia\VCS\Exception\RepositoryNotFound;
include_once __DIR__ . '/../shared/api.php';
$redeployVcs = function (Request $request, Document $function, Document $project, Document $installation, Database $dbForProject, Document $template, GitHub $github) {
$redeployVcs = function (Request $request, Document $function, Document $project, Document $installation, Database $dbForProject, Build $queueForBuilds, Document $template, GitHub $github) {
$deploymentId = ID::unique();
$entrypoint = $function->getAttribute('entrypoint', '');
$providerInstallationId = $installation->getAttribute('providerInstallationId', '');
@@ -59,7 +59,14 @@ $redeployVcs = function (Request $request, Document $function, Document $project
$github->initializeVariables($providerInstallationId, $privateKey, $githubAppId);
$owner = $github->getOwnerName($providerInstallationId);
$providerRepositoryId = $function->getAttribute('providerRepositoryId', '');
$repositoryName = $github->getRepositoryName($providerRepositoryId);
try {
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($repositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
} catch (RepositoryNotFound $e) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
$providerBranch = $function->getAttribute('providerBranch', 'main');
$authorUrl = "https://github.com/$owner";
$repositoryUrl = "https://github.com/$owner/$repositoryName";
@@ -109,8 +116,7 @@ $redeployVcs = function (Request $request, Document $function, Document $project
'activate' => true,
]));
$buildEvent = new Build();
$buildEvent
$queueForBuilds
->setType(BUILD_TYPE_DEPLOYMENT)
->setResource($function)
->setDeployment($deployment)
@@ -158,10 +164,11 @@ App::post('/v1/functions')
->inject('dbForProject')
->inject('project')
->inject('user')
->inject('events')
->inject('queueForEvents')
->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, 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 $eventsInstance, 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, 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) {
$functionId = ($functionId == 'unique()') ? ID::unique() : $functionId;
// build from template
@@ -261,7 +268,7 @@ App::post('/v1/functions')
// Redeploy vcs logic
if (!empty($providerRepositoryId)) {
$redeployVcs($request, $function, $project, $installation, $dbForProject, $template, $github);
$redeployVcs($request, $function, $project, $installation, $dbForProject, $queueForBuilds, $template, $github);
}
$functionsDomain = App::getEnv('_APP_DOMAIN_FUNCTIONS', '');
@@ -286,7 +293,11 @@ App::post('/v1/functions')
/** Trigger Webhook */
$ruleModel = new Rule();
$ruleCreate = new Event(Event::WEBHOOK_QUEUE_NAME, Event::WEBHOOK_CLASS_NAME);
$ruleCreate =
$queueForEvents
->setClass(Event::WEBHOOK_CLASS_NAME)
->setQueue(Event::WEBHOOK_QUEUE_NAME);
$ruleCreate
->setProject($project)
->setEvent('rules.[ruleId].create')
@@ -326,7 +337,7 @@ App::post('/v1/functions')
);
}
$eventsInstance->setParam('functionId', $function->getId());
$queueForEvents->setParam('functionId', $function->getId());
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -530,7 +541,7 @@ App::get('/v1/functions/:functionId/usage')
'range' => $range,
'executionsTotal' => $stats["executions.$functionId.compute.total"] ?? [],
'executionsFailure' => $stats["executions.$functionId.compute.failure"] ?? [],
'executionsSuccesse' => $stats["executions.$functionId.compute.success"] ?? [],
'executionsSuccess' => $stats["executions.$functionId.compute.success"] ?? [],
'executionsTime' => $stats["executions.$functionId.compute.time"] ?? [],
'buildsTotal' => $stats["builds.$functionId.compute.total"] ?? [],
'buildsFailure' => $stats["builds.$functionId.compute.failure"] ?? [],
@@ -679,10 +690,11 @@ App::put('/v1/functions/:functionId')
->inject('response')
->inject('dbForProject')
->inject('project')
->inject('events')
->inject('queueForEvents')
->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, string $installationId, string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, Request $request, Response $response, Database $dbForProject, Document $project, Event $eventsInstance, 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, string $installationId, string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, Request $request, Response $response, Database $dbForProject, Document $project, Event $queueForEvents, Build $queueForBuilds, Database $dbForConsole, GitHub $github) use ($redeployVcs) {
// TODO: If only branch changes, re-deploy
$function = $dbForProject->getDocument('functions', $functionId);
@@ -807,7 +819,7 @@ App::put('/v1/functions/:functionId')
// Redeploy logic
if (!$isConnected && !empty($providerRepositoryId)) {
$redeployVcs($request, $function, $project, $installation, $dbForProject, new Document(), $github);
$redeployVcs($request, $function, $project, $installation, $dbForProject, $queueForBuilds, new Document(), $github);
}
// Inform scheduler if function is still active
@@ -818,7 +830,7 @@ App::put('/v1/functions/:functionId')
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
$eventsInstance->setParam('functionId', $function->getId());
$queueForEvents->setParam('functionId', $function->getId());
$response->dynamic($function, Response::MODEL_FUNCTION);
});
@@ -865,8 +877,7 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId/download')
->setContentType('application/gzip')
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
->addHeader('X-Peak', \memory_get_peak_usage())
->addHeader('Content-Disposition', 'attachment; filename="' . $deploymentId . '.tar.gz"')
;
->addHeader('Content-Disposition', 'attachment; filename="' . $deploymentId . '.tar.gz"');
$size = $deviceFunctions->getFileSize($path);
$rangeHeader = $request->getHeader('range');
@@ -928,9 +939,9 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId')
->param('deploymentId', '', new UID(), 'Deployment ID.')
->inject('response')
->inject('dbForProject')
->inject('events')
->inject('queueForEvents')
->inject('dbForConsole')
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Event $events, Database $dbForConsole) {
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Event $queueForEvents, Database $dbForConsole) {
$function = $dbForProject->getDocument('functions', $functionId);
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
@@ -965,7 +976,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId')
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
$events
$queueForEvents
->setParam('functionId', $function->getId())
->setParam('deploymentId', $deployment->getId());
@@ -988,10 +999,10 @@ App::delete('/v1/functions/:functionId')
->param('functionId', '', new UID(), 'Function ID.')
->inject('response')
->inject('dbForProject')
->inject('deletes')
->inject('events')
->inject('queueForDeletes')
->inject('queueForEvents')
->inject('dbForConsole')
->action(function (string $functionId, Response $response, Database $dbForProject, Delete $deletes, Event $events, Database $dbForConsole) {
->action(function (string $functionId, Response $response, Database $dbForProject, Delete $queueForDeletes, Event $queueForEvents, Database $dbForConsole) {
$function = $dbForProject->getDocument('functions', $functionId);
@@ -1010,11 +1021,11 @@ App::delete('/v1/functions/:functionId')
->setAttribute('active', false);
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
$deletes
$queueForDeletes
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($function);
$events->setParam('functionId', $function->getId());
$queueForEvents->setParam('functionId', $function->getId());
$response->noContent();
});
@@ -1043,11 +1054,13 @@ App::post('/v1/functions/:functionId/deployments')
->inject('request')
->inject('response')
->inject('dbForProject')
->inject('events')
->inject('queueForEvents')
->inject('project')
->inject('deviceFunctions')
->inject('deviceLocal')
->action(function (string $functionId, ?string $entrypoint, ?string $commands, mixed $code, mixed $activate, Request $request, Response $response, Database $dbForProject, Event $events, Document $project, Device $deviceFunctions, Device $deviceLocal) {
->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 $deviceFunctions, Device $deviceLocal, Build $queueForBuilds) {
$activate = filter_var($activate, FILTER_VALIDATE_BOOLEAN);
$function = $dbForProject->getDocument('functions', $functionId);
@@ -1191,8 +1204,7 @@ App::post('/v1/functions/:functionId/deployments')
}
// Start the build
$buildEvent = new Build();
$buildEvent
$queueForBuilds
->setType(BUILD_TYPE_DEPLOYMENT)
->setResource($function)
->setDeployment($deployment)
@@ -1229,7 +1241,7 @@ App::post('/v1/functions/:functionId/deployments')
$metadata = null;
$events
$queueForEvents
->setParam('functionId', $function->getId())
->setParam('deploymentId', $deployment->getId());
@@ -1367,10 +1379,10 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
->param('deploymentId', '', new UID(), 'Deployment ID.')
->inject('response')
->inject('dbForProject')
->inject('deletes')
->inject('events')
->inject('queueForDeletes')
->inject('queueForEvents')
->inject('deviceFunctions')
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Delete $deletes, Event $events, Device $deviceFunctions) {
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Delete $queueForDeletes, Event $queueForEvents, Device $deviceFunctions) {
$function = $dbForProject->getDocument('functions', $functionId);
if ($function->isEmpty()) {
@@ -1403,11 +1415,11 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
])));
}
$events
$queueForEvents
->setParam('functionId', $function->getId())
->setParam('deploymentId', $deployment->getId());
$deletes
$queueForDeletes
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($deployment);
@@ -1434,8 +1446,9 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
->inject('response')
->inject('dbForProject')
->inject('project')
->inject('events')
->action(function (string $functionId, string $deploymentId, string $buildId, Request $request, Response $response, Database $dbForProject, Document $project, Event $events) use ($redeployVcs) {
->inject('queueForEvents')
->inject('queueForBuilds')
->action(function (string $functionId, string $deploymentId, string $buildId, Request $request, Response $response, Database $dbForProject, Document $project, Event $queueForEvents, Build $queueForBuilds) {
$function = $dbForProject->getDocument('functions', $functionId);
@@ -1467,16 +1480,14 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
'search' => implode(' ', [$deploymentId, $function->getAttribute('entrypoint')]),
]));
$buildEvent = new Build();
$buildEvent
$queueForBuilds
->setType(BUILD_TYPE_DEPLOYMENT)
->setResource($function)
->setDeployment($deployment)
->setProject($project)
->trigger();
$events
$queueForEvents
->setParam('functionId', $function->getId())
->setParam('deploymentId', $deployment->getId());
@@ -1505,12 +1516,12 @@ App::post('/v1/functions/:functionId/executions')
->inject('project')
->inject('dbForProject')
->inject('user')
->inject('events')
->inject('queueForEvents')
->inject('usage')
->inject('mode')
->inject('queueForFunctions')
->inject('geodb')
->action(function (string $functionId, string $body, bool $async, string $path, string $method, array $headers, Response $response, Document $project, Database $dbForProject, Document $user, Event $events, Stats $usage, string $mode, Func $queueForFunctions, Reader $geodb) {
->action(function (string $functionId, string $body, bool $async, string $path, string $method, array $headers, Response $response, Document $project, Database $dbForProject, Document $user, Event $queueForEvents, Stats $usage, string $mode, Func $queueForFunctions, Reader $geodb) {
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
@@ -1626,7 +1637,7 @@ App::post('/v1/functions/:functionId/executions')
'search' => implode(' ', [$functionId, $executionId]),
]);
$events
$queueForEvents
->setParam('functionId', $function->getId())
->setParam('executionId', $execution->getId())
->setContext('function', $function);
+38 -27
View File
@@ -14,6 +14,7 @@ use Utopia\Registry\Registry;
use Utopia\Storage\Device;
use Utopia\Storage\Device\Local;
use Utopia\Storage\Storage;
use Utopia\Validator\Text;
App::get('/v1/health')
->desc('Get HTTP')
@@ -347,10 +348,11 @@ App::get('/v1/health/queue/webhooks')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
->inject('queue')
->inject('response')
->action(function (Response $response) {
$response->dynamic(new Document([ 'size' => Resque::size(Event::WEBHOOK_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
->action(function (Connection $queue, Response $response) {
$client = new Client(Event::WEBHOOK_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
App::get('/v1/health/queue/logs')
@@ -364,10 +366,11 @@ App::get('/v1/health/queue/logs')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
->inject('queue')
->inject('response')
->action(function (Response $response) {
$response->dynamic(new Document([ 'size' => Resque::size(Event::AUDITS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
->action(function (Connection $queue, Response $response) {
$client = new Client(Event::AUDITS_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
App::get('/v1/health/queue/certificates')
@@ -381,10 +384,11 @@ App::get('/v1/health/queue/certificates')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
->inject('queue')
->inject('response')
->action(function (Response $response) {
$response->dynamic(new Document([ 'size' => Resque::size(Event::CERTIFICATES_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
->action(function (Connection $queue, Response $response) {
$client = new Client(Event::CERTIFICATES_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
App::get('/v1/health/queue/builds')
@@ -398,10 +402,11 @@ App::get('/v1/health/queue/builds')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
->inject('queue')
->inject('response')
->action(function (Response $response) {
$response->dynamic(new Document([ 'size' => Resque::size(Event::BUILDS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
->action(function (Connection $queue, Response $response) {
$client = new Client(Event::BUILDS_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
App::get('/v1/health/queue/databases')
@@ -415,10 +420,12 @@ App::get('/v1/health/queue/databases')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
->param('name', 'database_db_main', new Text(256), 'Queue name for which to check the queue size', true)
->inject('queue')
->inject('response')
->action(function (Response $response) {
$response->dynamic(new Document([ 'size' => Resque::size(Event::DATABASE_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
->action(function (string $name, Connection $queue, Response $response) {
$client = new Client($name, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
App::get('/v1/health/queue/deletes')
@@ -432,10 +439,11 @@ App::get('/v1/health/queue/deletes')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
->inject('queue')
->inject('response')
->action(function (Response $response) {
$response->dynamic(new Document([ 'size' => Resque::size(Event::DELETE_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
->action(function (Connection $queue, Response $response) {
$client = new Client(Event::DELETE_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
App::get('/v1/health/queue/mails')
@@ -449,10 +457,11 @@ App::get('/v1/health/queue/mails')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
->inject('queue')
->inject('response')
->action(function (Response $response) {
$response->dynamic(new Document([ 'size' => Resque::size(Event::MAILS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
->action(function (Connection $queue, Response $response) {
$client = new Client(Event::MAILS_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
App::get('/v1/health/queue/messaging')
@@ -466,10 +475,11 @@ App::get('/v1/health/queue/messaging')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
->inject('queue')
->inject('response')
->action(function (Response $response) {
$response->dynamic(new Document([ 'size' => Resque::size(Event::MESSAGING_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
->action(function (Connection $queue, Response $response) {
$client = new Client(Event::MESSAGING_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
App::get('/v1/health/queue/migrations')
@@ -483,10 +493,11 @@ App::get('/v1/health/queue/migrations')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
->inject('queue')
->inject('response')
->action(function (Response $response) {
$response->dynamic(new Document([ 'size' => Resque::size(Event::MIGRATIONS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
->action(function (Connection $queue, Response $response) {
$client = new Client(Event::MIGRATIONS_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
App::get('/v1/health/queue/functions')
+31 -32
View File
@@ -51,8 +51,9 @@ App::post('/v1/migrations/appwrite')
->inject('dbForProject')
->inject('project')
->inject('user')
->inject('events')
->action(function (array $resources, string $endpoint, string $projectId, string $apiKey, Response $response, Database $dbForProject, Document $project, Document $user, Event $events) {
->inject('queueForEvents')
->inject('queueForMigrations')
->action(function (array $resources, string $endpoint, string $projectId, string $apiKey, Response $response, Database $dbForProject, Document $project, Document $user, Event $queueForEvents, Migration $queueForMigrations) {
$migration = $dbForProject->createDocument('migrations', new Document([
'$id' => ID::unique(),
'status' => 'pending',
@@ -69,11 +70,10 @@ App::post('/v1/migrations/appwrite')
'errors' => [],
]));
$events->setParam('migrationId', $migration->getId());
$queueForEvents->setParam('migrationId', $migration->getId());
// Trigger Transfer
$event = new Migration();
$event
$queueForMigrations
->setMigration($migration)
->setProject($project)
->setUser($user)
@@ -104,9 +104,10 @@ App::post('/v1/migrations/firebase/oauth')
->inject('dbForConsole')
->inject('project')
->inject('user')
->inject('events')
->inject('queueForEvents')
->inject('queueForMigrations')
->inject('request')
->action(function (array $resources, string $projectId, Response $response, Database $dbForProject, Database $dbForConsole, Document $project, Document $user, Event $events, Request $request) {
->action(function (array $resources, string $projectId, Response $response, Database $dbForProject, Database $dbForConsole, Document $project, Document $user, Event $queueForEvents, Migration $queueForMigrations, Request $request) {
$firebase = new OAuth2Firebase(
App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''),
App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''),
@@ -171,11 +172,10 @@ App::post('/v1/migrations/firebase/oauth')
'errors' => []
]));
$events->setParam('migrationId', $migration->getId());
$queueForEvents->setParam('migrationId', $migration->getId());
// Trigger Transfer
$event = new Migration();
$event
$queueForMigrations
->setMigration($migration)
->setProject($project)
->setUser($user)
@@ -205,8 +205,9 @@ App::post('/v1/migrations/firebase')
->inject('dbForProject')
->inject('project')
->inject('user')
->inject('events')
->action(function (array $resources, string $serviceAccount, Response $response, Database $dbForProject, Document $project, Document $user, Event $events) {
->inject('queueForEvents')
->inject('queueForMigrations')
->action(function (array $resources, string $serviceAccount, Response $response, Database $dbForProject, Document $project, Document $user, Event $queueForEvents, Migration $queueForMigrations) {
$serviceAccountData = json_decode($serviceAccount, true);
if (empty($serviceAccountData)) {
@@ -231,11 +232,10 @@ App::post('/v1/migrations/firebase')
'errors' => [],
]));
$events->setParam('migrationId', $migration->getId());
$queueForEvents->setParam('migrationId', $migration->getId());
// Trigger Transfer
$event = new Migration();
$event
$queueForMigrations
->setMigration($migration)
->setProject($project)
->setUser($user)
@@ -270,8 +270,9 @@ App::post('/v1/migrations/supabase')
->inject('dbForProject')
->inject('project')
->inject('user')
->inject('events')
->action(function (array $resources, string $endpoint, string $apiKey, string $databaseHost, string $username, string $password, int $port, Response $response, Database $dbForProject, Document $project, Document $user, Event $events) {
->inject('queueForEvents')
->inject('queueForMigrations')
->action(function (array $resources, string $endpoint, string $apiKey, string $databaseHost, string $username, string $password, int $port, Response $response, Database $dbForProject, Document $project, Document $user, Event $queueForEvents, Migration $queueForMigrations) {
$migration = $dbForProject->createDocument('migrations', new Document([
'$id' => ID::unique(),
'status' => 'pending',
@@ -291,11 +292,10 @@ App::post('/v1/migrations/supabase')
'errors' => [],
]));
$events->setParam('migrationId', $migration->getId());
$queueForEvents->setParam('migrationId', $migration->getId());
// Trigger Transfer
$event = new Migration();
$event
$queueForMigrations
->setMigration($migration)
->setProject($project)
->setUser($user)
@@ -331,8 +331,9 @@ App::post('/v1/migrations/nhost')
->inject('dbForProject')
->inject('project')
->inject('user')
->inject('events')
->action(function (array $resources, string $subdomain, string $region, string $adminSecret, string $database, string $username, string $password, int $port, Response $response, Database $dbForProject, Document $project, Document $user, Event $events) {
->inject('queueForEvents')
->inject('queueForMigrations')
->action(function (array $resources, string $subdomain, string $region, string $adminSecret, string $database, string $username, string $password, int $port, Response $response, Database $dbForProject, Document $project, Document $user, Event $queueForEvents, Migration $queueForMigrations) {
$migration = $dbForProject->createDocument('migrations', new Document([
'$id' => ID::unique(),
'status' => 'pending',
@@ -353,11 +354,10 @@ App::post('/v1/migrations/nhost')
'errors' => [],
]));
$events->setParam('migrationId', $migration->getId());
$queueForEvents->setParam('migrationId', $migration->getId());
// Trigger Transfer
$event = new Migration();
$event
$queueForMigrations
->setMigration($migration)
->setProject($project)
->setUser($user)
@@ -995,8 +995,8 @@ App::patch('/v1/migrations/:migrationId')
->inject('dbForProject')
->inject('project')
->inject('user')
->inject('events')
->action(function (string $migrationId, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventInstance) {
->inject('queueForMigrations')
->action(function (string $migrationId, Response $response, Database $dbForProject, Document $project, Document $user, Migration $queueForMigrations) {
$migration = $dbForProject->getDocument('migrations', $migrationId);
if ($migration->isEmpty()) {
@@ -1012,8 +1012,7 @@ App::patch('/v1/migrations/:migrationId')
->setAttribute('dateUpdated', \time());
// Trigger Migration
$event = new Migration();
$event
$queueForMigrations
->setMigration($migration)
->setProject($project)
->setUser($user)
@@ -1038,8 +1037,8 @@ App::delete('/v1/migrations/:migrationId')
->param('migrationId', '', new UID(), 'Migration ID.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $migrationId, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $migrationId, Response $response, Database $dbForProject, Event $queueForEvents) {
$migration = $dbForProject->getDocument('migrations', $migrationId);
if ($migration->isEmpty()) {
@@ -1050,7 +1049,7 @@ App::delete('/v1/migrations/:migrationId')
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove migration from DB');
}
$events->setParam('migrationId', $migration->getId());
$queueForEvents->setParam('migrationId', $migration->getId());
$response->noContent();
});
+10 -11
View File
@@ -92,12 +92,12 @@ App::post('/v1/projects')
$projectId = ($projectId == 'unique()') ? ID::unique() : $projectId;
$backups['database_db_fra1_v14x_02'] = ['from' => '7:30', 'to' => '8:15'];
$backups['database_db_fra1_v14x_03'] = ['from' => '10:30', 'to' => '11:15'];
$backups['database_db_fra1_v14x_04'] = ['from' => '13:30', 'to' => '14:15'];
$backups['database_db_fra1_v14x_05'] = ['from' => '4:30', 'to' => '5:15'];
$backups['database_db_fra1_v14x_06'] = ['from' => '16:30', 'to' => '17:15'];
$backups['database_db_fra1_v14x_07'] = ['from' => '19:30', 'to' => '20:15'];
$backups['database_db_fra1_v14x_02'] = ['from' => '03:00', 'to' => '05:00'];
$backups['database_db_fra1_v14x_03'] = ['from' => '00:00', 'to' => '02:00'];
$backups['database_db_fra1_v14x_04'] = ['from' => '00:00', 'to' => '02:00'];
$backups['database_db_fra1_v14x_05'] = ['from' => '00:00', 'to' => '02:00'];
$backups['database_db_fra1_v14x_06'] = ['from' => '00:00', 'to' => '02:00'];
$backups['database_db_fra1_v14x_07'] = ['from' => '00:00', 'to' => '02:00'];
$databases = Config::getParam('pools-database', []);
@@ -123,7 +123,7 @@ App::post('/v1/projects')
$databaseOverride = App::getEnv('_APP_DATABASE_OVERRIDE', null);
$index = array_search($databaseOverride, $databases);
if ($index) {
if ($index !== false) {
$database = $databases[$index];
} else {
$database = $databases[array_rand($databases)];
@@ -864,15 +864,15 @@ App::delete('/v1/projects/:projectId')
->inject('response')
->inject('user')
->inject('dbForConsole')
->inject('deletes')
->action(function (string $projectId, Response $response, Document $user, Database $dbForConsole, Delete $deletes) {
->inject('queueForDeletes')
->action(function (string $projectId, Response $response, Document $user, Database $dbForConsole, Delete $queueForDeletes) {
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$deletes
$queueForDeletes
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($project);
@@ -1703,7 +1703,6 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale')
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
$message
->setParam('{{hello}}', $localeObj->getText("emails.{$type}.hello"))
->setParam('{{user}}', '')
->setParam('{{footer}}', $localeObj->getText("emails.{$type}.footer"))
->setParam('{{body}}', $localeObj->getText('emails.' . $type . '.body'))
->setParam('{{thanks}}', $localeObj->getText("emails.{$type}.thanks"))
+15 -15
View File
@@ -37,10 +37,11 @@ App::post('/v1/proxy/rules')
->param('resourceId', '', new UID(), 'ID of resource for the action type. If resourceType is "api", leave empty. If resourceType is "function", provide ID of the function.', true)
->inject('response')
->inject('project')
->inject('events')
->inject('queueForCertificates')
->inject('queueForEvents')
->inject('dbForConsole')
->inject('dbForProject')
->action(function (string $domain, string $resourceType, string $resourceId, Response $response, Document $project, Event $events, Database $dbForConsole, Database $dbForProject) {
->action(function (string $domain, string $resourceType, string $resourceId, Response $response, Document $project, Certificate $queueForCertificates, Event $queueForEvents, Database $dbForConsole, Database $dbForProject) {
$mainDomain = App::getEnv('_APP_DOMAIN', '');
if ($domain === $mainDomain) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'You cannot assign your main domain to specific resource. Please use subdomain or a different domain.');
@@ -113,8 +114,7 @@ App::post('/v1/proxy/rules')
if ($validator->isValid($domain->get())) {
$status = 'verifying';
$event = new Certificate();
$event
$queueForCertificates
->setDomain(new Document([
'domain' => $rule->getAttribute('domain')
]))
@@ -125,7 +125,7 @@ App::post('/v1/proxy/rules')
$rule->setAttribute('status', $status);
$rule = $dbForConsole->createDocument('rules', $rule);
$events->setParam('ruleId', $rule->getId());
$queueForEvents->setParam('ruleId', $rule->getId());
$rule->setAttribute('logs', '');
@@ -235,9 +235,9 @@ App::delete('/v1/proxy/rules/:ruleId')
->inject('response')
->inject('project')
->inject('dbForConsole')
->inject('deletes')
->inject('events')
->action(function (string $ruleId, Response $response, Document $project, Database $dbForConsole, Delete $deletes, Event $events) {
->inject('queueForDeletes')
->inject('queueForEvents')
->action(function (string $ruleId, Response $response, Document $project, Database $dbForConsole, Delete $queueForDeletes, Event $queueForEvents) {
$rule = $dbForConsole->getDocument('rules', $ruleId);
if ($rule->isEmpty() || $rule->getAttribute('projectInternalId') !== $project->getInternalId()) {
@@ -246,11 +246,11 @@ App::delete('/v1/proxy/rules/:ruleId')
$dbForConsole->deleteDocument('rules', $rule->getId());
$deletes
$queueForDeletes
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($rule);
$events->setParam('ruleId', $rule->getId());
$queueForEvents->setParam('ruleId', $rule->getId());
$response->noContent();
});
@@ -270,10 +270,11 @@ App::patch('/v1/proxy/rules/:ruleId/verification')
->label('sdk.response.model', Response::MODEL_PROXY_RULE)
->param('ruleId', '', new UID(), 'Rule ID.')
->inject('response')
->inject('events')
->inject('queueForCertificates')
->inject('queueForEvents')
->inject('project')
->inject('dbForConsole')
->action(function (string $ruleId, Response $response, Event $events, Document $project, Database $dbForConsole) {
->action(function (string $ruleId, Response $response, Certificate $queueForCertificates, Event $queueForEvents, Document $project, Database $dbForConsole) {
$rule = $dbForConsole->getDocument('rules', $ruleId);
if ($rule->isEmpty() || $rule->getAttribute('projectInternalId') !== $project->getInternalId()) {
@@ -300,14 +301,13 @@ App::patch('/v1/proxy/rules/:ruleId/verification')
$dbForConsole->updateDocument('rules', $rule->getId(), $rule->setAttribute('status', 'verifying'));
// Issue a TLS certificate when domain is verified
$event = new Certificate();
$event
$queueForCertificates
->setDomain(new Document([
'domain' => $rule->getAttribute('domain')
]))
->trigger();
$events->setParam('ruleId', $rule->getId());
$queueForEvents->setParam('ruleId', $rule->getId());
$certificate = $dbForConsole->getDocument('certificates', $rule->getAttribute('certificateId', ''));
$rule->setAttribute('logs', $certificate->getAttribute('logs', ''));
+24 -22
View File
@@ -72,8 +72,8 @@ App::post('/v1/storage/buckets')
->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true)
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, string $compression, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, string $compression, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $queueForEvents) {
$bucketId = $bucketId === 'unique()' ? ID::unique() : $bucketId;
@@ -135,7 +135,7 @@ App::post('/v1/storage/buckets')
throw new Exception(Exception::STORAGE_BUCKET_ALREADY_EXISTS);
}
$events
$queueForEvents
->setParam('bucketId', $bucket->getId())
;
@@ -246,8 +246,8 @@ App::put('/v1/storage/buckets/:bucketId')
->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true)
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, string $compression, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, string $compression, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $queueForEvents) {
$bucket = $dbForProject->getDocument('buckets', $bucketId);
if ($bucket->isEmpty()) {
@@ -280,7 +280,7 @@ App::put('/v1/storage/buckets/:bucketId')
->setAttribute('antivirus', $antivirus));
$dbForProject->updateCollection('bucket_' . $bucket->getInternalId(), $permissions, $fileSecurity);
$events
$queueForEvents
->setParam('bucketId', $bucket->getId())
;
@@ -304,9 +304,9 @@ App::delete('/v1/storage/buckets/:bucketId')
->param('bucketId', '', new UID(), 'Bucket unique ID.')
->inject('response')
->inject('dbForProject')
->inject('deletes')
->inject('events')
->action(function (string $bucketId, Response $response, Database $dbForProject, Delete $deletes, Event $events) {
->inject('queueForDeletes')
->inject('queueForEvents')
->action(function (string $bucketId, Response $response, Database $dbForProject, Delete $queueForDeletes, Event $queueForEvents) {
$bucket = $dbForProject->getDocument('buckets', $bucketId);
if ($bucket->isEmpty()) {
@@ -317,11 +317,11 @@ App::delete('/v1/storage/buckets/:bucketId')
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove bucket from DB');
}
$deletes
$queueForDeletes
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($bucket);
$events
$queueForEvents
->setParam('bucketId', $bucket->getId())
->setPayload($response->output($bucket, Response::MODEL_BUCKET))
;
@@ -359,11 +359,12 @@ App::post('/v1/storage/buckets/:bucketId/files')
->inject('response')
->inject('dbForProject')
->inject('user')
->inject('events')
->inject('queueForEvents')
->inject('mode')
->inject('deviceFiles')
->inject('deviceLocal')
->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) {
->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, string $mode, Device $deviceFiles, Device $deviceLocal) {
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
@@ -669,7 +670,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
}
}
$events
$queueForEvents
->setParam('bucketId', $bucket->getId())
->setParam('fileId', $file->getId())
->setContext('bucket', $bucket)
@@ -1305,8 +1306,9 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
->inject('dbForProject')
->inject('user')
->inject('mode')
->inject('events')
->action(function (string $bucketId, string $fileId, ?string $name, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $events) {
->inject('queueForEvents')
->action(function (string $bucketId, string $fileId, ?string $name, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $queueForEvents) {
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
@@ -1378,7 +1380,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
$file = Authorization::skip(fn() => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file));
}
$events
$queueForEvents
->setParam('bucketId', $bucket->getId())
->setParam('fileId', $file->getId())
->setContext('bucket', $bucket)
@@ -1409,11 +1411,11 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
->param('fileId', '', new UID(), 'File ID.')
->inject('response')
->inject('dbForProject')
->inject('events')
->inject('queueForEvents')
->inject('mode')
->inject('deviceFiles')
->inject('deletes')
->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, string $mode, Device $deviceFiles, Delete $deletes) {
->inject('queueForDeletes')
->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $queueForEvents, string $mode, Device $deviceFiles, Delete $queueForDeletes) {
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
@@ -1453,7 +1455,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
}
if ($deviceDeleted) {
$deletes
$queueForDeletes
->setType(DELETE_TYPE_CACHE_BY_RESOURCE)
->setResource('file/' . $fileId)
;
@@ -1475,7 +1477,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to delete file from device');
}
$events
$queueForEvents
->setParam('bucketId', $bucket->getId())
->setParam('fileId', $file->getId())
->setContext('bucket', $bucket)
+39 -43
View File
@@ -60,8 +60,8 @@ App::post('/v1/teams')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
$isAppUser = Auth::isAppUser(Authorization::getRoles());
@@ -117,10 +117,10 @@ App::post('/v1/teams')
$dbForProject->deleteCachedDocument('users', $user->getId());
}
$events->setParam('teamId', $team->getId());
$queueForEvents->setParam('teamId', $team->getId());
if (!empty($user->getId())) {
$events->setParam('userId', $user->getId());
$queueForEvents->setParam('userId', $user->getId());
}
$response
@@ -256,8 +256,8 @@ App::put('/v1/teams/:teamId')
->inject('requestTimestamp')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $teamId, string $name, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $teamId, string $name, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $queueForEvents) {
$team = $dbForProject->getDocument('teams', $teamId);
@@ -273,7 +273,7 @@ App::put('/v1/teams/:teamId')
return $dbForProject->updateDocument('teams', $team->getId(), $team);
});
$events->setParam('teamId', $team->getId());
$queueForEvents->setParam('teamId', $team->getId());
$response->dynamic($team, Response::MODEL_TEAM);
});
@@ -298,8 +298,8 @@ App::put('/v1/teams/:teamId/prefs')
->param('prefs', '', new Assoc(), 'Prefs key-value JSON object.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $teamId, array $prefs, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $teamId, array $prefs, Response $response, Database $dbForProject, Event $queueForEvents) {
$team = $dbForProject->getDocument('teams', $teamId);
@@ -309,7 +309,7 @@ App::put('/v1/teams/:teamId/prefs')
$team = $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('prefs', $prefs));
$events->setParam('teamId', $team->getId());
$queueForEvents->setParam('teamId', $team->getId());
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
@@ -330,9 +330,9 @@ App::delete('/v1/teams/:teamId')
->param('teamId', '', new UID(), 'Team ID.')
->inject('response')
->inject('dbForProject')
->inject('events')
->inject('deletes')
->action(function (string $teamId, Response $response, Database $dbForProject, Event $events, Delete $deletes) {
->inject('queueForEvents')
->inject('queueForDeletes')
->action(function (string $teamId, Response $response, Database $dbForProject, Event $queueForEvents, Delete $queueForDeletes) {
$team = $dbForProject->getDocument('teams', $teamId);
@@ -344,11 +344,11 @@ App::delete('/v1/teams/:teamId')
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove team from DB');
}
$deletes
$queueForDeletes
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($team);
$events
$queueForEvents
->setParam('teamId', $team->getId())
->setPayload($response->output($team, Response::MODEL_TEAM))
;
@@ -385,10 +385,10 @@ App::post('/v1/teams/:teamId/memberships')
->inject('user')
->inject('dbForProject')
->inject('locale')
->inject('mails')
->inject('messaging')
->inject('events')
->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, EventPhone $messaging, Event $events) {
->inject('queueForMails')
->inject('queueForMessaging')
->inject('queueForEvents')
->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, EventPhone $queueForMessaging, Event $queueForEvents) {
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
@@ -555,7 +555,12 @@ App::post('/v1/teams/:teamId/memberships')
$customTemplate = $project->getAttribute('templates', [])['email.invitation-' . $locale->default] ?? [];
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl');
$message->setParam('{{body}}', $body);
$message
->setParam('{{body}}', $body)
->setParam('{{hello}}', $locale->getText("emails.invitation.hello"))
->setParam('{{footer}}', $locale->getText("emails.invitation.footer"))
->setParam('{{thanks}}', $locale->getText("emails.invitation.thanks"))
->setParam('{{signature}}', $locale->getText("emails.invitation.signature"));
$body = $message->render();
$smtp = $project->getAttribute('smtp', []);
@@ -576,7 +581,7 @@ App::post('/v1/teams/:teamId/memberships')
$replyTo = $smtp['replyTo'];
}
$mails
$queueForMails
->setSmtpHost($smtp['host'] ?? '')
->setSmtpPort($smtp['port'] ?? '')
->setSmtpUsername($smtp['username'] ?? '')
@@ -598,7 +603,7 @@ App::post('/v1/teams/:teamId/memberships')
$subject = $customTemplate['subject'] ?? $subject;
}
$mails
$queueForMails
->setSmtpReplyTo($replyTo)
->setSmtpSenderEmail($senderEmail)
->setSmtpSenderName($senderName);
@@ -606,16 +611,7 @@ App::post('/v1/teams/:teamId/memberships')
$emailVariables = [
'owner' => $user->getAttribute('name'),
'subject' => $subject,
'hello' => $locale->getText("emails.invitation.hello"),
'body' => $body,
'footer' => $locale->getText("emails.invitation.footer"),
'thanks' => $locale->getText("emails.invitation.thanks"),
'signature' => $locale->getText("emails.invitation.signature"),
'direction' => $locale->getText('settings.direction'),
'bg-body' => '#f7f7f7',
'bg-content' => '#ffffff',
'text-content' => '#000000',
/* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */
'user' => $user->getAttribute('name'),
'team' => $team->getAttribute('name'),
@@ -623,7 +619,7 @@ App::post('/v1/teams/:teamId/memberships')
'redirect' => $url
];
$mails
$queueForMails
->setSubject($subject)
->setBody($body)
->setRecipient($invitee->getAttribute('email'))
@@ -642,14 +638,14 @@ App::post('/v1/teams/:teamId/memberships')
$message = $message->setParam('{{token}}', $url);
$message = $message->render();
$messaging
$queueForMessaging
->setRecipient($phone)
->setMessage($message)
->trigger();
}
}
$events
$queueForEvents
->setParam('teamId', $team->getId())
->setParam('membershipId', $membership->getId())
;
@@ -812,8 +808,8 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
$team = $dbForProject->getDocument('teams', $teamId);
if ($team->isEmpty()) {
@@ -849,7 +845,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
*/
$dbForProject->deleteCachedDocument('users', $profile->getId());
$events
$queueForEvents
->setParam('teamId', $team->getId())
->setParam('membershipId', $membership->getId());
@@ -887,8 +883,8 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
->inject('dbForProject')
->inject('project')
->inject('geodb')
->inject('events')
->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Reader $geodb, Event $events) {
->inject('queueForEvents')
->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Reader $geodb, Event $queueForEvents) {
$protocol = $request->getProtocol();
$membership = $dbForProject->getDocument('memberships', $membershipId);
@@ -972,7 +968,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
$team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1)));
$events
$queueForEvents
->setParam('teamId', $team->getId())
->setParam('membershipId', $membership->getId())
;
@@ -1014,8 +1010,8 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
->param('membershipId', '', new UID(), 'Membership ID.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject, Event $queueForEvents) {
$membership = $dbForProject->getDocument('memberships', $membershipId);
@@ -1054,7 +1050,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team));
}
$events
$queueForEvents
->setParam('teamId', $team->getId())
->setParam('membershipId', $membership->getId())
->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP))
+65 -68
View File
@@ -41,7 +41,7 @@ use Appwrite\Auth\Validator\PasswordDictionary;
use Appwrite\Auth\Validator\PersonalData;
/** TODO: Remove function when we move to using utopia/platform */
function createUser(string $hash, mixed $hashOptions, string $userId, ?string $email, ?string $password, ?string $phone, string $name, Document $project, Database $dbForProject, Event $events): Document
function createUser(string $hash, mixed $hashOptions, string $userId, ?string $email, ?string $password, ?string $phone, string $name, Document $project, Database $dbForProject, Event $queueForEvents): Document
{
$hashOptionsObject = (\is_string($hashOptions)) ? \json_decode($hashOptions, true) : $hashOptions; // Cast to JSON array
$passwordHistory = $project->getAttribute('auths', [])['passwordHistory'] ?? 0;
@@ -102,7 +102,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
throw new Exception(Exception::USER_ALREADY_EXISTS);
}
$events->setParam('userId', $user->getId());
$queueForEvents->setParam('userId', $user->getId());
return $user;
}
@@ -130,10 +130,9 @@ App::post('/v1/users')
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, ?string $email, ?string $phone, ?string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('plaintext', '{}', $userId, $email, $password, $phone, $name, $project, $dbForProject, $events);
->inject('queueForEvents')
->action(function (string $userId, ?string $email, ?string $phone, ?string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $queueForEvents) {
$user = createUser('plaintext', '{}', $userId, $email, $password, $phone, $name, $project, $dbForProject, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -162,9 +161,9 @@ App::post('/v1/users/bcrypt')
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('bcrypt', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
->inject('queueForEvents')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $queueForEvents) {
$user = createUser('bcrypt', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -193,9 +192,9 @@ App::post('/v1/users/md5')
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('md5', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
->inject('queueForEvents')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $queueForEvents) {
$user = createUser('md5', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -224,9 +223,9 @@ App::post('/v1/users/argon2')
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('argon2', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
->inject('queueForEvents')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $queueForEvents) {
$user = createUser('argon2', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -256,15 +255,15 @@ App::post('/v1/users/sha')
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $passwordVersion, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, string $email, string $password, string $passwordVersion, string $name, Response $response, Document $project, Database $dbForProject, Event $queueForEvents) {
$options = '{}';
if (!empty($passwordVersion)) {
$options = '{"version":"' . $passwordVersion . '"}';
}
$user = createUser('sha', $options, $userId, $email, $password, null, $name, $project, $dbForProject, $events);
$user = createUser('sha', $options, $userId, $email, $password, null, $name, $project, $dbForProject, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -293,9 +292,9 @@ App::post('/v1/users/phpass')
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('phpass', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
->inject('queueForEvents')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $queueForEvents) {
$user = createUser('phpass', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -329,8 +328,8 @@ App::post('/v1/users/scrypt')
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $passwordSalt, int $passwordCpu, int $passwordMemory, int $passwordParallel, int $passwordLength, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, string $email, string $password, string $passwordSalt, int $passwordCpu, int $passwordMemory, int $passwordParallel, int $passwordLength, string $name, Response $response, Document $project, Database $dbForProject, Event $queueForEvents) {
$options = [
'salt' => $passwordSalt,
'costCpu' => $passwordCpu,
@@ -339,7 +338,7 @@ App::post('/v1/users/scrypt')
'length' => $passwordLength
];
$user = createUser('scrypt', \json_encode($options), $userId, $email, $password, null, $name, $project, $dbForProject, $events);
$user = createUser('scrypt', \json_encode($options), $userId, $email, $password, null, $name, $project, $dbForProject, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -371,9 +370,9 @@ App::post('/v1/users/scrypt-modified')
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $passwordSalt, string $passwordSaltSeparator, string $passwordSignerKey, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('scryptMod', '{"signerKey":"' . $passwordSignerKey . '","saltSeparator":"' . $passwordSaltSeparator . '","salt":"' . $passwordSalt . '"}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
->inject('queueForEvents')
->action(function (string $userId, string $email, string $password, string $passwordSalt, string $passwordSaltSeparator, string $passwordSignerKey, string $name, Response $response, Document $project, Database $dbForProject, Event $queueForEvents) {
$user = createUser('scryptMod', '{"signerKey":"' . $passwordSignerKey . '","saltSeparator":"' . $passwordSaltSeparator . '","salt":"' . $passwordSalt . '"}', $userId, $email, $password, null, $name, $project, $dbForProject, $queueForEvents);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -716,8 +715,8 @@ App::patch('/v1/users/:userId/status')
->param('status', null, new Boolean(true), 'User Status. To activate the user pass `true` and to block the user pass `false`.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, bool $status, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, bool $status, Response $response, Database $dbForProject, Event $queueForEvents) {
$user = $dbForProject->getDocument('users', $userId);
@@ -727,7 +726,7 @@ App::patch('/v1/users/:userId/status')
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('status', (bool) $status));
$events
$queueForEvents
->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_USER);
@@ -752,8 +751,8 @@ App::put('/v1/users/:userId/labels')
->param('labels', [], new ArrayList(new Text(36, allowList: [...Text::NUMBERS, ...Text::ALPHABET_UPPER, ...Text::ALPHABET_LOWER]), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of user labels. Replaces the previous labels. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' labels are allowed, each up to 36 alphanumeric characters long.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, array $labels, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, array $labels, Response $response, Database $dbForProject, Event $queueForEvents) {
$user = $dbForProject->getDocument('users', $userId);
@@ -765,7 +764,7 @@ App::put('/v1/users/:userId/labels')
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
$events
$queueForEvents
->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_USER);
@@ -790,8 +789,8 @@ App::patch('/v1/users/:userId/verification/phone')
->param('phoneVerification', false, new Boolean(), 'User phone verification status.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, bool $phoneVerification, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, bool $phoneVerification, Response $response, Database $dbForProject, Event $queueForEvents) {
$user = $dbForProject->getDocument('users', $userId);
@@ -801,7 +800,7 @@ App::patch('/v1/users/:userId/verification/phone')
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('phoneVerification', $phoneVerification));
$events
$queueForEvents
->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_USER);
@@ -827,8 +826,8 @@ App::patch('/v1/users/:userId/name')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $name, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, string $name, Response $response, Database $dbForProject, Event $queueForEvents) {
$user = $dbForProject->getDocument('users', $userId);
@@ -840,7 +839,7 @@ App::patch('/v1/users/:userId/name')
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
$events->setParam('userId', $user->getId());
$queueForEvents->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_USER);
});
@@ -866,8 +865,8 @@ App::patch('/v1/users/:userId/password')
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $password, Response $response, Document $project, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, string $password, Response $response, Document $project, Database $dbForProject, Event $queueForEvents) {
$user = $dbForProject->getDocument('users', $userId);
@@ -905,7 +904,7 @@ App::patch('/v1/users/:userId/password')
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
$events->setParam('userId', $user->getId());
$queueForEvents->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_USER);
});
@@ -930,8 +929,8 @@ App::patch('/v1/users/:userId/email')
->param('email', '', new Email(), 'User email.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, string $email, Response $response, Database $dbForProject, Event $queueForEvents) {
$user = $dbForProject->getDocument('users', $userId);
@@ -962,7 +961,7 @@ App::patch('/v1/users/:userId/email')
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
}
$events->setParam('userId', $user->getId());
$queueForEvents->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_USER);
});
@@ -986,8 +985,8 @@ App::patch('/v1/users/:userId/phone')
->param('number', '', new Phone(), 'User phone number.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $number, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, string $number, Response $response, Database $dbForProject, Event $queueForEvents) {
$user = $dbForProject->getDocument('users', $userId);
@@ -1006,7 +1005,7 @@ App::patch('/v1/users/:userId/phone')
throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS);
}
$events->setParam('userId', $user->getId());
$queueForEvents->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_USER);
});
@@ -1031,8 +1030,8 @@ App::patch('/v1/users/:userId/verification')
->param('emailVerification', false, new Boolean(), 'User email verification status.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, bool $emailVerification, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, bool $emailVerification, Response $response, Database $dbForProject, Event $queueForEvents) {
$user = $dbForProject->getDocument('users', $userId);
@@ -1042,7 +1041,7 @@ App::patch('/v1/users/:userId/verification')
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', $emailVerification));
$events->setParam('userId', $user->getId());
$queueForEvents->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_USER);
});
@@ -1064,8 +1063,8 @@ App::patch('/v1/users/:userId/prefs')
->param('prefs', '', new Assoc(), 'Prefs key-value JSON object.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, array $prefs, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, array $prefs, Response $response, Database $dbForProject, Event $queueForEvents) {
$user = $dbForProject->getDocument('users', $userId);
@@ -1075,7 +1074,7 @@ App::patch('/v1/users/:userId/prefs')
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs));
$events
$queueForEvents
->setParam('userId', $user->getId());
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
@@ -1099,8 +1098,8 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
->param('sessionId', '', new UID(), 'Session ID.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $sessionId, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, string $sessionId, Response $response, Database $dbForProject, Event $queueForEvents) {
$user = $dbForProject->getDocument('users', $userId);
@@ -1117,7 +1116,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
$dbForProject->deleteDocument('sessions', $session->getId());
$dbForProject->deleteCachedDocument('users', $user->getId());
$events
$queueForEvents
->setParam('userId', $user->getId())
->setParam('sessionId', $sessionId)
->setPayload($response->output($session, Response::MODEL_SESSION));
@@ -1142,8 +1141,8 @@ App::delete('/v1/users/:userId/sessions')
->param('userId', '', new UID(), 'User ID.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, Response $response, Database $dbForProject, Event $events) {
->inject('queueForEvents')
->action(function (string $userId, Response $response, Database $dbForProject, Event $queueForEvents) {
$user = $dbForProject->getDocument('users', $userId);
@@ -1161,7 +1160,7 @@ App::delete('/v1/users/:userId/sessions')
$dbForProject->deleteCachedDocument('users', $user->getId());
$events
$queueForEvents
->setParam('userId', $user->getId())
->setPayload($response->output($user, Response::MODEL_USER));
@@ -1185,9 +1184,9 @@ App::delete('/v1/users/:userId')
->param('userId', '', new UID(), 'User ID.')
->inject('response')
->inject('dbForProject')
->inject('events')
->inject('deletes')
->action(function (string $userId, Response $response, Database $dbForProject, Event $events, Delete $deletes) {
->inject('queueForEvents')
->inject('queueForDeletes')
->action(function (string $userId, Response $response, Database $dbForProject, Event $queueForEvents, Delete $queueForDeletes) {
$user = $dbForProject->getDocument('users', $userId);
@@ -1200,11 +1199,11 @@ App::delete('/v1/users/:userId')
$dbForProject->deleteDocument('users', $userId);
$deletes
$queueForDeletes
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($clone);
$events
$queueForEvents
->setParam('userId', $user->getId())
->setPayload($response->output($clone, Response::MODEL_USER));
@@ -1228,9 +1227,7 @@ App::delete('/v1/users/identities/:identityId')
->param('identityId', '', new UID(), 'Identity ID.')
->inject('response')
->inject('dbForProject')
->inject('events')
->inject('deletes')
->action(function (string $identityId, Response $response, Database $dbForProject, Event $events, Delete $deletes) {
->action(function (string $identityId, Response $response, Database $dbForProject) {
$identity = $dbForProject->getDocument('identities', $identityId);
+61 -23
View File
@@ -22,7 +22,6 @@ use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\UID;
use Utopia\Detector\Adapter\Bun;
use Utopia\Detector\Adapter\CPP;
use Utopia\Detector\Adapter\Dart;
@@ -36,10 +35,11 @@ use Utopia\Detector\Adapter\Ruby;
use Utopia\Detector\Adapter\Swift;
use Utopia\Detector\Detector;
use Utopia\Validator\Boolean;
use Utopia\VCS\Exception\RepositoryNotFound;
use function Swoole\Coroutine\batch;
$createGitDeployments = function (GitHub $github, string $providerInstallationId, array $repositories, string $providerBranch, string $providerBranchUrl, string $providerRepositoryName, string $providerRepositoryUrl, string $providerRepositoryOwner, string $providerCommitHash, string $providerCommitAuthor, string $providerCommitAuthorUrl, string $providerCommitMessage, string $providerCommitUrl, string $providerPullRequestId, bool $external, Database $dbForConsole, callable $getProjectDB, Request $request) {
$createGitDeployments = function (GitHub $github, string $providerInstallationId, array $repositories, string $providerBranch, string $providerBranchUrl, string $providerRepositoryName, string $providerRepositoryUrl, string $providerRepositoryOwner, string $providerCommitHash, string $providerCommitAuthor, string $providerCommitAuthorUrl, string $providerCommitMessage, string $providerCommitUrl, string $providerPullRequestId, bool $external, Database $dbForConsole, Build $queueForBuilds, callable $getProjectDB, Request $request) {
foreach ($repositories as $resource) {
$resourceType = $resource->getAttribute('resourceType');
@@ -66,7 +66,14 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
}
$owner = $github->getOwnerName($providerInstallationId) ?? '';
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
try {
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($repositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
} catch (RepositoryNotFound $e) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
if (empty($repositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
@@ -154,7 +161,14 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
$message = 'Authorization required for external contributor.';
$providerRepositoryId = $resource->getAttribute('providerRepositoryId');
$repositoryName = $github->getRepositoryName($providerRepositoryId);
try {
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($repositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
} catch (RepositoryNotFound $e) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
$owner = $github->getOwnerName($providerInstallationId);
$github->updateCommitStatus($repositoryName, $providerCommitHash, $owner, 'failure', $message, $authorizeUrl, $name);
continue;
@@ -206,15 +220,21 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
$message = 'Starting...';
$providerRepositoryId = $resource->getAttribute('providerRepositoryId');
$repositoryName = $github->getRepositoryName($providerRepositoryId);
try {
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($repositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
} catch (RepositoryNotFound $e) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
$owner = $github->getOwnerName($providerInstallationId);
$providerTargetUrl = $request->getProtocol() . '://' . $request->getHostname() . "/console/project-$projectId/functions/function-$functionId";
$github->updateCommitStatus($repositoryName, $providerCommitHash, $owner, 'pending', $message, $providerTargetUrl, $name);
}
$buildEvent = new Build();
$buildEvent
$queueForBuilds
->setType(BUILD_TYPE_DEPLOYMENT)
->setResource($function)
->setDeployment($deployment)
@@ -274,7 +294,7 @@ App::get('/v1/vcs/github/callback')
->label('scope', 'public')
->label('error', __DIR__ . '/../../views/general/error.phtml')
->param('installation_id', '', new Text(256, 0), 'GitHub installation ID', true)
->param('setup_action', '', new Text(256, 0), 'GitHub setup actuon type', true)
->param('setup_action', '', new Text(256, 0), 'GitHub setup action type', true)
->param('state', '', new Text(2048), 'GitHub state. Contains info sent when starting authorization flow.', true)
->param('code', '', new Text(2048, 0), 'OAuth2 code. This is a temporary code that the will be later exchanged for an access token.', true)
->inject('gitHub')
@@ -459,9 +479,12 @@ App::post('/v1/vcs/github/installations/:installationId/providerRepositories/:pr
$github->initializeVariables($providerInstallationId, $privateKey, $githubAppId);
$owner = $github->getOwnerName($providerInstallationId);
$repositoryName = $github->getRepositoryName($providerRepositoryId);
if (empty($repositoryName)) {
try {
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($repositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
} catch (RepositoryNotFound $e) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
@@ -721,9 +744,12 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories/:pro
$github->initializeVariables($providerInstallationId, $privateKey, $githubAppId);
$owner = $github->getOwnerName($providerInstallationId) ?? '';
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($repositoryName)) {
try {
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($repositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
} catch (RepositoryNotFound $e) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
@@ -767,9 +793,12 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories/:pro
$github->initializeVariables($providerInstallationId, $privateKey, $githubAppId);
$owner = $github->getOwnerName($providerInstallationId) ?? '';
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($repositoryName)) {
try {
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($repositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
} catch (RepositoryNotFound $e) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
@@ -792,8 +821,9 @@ App::post('/v1/vcs/github/events')
->inject('response')
->inject('dbForConsole')
->inject('getProjectDB')
->inject('queueForBuilds')
->action(
function (GitHub $github, Request $request, Response $response, Database $dbForConsole, callable $getProjectDB) use ($createGitDeployments) {
function (GitHub $github, Request $request, Response $response, Database $dbForConsole, callable $getProjectDB, Build $queueForBuilds) use ($createGitDeployments) {
$payload = $request->getRawPayload();
$signatureRemote = $request->getHeader('x-hub-signature-256', '');
$signatureLocal = App::getEnv('_APP_VCS_GITHUB_WEBHOOK_SECRET', '');
@@ -834,7 +864,7 @@ App::post('/v1/vcs/github/events')
// create new deployment only on push and not when branch is created
if (!$providerBranchCreated) {
$createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForConsole, $getProjectDB, $request);
$createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForConsole, $queueForBuilds, $getProjectDB, $request);
}
} elseif ($event == $github::EVENT_INSTALLATION) {
if ($parsedPayload["action"] == "deleted") {
@@ -890,7 +920,7 @@ App::post('/v1/vcs/github/events')
Query::orderDesc('$createdAt')
]);
$createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $external, $dbForConsole, $getProjectDB, $request);
$createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $external, $dbForConsole, $queueForBuilds, $getProjectDB, $request);
} elseif ($parsedPayload["action"] == "closed") {
// Allowed external contributions cleanup
@@ -1054,7 +1084,8 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor
->inject('project')
->inject('dbForConsole')
->inject('getProjectDB')
->action(function (string $installationId, string $repositoryId, string $providerPullRequestId, GitHub $github, Request $request, Response $response, Document $project, Database $dbForConsole, callable $getProjectDB) use ($createGitDeployments) {
->inject('queueForBuilds')
->action(function (string $installationId, string $repositoryId, string $providerPullRequestId, GitHub $github, Request $request, Response $response, Document $project, Database $dbForConsole, callable $getProjectDB, Build $queueForBuilds) use ($createGitDeployments) {
$installation = $dbForConsole->getDocument('installations', $installationId);
if ($installation->isEmpty()) {
@@ -1089,13 +1120,20 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor
$providerRepositoryId = $repository->getAttribute('providerRepositoryId');
$owner = $github->getOwnerName($providerInstallationId);
$repositoryName = $github->getRepositoryName($providerRepositoryId);
try {
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
if (empty($repositoryName)) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
} catch (RepositoryNotFound $e) {
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
$pullRequestResponse = $github->getPullRequest($owner, $repositoryName, $providerPullRequestId);
$providerBranch = \explode(':', $pullRequestResponse['head']['label'])[1] ?? '';
$providerCommitHash = $pullRequestResponse['head']['sha'] ?? '';
$createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerCommitHash, $providerPullRequestId, true, $dbForConsole, $getProjectDB, $request);
$createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerCommitHash, $providerPullRequestId, true, $dbForConsole, $queueForBuilds, $getProjectDB, $request);
$response->noContent();
});
+14 -6
View File
@@ -117,12 +117,14 @@ function router(App $utopia, Database $dbForConsole, SwooleRequest $swooleReques
$path .= '?' . $query;
}
$requestHeaders = $request->getHeaders();
$body = \json_encode([
'async' => false,
'body' => $swooleRequest->getContent() ?? '',
'method' => $swooleRequest->server['request_method'],
'path' => $path,
'headers' => $swooleRequest->header
'headers' => $requestHeaders
]);
$headers = [
@@ -208,7 +210,8 @@ App::init()
->inject('localeCodes')
->inject('clients')
->inject('servers')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForConsole, Document $user, Locale $locale, array $localeCodes, array $clients, array $servers) {
->inject('queueForCertificates')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForConsole, Document $user, Locale $locale, array $localeCodes, array $clients, array $servers, Certificate $queueForCertificates) {
/*
* Appwrite Router
*/
@@ -299,7 +302,7 @@ App::init()
Console::info('Issuing a TLS certificate for the main domain (' . $domain->get() . ') in a few seconds...');
(new Certificate())
$queueForCertificates
->setDomain($domainDocument)
->setSkipRenewCheck(true)
->trigger();
@@ -422,7 +425,7 @@ App::init()
->addHeader('Server', 'Appwrite')
->addHeader('X-Content-Type-Options', 'nosniff')
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-Appwrite-Timeout, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma')
->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Origin', $refDomain)
->addHeader('Access-Control-Allow-Credentials', 'true');
@@ -586,7 +589,7 @@ App::options()
$response
->addHeader('Server', 'Appwrite')
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-Appwrite-Timeout, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Fallback-Cookies')
->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Origin', $origin)
->addHeader('Access-Control-Allow-Credentials', 'true')
@@ -689,7 +692,11 @@ App::error()
break;
}
} elseif ($error instanceof Utopia\Database\Exception\Conflict) {
$error = new AppwriteException(AppwriteException::DOCUMENT_UPDATE_CONFLICT, null, null, $error);
$error = new AppwriteException(AppwriteException::DOCUMENT_UPDATE_CONFLICT, previous: $error);
$code = $error->getCode();
$message = $error->getMessage();
} elseif ($error instanceof Utopia\Database\Exception\Timeout) {
$error = new AppwriteException(AppwriteException::DATABASE_TIMEOUT, previous: $error);
$code = $error->getCode();
$message = $error->getMessage();
}
@@ -705,6 +712,7 @@ App::error()
case 402: // Error allowed publicly
case 403: // Error allowed publicly
case 404: // Error allowed publicly
case 408: // Error allowed publicly
case 409: // Error allowed publicly
case 412: // Error allowed publicly
case 416: // Error allowed publicly
+66 -5
View File
@@ -17,6 +17,9 @@ use Utopia\Validator\WhiteList;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Validator\UID;
use Utopia\Validator\Nullable;
use Utopia\VCS\Adapter\Git\GitHub;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
App::get('/v1/mock/tests/foo')
->desc('Get Foo')
@@ -248,8 +251,7 @@ App::get('/v1/mock/tests/general/download')
->addHeader('Content-Disposition', 'attachment; filename="test.txt"')
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
->addHeader('X-Peak', \memory_get_peak_usage())
->send("GET:/v1/mock/tests/general/download:passed")
;
->send("GET:/v1/mock/tests/general/download:passed");
});
App::post('/v1/mock/tests/general/upload')
@@ -331,7 +333,7 @@ App::post('/v1/mock/tests/general/upload')
}
if ($file['size'] !== 38756) {
throw new Exception(Exception::GENERAL_MOCK, 'Wrong file size');
throw new Exception(Exception::GENERAL_MOCK, 'Wrong file size');
}
if (\md5(\file_get_contents($file['tmp_name'])) !== 'd80e7e6999a3eb2ae0d631a96fe135a4') {
@@ -506,8 +508,7 @@ App::get('/v1/mock/tests/general/502-error')
$response
->setStatusCode(502)
->text('This is a text error')
;
->text('This is a text error');
});
App::get('/v1/mock/tests/general/oauth2')
@@ -646,6 +647,66 @@ App::patch('/v1/mock/functions-v2')
$response->noContent();
});
App::get('/v1/mock/github/callback')
->desc('Create installation document using GitHub installation id')
->groups(['mock', 'api', 'vcs'])
->label('scope', 'public')
->label('docs', false)
->param('providerInstallationId', '', new UID(), 'GitHub installation ID')
->param('projectId', '', new UID(), 'Project ID of the project where app is to be installed')
->inject('gitHub')
->inject('project')
->inject('response')
->inject('dbForConsole')
->action(function (string $providerInstallationId, string $projectId, GitHub $github, Document $project, Response $response, Database $dbForConsole) {
$isDevelopment = App::getEnv('_APP_ENV', 'development') === 'development';
if (!$isDevelopment) {
throw new Exception(Exception::GENERAL_NOT_IMPLEMENTED);
}
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
$error = 'Project with the ID from state could not be found.';
throw new Exception(Exception::PROJECT_NOT_FOUND, $error);
}
if (!empty($providerInstallationId)) {
$privateKey = App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY');
$githubAppId = App::getEnv('_APP_VCS_GITHUB_APP_ID');
$github->initializeVariables($providerInstallationId, $privateKey, $githubAppId);
$owner = $github->getOwnerName($providerInstallationId) ?? '';
$projectInternalId = $project->getInternalId();
$teamId = $project->getAttribute('teamId', '');
$installation = new Document([
'$id' => ID::unique(),
'$permissions' => [
Permission::read(Role::team(ID::custom($teamId))),
Permission::update(Role::team(ID::custom($teamId), 'owner')),
Permission::update(Role::team(ID::custom($teamId), 'developer')),
Permission::delete(Role::team(ID::custom($teamId), 'owner')),
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
],
'providerInstallationId' => $providerInstallationId,
'projectId' => $projectId,
'projectInternalId' => $projectInternalId,
'provider' => 'github',
'organization' => $owner,
'personal' => false
]);
$installation = $dbForConsole->createDocument('installations', $installation);
}
$response->json([
'installationId' => $installation->getId(),
]);
});
App::shutdown()
->groups(['mock'])
->inject('utopia')
+38 -38
View File
@@ -96,15 +96,15 @@ App::init()
->inject('response')
->inject('project')
->inject('user')
->inject('events')
->inject('audits')
->inject('deletes')
->inject('database')
->inject('queueForEvents')
->inject('queueForAudits')
->inject('queueForDeletes')
->inject('queueForDatabase')
->inject('dbForProject')
->inject('mode')
->inject('mails')
->inject('queueForMails')
->inject('usage')
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Delete $deletes, EventDatabase $database, Database $dbForProject, string $mode, Mail $mails, Stats $usage) use ($databaseListener) {
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Database $dbForProject, string $mode, Mail $queueForMails, Stats $usage) use ($databaseListener) {
$route = $utopia->getRoute();
@@ -173,12 +173,12 @@ App::init()
/*
* Background Jobs
*/
$events
$queueForEvents
->setEvent($route->getLabel('event', ''))
->setProject($project)
->setUser($user);
$audits
$queueForAudits
->setMode($mode)
->setUserAgent($request->getUserAgent(''))
->setIP($request->getIP())
@@ -194,8 +194,8 @@ App::init()
->setParam('project.{scope}.network.inbound', 0)
->setParam('project.{scope}.network.outbound', 0);
$deletes->setProject($project);
$database->setProject($project);
$queueForDeletes->setProject($project);
$queueForDatabase->setProject($project);
$dbForProject->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', fn ($event, Document $document) => $databaseListener($event, $document, $usage));
$dbForProject->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', fn ($event, Document $document) => $databaseListener($event, $document, $usage));
@@ -360,35 +360,35 @@ App::shutdown()
->inject('response')
->inject('project')
->inject('user')
->inject('events')
->inject('audits')
->inject('queueForEvents')
->inject('queueForAudits')
->inject('usage')
->inject('deletes')
->inject('database')
->inject('queueForDeletes')
->inject('queueForDatabase')
->inject('dbForProject')
->inject('queueForFunctions')
->inject('mode')
->inject('dbForConsole')
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Stats $usage, Delete $deletes, EventDatabase $database, Database $dbForProject, Func $queueForFunctions, string $mode, Database $dbForConsole) use ($parseLabel) {
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Audit $queueForAudits, Stats $usage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Database $dbForProject, Func $queueForFunctions, string $mode, Database $dbForConsole) use ($parseLabel) {
$responsePayload = $response->getPayload();
if (!empty($events->getEvent())) {
if (empty($events->getPayload())) {
$events->setPayload($responsePayload);
if (!empty($queueForEvents->getEvent())) {
if (empty($queueForEvents->getPayload())) {
$queueForEvents->setPayload($responsePayload);
}
/**
* Trigger functions.
*/
$queueForFunctions
->from($events)
->from($queueForEvents)
->trigger();
/**
* Trigger webhooks.
*/
$events
$queueForEvents
->setClass(Event::WEBHOOK_CLASS_NAME)
->setQueue(Event::WEBHOOK_QUEUE_NAME)
->trigger();
@@ -397,12 +397,12 @@ App::shutdown()
* Trigger realtime.
*/
if ($project->getId() !== 'console') {
$allEvents = Event::generateEvents($events->getEvent(), $events->getParams());
$payload = new Document($events->getPayload());
$allEvents = Event::generateEvents($queueForEvents->getEvent(), $queueForEvents->getParams());
$payload = new Document($queueForEvents->getPayload());
$db = $events->getContext('database');
$collection = $events->getContext('collection');
$bucket = $events->getContext('bucket');
$db = $queueForEvents->getContext('database');
$collection = $queueForEvents->getContext('collection');
$bucket = $queueForEvents->getContext('bucket');
$target = Realtime::fromPayload(
// Pass first, most verbose event pattern
@@ -416,13 +416,13 @@ App::shutdown()
Realtime::send(
projectId: $target['projectId'] ?? $project->getId(),
payload: $events->getPayload(),
payload: $queueForEvents->getPayload(),
events: $allEvents,
channels: $target['channels'],
roles: $target['roles'],
options: [
'permissionsChanged' => $target['permissionsChanged'],
'userId' => $events->getParam('userId')
'userId' => $queueForEvents->getParam('userId')
]
);
}
@@ -438,36 +438,36 @@ App::shutdown()
if (!empty($pattern)) {
$resource = $parseLabel($pattern, $responsePayload, $requestParams, $user);
if (!empty($resource) && $resource !== $pattern) {
$audits->setResource($resource);
$queueForAudits->setResource($resource);
}
}
if (!$user->isEmpty()) {
$audits->setUser($user);
$queueForAudits->setUser($user);
}
if (!empty($audits->getResource()) && !empty($audits->getUser()->getId())) {
if (!empty($queueForAudits->getResource()) && !empty($queueForAudits->getUser()->getId())) {
/**
* audits.payload is switched to default true
* in order to auto audit payload for all endpoints
*/
$pattern = $route->getLabel('audits.payload', true);
if (!empty($pattern)) {
$audits->setPayload($responsePayload);
$queueForAudits->setPayload($responsePayload);
}
foreach ($events->getParams() as $key => $value) {
$audits->setParam($key, $value);
foreach ($queueForEvents->getParams() as $key => $value) {
$queueForAudits->setParam($key, $value);
}
$audits->trigger();
$queueForAudits->trigger();
}
if (!empty($deletes->getType())) {
$deletes->trigger();
if (!empty($queueForDeletes->getType())) {
$queueForDeletes->trigger();
}
if (!empty($database->getType())) {
$database->trigger();
if (!empty($queueForDatabase->getType())) {
$queueForDatabase->trigger();
}
/**
+62 -24
View File
@@ -18,7 +18,7 @@ ini_set('display_startup_errors', 1);
ini_set('default_socket_timeout', -1);
error_reporting(E_ALL);
use Appwrite\Event\Usage;
use Appwrite\Event\Migration;
use Appwrite\Extend\Exception;
use Appwrite\Auth\Auth;
use Appwrite\Event\Audit;
@@ -69,7 +69,8 @@ use Utopia\Pools\Group;
use Utopia\Pools\Pool;
use Ahc\Jwt\JWT;
use Ahc\Jwt\JWTException;
use Appwrite\Auth\OAuth2\Github;
use Appwrite\Event\Build;
use Appwrite\Event\Certificate;
use Appwrite\Event\Func;
use MaxMind\Db\Reader;
use PHPMailer\PHPMailer\PHPMailer;
@@ -108,8 +109,8 @@ const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return
const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours
const APP_USER_ACCCESS = 24 * 60 * 60; // 24 hours
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
const APP_CACHE_BUSTER = 512;
const APP_VERSION_STABLE = '1.4.5';
const APP_CACHE_BUSTER = 515;
const APP_VERSION_STABLE = '1.4.9';
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
@@ -118,6 +119,7 @@ const APP_DATABASE_ATTRIBUTE_URL = 'url';
const APP_DATABASE_ATTRIBUTE_INT_RANGE = 'intRange';
const APP_DATABASE_ATTRIBUTE_FLOAT_RANGE = 'floatRange';
const APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH = 1073741824; // 2^32 bits / 4 bits per char
const APP_DATABASE_TIMEOUT_MILLISECONDS = 15000;
const APP_STORAGE_UPLOADS = '/storage/uploads';
const APP_STORAGE_FUNCTIONS = '/storage/functions';
const APP_STORAGE_BUILDS = '/storage/builds';
@@ -145,6 +147,8 @@ const DATABASE_TYPE_CREATE_ATTRIBUTE = 'createAttribute';
const DATABASE_TYPE_CREATE_INDEX = 'createIndex';
const DATABASE_TYPE_DELETE_ATTRIBUTE = 'deleteAttribute';
const DATABASE_TYPE_DELETE_INDEX = 'deleteIndex';
const DATABASE_TYPE_DELETE_COLLECTION = 'deleteCollection';
const DATABASE_TYPE_DELETE_DATABASE = 'deleteDatabase';
// Build Worker Types
const BUILD_TYPE_DEPLOYMENT = 'deployment';
const BUILD_TYPE_RETRY = 'retry';
@@ -259,14 +263,6 @@ Config::load('storage-mimes', __DIR__ . '/config/storage/mimes.php');
Config::load('storage-inputs', __DIR__ . '/config/storage/inputs.php');
Config::load('storage-outputs', __DIR__ . '/config/storage/outputs.php');
$user = App::getEnv('_APP_REDIS_USER', '');
$pass = App::getEnv('_APP_REDIS_PASS', '');
if (!empty($user) || !empty($pass)) {
Resque::setBackend('redis://' . $user . ':' . $pass . '@' . App::getEnv('_APP_REDIS_HOST', '') . ':' . App::getEnv('_APP_REDIS_PORT', ''));
} else {
Resque::setBackend(App::getEnv('_APP_REDIS_HOST', '') . ':' . App::getEnv('_APP_REDIS_PORT', ''));
}
/**
* New DB Filters
*/
@@ -887,18 +883,39 @@ App::setResource('localeCodes', function () {
});
// Queues
App::setResource('events', fn() => new Event('', ''));
App::setResource('audits', fn() => new Audit());
App::setResource('mails', fn() => new Mail());
App::setResource('deletes', fn() => new Delete());
App::setResource('database', fn() => new EventDatabase());
App::setResource('messaging', fn() => new Phone());
App::setResource('queue', function (Group $pools) {
return $pools->get('queue')->pop()->getResource();
}, ['pools']);
App::setResource('queueForMessaging', function (Connection $queue) {
return new Phone($queue);
}, ['queue']);
App::setResource('queueForMails', function (Connection $queue) {
return new Mail($queue);
}, ['queue']);
App::setResource('queueForBuilds', function (Connection $queue) {
return new Build($queue);
}, ['queue']);
App::setResource('queueForDatabase', function (Connection $queue) {
return new EventDatabase($queue);
}, ['queue']);
App::setResource('queueForDeletes', function (Connection $queue) {
return new Delete($queue);
}, ['queue']);
App::setResource('queueForEvents', function (Connection $queue) {
return new Event($queue);
}, ['queue']);
App::setResource('queueForAudits', function (Connection $queue) {
return new Audit($queue);
}, ['queue']);
App::setResource('queueForFunctions', function (Connection $queue) {
return new Func($queue);
}, ['queue']);
App::setResource('queueForCertificates', function (Connection $queue) {
return new Certificate($queue);
}, ['queue']);
App::setResource('queueForMigrations', function (Connection $queue) {
return new Migration($queue);
}, ['queue']);
App::setResource('usage', function ($register) {
return new Stats($register->get('statsd'));
}, ['register']);
@@ -1032,6 +1049,9 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons
}
}
$dbForProject->setMetadata('user', $user->getId());
$dbForConsole->setMetadata('user', $user->getId());
return $user;
}, ['mode', 'project', 'console', 'request', 'response', 'dbForProject', 'dbForConsole']);
@@ -1099,11 +1119,15 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForConsole,
$dbAdapter = $pools
->get($project->getAttribute('database'))
->pop()
->getResource()
;
->getResource();
$database = new Database($dbAdapter, $cache);
$database->setNamespace('_' . $project->getInternalId());
$database
->setNamespace('_' . $project->getInternalId())
->setMetadata('host', \gethostname())
->setMetadata('project', $project->getId())
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS);
return $database;
}, ['pools', 'dbForConsole', 'cache', 'project']);
@@ -1117,7 +1141,11 @@ App::setResource('dbForConsole', function (Group $pools, Cache $cache) {
$database = new Database($dbAdapter, $cache);
$database->setNamespace('_console');
$database
->setNamespace('_console')
->setMetadata('host', \gethostname())
->setMetadata('project', 'console')
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS);
return $database;
}, ['pools', 'cache']);
@@ -1134,7 +1162,13 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
if (isset($databases[$databaseName])) {
$database = $databases[$databaseName];
$database->setNamespace('_' . $project->getInternalId());
$database
->setNamespace('_' . $project->getInternalId())
->setMetadata('host', \gethostname())
->setMetadata('project', $project->getId())
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS);
return $database;
}
@@ -1147,7 +1181,11 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
$databases[$databaseName] = $database;
$database->setNamespace('_' . $project->getInternalId());
$database
->setNamespace('_' . $project->getInternalId())
->setMetadata('host', \gethostname())
->setMetadata('project', $project->getId())
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS);
return $database;
};
+37 -25
View File
@@ -1,8 +1,10 @@
<?php
use Appwrite\Auth\Auth;
use Appwrite\Extend\Exception;
use Appwrite\Messaging\Adapter\Realtime;
use Appwrite\Network\Validator\Origin;
use Appwrite\Utopia\Request;
use Appwrite\Utopia\Response;
use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
@@ -20,7 +22,6 @@ use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Appwrite\Utopia\Request;
use Utopia\Cache\Adapter\Sharding;
use Utopia\Cache\Cache;
use Utopia\Config\Config;
@@ -28,6 +29,9 @@ use Utopia\Database\Database;
use Utopia\WebSocket\Server;
use Utopia\WebSocket\Adapter;
/**
* @var \Utopia\Registry\Registry $register
*/
require_once __DIR__ . '/init.php';
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
@@ -47,7 +51,10 @@ function getConsoleDB(): Database
$database = new Database($dbAdapter, getCache());
$database->setNamespace('_console');
$database
->setNamespace('_console')
->setMetadata('host', \gethostname())
->setMetadata('project', '_console');
return $database;
}
@@ -70,7 +77,11 @@ function getProjectDB(Document $project): Database
;
$database = new Database($dbAdapter, getCache());
$database->setNamespace('_' . $project->getInternalId());
$database
->setNamespace('_' . $project->getInternalId())
->setMetadata('host', \gethostname())
->setMetadata('project', $project->getId());
return $database;
}
@@ -122,12 +133,12 @@ $server = new Server($adapter);
$logError = function (Throwable $error, string $action) use ($register) {
$logger = $register->get('logger');
if ($logger) {
if ($logger && !$error instanceof Exception) {
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
$log = new Log();
$log->setNamespace("realtime");
$log->setServer(\gethostname());
$log->setServer(gethostname());
$log->setVersion($version);
$log->setType(Log::TYPE_ERROR);
$log->setMessage($error->getMessage());
@@ -182,7 +193,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
$statsDocument = Authorization::skip(fn () => $database->createDocument('realtime', $document));
break;
} catch (\Throwable $th) {
} catch (Throwable) {
Console::warning("Collection not ready. Retrying connection ({$attempts})...");
sleep(DATABASE_RECONNECT_SLEEP);
}
@@ -210,7 +221,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
->setAttribute('value', json_encode($payload));
Authorization::skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument));
} catch (\Throwable $th) {
} catch (Throwable $th) {
call_user_func($logError, $th, "updateWorkerDocument");
} finally {
$register->get('pools')->reclaim();
@@ -362,7 +373,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
$stats->incr($event['project'], 'messages', $num);
}
});
} catch (\Throwable $th) {
} catch (Throwable $th) {
call_user_func($logError, $th, "pubSubConnection");
Console::error('Pub/sub error: ' . $th->getMessage());
@@ -389,19 +400,19 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
App::setResource('response', fn() => $response);
try {
/** @var \Utopia\Database\Document $project */
/** @var Document $project */
$project = $app->getResource('project');
/*
* Project Check
*/
if (empty($project->getId())) {
throw new Exception('Missing or unknown project ID', 1008);
throw new Exception(Exception::REALTIME_POLICY_VIOLATION, 'Missing or unknown project ID');
}
$dbForProject = getProjectDB($project);
$console = $app->getResource('console'); /** @var \Utopia\Database\Document $console */
$user = $app->getResource('user'); /** @var \Utopia\Database\Document $user */
$console = $app->getResource('console'); /** @var Document $console */
$user = $app->getResource('user'); /** @var Document $user */
/*
* Abuse Check
@@ -416,7 +427,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
$abuse = new Abuse($timeLimit);
if (App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled' && $abuse->check()) {
throw new Exception('Too many requests', 1013);
throw new Exception(Exception::REALTIME_TOO_MANY_MESSAGES, 'Too many requests');
}
/*
@@ -425,10 +436,10 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
* Skip this check for non-web platforms which are not required to send an origin header.
*/
$origin = $request->getOrigin();
$originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
$originValidator = new Origin(array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
if (!$originValidator->isValid($origin) && $project->getId() !== 'console') {
throw new Exception($originValidator->getDescription(), 1008);
throw new Exception(Exception::REALTIME_POLICY_VIOLATION, $originValidator->getDescription());
}
$roles = Auth::getRoles($user);
@@ -439,7 +450,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
* Channels Check
*/
if (empty($channels)) {
throw new Exception('Missing channels', 1008);
throw new Exception(Exception::REALTIME_POLICY_VIOLATION, 'Missing channels');
}
$realtime->subscribe($project->getId(), $connection, $roles, $channels);
@@ -460,7 +471,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
]);
$stats->incr($project->getId(), 'connections');
$stats->incr($project->getId(), 'connectionsTotal');
} catch (\Throwable $th) {
} catch (Throwable $th) {
call_user_func($logError, $th, "initServer");
$response = [
@@ -486,7 +497,6 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
$server->onMessage(function (int $connection, string $message) use ($server, $register, $realtime, $containerId) {
try {
$app = new App('UTC');
$response = new Response(new SwooleResponse());
$projectId = $realtime->connections[$connection]['projectId'];
$database = getConsoleDB();
@@ -494,6 +504,8 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
if ($projectId !== 'console') {
$project = Authorization::skip(fn() => $database->getDocument('projects', $projectId));
$database = getProjectDB($project);
} else {
$project = null;
}
/*
@@ -510,22 +522,22 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
$abuse = new Abuse($timeLimit);
if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
throw new Exception('Too many messages', 1013);
throw new Exception(Exception::REALTIME_TOO_MANY_MESSAGES, 'Too many messages.');
}
$message = json_decode($message, true);
if (is_null($message) || (!array_key_exists('type', $message) && !array_key_exists('data', $message))) {
throw new Exception('Message format is not valid.', 1003);
throw new Exception(Exception::REALTIME_MESSAGE_FORMAT_INVALID, 'Message format is not valid.');
}
switch ($message['type']) {
/**
/**
* This type is used to authenticate.
*/
case 'authentication':
if (!array_key_exists('session', $message['data'])) {
throw new Exception('Payload is not valid.', 1003);
throw new Exception(Exception::REALTIME_MESSAGE_FORMAT_INVALID, 'Payload is not valid.');
}
$session = Auth::decodeSession($message['data']['session']);
@@ -540,7 +552,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration) // Validate user has valid login token
) {
// cookie not valid
throw new Exception('Session is not valid.', 1003);
throw new Exception(Exception::REALTIME_MESSAGE_FORMAT_INVALID, 'Session is not valid.');
}
$roles = Auth::getRoles($user);
@@ -560,9 +572,9 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
break;
default:
throw new Exception('Message type is not valid.', 1003);
throw new Exception(Exception::REALTIME_MESSAGE_FORMAT_INVALID, 'Message type is not valid.');
}
} catch (\Throwable $th) {
} catch (Throwable $th) {
$response = [
'type' => 'error',
'data' => [
+1 -2
View File
@@ -188,7 +188,6 @@ services:
- traefik.http.routers.appwrite_realtime_wss.rule=PathPrefix(`/v1/realtime`)
- traefik.http.routers.appwrite_realtime_wss.service=appwrite_realtime
- traefik.http.routers.appwrite_realtime_wss.tls=true
- traefik.http.routers.appwrite_realtime_wss.tls.certresolver=dns
networks:
- appwrite
depends_on:
@@ -668,7 +667,7 @@ services:
<<: *x-logging
restart: unless-stopped
stop_signal: SIGINT
image: openruntimes/executor:0.4.3
image: openruntimes/executor:0.4.5
networks:
- appwrite
- runtimes
+151 -33
View File
@@ -2,32 +2,41 @@
require_once __DIR__ . '/init.php';
use Appwrite\Event\Event;
use Appwrite\Event\Audit;
use Appwrite\Event\Build;
use Appwrite\Event\Certificate;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Delete;
use Appwrite\Event\Func;
use Appwrite\Event\Usage;
use Appwrite\Event\Mail;
use Appwrite\Event\Messaging;
use Appwrite\Event\Migration;
use Appwrite\Event\Phone;
use Appwrite\Platform\Appwrite;
use Appwrite\Usage\Stats;
use Swoole\Runtime;
use Utopia\App;
use Utopia\Cache\Adapter\Sharding;
use Utopia\Cache\Cache;
use Utopia\CLI\CLI;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\Queue\Adapter\Swoole;
use Utopia\Platform\Service;
use Utopia\Queue\Message;
use Utopia\Queue\Server;
use Utopia\Registry\Registry;
use Utopia\Logger\Log;
use Utopia\Logger\Logger;
use Utopia\Pools\Group;
use Utopia\Queue\Connection;
Authorization::disable();
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
global $register;
Server::setResource('register', fn() => $register);
Server::setResource('register', fn () => $register);
Server::setResource('dbForConsole', function (Cache $cache, Registry $register) {
$pools = $register->get('pools');
@@ -63,6 +72,37 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register,
return $adapter;
}, ['cache', 'register', 'message', 'dbForConsole']);
Server::setResource('getProjectDB', function (Group $pools, Database $dbForConsole, $cache) {
$databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools
return function (Document $project) use ($pools, $dbForConsole, $cache, &$databases): Database {
if ($project->isEmpty() || $project->getId() === 'console') {
return $dbForConsole;
}
$databaseName = $project->getAttribute('database');
if (isset($databases[$databaseName])) {
$database = $databases[$databaseName];
$database->setNamespace('_' . $project->getInternalId());
return $database;
}
$dbAdapter = $pools
->get($databaseName)
->pop()
->getResource();
$database = new Database($dbAdapter, $cache);
$databases[$databaseName] = $database;
$database->setNamespace('_' . $project->getInternalId());
return $database;
};
}, ['pools', 'dbForConsole', 'cache']);
Server::setResource('cache', function (Registry $register) {
$pools = $register->get('pools');
$list = Config::getParam('pools-cache', []);
@@ -78,50 +118,121 @@ Server::setResource('cache', function (Registry $register) {
return new Cache(new Sharding($adapters));
}, ['register']);
Server::setResource('queueForFunctions', function (Registry $register) {
$pools = $register->get('pools');
return new Func(
$pools
->get('queue')
->pop()
->getResource()
);
}, ['register']);
Server::setResource('log', fn() => new Log());
Server::setResource('logger', function ($register) {
Server::setResource('usage', function ($register) {
return new Stats($register->get('statsd'));
}, ['register']);
Server::setResource('queue', function (Group $pools) {
return $pools->get('queue')->pop()->getResource();
}, ['pools']);
Server::setResource('queueForDatabase', function (Connection $queue) {
return new EventDatabase($queue);
}, ['queue']);
Server::setResource('queueForMessaging', function (Connection $queue) {
return new Phone($queue);
}, ['queue']);
Server::setResource('queueForMails', function (Connection $queue) {
return new Mail($queue);
}, ['queue']);
Server::setResource('queueForBuilds', function (Connection $queue) {
return new Build($queue);
}, ['queue']);
Server::setResource('queueForDeletes', function (Connection $queue) {
return new Delete($queue);
}, ['queue']);
Server::setResource('queueForEvents', function (Connection $queue) {
return new Event($queue);
}, ['queue']);
Server::setResource('queueForAudits', function (Connection $queue) {
return new Audit($queue);
}, ['queue']);
Server::setResource('queueForFunctions', function (Connection $queue) {
return new Func($queue);
}, ['queue']);
Server::setResource('queueForCertificates', function (Connection $queue) {
return new Certificate($queue);
}, ['queue']);
Server::setResource('queueForMigrations', function (Connection $queue) {
return new Migration($queue);
}, ['queue']);
Server::setResource('logger', function (Registry $register) {
return $register->get('logger');
}, ['register']);
Server::setResource('statsd', function ($register) {
return $register->get('statsd');
}, ['register']);
Server::setResource('pools', function ($register) {
Server::setResource('pools', function (Registry $register) {
return $register->get('pools');
}, ['register']);
Server::setResource('getFunctionsDevice', function () {
return function (string $projectId) {
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $projectId);
};
});
Server::setResource('getFilesDevice', function () {
return function (string $projectId) {
return getDevice(APP_STORAGE_UPLOADS . '/app-' . $projectId);
};
});
Server::setResource('getBuildsDevice', function () {
return function (string $projectId) {
return getDevice(APP_STORAGE_BUILDS . '/app-' . $projectId);
};
});
Server::setResource('getCacheDevice', function () {
return function (string $projectId) {
return getDevice(APP_STORAGE_CACHE . '/app-' . $projectId);
};
});
$pools = $register->get('pools');
$connection = $pools->get('queue')->pop()->getResource();
$workerNumber = swoole_cpu_num() * intval(App::getEnv('_APP_WORKER_PER_CORE', 6));
$platform = new Appwrite();
$args = $_SERVER['argv'];
if (empty(App::getEnv('QUEUE'))) {
throw new Exception('Please configure "QUEUE" environment variable.');
if (!isset($args[1])) {
Console::error('Missing worker name');
Console::exit(1);
}
$adapter = new Swoole($connection, $workerNumber, App::getEnv('QUEUE'));
$server = new Server($adapter);
\array_shift($args);
$workerName = $args[0];
$workerIndex = $args[1] ?? '';
$server
if (!empty($workerIndex)) {
$workerName .= '_' . $workerIndex;
}
try {
/**
* Any worker can be configured with the following env vars:
* - _APP_WORKERS_NUM The total number of worker processes
* - _APP_WORKER_PER_CORE The number of worker processes per core (ignored if _APP_WORKERS_NUM is set)
* - _APP_QUEUE_NAME The name of the queue to read for database events
*/
if ($workerName === 'databases') {
$queueName = App::getEnv('_APP_QUEUE_NAME', 'database_db_main');
} else {
$queueName = App::getEnv('_APP_QUEUE_NAME', 'v1-' . strtolower($workerName));
}
$platform->init(Service::TYPE_WORKER, [
'workersNum' => App::getEnv('_APP_WORKERS_NUM', 1),
'connection' => $pools->get('queue')->pop()->getResource(),
'workerName' => strtolower($workerName) ?? null,
'queueName' => $queueName
]);
} catch (\Exception $e) {
Console::error($e->getMessage() . ', File: ' . $e->getFile() . ', Line: ' . $e->getLine());
}
$worker = $platform->getWorker();
$worker
->shutdown()
->inject('pools')
->action(function (Group $pools) {
$pools->reclaim();
});
$server
$worker
->error()
->inject('error')
->inject('logger')
@@ -160,3 +271,10 @@ $server
Console::error('[Error] File: ' . $error->getFile());
Console::error('[Error] Line: ' . $error->getLine());
});
$worker->workerStart()
->action(function () use ($workerName) {
Console::info("Worker $workerName started");
});
$worker->start();
-62
View File
@@ -1,62 +0,0 @@
<?php
use Appwrite\Resque\Worker;
use Utopia\Audit\Audit;
use Utopia\CLI\Console;
use Utopia\Database\Document;
require_once __DIR__ . '/../init.php';
Console::title('Audits V1 Worker');
Console::success(APP_NAME . ' audits worker v1 has started');
class AuditsV1 extends Worker
{
public function getName(): string
{
return "audits";
}
public function init(): void
{
}
public function run(): void
{
$event = $this->args['event'];
$payload = $this->args['payload'];
$mode = $this->args['mode'];
$resource = $this->args['resource'];
$userAgent = $this->args['userAgent'];
$ip = $this->args['ip'];
$user = new Document($this->args['user']);
$project = new Document($this->args['project']);
$userName = $user->getAttribute('name', '');
$userEmail = $user->getAttribute('email', '');
$dbForProject = $this->getProjectDB($project);
$audit = new Audit($dbForProject);
$audit->log(
userId: $user->getInternalId(),
// Pass first, most verbose event pattern
event: $event,
resource: $resource,
userAgent: $userAgent,
ip: $ip,
location: '',
data: [
'userId' => $user->getId(),
'userName' => $userName,
'userEmail' => $userEmail,
'mode' => $mode,
'data' => $payload,
]
);
}
public function shutdown(): void
{
}
}
-106
View File
@@ -1,106 +0,0 @@
<?php
use Appwrite\Resque\Worker;
use Appwrite\Template\Template;
use Utopia\App;
use Utopia\CLI\Console;
use PHPMailer\PHPMailer\PHPMailer;
require_once __DIR__ . '/../init.php';
Console::title('Mails V1 Worker');
Console::success(APP_NAME . ' mails worker v1 has started' . "\n");
class MailsV1 extends Worker
{
public function getName(): string
{
return "mails";
}
public function init(): void
{
}
public function run(): void
{
global $register;
$smtp = $this->args['smtp'];
if (empty($smtp) && empty(App::getEnv('_APP_SMTP_HOST'))) {
Console::info('Skipped mail processing. No SMTP configuration has been set.');
return;
}
$recipient = $this->args['recipient'];
$subject = $this->args['subject'];
$body = $this->args['body'];
$variables = $this->args['variables'];
$name = $this->args['name'];
$body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl');
foreach ($variables as $key => $value) {
$body->setParam('{{' . $key . '}}', $value);
}
$body = $body->render();
/** @var PHPMailer $mail */
$mail = empty($smtp)
? $register->get('smtp')
: $this->getMailer($smtp);
$mail->clearAddresses();
$mail->clearAllRecipients();
$mail->clearReplyTos();
$mail->clearAttachments();
$mail->clearBCCs();
$mail->clearCCs();
$mail->addAddress($recipient, $name);
$mail->Subject = $subject;
$mail->Body = $body;
$mail->AltBody = \strip_tags($body);
try {
$mail->send();
} catch (\Exception $error) {
throw new Exception('Error sending mail: ' . $error->getMessage(), 500);
}
}
protected function getMailer(array $smtp): PHPMailer
{
$mail = new PHPMailer(true);
$mail->isSMTP();
$username = $smtp['username'];
$password = $smtp['password'];
$mail->XMailer = 'Appwrite Mailer';
$mail->Host = $smtp['host'];
$mail->Port = $smtp['port'];
$mail->SMTPAuth = (!empty($username) && !empty($password));
$mail->Username = $username;
$mail->Password = $password;
$mail->SMTPSecure = $smtp['secure'];
$mail->SMTPAutoTLS = false;
$mail->CharSet = 'UTF-8';
$mail->setFrom($smtp['senderEmail'], $smtp['senderName']);
if (!empty($smtp['replyTo'])) {
$mail->addReplyTo($smtp['replyTo'], $smtp['senderName']);
}
$mail->isHTML();
return $mail;
}
public function shutdown(): void
{
}
}
-78
View File
@@ -1,78 +0,0 @@
<?php
use Appwrite\Resque\Worker;
use Utopia\App;
use Utopia\CLI\Console;
use Utopia\DSN\DSN;
use Utopia\Messaging\Adapter;
use Utopia\Messaging\Adapters\SMS\Mock;
use Utopia\Messaging\Adapters\SMS\Msg91;
use Utopia\Messaging\Adapters\SMS\Telesign;
use Utopia\Messaging\Adapters\SMS\TextMagic;
use Utopia\Messaging\Adapters\SMS\Twilio;
use Utopia\Messaging\Adapters\SMS\Vonage;
use Utopia\Messaging\Messages\SMS;
require_once __DIR__ . '/../init.php';
Console::title('Messaging V1 Worker');
Console::success(APP_NAME . ' messaging worker v1 has started' . "\n");
class MessagingV1 extends Worker
{
protected ?Adapter $sms = null;
protected ?string $from = null;
public function getName(): string
{
return "mails";
}
public function init(): void
{
$dsn = new DSN(App::getEnv('_APP_SMS_PROVIDER'));
$user = $dsn->getUser();
$secret = $dsn->getPassword();
$this->sms = match ($dsn->getHost()) {
'mock' => new Mock($user, $secret), // used for tests
'twilio' => new Twilio($user, $secret),
'text-magic' => new TextMagic($user, $secret),
'telesign' => new Telesign($user, $secret),
'msg91' => new Msg91($user, $secret),
'vonage' => new Vonage($user, $secret),
default => null
};
$this->from = App::getEnv('_APP_SMS_FROM');
}
public function run(): void
{
if (empty(App::getEnv('_APP_SMS_PROVIDER'))) {
Console::info('Skipped sms processing. No Phone provider has been set.');
return;
}
if (empty($this->from)) {
Console::info('Skipped sms processing. No phone number has been set.');
return;
}
$message = new SMS(
to: [$this->args['recipient']],
content: $this->args['message'],
from: $this->from,
);
try {
$this->sms->send($message);
} catch (\Exception $error) {
throw new Exception('Error sending message: ' . $error->getMessage(), 500);
}
}
public function shutdown(): void
{
}
}
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php delete-orphaned-projects $@
+1 -8
View File
@@ -1,10 +1,3 @@
#!/bin/sh
if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ]
then
REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
INTERVAL=1 QUEUE='v1-audits' APP_INCLUDE='/usr/src/code/app/workers/audits.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
php /usr/src/code/app/worker.php audits $@
+1 -8
View File
@@ -1,10 +1,3 @@
#!/bin/sh
if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ]
then
REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
INTERVAL=0.1 QUEUE='v1-builds' APP_INCLUDE='/usr/src/code/app/workers/builds.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
php /usr/src/code/app/worker.php builds $@
+1 -8
View File
@@ -1,10 +1,3 @@
#!/bin/sh
if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ]
then
REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
INTERVAL=1 QUEUE='v1-certificates' APP_INCLUDE='/usr/src/code/app/workers/certificates.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
php /usr/src/code/app/worker.php certificates $@
+1 -8
View File
@@ -1,10 +1,3 @@
#!/bin/sh
if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ]
then
REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
INTERVAL=0.1 QUEUE='v1-database' APP_INCLUDE='/usr/src/code/app/workers/databases.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
php /usr/src/code/app/worker.php databases $@
+1 -8
View File
@@ -1,10 +1,3 @@
#!/bin/sh
if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ]
then
REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
INTERVAL=1 QUEUE='v1-deletes' APP_INCLUDE='/usr/src/code/app/workers/deletes.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
php /usr/src/code/app/worker.php deletes $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
QUEUE=v1-functions php /usr/src/code/app/workers/functions.php $@
php /usr/src/code/app/worker.php functions $@
+1 -8
View File
@@ -1,10 +1,3 @@
#!/bin/sh
if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ]
then
REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
INTERVAL=1 QUEUE='v1-mails' APP_INCLUDE='/usr/src/code/app/workers/mails.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
php /usr/src/code/app/worker.php mails $@
+1 -8
View File
@@ -1,10 +1,3 @@
#!/bin/sh
if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ]
then
REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
INTERVAL=1 QUEUE='v1-messaging' APP_INCLUDE='/usr/src/code/app/workers/messaging.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
php /usr/src/code/app/worker.php messaging $@
+1 -8
View File
@@ -1,10 +1,3 @@
#!/bin/sh
if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ]
then
REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
INTERVAL=0.1 QUEUE='v1-migrations' APP_INCLUDE='/usr/src/code/app/workers/migrations.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
php /usr/src/code/app/worker.php migrations $@
+1 -8
View File
@@ -1,10 +1,3 @@
#!/bin/sh
if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ]
then
REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
INTERVAL=0.1 QUEUE='v1-webhooks' APP_INCLUDE='/usr/src/code/app/workers/webhooks.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
php /usr/src/code/app/worker.php webhooks $@
+7 -8
View File
@@ -43,32 +43,31 @@
"ext-sockets": "*",
"appwrite/php-runtimes": "0.13.*",
"appwrite/php-clamav": "2.0.*",
"utopia-php/abuse": "0.31.*",
"utopia-php/abuse": "0.32.*",
"utopia-php/analytics": "0.10.*",
"utopia-php/audit": "0.33.*",
"utopia-php/audit": "0.34.*",
"utopia-php/cache": "0.8.*",
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.43.*",
"utopia-php/database": "0.44.*",
"utopia-php/domains": "0.3.*",
"utopia-php/dsn": "0.1.*",
"utopia-php/framework": "0.31.0",
"utopia-php/image": "0.5.*",
"utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.3.*",
"utopia-php/messaging": "0.1.*",
"utopia-php/messaging": "0.2.*",
"utopia-php/migration": "0.3.*",
"utopia-php/orchestration": "0.9.*",
"utopia-php/platform": "0.4.*",
"utopia-php/platform": "0.5.*",
"utopia-php/pools": "0.4.*",
"utopia-php/preloader": "0.2.*",
"utopia-php/queue": "0.5.*",
"utopia-php/registry": "0.5.*",
"utopia-php/storage": "0.17.*",
"utopia-php/storage": "0.18.*",
"utopia-php/swoole": "0.5.*",
"utopia-php/vcs": "0.5.*",
"utopia-php/vcs": "0.6.*",
"utopia-php/websocket": "0.1.*",
"resque/php-resque": "1.3.6",
"matomo/device-detector": "6.1.*",
"dragonmantank/cron-expression": "3.3.2",
"influxdb/influxdb-php": "1.15.2",
Generated
+115 -312
View File
@@ -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": "13a3bdc7c1dec5756bf58ec73a49753d",
"content-hash": "9afc62ce9c6ba587b9c028e11494e026",
"packages": [
{
"name": "adhocore/jwt",
@@ -156,11 +156,11 @@
},
{
"name": "appwrite/php-runtimes",
"version": "0.13.0",
"version": "0.13.1",
"source": {
"type": "git",
"url": "https://github.com/appwrite/runtimes.git",
"reference": "5ab496b3908992b39275994a23783701c4b3de84"
"reference": "b584d19cdcd82737d0ee5c34d23de791f5ed3610"
},
"require": {
"php": ">=8.0",
@@ -195,7 +195,7 @@
"php",
"runtimes"
],
"time": "2023-09-12T19:38:43+00:00"
"time": "2023-10-16T15:39:53+00:00"
},
{
"name": "chillerlan/php-qrcode",
@@ -339,53 +339,6 @@
],
"time": "2022-07-05T22:32:14+00:00"
},
{
"name": "colinmollenhour/credis",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/colinmollenhour/credis.git",
"reference": "28810439de1d9597b7ba11794ed9479fb6f3de7c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/colinmollenhour/credis/zipball/28810439de1d9597b7ba11794ed9479fb6f3de7c",
"reference": "28810439de1d9597b7ba11794ed9479fb6f3de7c",
"shasum": ""
},
"require": {
"php": ">=5.6.0"
},
"suggest": {
"ext-redis": "Improved performance for communicating with redis"
},
"type": "library",
"autoload": {
"classmap": [
"Client.php",
"Cluster.php",
"Sentinel.php",
"Module.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Colin Mollenhour",
"email": "colin@mollenhour.com"
}
],
"description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.",
"homepage": "https://github.com/colinmollenhour/credis",
"support": {
"issues": "https://github.com/colinmollenhour/credis/issues",
"source": "https://github.com/colinmollenhour/credis/tree/v1.15.0"
},
"time": "2023-04-18T15:34:23+00:00"
},
{
"name": "dragonmantank/cron-expression",
"version": "v3.3.2",
@@ -898,72 +851,6 @@
},
"time": "2021-10-08T21:21:46+00:00"
},
{
"name": "laravel/pint",
"version": "v1.2.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
"reference": "e60e2112ee779ce60f253695b273d1646a17d6f1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/pint/zipball/e60e2112ee779ce60f253695b273d1646a17d6f1",
"reference": "e60e2112ee779ce60f253695b273d1646a17d6f1",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-mbstring": "*",
"ext-tokenizer": "*",
"ext-xml": "*",
"php": "^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.11.0",
"illuminate/view": "^9.32.0",
"laravel-zero/framework": "^9.2.0",
"mockery/mockery": "^1.5.1",
"nunomaduro/larastan": "^2.2.0",
"nunomaduro/termwind": "^1.14.0",
"pestphp/pest": "^1.22.1"
},
"bin": [
"builds/pint"
],
"type": "project",
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Seeders\\": "database/seeders/",
"Database\\Factories\\": "database/factories/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nuno Maduro",
"email": "enunomaduro@gmail.com"
}
],
"description": "An opinionated code formatter for PHP.",
"homepage": "https://laravel.com",
"keywords": [
"format",
"formatter",
"lint",
"linter",
"php"
],
"support": {
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
"time": "2022-11-29T16:25:20+00:00"
},
{
"name": "league/csv",
"version": "9.7.1",
@@ -1050,16 +937,16 @@
},
{
"name": "matomo/device-detector",
"version": "6.1.5",
"version": "6.1.6",
"source": {
"type": "git",
"url": "https://github.com/matomo-org/device-detector.git",
"reference": "40ca2990dba2c1719e5c62168e822e0b86c167d4"
"reference": "5cbea85106e561c7138d03603eb6e05128480409"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/40ca2990dba2c1719e5c62168e822e0b86c167d4",
"reference": "40ca2990dba2c1719e5c62168e822e0b86c167d4",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/5cbea85106e561c7138d03603eb6e05128480409",
"reference": "5cbea85106e561c7138d03603eb6e05128480409",
"shasum": ""
},
"require": {
@@ -1115,7 +1002,7 @@
"source": "https://github.com/matomo-org/matomo",
"wiki": "https://dev.matomo.org/"
},
"time": "2023-08-17T16:17:41+00:00"
"time": "2023-10-02T10:01:54+00:00"
},
{
"name": "mongodb/mongodb",
@@ -1476,56 +1363,6 @@
},
"time": "2023-04-04T09:54:51+00:00"
},
{
"name": "psr/log",
"version": "1.1.4",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"time": "2021-05-03T11:20:27+00:00"
},
{
"name": "ralouphie/getallheaders",
"version": "3.0.3",
@@ -1570,89 +1407,6 @@
},
"time": "2019-03-08T08:55:37+00:00"
},
{
"name": "resque/php-resque",
"version": "v1.3.6",
"source": {
"type": "git",
"url": "https://github.com/resque/php-resque.git",
"reference": "fe41c04763699b1318d97ed14cc78583e9380161"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/resque/php-resque/zipball/fe41c04763699b1318d97ed14cc78583e9380161",
"reference": "fe41c04763699b1318d97ed14cc78583e9380161",
"shasum": ""
},
"require": {
"colinmollenhour/credis": "~1.7",
"php": ">=5.6.0",
"psr/log": "~1.0"
},
"require-dev": {
"phpunit/phpunit": "^5.7"
},
"suggest": {
"ext-pcntl": "REQUIRED for forking processes on platforms that support it (so anything but Windows).",
"ext-proctitle": "Allows php-resque to rename the title of UNIX processes to show the status of a worker.",
"ext-redis": "Native PHP extension for Redis connectivity. Credis will automatically utilize when available."
},
"bin": [
"bin/resque",
"bin/resque-scheduler"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-0": {
"Resque": "lib",
"ResqueScheduler": "lib"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Dan Hunsaker",
"email": "danhunsaker+resque@gmail.com",
"role": "Maintainer"
},
{
"name": "Rajib Ahmed",
"homepage": "https://github.com/rajibahmed",
"role": "Maintainer"
},
{
"name": "Steve Klabnik",
"email": "steve@steveklabnik.com",
"role": "Maintainer"
},
{
"name": "Chris Boulton",
"email": "chris@bigcommerce.com",
"role": "Creator"
}
],
"description": "Redis backed library for creating background jobs and processing them later. Based on resque for Ruby.",
"homepage": "http://www.github.com/resque/php-resque/",
"keywords": [
"background",
"job",
"redis",
"resque"
],
"support": {
"issues": "https://github.com/resque/php-resque/issues",
"source": "https://github.com/resque/php-resque/tree/v1.3.6"
},
"time": "2020-04-16T16:39:50+00:00"
},
{
"name": "slickdeals/statsd",
"version": "3.1.0",
@@ -1861,23 +1615,23 @@
},
{
"name": "utopia-php/abuse",
"version": "0.31.1",
"version": "0.32.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "b2ad372d1070f55f9545cb811b6ed2d40094e6dd"
"reference": "9717ffb2d7711f3fd621bb6df3edf5724c08ea78"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/b2ad372d1070f55f9545cb811b6ed2d40094e6dd",
"reference": "b2ad372d1070f55f9545cb811b6ed2d40094e6dd",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/9717ffb2d7711f3fd621bb6df3edf5724c08ea78",
"reference": "9717ffb2d7711f3fd621bb6df3edf5724c08ea78",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-pdo": "*",
"php": ">=8.0",
"utopia-php/database": "0.43.*"
"utopia-php/database": "0.44.*"
},
"require-dev": {
"laravel/pint": "1.5.*",
@@ -1904,9 +1658,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.31.1"
"source": "https://github.com/utopia-php/abuse/tree/0.32.0"
},
"time": "2023-08-29T11:07:46+00:00"
"time": "2023-10-18T07:28:55+00:00"
},
{
"name": "utopia-php/analytics",
@@ -1956,21 +1710,21 @@
},
{
"name": "utopia-php/audit",
"version": "0.33.1",
"version": "0.34.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "c117e8e9ce4e3e1b369e8b5b55b2d6ab3138eadd"
"reference": "cf34cc3f9f20da4e574a9be4517e1a11025a858f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/c117e8e9ce4e3e1b369e8b5b55b2d6ab3138eadd",
"reference": "c117e8e9ce4e3e1b369e8b5b55b2d6ab3138eadd",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/cf34cc3f9f20da4e574a9be4517e1a11025a858f",
"reference": "cf34cc3f9f20da4e574a9be4517e1a11025a858f",
"shasum": ""
},
"require": {
"php": ">=8.0",
"utopia-php/database": "0.43.*"
"utopia-php/database": "0.44.*"
},
"require-dev": {
"laravel/pint": "1.5.*",
@@ -1997,9 +1751,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.33.1"
"source": "https://github.com/utopia-php/audit/tree/0.34.0"
},
"time": "2023-08-29T11:07:40+00:00"
"time": "2023-10-18T07:43:25+00:00"
},
{
"name": "utopia-php/cache",
@@ -2152,16 +1906,16 @@
},
{
"name": "utopia-php/database",
"version": "0.43.4",
"version": "0.44.4",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "cabdd02e8dc1732eb0b22007c511e7bb3caa5c8c"
"reference": "b0c3fd8ecfedc3646d7780f2d6b38955a66baf48"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/cabdd02e8dc1732eb0b22007c511e7bb3caa5c8c",
"reference": "cabdd02e8dc1732eb0b22007c511e7bb3caa5c8c",
"url": "https://api.github.com/repos/utopia-php/database/zipball/b0c3fd8ecfedc3646d7780f2d6b38955a66baf48",
"reference": "b0c3fd8ecfedc3646d7780f2d6b38955a66baf48",
"shasum": ""
},
"require": {
@@ -2174,7 +1928,7 @@
},
"require-dev": {
"fakerphp/faker": "^1.14",
"laravel/pint": "1.4.*",
"laravel/pint": "1.13.*",
"pcov/clobber": "^2.0",
"phpstan/phpstan": "1.10.*",
"phpunit/phpunit": "^9.4",
@@ -2202,9 +1956,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.43.4"
"source": "https://github.com/utopia-php/database/tree/0.44.4"
},
"time": "2023-09-28T09:00:05+00:00"
"time": "2023-10-26T07:08:12+00:00"
},
{
"name": "utopia-php/domains",
@@ -2516,16 +2270,16 @@
},
{
"name": "utopia-php/messaging",
"version": "0.1.1",
"version": "0.2.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/messaging.git",
"reference": "a75d66ddd59b834ab500a4878a2c084e6572604a"
"reference": "2d0f474a106bb1da285f85e105c29b46085d3a43"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/a75d66ddd59b834ab500a4878a2c084e6572604a",
"reference": "a75d66ddd59b834ab500a4878a2c084e6572604a",
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/2d0f474a106bb1da285f85e105c29b46085d3a43",
"reference": "2d0f474a106bb1da285f85e105c29b46085d3a43",
"shasum": ""
},
"require": {
@@ -2534,8 +2288,8 @@
},
"require-dev": {
"laravel/pint": "^1.2",
"phpmailer/phpmailer": "6.6.*",
"phpunit/phpunit": "9.5.*"
"phpmailer/phpmailer": "6.8.*",
"phpunit/phpunit": "9.6.*"
},
"type": "library",
"autoload": {
@@ -2558,9 +2312,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/messaging/issues",
"source": "https://github.com/utopia-php/messaging/tree/0.1.1"
"source": "https://github.com/utopia-php/messaging/tree/0.2.0"
},
"time": "2023-02-07T05:42:46+00:00"
"time": "2023-09-14T20:48:42+00:00"
},
{
"name": "utopia-php/migration",
@@ -2722,16 +2476,16 @@
},
{
"name": "utopia-php/platform",
"version": "0.4.2",
"version": "0.5.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/platform.git",
"reference": "6e3d6db9ee8f99e36c2df331b58de2e6e3e37eb9"
"reference": "229a7b1fa1f39afd1532f7a515326a6afc222a26"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/platform/zipball/6e3d6db9ee8f99e36c2df331b58de2e6e3e37eb9",
"reference": "6e3d6db9ee8f99e36c2df331b58de2e6e3e37eb9",
"url": "https://api.github.com/repos/utopia-php/platform/zipball/229a7b1fa1f39afd1532f7a515326a6afc222a26",
"reference": "229a7b1fa1f39afd1532f7a515326a6afc222a26",
"shasum": ""
},
"require": {
@@ -2765,9 +2519,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/platform/issues",
"source": "https://github.com/utopia-php/platform/tree/0.4.2"
"source": "https://github.com/utopia-php/platform/tree/0.5.0"
},
"time": "2023-08-30T16:28:31+00:00"
"time": "2023-10-16T20:28:49+00:00"
},
{
"name": "utopia-php/pools",
@@ -2988,16 +2742,16 @@
},
{
"name": "utopia-php/storage",
"version": "0.17.0",
"version": "0.18.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/storage.git",
"reference": "efec5376c02d3d8330f1beb1469e6d6e313e21ee"
"reference": "983e6dee137012f9f57f126d3c79aab54e4e8824"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/storage/zipball/efec5376c02d3d8330f1beb1469e6d6e313e21ee",
"reference": "efec5376c02d3d8330f1beb1469e6d6e313e21ee",
"url": "https://api.github.com/repos/utopia-php/storage/zipball/983e6dee137012f9f57f126d3c79aab54e4e8824",
"reference": "983e6dee137012f9f57f126d3c79aab54e4e8824",
"shasum": ""
},
"require": {
@@ -3037,9 +2791,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/storage/issues",
"source": "https://github.com/utopia-php/storage/tree/0.17.0"
"source": "https://github.com/utopia-php/storage/tree/0.18.1"
},
"time": "2023-08-21T11:28:36+00:00"
"time": "2023-10-24T14:44:19+00:00"
},
{
"name": "utopia-php/swoole",
@@ -3094,26 +2848,25 @@
},
{
"name": "utopia-php/system",
"version": "0.7.1",
"version": "0.7.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/system.git",
"reference": "01bf0d283aded0ee0a7a6e5ff540acf64270ab27"
"reference": "4593d4d334b0c15879c4744a826e0362924c5d66"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/system/zipball/01bf0d283aded0ee0a7a6e5ff540acf64270ab27",
"reference": "01bf0d283aded0ee0a7a6e5ff540acf64270ab27",
"url": "https://api.github.com/repos/utopia-php/system/zipball/4593d4d334b0c15879c4744a826e0362924c5d66",
"reference": "4593d4d334b0c15879c4744a826e0362924c5d66",
"shasum": ""
},
"require": {
"laravel/pint": "1.2.*",
"php": ">=8.0.0"
},
"require-dev": {
"phpunit/phpunit": "^9.3",
"squizlabs/php_codesniffer": "^3.6",
"vimeo/psalm": "4.0.1"
"laravel/pint": "1.13.*",
"phpstan/phpstan": "1.10.*",
"phpunit/phpunit": "9.6.*"
},
"type": "library",
"autoload": {
@@ -3145,22 +2898,22 @@
],
"support": {
"issues": "https://github.com/utopia-php/system/issues",
"source": "https://github.com/utopia-php/system/tree/0.7.1"
"source": "https://github.com/utopia-php/system/tree/0.7.2"
},
"time": "2023-08-30T09:14:37+00:00"
"time": "2023-10-20T01:39:17+00:00"
},
{
"name": "utopia-php/vcs",
"version": "0.5.0",
"version": "0.6.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/vcs.git",
"reference": "47144f272030b7ed1b05471f2cb3aabeb8cb831c"
"reference": "d161d1156ef336d197a8d45384b531e5ec31243d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/47144f272030b7ed1b05471f2cb3aabeb8cb831c",
"reference": "47144f272030b7ed1b05471f2cb3aabeb8cb831c",
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/d161d1156ef336d197a8d45384b531e5ec31243d",
"reference": "d161d1156ef336d197a8d45384b531e5ec31243d",
"shasum": ""
},
"require": {
@@ -3194,9 +2947,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/vcs/issues",
"source": "https://github.com/utopia-php/vcs/tree/0.5.0"
"source": "https://github.com/utopia-php/vcs/tree/0.6.1"
},
"time": "2023-09-13T19:05:52+00:00"
"time": "2023-10-19T07:43:31+00:00"
},
{
"name": "utopia-php/websocket",
@@ -4604,6 +4357,56 @@
],
"time": "2022-04-01T12:37:26+00:00"
},
{
"name": "psr/log",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
"reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
"shasum": ""
},
"require": {
"php": ">=8.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/3.0.0"
},
"time": "2021-07-14T16:46:02+00:00"
},
{
"name": "sebastian/cli-parser",
"version": "1.0.1",
+3 -16
View File
@@ -211,7 +211,6 @@ services:
- traefik.http.routers.appwrite_realtime_wss.rule=PathPrefix(`/v1/realtime`)
- traefik.http.routers.appwrite_realtime_wss.service=appwrite_realtime
- traefik.http.routers.appwrite_realtime_wss.tls=true
- traefik.http.routers.appwrite_realtime_wss.tls.certresolver=dns
networks:
- appwrite
volumes:
@@ -379,6 +378,8 @@ services:
- _APP_DB_PASS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG
- _APP_WORKERS_NUM
- _APP_QUEUE_NAME
appwrite-worker-builds:
entrypoint: worker-builds
@@ -721,7 +722,7 @@ services:
hostname: appwrite-executor
<<: *x-logging
stop_signal: SIGINT
image: openruntimes/executor:0.4.3
image: openruntimes/executor:0.4.5
restart: unless-stopped
networks:
- appwrite
@@ -871,7 +872,6 @@ services:
# MailCatcher - An SMTP server. Catches all system emails and displays them in a nice UI.
# RequestCatcher - An HTTP server. Catches all system https calls and displays them using a simple HTTP API. Used to debug & tests webhooks and HTTP tasks
# RedisCommander - A nice UI for exploring Redis data
# Resque - A nice UI for exploring Redis pub/sub, view the different queues workloads, pending and failed tasks
# Chronograf - A nice UI for exploring InfluxDB data
# Webgrind - A nice UI for exploring and debugging code-level stuff
@@ -913,19 +913,6 @@ services:
# ports:
# - "8081:8081"
# resque:
# image: appwrite/resque-web:1.1.0
# restart: unless-stopped
# networks:
# - appwrite
# ports:
# - "5678:5678"
# environment:
# - RESQUE_WEB_HOST=redis
# - RESQUE_WEB_PORT=6379
# - RESQUE_WEB_HTTP_BASIC_AUTH_USER=user
# - RESQUE_WEB_HTTP_BASIC_AUTH_PASSWORD=password
# chronograf:
# image: chronograf:1.6
# container_name: appwrite-chronograf
@@ -0,0 +1 @@
appwrite health getQueueBuilds
@@ -0,0 +1,2 @@
appwrite health getQueueDatabases \
@@ -0,0 +1 @@
appwrite health getQueueDeletes
@@ -0,0 +1 @@
appwrite health getQueueMails
@@ -0,0 +1 @@
appwrite health getQueueMessaging
@@ -0,0 +1 @@
appwrite health getQueueMigrations
@@ -1,18 +0,0 @@
import { Client, Account } from "@appwrite.io/console";
const client = new Client();
const account = new Account(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
const promise = account.createWithInviteCode('[USER_ID]', 'email@example.com', 'password');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});
@@ -1,15 +1,15 @@
import { Client, Projects } from "@appwrite.io/console";
import { Client, Health } from "@appwrite.io/console";
const client = new Client();
const projects = new Projects(client);
const health = new Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
const promise = projects.listDomains('[PROJECT_ID]');
const promise = health.getQueueBuilds();
promise.then(function (response) {
console.log(response); // Success
@@ -1,15 +1,15 @@
import { Client, Projects } from "@appwrite.io/console";
import { Client, Health } from "@appwrite.io/console";
const client = new Client();
const projects = new Projects(client);
const health = new Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
const promise = projects.createDomain('[PROJECT_ID]', '');
const promise = health.getQueueDatabases();
promise.then(function (response) {
console.log(response); // Success
@@ -1,15 +1,15 @@
import { Client, Projects } from "@appwrite.io/console";
import { Client, Health } from "@appwrite.io/console";
const client = new Client();
const projects = new Projects(client);
const health = new Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
const promise = projects.getDomain('[PROJECT_ID]', '[DOMAIN_ID]');
const promise = health.getQueueDeletes();
promise.then(function (response) {
console.log(response); // Success
@@ -1,15 +1,15 @@
import { Client, Projects } from "@appwrite.io/console";
import { Client, Health } from "@appwrite.io/console";
const client = new Client();
const projects = new Projects(client);
const health = new Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
const promise = projects.deleteDomain('[PROJECT_ID]', '[DOMAIN_ID]');
const promise = health.getQueueMails();
promise.then(function (response) {
console.log(response); // Success
@@ -0,0 +1,18 @@
import { Client, Health } from "@appwrite.io/console";
const client = new Client();
const health = new Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
const promise = health.getQueueMessaging();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});
@@ -0,0 +1,18 @@
import { Client, Health } from "@appwrite.io/console";
const client = new Client();
const health = new Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
const promise = health.getQueueMigrations();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});
@@ -1,18 +0,0 @@
import { Client, Projects } from "@appwrite.io/console";
const client = new Client();
const projects = new Projects(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
const promise = projects.updateDomainVerification('[PROJECT_ID]', '[DOMAIN_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});
@@ -1,18 +0,0 @@
import { Client, Teams } from "@appwrite.io/console";
const client = new Client();
const teams = new Teams(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
const promise = teams.updateMembershipRoles('[TEAM_ID]', '[MEMBERSHIP_ID]', []);
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});
@@ -0,0 +1,21 @@
import 'package:dart_appwrite/dart_appwrite.dart';
void main() { // Init SDK
Client client = Client();
Health health = Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
Future result = health.getQueueBuilds();
result
.then((response) {
print(response);
}).catchError((error) {
print(error.response);
});
}
@@ -0,0 +1,22 @@
import 'package:dart_appwrite/dart_appwrite.dart';
void main() { // Init SDK
Client client = Client();
Health health = Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
Future result = health.getQueueDatabases(
);
result
.then((response) {
print(response);
}).catchError((error) {
print(error.response);
});
}
@@ -0,0 +1,21 @@
import 'package:dart_appwrite/dart_appwrite.dart';
void main() { // Init SDK
Client client = Client();
Health health = Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
Future result = health.getQueueDeletes();
result
.then((response) {
print(response);
}).catchError((error) {
print(error.response);
});
}
@@ -0,0 +1,21 @@
import 'package:dart_appwrite/dart_appwrite.dart';
void main() { // Init SDK
Client client = Client();
Health health = Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
Future result = health.getQueueMails();
result
.then((response) {
print(response);
}).catchError((error) {
print(error.response);
});
}
@@ -0,0 +1,21 @@
import 'package:dart_appwrite/dart_appwrite.dart';
void main() { // Init SDK
Client client = Client();
Health health = Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
Future result = health.getQueueMessaging();
result
.then((response) {
print(response);
}).catchError((error) {
print(error.response);
});
}
@@ -0,0 +1,21 @@
import 'package:dart_appwrite/dart_appwrite.dart';
void main() { // Init SDK
Client client = Client();
Health health = Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
Future result = health.getQueueMigrations();
result
.then((response) {
print(response);
}).catchError((error) {
print(error.response);
});
}
@@ -0,0 +1,21 @@
import * as sdk from "https://deno.land/x/appwrite/mod.ts";
// Init SDK
let client = new sdk.Client();
let health = new sdk.Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
let promise = health.getQueueBuilds();
promise.then(function (response) {
console.log(response);
}, function (error) {
console.log(error);
});
@@ -0,0 +1,21 @@
import * as sdk from "https://deno.land/x/appwrite/mod.ts";
// Init SDK
let client = new sdk.Client();
let health = new sdk.Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
let promise = health.getQueueDatabases();
promise.then(function (response) {
console.log(response);
}, function (error) {
console.log(error);
});
@@ -0,0 +1,21 @@
import * as sdk from "https://deno.land/x/appwrite/mod.ts";
// Init SDK
let client = new sdk.Client();
let health = new sdk.Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
let promise = health.getQueueDeletes();
promise.then(function (response) {
console.log(response);
}, function (error) {
console.log(error);
});
@@ -0,0 +1,21 @@
import * as sdk from "https://deno.land/x/appwrite/mod.ts";
// Init SDK
let client = new sdk.Client();
let health = new sdk.Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
let promise = health.getQueueMails();
promise.then(function (response) {
console.log(response);
}, function (error) {
console.log(error);
});
@@ -0,0 +1,21 @@
import * as sdk from "https://deno.land/x/appwrite/mod.ts";
// Init SDK
let client = new sdk.Client();
let health = new sdk.Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
let promise = health.getQueueMessaging();
promise.then(function (response) {
console.log(response);
}, function (error) {
console.log(error);
});
@@ -0,0 +1,21 @@
import * as sdk from "https://deno.land/x/appwrite/mod.ts";
// Init SDK
let client = new sdk.Client();
let health = new sdk.Health(client);
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
let promise = health.getQueueMigrations();
promise.then(function (response) {
console.log(response);
}, function (error) {
console.log(error);
});
@@ -0,0 +1,12 @@
using Appwrite;
using Appwrite.Services;
using Appwrite.Models;
var client = new Client()
.SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.SetProject("5df5acd0d48c2") // Your project ID
.SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key
var health = new Health(client);
HealthQueue result = await health.GetQueueBuilds();
@@ -0,0 +1,12 @@
using Appwrite;
using Appwrite.Services;
using Appwrite.Models;
var client = new Client()
.SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.SetProject("5df5acd0d48c2") // Your project ID
.SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key
var health = new Health(client);
HealthQueue result = await health.GetQueueDatabases();
@@ -0,0 +1,12 @@
using Appwrite;
using Appwrite.Services;
using Appwrite.Models;
var client = new Client()
.SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.SetProject("5df5acd0d48c2") // Your project ID
.SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key
var health = new Health(client);
HealthQueue result = await health.GetQueueDeletes();
@@ -0,0 +1,12 @@
using Appwrite;
using Appwrite.Services;
using Appwrite.Models;
var client = new Client()
.SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.SetProject("5df5acd0d48c2") // Your project ID
.SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key
var health = new Health(client);
HealthQueue result = await health.GetQueueMails();
@@ -0,0 +1,12 @@
using Appwrite;
using Appwrite.Services;
using Appwrite.Models;
var client = new Client()
.SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.SetProject("5df5acd0d48c2") // Your project ID
.SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key
var health = new Health(client);
HealthQueue result = await health.GetQueueMessaging();
@@ -0,0 +1,12 @@
using Appwrite;
using Appwrite.Services;
using Appwrite.Models;
var client = new Client()
.SetEndPoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.SetProject("5df5acd0d48c2") // Your project ID
.SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key
var health = new Health(client);
HealthQueue result = await health.GetQueueMigrations();
@@ -0,0 +1,5 @@
query {
healthGetQueueBuilds {
size
}
}
@@ -0,0 +1,5 @@
query {
healthGetQueueDatabases {
size
}
}
@@ -0,0 +1,5 @@
query {
healthGetQueueDeletes {
size
}
}
@@ -0,0 +1,5 @@
query {
healthGetQueueMails {
size
}
}
@@ -0,0 +1,5 @@
query {
healthGetQueueMessaging {
size
}
}
@@ -0,0 +1,5 @@
query {
healthGetQueueMigrations {
size
}
}
@@ -0,0 +1,19 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Health;
Client client = new Client()
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2") // Your project ID
.setKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key
Health health = new Health(client);
health.getQueueBuilds(new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
System.out.println(result);
}));

Some files were not shown because too many files have changed in this diff Show More