mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
274
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fc214afbe | ||
|
|
c768375e13 | ||
|
|
fcc5a747d1 | ||
|
|
78e4c0611b | ||
|
|
74a3d6531f | ||
|
|
45092a1049 | ||
|
|
868bba52aa | ||
|
|
0b4716721d | ||
|
|
2ffcb9b07e | ||
|
|
d91f6960f7 | ||
|
|
3542d360b0 | ||
|
|
9a821e250f | ||
|
|
d1715e3bf4 | ||
|
|
c8a3b709ee | ||
|
|
fed197a313 | ||
|
|
ec85ec9f2a | ||
|
|
1a59361200 | ||
|
|
658396b4a8 | ||
|
|
53438accce | ||
|
|
84f47dc1d2 | ||
|
|
1538f78c18 | ||
|
|
6acf6adf99 | ||
|
|
af3d6b2308 | ||
|
|
260928942b | ||
|
|
bbcb5e8a6e | ||
|
|
03d6eb7401 | ||
|
|
821e323a40 | ||
|
|
cab2233816 | ||
|
|
3a8c5a2e65 | ||
|
|
faeb9aa8d4 | ||
|
|
92dfe93033 | ||
|
|
3a524c24d9 | ||
|
|
b78725e650 | ||
|
|
e7a847a417 | ||
|
|
0ad44ceb94 | ||
|
|
9fe0a5a31b | ||
|
|
07f7271c51 | ||
|
|
d91a0e3048 | ||
|
|
ea484e593b | ||
|
|
ca1c83c2cf | ||
|
|
8c4473932f | ||
|
|
d5c24df28d | ||
|
|
141cdf4c82 | ||
|
|
f79a310965 | ||
|
|
65d99f8f90 | ||
|
|
c04f54da64 | ||
|
|
17888cc02d | ||
|
|
d2787c8555 | ||
|
|
42ca924557 | ||
|
|
a8098831a3 | ||
|
|
3f5e40ad46 | ||
|
|
10d882ce50 | ||
|
|
7a5d64a85f | ||
|
|
b03783c588 | ||
|
|
6567cff5dc | ||
|
|
db5c44c843 | ||
|
|
b2e1c162d2 | ||
|
|
e3c261b9e4 | ||
|
|
0dd2889de5 | ||
|
|
cc8705253e | ||
|
|
14e81c2e27 | ||
|
|
d60e7c641f | ||
|
|
f287e60e87 | ||
|
|
3f7d35065e | ||
|
|
abc67ab0c6 | ||
|
|
c2ae330888 | ||
|
|
1577be9172 | ||
|
|
505b481537 | ||
|
|
2ab6156db4 | ||
|
|
0f7c73c1ab | ||
|
|
928ae74ffe | ||
|
|
e4a86d9777 | ||
|
|
44a9aed48e | ||
|
|
ad78259c10 | ||
|
|
2c4a9e5ea9 | ||
|
|
3b1233eaa9 | ||
|
|
2a5df03c89 | ||
|
|
c3ddc6a05d | ||
|
|
db792999c1 | ||
|
|
ed4319314a | ||
|
|
2a5f21e982 | ||
|
|
7dbb1c6399 | ||
|
|
00db19257d | ||
|
|
f0a4cf78ab | ||
|
|
dae01f7077 | ||
|
|
26af9b7463 | ||
|
|
459db9b43e | ||
|
|
3476ab2627 | ||
|
|
cbf1085850 | ||
|
|
dac0e2a543 | ||
|
|
c076dfe6f1 | ||
|
|
f5aebe6673 | ||
|
|
70effd1e99 | ||
|
|
e7ace61273 | ||
|
|
6b6f04d2d3 | ||
|
|
be761b31c1 | ||
|
|
eb75b527ad | ||
|
|
d4ad369a7e | ||
|
|
eb7e2fd23b | ||
|
|
36eabfa2dd | ||
|
|
2634c928c7 | ||
|
|
e462d73f65 | ||
|
|
e2baefe8c6 | ||
|
|
4ffde8e827 | ||
|
|
57a695367b | ||
|
|
681688e252 | ||
|
|
a8718bccb5 | ||
|
|
eba03cb126 | ||
|
|
622bdb7b2b | ||
|
|
c8720805c7 | ||
|
|
fdb11af6bb | ||
|
|
b09386727b | ||
|
|
f3e8994bb8 | ||
|
|
fb68dcc89e | ||
|
|
5abcb86fd7 | ||
|
|
ff93957922 | ||
|
|
179a045399 | ||
|
|
d0985db27d | ||
|
|
3788d5bceb | ||
|
|
f785ffbd71 | ||
|
|
c1fb4ecf39 | ||
|
|
e6a97bb36a | ||
|
|
a1539395c6 | ||
|
|
94468aa28f | ||
|
|
72ee7d7f34 | ||
|
|
8d7be399d3 | ||
|
|
f42a78ef9c | ||
|
|
5842f1950a | ||
|
|
ba4f708137 | ||
|
|
2fdd0656d0 | ||
|
|
790cdc297b | ||
|
|
990698e423 | ||
|
|
632f78140f | ||
|
|
243ddd4b33 | ||
|
|
93a99b561c | ||
|
|
6a5defb91c | ||
|
|
2f93dcc4df | ||
|
|
603b8ebd8c | ||
|
|
4dee937e36 | ||
|
|
bb92074093 | ||
|
|
fb127270ce | ||
|
|
11ceeff5ca | ||
|
|
8ed5489d9c | ||
|
|
1fefb7e133 | ||
|
|
6a6c3445fa | ||
|
|
6fe725ff9d | ||
|
|
4115537f72 | ||
|
|
26b2c27eb0 | ||
|
|
62bc540db0 | ||
|
|
1ef5c9bfcd | ||
|
|
bfe042dc3e | ||
|
|
5518ca165e | ||
|
|
13a879c274 | ||
|
|
7b5be4e154 | ||
|
|
3c7fae7843 | ||
|
|
44ed6826a9 | ||
|
|
36fddd4156 | ||
|
|
7a2ee683e3 | ||
|
|
359b3326d9 | ||
|
|
7a94bd143c | ||
|
|
9b7a5f55b7 | ||
|
|
e5dfed0aa3 | ||
|
|
215a139e87 | ||
|
|
64fde6cddd | ||
|
|
370704fafd | ||
|
|
6629fdd87f | ||
|
|
554bc89cb5 | ||
|
|
b08e3d4e7b | ||
|
|
90cf28389c | ||
|
|
8581df9c14 | ||
|
|
de96e0f3dc | ||
|
|
03f2041913 | ||
|
|
6b1330e400 | ||
|
|
faf39fcc81 | ||
|
|
06e385b346 | ||
|
|
7a2f7f5a17 | ||
|
|
671b1624d5 | ||
|
|
cc1272f80b | ||
|
|
9b2fbc5c52 | ||
|
|
4710310629 | ||
|
|
4245c0b86e | ||
|
|
6b0586eaf6 | ||
|
|
018b7c38bd | ||
|
|
7e12da5a2a | ||
|
|
e109f1e008 | ||
|
|
4f539f1ed4 | ||
|
|
7104f9e2c8 | ||
|
|
632c902e1c | ||
|
|
c1f10b06a3 | ||
|
|
c4806e883e | ||
|
|
2c71de1d1b | ||
|
|
2e89113e6a | ||
|
|
edee5400ba | ||
|
|
82dfe5ddee | ||
|
|
0885f31dd7 | ||
|
|
9472bff8f9 | ||
|
|
68548ebd47 | ||
|
|
b9ac8e644d | ||
|
|
7b8e37b03d | ||
|
|
9960912bb1 | ||
|
|
1869852985 | ||
|
|
35163ff52a | ||
|
|
f44543f083 | ||
|
|
cefc1b6519 | ||
|
|
eb5fc0797f | ||
|
|
464b913e90 | ||
|
|
336afc5ca2 | ||
|
|
33f92d9ab3 | ||
|
|
61e2b7a787 | ||
|
|
5a3fd99a28 | ||
|
|
eefbc68f6b | ||
|
|
7791cdc201 | ||
|
|
daec743e8c | ||
|
|
c2ce7d0aa1 | ||
|
|
9eea574df5 | ||
|
|
da504ba46c | ||
|
|
c2c645188d | ||
|
|
7d23b0af5f | ||
|
|
0853de0760 | ||
|
|
b2e4513af3 | ||
|
|
a26c9214cb | ||
|
|
d3b91b5ec5 | ||
|
|
a5ea32c237 | ||
|
|
88efb36ead | ||
|
|
902f20f20c | ||
|
|
f6281158a2 | ||
|
|
154e972217 | ||
|
|
0c2374e66a | ||
|
|
15863c2886 | ||
|
|
618c14524d | ||
|
|
6c4983f65f | ||
|
|
ea282a1761 | ||
|
|
8fed930b7d | ||
|
|
a66fc13ebc | ||
|
|
8d7ab130ff | ||
|
|
569d54bee3 | ||
|
|
5138d4c0f9 | ||
|
|
d37bfa0a5e | ||
|
|
2cce14418c | ||
|
|
e6b0d22e07 | ||
|
|
ba8cafbd45 | ||
|
|
e920c1f8b4 | ||
|
|
8ac7aca2a4 | ||
|
|
ec17284bfd | ||
|
|
2d123f60e1 | ||
|
|
7721f29d0e | ||
|
|
af87c24cfd | ||
|
|
4b7c13d3e2 | ||
|
|
bb9dd4423d | ||
|
|
303212fba8 | ||
|
|
acc408f5ab | ||
|
|
086116d0f0 | ||
|
|
e93681afc0 | ||
|
|
7d2b4503e3 | ||
|
|
0d314df561 | ||
|
|
006d4237f5 | ||
|
|
2c3b860e63 | ||
|
|
613a733169 | ||
|
|
0587aec643 | ||
|
|
b334f2e345 | ||
|
|
777c8dd587 | ||
|
|
4be8be1353 | ||
|
|
8cc1c0d6dc | ||
|
|
eaba2eb7e5 | ||
|
|
9ccaa5a883 | ||
|
|
93fa7496b1 | ||
|
|
45f16e560c | ||
|
|
ec93239630 | ||
|
|
2f7b0c9938 | ||
|
|
ef12b75013 | ||
|
|
bed88baa6c | ||
|
|
9562b95285 | ||
|
|
e9fda6168c | ||
|
|
a6768bdc32 |
@@ -1,4 +1,5 @@
|
||||
_APP_ENV=development
|
||||
_APP_EDITION=self-hosted
|
||||
_APP_LOCALE=en
|
||||
_APP_WORKER_PER_CORE=6
|
||||
_APP_CONSOLE_WHITELIST_ROOT=disabled
|
||||
@@ -73,11 +74,12 @@ _APP_EXECUTOR_SECRET=your-secret-key
|
||||
_APP_EXECUTOR_HOST=http://proxy/v1
|
||||
_APP_FUNCTIONS_RUNTIMES=php-8.0,node-18.0,python-3.9,ruby-3.1
|
||||
_APP_MAINTENANCE_INTERVAL=86400
|
||||
_APP_MAINTENANCE_DELAY=
|
||||
_APP_MAINTENANCE_RETENTION_CACHE=2592000
|
||||
_APP_MAINTENANCE_RETENTION_EXECUTION=1209600
|
||||
_APP_MAINTENANCE_RETENTION_ABUSE=86400
|
||||
_APP_MAINTENANCE_RETENTION_AUDIT=1209600
|
||||
_APP_USAGE_AGGREGATION_INTERVAL=60000
|
||||
_APP_USAGE_AGGREGATION_INTERVAL=20
|
||||
_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000
|
||||
_APP_MAINTENANCE_RETENTION_SCHEDULES=86400
|
||||
_APP_USAGE_STATS=enabled
|
||||
|
||||
@@ -17,6 +17,12 @@ jobs:
|
||||
fetch-depth: 2
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
@@ -35,11 +41,11 @@ jobs:
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
platforms: linux/amd64,linux/arm64
|
||||
build-args: |
|
||||
VERSION=${{ steps.meta.outputs.version }}
|
||||
VITE_APPWRITE_GROWTH_ENDPOINT=https://growth.appwrite.io/v1
|
||||
VITE_GA_PROJECT=G-L7G2B6PLDS
|
||||
VITE_CONSOLE_MODE=cloud
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
|
||||
@@ -13,3 +13,4 @@ debug/
|
||||
app/sdks
|
||||
dev/yasd_init.php
|
||||
.phpunit.result.cache
|
||||
appwrite.json
|
||||
|
||||
+2
-1
@@ -99,7 +99,8 @@ RUN chmod +x /usr/local/bin/doctor && \
|
||||
chmod +x /usr/local/bin/worker-webhooks && \
|
||||
chmod +x /usr/local/bin/worker-migrations && \
|
||||
chmod +x /usr/local/bin/worker-hamster && \
|
||||
chmod +x /usr/local/bin/worker-usage
|
||||
chmod +x /usr/local/bin/worker-usage && \
|
||||
chmod +x /usr/local/bin/worker-usage-dump
|
||||
|
||||
|
||||
# Cloud Executabless
|
||||
|
||||
+27
-3
@@ -25,7 +25,7 @@ use Utopia\Registry\Registry;
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
CLI::setResource('register', fn()=>$register);
|
||||
CLI::setResource('register', fn() => $register);
|
||||
|
||||
CLI::setResource('cache', function ($pools) {
|
||||
$list = Config::getParam('pools-cache', []);
|
||||
@@ -72,7 +72,7 @@ CLI::setResource('dbForConsole', function ($pools, $cache) {
|
||||
$collections = Config::getParam('collections', [])['console'];
|
||||
$last = \array_key_last($collections);
|
||||
|
||||
if (!($dbForConsole->exists($dbForConsole->getDefaultDatabase(), $last))) { /** TODO cache ready variable using registry */
|
||||
if (!($dbForConsole->exists($dbForConsole->getDatabase(), $last))) { /** TODO cache ready variable using registry */
|
||||
throw new Exception('Tables not ready yet.');
|
||||
}
|
||||
|
||||
@@ -103,7 +103,19 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
|
||||
|
||||
if (isset($databases[$databaseName])) {
|
||||
$database = $databases[$databaseName];
|
||||
$database->setNamespace('_' . $project->getInternalId());
|
||||
|
||||
if ($project->getAttribute('database') === DATABASE_SHARED_TABLES) {
|
||||
$database
|
||||
->setShareTables(true)
|
||||
->setTenant($project->getInternalId())
|
||||
->setNamespace('');
|
||||
} else {
|
||||
$database
|
||||
->setShareTables(false)
|
||||
->setTenant(null)
|
||||
->setNamespace('_' . $project->getInternalId());
|
||||
}
|
||||
|
||||
return $database;
|
||||
}
|
||||
|
||||
@@ -116,6 +128,18 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
|
||||
|
||||
$databases[$databaseName] = $database;
|
||||
|
||||
if ($project->getAttribute('database') === DATABASE_SHARED_TABLES) {
|
||||
$database
|
||||
->setShareTables(true)
|
||||
->setTenant($project->getInternalId())
|
||||
->setNamespace('');
|
||||
} else {
|
||||
$database
|
||||
->setShareTables(false)
|
||||
->setTenant(null)
|
||||
->setNamespace('_' . $project->getInternalId());
|
||||
}
|
||||
|
||||
$database
|
||||
->setNamespace('_' . $project->getInternalId())
|
||||
->setMetadata('host', \gethostname())
|
||||
|
||||
+25
-3
@@ -31,7 +31,7 @@ return [
|
||||
Exception::GENERAL_SERVICE_DISABLED => [
|
||||
'name' => Exception::GENERAL_SERVICE_DISABLED,
|
||||
'description' => 'The requested service is disabled. You can enable the service from the Appwrite console.',
|
||||
'code' => 503,
|
||||
'code' => 403,
|
||||
],
|
||||
Exception::GENERAL_UNAUTHORIZED_SCOPE => [
|
||||
'name' => Exception::GENERAL_UNAUTHORIZED_SCOPE,
|
||||
@@ -103,6 +103,11 @@ return [
|
||||
'description' => 'This method was not fully implemented yet. If you believe this is a mistake, please upgrade your Appwrite server version.',
|
||||
'code' => 405,
|
||||
],
|
||||
Exception::GENERAL_BAD_REQUEST => [
|
||||
'name' => Exception::GENERAL_BAD_REQUEST,
|
||||
'description' => 'There was an error processing your request. Please check the inputs and try again.',
|
||||
'code' => 400,
|
||||
],
|
||||
|
||||
/** User Errors */
|
||||
Exception::USER_COUNT_EXCEEDED => [
|
||||
@@ -251,6 +256,11 @@ return [
|
||||
'description' => 'User phone is already verified',
|
||||
'code' => 409
|
||||
],
|
||||
Exception::USER_DELETION_PROHIBITED => [
|
||||
'name' => Exception::USER_DELETION_PROHIBITED,
|
||||
'description' => 'User deletion is not allowed for users with active memberships. Please delete all confirmed memberships before deleting the account.',
|
||||
'code' => 400
|
||||
],
|
||||
|
||||
/** Teams */
|
||||
Exception::TEAM_NOT_FOUND => [
|
||||
@@ -768,10 +778,22 @@ return [
|
||||
],
|
||||
|
||||
/** Health */
|
||||
Exception::QUEUE_SIZE_EXCEEDED => [
|
||||
'name' => Exception::QUEUE_SIZE_EXCEEDED,
|
||||
Exception::HEALTH_QUEUE_SIZE_EXCEEDED => [
|
||||
'name' => Exception::HEALTH_QUEUE_SIZE_EXCEEDED,
|
||||
'description' => 'Queue size threshold hit.',
|
||||
'code' => 503,
|
||||
'publish' => false
|
||||
],
|
||||
|
||||
Exception::HEALTH_CERTIFICATE_EXPIRED => [
|
||||
'name' => Exception::HEALTH_CERTIFICATE_EXPIRED,
|
||||
'description' => 'The SSL certificate for the specified domain has expired and is no longer valid.',
|
||||
'code' => 404,
|
||||
],
|
||||
|
||||
Exception::HEALTH_INVALID_HOST => [
|
||||
'name' => Exception::HEALTH_INVALID_HOST,
|
||||
'description' => 'Failed to establish a connection to the specified domain. Please verify the domain name and ensure that the server is running and accessible.',
|
||||
'code' => 404,
|
||||
],
|
||||
];
|
||||
|
||||
@@ -303,7 +303,7 @@ return [
|
||||
[
|
||||
'key' => 'ruby',
|
||||
'name' => 'Ruby',
|
||||
'version' => '10.1.0',
|
||||
'version' => '10.1.1',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-ruby',
|
||||
'package' => 'https://rubygems.org/gems/appwrite',
|
||||
'enabled' => true,
|
||||
|
||||
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
@@ -408,7 +408,7 @@ return [
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SMTP_SECURE',
|
||||
'description' => 'SMTP secure connection protocol. Empty by default, change to \'tls\' if running on a secure connection.',
|
||||
'description' => 'SMTP secure connection protocol. Empty by default, change to \'tls\' or \'ssl\' if running on a secure connection.',
|
||||
'introduction' => '',
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
@@ -948,6 +948,15 @@ return [
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_DELAY',
|
||||
'description' => 'Delay value containing the number of seconds that the Appwrite maintenance process should wait before executing system cleanups and optimizations. The default value is 0 seconds.',
|
||||
'introduction' => '1.5.0',
|
||||
'default' => '0',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_RETENTION_CACHE',
|
||||
'description' => 'The maximum duration (in seconds) upto which to retain cached files. The default value is 2592000 seconds (30 days).',
|
||||
|
||||
@@ -110,7 +110,7 @@ App::post('/v1/account')
|
||||
Query::equal('providerEmail', [$email]),
|
||||
]);
|
||||
if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) {
|
||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST); /** Return a generic bad request to prevent exposing existing accounts */
|
||||
}
|
||||
|
||||
if ($project->getAttribute('auths', [])['personalDataCheck'] ?? false) {
|
||||
@@ -253,7 +253,7 @@ App::post('/v1/account/sessions/email')
|
||||
$dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$session = $dbForProject->createDocument('sessions', $session->setAttribute('$permissions', [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
@@ -578,7 +578,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
$currentDocument = $dbForProject->getDocument('sessions', $current);
|
||||
if (!$currentDocument->isEmpty()) {
|
||||
$dbForProject->deleteDocument('sessions', $currentDocument->getId());
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,7 +637,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
Query::equal('providerEmail', [$email]),
|
||||
]);
|
||||
if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) {
|
||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST); /** Return a generic bad request to prevent exposing existing accounts */
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -695,7 +695,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
Query::notEqual('userId', $user->getId()),
|
||||
]);
|
||||
if (!empty($identitiesWithMatchingEmail)) {
|
||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST); /** Return a generic bad request to prevent exposing existing accounts */
|
||||
}
|
||||
|
||||
$dbForProject->createDocument('identities', new Document([
|
||||
@@ -766,7 +766,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$session->setAttribute('expire', $expire);
|
||||
|
||||
@@ -944,7 +944,7 @@ App::post('/v1/account/sessions/magic-url')
|
||||
Query::equal('providerEmail', [$email]),
|
||||
]);
|
||||
if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) {
|
||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST); /** Return a generic bad request to prevent exposing existing accounts */
|
||||
}
|
||||
|
||||
$userId = $userId === 'unique()' ? ID::unique() : $userId;
|
||||
@@ -1000,7 +1000,7 @@ App::post('/v1/account/sessions/magic-url')
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
if (empty($url)) {
|
||||
$url = $request->getProtocol() . '://' . $request->getHostname() . '/auth/magic-url';
|
||||
@@ -1177,7 +1177,7 @@ App::put('/v1/account/sessions/magic-url')
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$tokens = $user->getAttribute('tokens', []);
|
||||
|
||||
@@ -1186,7 +1186,7 @@ App::put('/v1/account/sessions/magic-url')
|
||||
* the recovery token but actually we don't need it anymore.
|
||||
*/
|
||||
$dbForProject->deleteDocument('tokens', $token);
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$user->setAttribute('emailVerification', true);
|
||||
|
||||
@@ -1324,7 +1324,7 @@ App::post('/v1/account/sessions/phone')
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl');
|
||||
|
||||
@@ -1336,8 +1336,6 @@ App::post('/v1/account/sessions/phone')
|
||||
$message = $message->setParam('{{token}}', $secret);
|
||||
$message = $message->render();
|
||||
|
||||
var_dump($request->getIP());
|
||||
var_dump($project->getId());
|
||||
$queueForMessaging
|
||||
->setRecipient($phone)
|
||||
->setMessage($message)
|
||||
@@ -1431,14 +1429,14 @@ App::put('/v1/account/sessions/phone')
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
/**
|
||||
* We act like we're updating and validating
|
||||
* the recovery token but actually we don't need it anymore.
|
||||
*/
|
||||
$dbForProject->deleteDocument('tokens', $token);
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$user->setAttribute('phoneVerification', true);
|
||||
|
||||
@@ -1583,7 +1581,7 @@ App::post('/v1/account/sessions/anonymous')
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$queueForEvents
|
||||
->setParam('userId', $user->getId())
|
||||
@@ -1990,7 +1988,7 @@ App::patch('/v1/account/email')
|
||||
Query::notEqual('userId', $user->getId()),
|
||||
]);
|
||||
if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) {
|
||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST); /** Return a generic bad request to prevent exposing existing accounts */
|
||||
}
|
||||
|
||||
$user
|
||||
@@ -2009,7 +2007,7 @@ App::patch('/v1/account/email')
|
||||
try {
|
||||
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
|
||||
} catch (Duplicate) {
|
||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST); /** Return a generic bad request to prevent exposing existing accounts */
|
||||
}
|
||||
|
||||
$queueForEvents->setParam('userId', $user->getId());
|
||||
@@ -2216,7 +2214,7 @@ App::delete('/v1/account/sessions/:sessionId')
|
||||
;
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$queueForEvents
|
||||
->setParam('userId', $user->getId())
|
||||
@@ -2296,7 +2294,7 @@ App::patch('/v1/account/sessions/:sessionId')
|
||||
|
||||
$dbForProject->updateDocument('sessions', $sessionId, $session);
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||
|
||||
@@ -2366,7 +2364,7 @@ App::delete('/v1/account/sessions')
|
||||
}
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$queueForEvents
|
||||
->setParam('userId', $user->getId())
|
||||
@@ -2451,7 +2449,7 @@ App::post('/v1/account/recovery')
|
||||
Permission::delete(Role::user($profile->getId())),
|
||||
]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $profile->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $profile->getId());
|
||||
|
||||
$url = Template::parseURL($url);
|
||||
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $profile->getId(), 'secret' => $secret, 'expire' => $expire]);
|
||||
@@ -2528,7 +2526,7 @@ App::post('/v1/account/recovery')
|
||||
|
||||
$queueForMails
|
||||
->setRecipient($profile->getAttribute('email', ''))
|
||||
->setName($profile->getAttribute('name'))
|
||||
->setName($profile->getAttribute('name', ''))
|
||||
->setBody($body)
|
||||
->setVariables($emailVariables)
|
||||
->setSubject($subject)
|
||||
@@ -2632,7 +2630,7 @@ App::put('/v1/account/recovery')
|
||||
* the recovery token but actually we don't need it anymore.
|
||||
*/
|
||||
$dbForProject->deleteDocument('tokens', $recovery);
|
||||
$dbForProject->deleteCachedDocument('users', $profile->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $profile->getId());
|
||||
|
||||
$queueForEvents
|
||||
->setParam('userId', $profile->getId())
|
||||
@@ -2703,7 +2701,7 @@ App::post('/v1/account/verification')
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$url = Template::parseURL($url);
|
||||
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $user->getId(), 'secret' => $verificationSecret, 'expire' => $expire]);
|
||||
@@ -2852,7 +2850,7 @@ App::put('/v1/account/verification')
|
||||
* the verification token but actually we don't need it anymore.
|
||||
*/
|
||||
$dbForProject->deleteDocument('tokens', $verification);
|
||||
$dbForProject->deleteCachedDocument('users', $profile->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $profile->getId());
|
||||
|
||||
$queueForEvents
|
||||
->setParam('userId', $userId)
|
||||
@@ -2927,7 +2925,7 @@ App::post('/v1/account/verification/phone')
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl');
|
||||
|
||||
@@ -2939,8 +2937,6 @@ App::post('/v1/account/verification/phone')
|
||||
$message = $message->setParam('{{token}}', $secret);
|
||||
$message = $message->render();
|
||||
|
||||
var_dump($request->getIP());
|
||||
var_dump($project->getId());
|
||||
$queueForMessaging
|
||||
->setRecipient($user->getAttribute('phone'))
|
||||
->setMessage($message)
|
||||
@@ -3013,7 +3009,7 @@ App::put('/v1/account/verification/phone')
|
||||
* We act like we're updating and validating the verification token but actually we don't need it anymore.
|
||||
*/
|
||||
$dbForProject->deleteDocument('tokens', $verification);
|
||||
$dbForProject->deleteCachedDocument('users', $profile->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $profile->getId());
|
||||
|
||||
$queueForEvents
|
||||
->setParam('userId', $user->getId())
|
||||
@@ -3038,15 +3034,27 @@ App::delete('/v1/account')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->inject('user')
|
||||
->inject('project')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForDeletes')
|
||||
->action(function (Document $user, Response $response, Database $dbForProject, Event $queueForEvents, Delete $queueForDeletes) {
|
||||
->action(function (Document $user, Document $project, Response $response, Database $dbForProject, Event $queueForEvents, Delete $queueForDeletes) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception(Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($project->getId() === 'console') {
|
||||
// get all memberships
|
||||
$memberships = $user->getAttribute('memberships', []);
|
||||
foreach ($memberships as $membership) {
|
||||
// prevent deletion if at least one active membership
|
||||
if ($membership->getAttribute('confirm', false)) {
|
||||
throw new Exception(Exception::USER_DELETION_PROHIBITED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dbForProject->deleteDocument('users', $user->getId());
|
||||
|
||||
$queueForDeletes
|
||||
|
||||
@@ -116,7 +116,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro
|
||||
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('sessions', $gitHubSession->getId(), $gitHubSession));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
} catch (Throwable $err) {
|
||||
$index = 0;
|
||||
do {
|
||||
|
||||
@@ -153,13 +153,13 @@ function createAttribute(string $databaseId, string $collectionId, Document $att
|
||||
} catch (LimitException) {
|
||||
throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED, 'Attribute limit exceeded');
|
||||
} catch (\Exception $e) {
|
||||
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId);
|
||||
$dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId());
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $collectionId);
|
||||
$dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId());
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId);
|
||||
$dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId());
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $collectionId);
|
||||
$dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId());
|
||||
|
||||
if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) {
|
||||
$twoWayKey = $options['twoWayKey'];
|
||||
@@ -197,13 +197,13 @@ function createAttribute(string $databaseId, string $collectionId, Document $att
|
||||
$dbForProject->deleteDocument('attributes', $attribute->getId());
|
||||
throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED, 'Attribute limit exceeded');
|
||||
} catch (\Exception $e) {
|
||||
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId());
|
||||
$dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId());
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId());
|
||||
$dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId());
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId());
|
||||
$dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId());
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId());
|
||||
$dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId());
|
||||
}
|
||||
|
||||
$queueForDatabase
|
||||
@@ -358,7 +358,7 @@ function updateAttribute(
|
||||
$relatedOptions = \array_merge($relatedAttribute->getAttribute('options'), $options);
|
||||
$relatedAttribute->setAttribute('options', $relatedOptions);
|
||||
$dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $primaryDocumentOptions['twoWayKey'], $relatedAttribute);
|
||||
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId());
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId());
|
||||
}
|
||||
} else {
|
||||
$dbForProject->updateAttribute(
|
||||
@@ -371,7 +371,7 @@ function updateAttribute(
|
||||
}
|
||||
|
||||
$attribute = $dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key, $attribute);
|
||||
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collection->getId());
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $collection->getId());
|
||||
|
||||
$queueForEvents
|
||||
->setContext('collection', $collection)
|
||||
@@ -703,8 +703,8 @@ App::delete('/v1/databases/:databaseId')
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove collection from DB');
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('databases', $database->getId());
|
||||
$dbForProject->deleteCachedCollection('databases_' . $database->getInternalId());
|
||||
$dbForProject->purgeCachedDocument('databases', $database->getId());
|
||||
$dbForProject->purgeCachedCollection('databases_' . $database->getInternalId());
|
||||
|
||||
$queueForDatabase
|
||||
->setType(DATABASE_TYPE_DELETE_DATABASE)
|
||||
@@ -1076,7 +1076,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId')
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove collection from DB');
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId());
|
||||
$dbForProject->purgeCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId());
|
||||
|
||||
$queueForDatabase
|
||||
->setType(DATABASE_TYPE_DELETE_COLLECTION)
|
||||
@@ -2248,8 +2248,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
|
||||
$attribute = $dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'deleting'));
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId);
|
||||
$dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId());
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $collectionId);
|
||||
$dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId());
|
||||
|
||||
if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) {
|
||||
$options = $attribute->getAttribute('options');
|
||||
@@ -2270,8 +2270,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
|
||||
$dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'deleting'));
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $options['relatedCollection']);
|
||||
$dbForProject->deleteCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId());
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $options['relatedCollection']);
|
||||
$dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2453,7 +2453,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
|
||||
throw new Exception(Exception::INDEX_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId);
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $collectionId);
|
||||
|
||||
$queueForDatabase
|
||||
->setType(DATABASE_TYPE_CREATE_INDEX)
|
||||
@@ -2620,7 +2620,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
|
||||
$index = $dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'deleting'));
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId);
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $collectionId);
|
||||
|
||||
$queueForDatabase
|
||||
->setType(DATABASE_TYPE_DELETE_INDEX)
|
||||
@@ -2997,6 +2997,33 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
$processDocument($collection, $document);
|
||||
}
|
||||
|
||||
$select = \array_reduce($queries, function ($result, $query) {
|
||||
return $result || ($query->getMethod() === Query::TYPE_SELECT);
|
||||
}, false);
|
||||
|
||||
// Check if the SELECT query includes $databaseId and $collectionId
|
||||
$hasDatabaseId = false;
|
||||
$hasCollectionId = false;
|
||||
if ($select) {
|
||||
$hasDatabaseId = \array_reduce($queries, function ($result, $query) {
|
||||
return $result || ($query->getMethod() === Query::TYPE_SELECT && \in_array('$databaseId', $query->getValues()));
|
||||
}, false);
|
||||
$hasCollectionId = \array_reduce($queries, function ($result, $query) {
|
||||
return $result || ($query->getMethod() === Query::TYPE_SELECT && \in_array('$collectionId', $query->getValues()));
|
||||
}, false);
|
||||
}
|
||||
|
||||
if ($select) {
|
||||
foreach ($documents as $document) {
|
||||
if (!$hasDatabaseId) {
|
||||
$document->removeAttribute('$databaseId');
|
||||
}
|
||||
if (!$hasCollectionId) {
|
||||
$document->removeAttribute('$collectionId');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $total,
|
||||
'documents' => $documents,
|
||||
|
||||
+106
-12
@@ -7,6 +7,7 @@ use Appwrite\Utopia\Response;
|
||||
use Utopia\App;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Domains\Validator\PublicDomain;
|
||||
use Utopia\Pools\Group;
|
||||
use Utopia\Queue\Client;
|
||||
use Utopia\Queue\Connection;
|
||||
@@ -14,7 +15,9 @@ use Utopia\Registry\Registry;
|
||||
use Utopia\Storage\Device;
|
||||
use Utopia\Storage\Device\Local;
|
||||
use Utopia\Storage\Storage;
|
||||
use Utopia\Validator\Domain;
|
||||
use Utopia\Validator\Integer;
|
||||
use Utopia\Validator\Multiple;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
@@ -356,7 +359,7 @@ App::get('/v1/health/queue/webhooks')
|
||||
$size = $client->getQueueSize();
|
||||
|
||||
if ($size >= $threshold) {
|
||||
throw new Exception(Exception::QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
|
||||
@@ -383,12 +386,62 @@ App::get('/v1/health/queue/logs')
|
||||
$size = $client->getQueueSize();
|
||||
|
||||
if ($size >= $threshold) {
|
||||
throw new Exception(Exception::QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
|
||||
}, ['response']);
|
||||
|
||||
App::get('/v1/health/certificate')
|
||||
->desc('Get the SSL certificate for a domain')
|
||||
->groups(['api', 'health'])
|
||||
->label('scope', 'health.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'health')
|
||||
->label('sdk.method', 'getCertificate')
|
||||
->label('sdk.description', '/docs/references/health/get-certificate.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_CERTIFICATE)
|
||||
->param('domain', null, new Multiple([new Domain(), new PublicDomain()]), Multiple::TYPE_STRING, 'Domain name')
|
||||
->inject('response')
|
||||
->action(function (string $domain, Response $response) {
|
||||
if (filter_var($domain, FILTER_VALIDATE_URL)) {
|
||||
$domain = parse_url($domain, PHP_URL_HOST);
|
||||
}
|
||||
|
||||
$sslContext = stream_context_create([
|
||||
"ssl" => [
|
||||
"capture_peer_cert" => true
|
||||
]
|
||||
]);
|
||||
$sslSocket = stream_socket_client("ssl://" . $domain . ":443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $sslContext);
|
||||
if (!$sslSocket) {
|
||||
throw new Exception(Exception::HEALTH_INVALID_HOST);
|
||||
}
|
||||
|
||||
$streamContextParams = stream_context_get_params($sslSocket);
|
||||
$peerCertificate = $streamContextParams['options']['ssl']['peer_certificate'];
|
||||
$certificatePayload = openssl_x509_parse($peerCertificate);
|
||||
|
||||
|
||||
$sslExpiration = $certificatePayload['validTo_time_t'];
|
||||
$status = $sslExpiration < time() ? 'fail' : 'pass';
|
||||
|
||||
if ($status === 'fail') {
|
||||
throw new Exception(Exception::HEALTH_CERTIFICATE_EXPIRED);
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'name' => $certificatePayload['name'],
|
||||
'subjectSN' => $certificatePayload['subject']['CN'],
|
||||
'issuerOrganisation' => $certificatePayload['issuer']['O'],
|
||||
'validFrom' => $certificatePayload['validFrom_time_t'],
|
||||
'validTo' => $certificatePayload['validTo_time_t'],
|
||||
'signatureTypeSN' => $certificatePayload['signatureTypeSN'],
|
||||
]), Response::MODEL_HEALTH_CERTIFICATE);
|
||||
}, ['response']);
|
||||
|
||||
App::get('/v1/health/queue/certificates')
|
||||
->desc('Get certificates queue')
|
||||
->groups(['api', 'health'])
|
||||
@@ -410,7 +463,7 @@ App::get('/v1/health/queue/certificates')
|
||||
$size = $client->getQueueSize();
|
||||
|
||||
if ($size >= $threshold) {
|
||||
throw new Exception(Exception::QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
|
||||
@@ -437,7 +490,7 @@ App::get('/v1/health/queue/builds')
|
||||
$size = $client->getQueueSize();
|
||||
|
||||
if ($size >= $threshold) {
|
||||
throw new Exception(Exception::QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
|
||||
@@ -465,7 +518,7 @@ App::get('/v1/health/queue/databases')
|
||||
$size = $client->getQueueSize();
|
||||
|
||||
if ($size >= $threshold) {
|
||||
throw new Exception(Exception::QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
|
||||
@@ -492,7 +545,7 @@ App::get('/v1/health/queue/deletes')
|
||||
$size = $client->getQueueSize();
|
||||
|
||||
if ($size >= $threshold) {
|
||||
throw new Exception(Exception::QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
|
||||
@@ -519,7 +572,7 @@ App::get('/v1/health/queue/mails')
|
||||
$size = $client->getQueueSize();
|
||||
|
||||
if ($size >= $threshold) {
|
||||
throw new Exception(Exception::QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
|
||||
@@ -546,7 +599,7 @@ App::get('/v1/health/queue/messaging')
|
||||
$size = $client->getQueueSize();
|
||||
|
||||
if ($size >= $threshold) {
|
||||
throw new Exception(Exception::QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
|
||||
@@ -573,7 +626,7 @@ App::get('/v1/health/queue/migrations')
|
||||
$size = $client->getQueueSize();
|
||||
|
||||
if ($size >= $threshold) {
|
||||
throw new Exception(Exception::QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
|
||||
@@ -600,7 +653,7 @@ App::get('/v1/health/queue/functions')
|
||||
$size = $client->getQueueSize();
|
||||
|
||||
if ($size >= $threshold) {
|
||||
throw new Exception(Exception::QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
|
||||
@@ -649,6 +702,47 @@ App::get('/v1/health/storage/local')
|
||||
$response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS);
|
||||
});
|
||||
|
||||
App::get('/v1/health/storage')
|
||||
->desc('Get storage')
|
||||
->groups(['api', 'health'])
|
||||
->label('scope', 'health.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'health')
|
||||
->label('sdk.method', 'getStorage')
|
||||
->label('sdk.description', '/docs/references/health/get-storage.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_STATUS)
|
||||
->inject('response')
|
||||
->inject('deviceFiles')
|
||||
->inject('deviceFunctions')
|
||||
->inject('deviceBuilds')
|
||||
->action(function (Response $response, Device $deviceFiles, Device $deviceFunctions, Device $deviceBuilds) {
|
||||
$devices = [$deviceFiles, $deviceFunctions, $deviceBuilds];
|
||||
$checkStart = \microtime(true);
|
||||
|
||||
foreach ($devices as $device) {
|
||||
if (!$device->write($device->getPath('health.txt'), 'test', 'text/plain')) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed writing test file to ' . $device->getRoot());
|
||||
}
|
||||
|
||||
if ($device->read($device->getPath('health.txt')) !== 'test') {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed reading test file from ' . $device->getRoot());
|
||||
}
|
||||
|
||||
if (!$device->delete($device->getPath('health.txt'))) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed deleting test file from ' . $device->getRoot());
|
||||
}
|
||||
}
|
||||
|
||||
$output = [
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
];
|
||||
|
||||
$response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS);
|
||||
});
|
||||
|
||||
App::get('/v1/health/anti-virus')
|
||||
->desc('Get antivirus')
|
||||
->groups(['api', 'health'])
|
||||
@@ -695,7 +789,7 @@ App::get('/v1/health/queue/failed/:name')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'health')
|
||||
->label('sdk.method', 'getFailedJobs')
|
||||
->param('queueName', '', new WhiteList([
|
||||
->param('name', '', new WhiteList([
|
||||
Event::DATABASE_QUEUE_NAME,
|
||||
Event::DELETE_QUEUE_NAME,
|
||||
Event::AUDITS_QUEUE_NAME,
|
||||
@@ -723,7 +817,7 @@ App::get('/v1/health/queue/failed/:name')
|
||||
$failed = $client->countFailedJobs();
|
||||
|
||||
if ($failed >= $threshold) {
|
||||
throw new Exception(Exception::QUEUE_SIZE_EXCEEDED, "Queue failed jobs threshold hit. Current size is {$failed} and threshold is {$threshold}.");
|
||||
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue failed jobs threshold hit. Current size is {$failed} and threshold is {$threshold}.");
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([ 'size' => $failed ]), Response::MODEL_HEALTH_QUEUE);
|
||||
|
||||
@@ -144,9 +144,30 @@ App::get('/v1/project/usage')
|
||||
];
|
||||
}, $dbForProject->find('buckets'));
|
||||
|
||||
// merge network inbound + outbound
|
||||
$projectBandwidth = [];
|
||||
foreach ($usage[METRIC_NETWORK_INBOUND] as $item) {
|
||||
$projectBandwidth[$item['date']] ??= 0;
|
||||
$projectBandwidth[$item['date']] += $item['value'];
|
||||
}
|
||||
|
||||
foreach ($usage[METRIC_NETWORK_OUTBOUND] as $item) {
|
||||
$projectBandwidth[$item['date']] ??= 0;
|
||||
$projectBandwidth[$item['date']] += $item['value'];
|
||||
}
|
||||
|
||||
|
||||
$network = [];
|
||||
foreach ($projectBandwidth as $date => $value) {
|
||||
$network[] = [
|
||||
'date' => $date,
|
||||
'value' => $value
|
||||
];
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'requests' => ($usage[METRIC_NETWORK_REQUESTS]),
|
||||
'network' => ($usage[METRIC_NETWORK_INBOUND] + $usage[METRIC_NETWORK_OUTBOUND]),
|
||||
'network' => $network,
|
||||
'users' => ($usage[METRIC_USERS]),
|
||||
'executions' => ($usage[METRIC_EXECUTIONS]),
|
||||
'executionsTotal' => $total[METRIC_EXECUTIONS],
|
||||
|
||||
@@ -9,6 +9,7 @@ use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\Template\Template;
|
||||
use Appwrite\Utopia\Database\Validator\ProjectId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Projects;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
@@ -71,12 +72,12 @@ App::post('/v1/projects')
|
||||
->param('legalCity', '', new Text(256), 'Project legal City. Max length: 256 chars.', true)
|
||||
->param('legalAddress', '', new Text(256), 'Project legal Address. Max length: 256 chars.', true)
|
||||
->param('legalTaxId', '', new Text(256), 'Project legal Tax ID. Max length: 256 chars.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->inject('cache')
|
||||
->inject('pools')
|
||||
->action(function (string $projectId, string $name, string $teamId, string $region, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, Cache $cache, Group $pools) {
|
||||
|
||||
->action(function (string $projectId, string $name, string $teamId, string $region, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Request $request, Response $response, Database $dbForConsole, Cache $cache, Group $pools) {
|
||||
|
||||
$team = $dbForConsole->getDocument('teams', $teamId);
|
||||
|
||||
@@ -85,8 +86,15 @@ App::post('/v1/projects')
|
||||
}
|
||||
|
||||
$auth = Config::getParam('auth', []);
|
||||
$auths = ['limit' => 0, 'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT, 'passwordHistory' => 0, 'passwordDictionary' => false, 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG, 'personalDataCheck' => false];
|
||||
foreach ($auth as $index => $method) {
|
||||
$auths = [
|
||||
'limit' => 0,
|
||||
'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT,
|
||||
'passwordHistory' => 0,
|
||||
'passwordDictionary' => false,
|
||||
'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG,
|
||||
'personalDataCheck' => false
|
||||
];
|
||||
foreach ($auth as $method) {
|
||||
$auths[$method['key'] ?? ''] = true;
|
||||
}
|
||||
|
||||
@@ -121,7 +129,7 @@ App::post('/v1/projects')
|
||||
}
|
||||
}
|
||||
|
||||
$databaseOverride = App::getEnv('_APP_DATABASE_OVERRIDE', null);
|
||||
$databaseOverride = App::getEnv('_APP_DATABASE_OVERRIDE');
|
||||
$index = array_search($databaseOverride, $databases);
|
||||
if ($index !== false) {
|
||||
$database = $databases[$index];
|
||||
@@ -133,6 +141,23 @@ App::post('/v1/projects')
|
||||
throw new Exception(Exception::PROJECT_RESERVED_PROJECT, "'console' is a reserved project.");
|
||||
}
|
||||
|
||||
// TODO: One in 20 projects use shared tables. Temporary until all projects are using shared tables.
|
||||
if (
|
||||
!\mt_rand(0, 19)
|
||||
&& App::getEnv('_APP_EDITION', 'self-hosted') !== 'self-hosted'
|
||||
) {
|
||||
$database = DATABASE_SHARED_TABLES;
|
||||
}
|
||||
|
||||
// TODO: Allow overriding in development mode. Temporary until all projects are using shared tables.
|
||||
if (
|
||||
App::isDevelopment()
|
||||
&& App::getEnv('_APP_EDITION', 'self-hosted') !== 'self-hosted'
|
||||
&& $request->getHeader('x-appwrite-share-tables', false)
|
||||
) {
|
||||
$database = DATABASE_SHARED_TABLES;
|
||||
}
|
||||
|
||||
try {
|
||||
$project = $dbForConsole->createDocument('projects', new Document([
|
||||
'$id' => $projectId,
|
||||
@@ -164,14 +189,26 @@ App::post('/v1/projects')
|
||||
'keys' => null,
|
||||
'auths' => $auths,
|
||||
'search' => implode(' ', [$projectId, $name]),
|
||||
'database' => $database
|
||||
'database' => $database,
|
||||
]));
|
||||
} catch (Duplicate $th) {
|
||||
} catch (Duplicate) {
|
||||
throw new Exception(Exception::PROJECT_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$dbForProject = new Database($pools->get($database)->pop()->getResource(), $cache);
|
||||
$dbForProject->setNamespace("_{$project->getInternalId()}");
|
||||
|
||||
if ($database === DATABASE_SHARED_TABLES) {
|
||||
$dbForProject
|
||||
->setShareTables(true)
|
||||
->setTenant($project->getInternalId())
|
||||
->setNamespace('');
|
||||
} else {
|
||||
$dbForProject
|
||||
->setShareTables(false)
|
||||
->setTenant(null)
|
||||
->setNamespace('_' . $project->getInternalId());
|
||||
}
|
||||
|
||||
$dbForProject->create();
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
@@ -188,33 +225,19 @@ App::post('/v1/projects')
|
||||
continue;
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
$indexes = [];
|
||||
$attributes = \array_map(function (array $attribute) {
|
||||
return new Document($attribute);
|
||||
}, $collection['attributes']);
|
||||
|
||||
foreach ($collection['attributes'] as $attribute) {
|
||||
$attributes[] = new Document([
|
||||
'$id' => $attribute['$id'],
|
||||
'type' => $attribute['type'],
|
||||
'size' => $attribute['size'],
|
||||
'required' => $attribute['required'],
|
||||
'signed' => $attribute['signed'],
|
||||
'array' => $attribute['array'],
|
||||
'filters' => $attribute['filters'],
|
||||
'default' => $attribute['default'] ?? null,
|
||||
'format' => $attribute['format'] ?? ''
|
||||
]);
|
||||
}
|
||||
$indexes = \array_map(function (array $index) {
|
||||
return new Document($index);
|
||||
}, $collection['indexes']);
|
||||
|
||||
foreach ($collection['indexes'] as $index) {
|
||||
$indexes[] = new Document([
|
||||
'$id' => $index['$id'],
|
||||
'type' => $index['type'],
|
||||
'attributes' => $index['attributes'],
|
||||
'lengths' => $index['lengths'],
|
||||
'orders' => $index['orders'],
|
||||
]);
|
||||
try {
|
||||
$dbForProject->createCollection($key, $attributes, $indexes);
|
||||
} catch (Duplicate) {
|
||||
// Collection already exists
|
||||
}
|
||||
$dbForProject->createCollection($key, $attributes, $indexes);
|
||||
}
|
||||
|
||||
$response
|
||||
@@ -820,7 +843,7 @@ App::post('/v1/projects/:projectId/webhooks')
|
||||
|
||||
$webhook = $dbForConsole->createDocument('webhooks', $webhook);
|
||||
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
@@ -941,7 +964,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
->setAttribute('httpPass', $httpPass);
|
||||
|
||||
$dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook);
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||
|
||||
$response->dynamic($webhook, Response::MODEL_WEBHOOK);
|
||||
});
|
||||
@@ -980,7 +1003,7 @@ App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature')
|
||||
$webhook->setAttribute('signatureKey', \bin2hex(\random_bytes(64)));
|
||||
|
||||
$dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook);
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||
|
||||
$response->dynamic($webhook, Response::MODEL_WEBHOOK);
|
||||
});
|
||||
@@ -1017,7 +1040,7 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
|
||||
$dbForConsole->deleteDocument('webhooks', $webhook->getId());
|
||||
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
@@ -1067,7 +1090,7 @@ App::post('/v1/projects/:projectId/keys')
|
||||
|
||||
$key = $dbForConsole->createDocument('keys', $key);
|
||||
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
@@ -1181,7 +1204,7 @@ App::put('/v1/projects/:projectId/keys/:keyId')
|
||||
|
||||
$dbForConsole->updateDocument('keys', $key->getId(), $key);
|
||||
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||
|
||||
$response->dynamic($key, Response::MODEL_KEY);
|
||||
});
|
||||
@@ -1218,7 +1241,7 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
|
||||
|
||||
$dbForConsole->deleteDocument('keys', $key->getId());
|
||||
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
@@ -1268,7 +1291,7 @@ App::post('/v1/projects/:projectId/platforms')
|
||||
|
||||
$platform = $dbForConsole->createDocument('platforms', $platform);
|
||||
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
@@ -1383,7 +1406,7 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
|
||||
|
||||
$dbForConsole->updateDocument('platforms', $platform->getId(), $platform);
|
||||
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||
|
||||
$response->dynamic($platform, Response::MODEL_PLATFORM);
|
||||
});
|
||||
@@ -1420,7 +1443,7 @@ App::delete('/v1/projects/:projectId/platforms/:platformId')
|
||||
|
||||
$dbForConsole->deleteDocument('platforms', $platformId);
|
||||
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
@@ -1446,7 +1469,7 @@ App::patch('/v1/projects/:projectId/smtp')
|
||||
->param('port', 587, new Integer(), 'SMTP server port', true)
|
||||
->param('username', '', new Text(0, 0), 'SMTP server username', true)
|
||||
->param('password', '', new Text(0, 0), 'SMTP server password', true)
|
||||
->param('secure', '', new WhiteList(['tls'], true), 'Does SMTP server use secure connection', true)
|
||||
->param('secure', '', new WhiteList(['tls', 'ssl'], true), 'Does SMTP server use secure connection', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, bool $enabled, string $senderName, string $senderEmail, string $replyTo, string $host, int $port, string $username, string $password, string $secure, Response $response, Database $dbForConsole) {
|
||||
|
||||
@@ -114,7 +114,7 @@ App::post('/v1/teams')
|
||||
]);
|
||||
|
||||
$membership = $dbForProject->createDocument('memberships', $membership);
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
}
|
||||
|
||||
$queueForEvents->setParam('teamId', $team->getId());
|
||||
@@ -380,7 +380,6 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.')
|
||||
->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) // TODO add our own built-in confirm page
|
||||
->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('user')
|
||||
@@ -389,7 +388,7 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
->inject('queueForMails')
|
||||
->inject('queueForMessaging')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, EventPhone $queueForMessaging, Event $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());
|
||||
|
||||
@@ -537,7 +536,7 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
|
||||
Authorization::skip(fn() => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $invitee->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $invitee->getId());
|
||||
} else {
|
||||
try {
|
||||
$membership = $dbForProject->createDocument('memberships', $membership);
|
||||
@@ -639,8 +638,6 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
$message = $message->setParam('{{token}}', $url);
|
||||
$message = $message->render();
|
||||
|
||||
var_dump($request->getIP());
|
||||
var_dump($project->getId());
|
||||
$queueForMessaging
|
||||
->setRecipient($phone)
|
||||
->setMessage($message)
|
||||
@@ -847,7 +844,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||
/**
|
||||
* Replace membership on profile
|
||||
*/
|
||||
$dbForProject->deleteCachedDocument('users', $profile->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $profile->getId());
|
||||
|
||||
$queueForEvents
|
||||
->setParam('teamId', $team->getId())
|
||||
@@ -962,15 +959,15 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
]));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
Authorization::setRole(Role::user($userId)->toString());
|
||||
|
||||
$membership = $dbForProject->updateDocument('memberships', $membership->getId(), $membership);
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1)));
|
||||
Authorization::skip(fn() => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
|
||||
|
||||
$queueForEvents
|
||||
->setParam('teamId', $team->getId())
|
||||
@@ -1047,11 +1044,10 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove membership from DB');
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
if ($membership->getAttribute('confirm')) { // Count only confirmed members
|
||||
$team->setAttribute('total', \max($team->getAttribute('total', 0) - 1, 0));
|
||||
Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team));
|
||||
Authorization::skip(fn() => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0));
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
|
||||
@@ -9,6 +9,7 @@ use Appwrite\Event\Event;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Identities;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Users;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
@@ -141,7 +142,6 @@ App::post('/v1/users')
|
||||
->inject('hooks')
|
||||
->action(function (string $userId, ?string $email, ?string $phone, ?string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $queueForEvents, Hooks $hooks) {
|
||||
$user = createUser('plaintext', '{}', $userId, $email, $password, $phone, $name, $project, $dbForProject, $queueForEvents, $hooks);
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($user, Response::MODEL_USER);
|
||||
@@ -1108,7 +1108,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
|
||||
}
|
||||
|
||||
$dbForProject->deleteDocument('sessions', $session->getId());
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$queueForEvents
|
||||
->setParam('userId', $user->getId())
|
||||
@@ -1151,7 +1151,7 @@ App::delete('/v1/users/:userId/sessions')
|
||||
//TODO: fix this
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$queueForEvents
|
||||
->setParam('userId', $user->getId())
|
||||
|
||||
+236
-54
@@ -9,9 +9,8 @@ use Utopia\Logger\Logger;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Logger\Log\User;
|
||||
use Swoole\Http\Request as SwooleRequest;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Pools\Group;
|
||||
use Appwrite\Utopia\Request;
|
||||
use MaxMind\Db\Reader;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\View;
|
||||
use Appwrite\Extend\Exception as AppwriteException;
|
||||
@@ -19,6 +18,8 @@ use Utopia\Config\Config;
|
||||
use Utopia\Domains\Domain;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Usage;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\Utopia\Response\Filters\V11 as ResponseV11;
|
||||
use Appwrite\Utopia\Response\Filters\V12 as ResponseV12;
|
||||
@@ -31,6 +32,7 @@ use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\Hostname;
|
||||
use Appwrite\Utopia\Request\Filters\V12 as RequestV12;
|
||||
@@ -38,6 +40,7 @@ use Appwrite\Utopia\Request\Filters\V13 as RequestV13;
|
||||
use Appwrite\Utopia\Request\Filters\V14 as RequestV14;
|
||||
use Appwrite\Utopia\Request\Filters\V15 as RequestV15;
|
||||
use Appwrite\Utopia\Request\Filters\V16 as RequestV16;
|
||||
use Executor\Executor;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
@@ -45,7 +48,7 @@ Config::setParam('domainVerification', false);
|
||||
Config::setParam('cookieDomain', 'localhost');
|
||||
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
|
||||
|
||||
function router(App $utopia, Database $dbForConsole, SwooleRequest $swooleRequest, Request $request, Response $response)
|
||||
function router(App $utopia, Database $dbForConsole, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, Usage $queueForUsage, Reader $geodb)
|
||||
{
|
||||
$utopia->getRoute()?->label('error', __DIR__ . '/../views/general/error.phtml');
|
||||
|
||||
@@ -117,59 +120,218 @@ function router(App $utopia, Database $dbForConsole, SwooleRequest $swooleReques
|
||||
$path .= '?' . $query;
|
||||
}
|
||||
|
||||
|
||||
$body = $swooleRequest->getContent() ?? '';
|
||||
$method = $swooleRequest->server['request_method'];
|
||||
|
||||
$requestHeaders = $request->getHeaders();
|
||||
|
||||
$body = \json_encode([
|
||||
'async' => false,
|
||||
'body' => $swooleRequest->getContent() ?? '',
|
||||
'method' => $swooleRequest->server['request_method'],
|
||||
'path' => $path,
|
||||
'headers' => $requestHeaders
|
||||
$project = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $projectId));
|
||||
|
||||
$dbForProject = $getProjectDB($project);
|
||||
|
||||
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
|
||||
|
||||
if ($function->isEmpty() || !$function->getAttribute('enabled')) {
|
||||
throw new AppwriteException(AppwriteException::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$version = $function->getAttribute('version', 'v2');
|
||||
$runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []);
|
||||
|
||||
$runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null;
|
||||
|
||||
if (\is_null($runtime)) {
|
||||
throw new AppwriteException(AppwriteException::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
|
||||
}
|
||||
|
||||
$deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deployment', '')));
|
||||
|
||||
if ($deployment->getAttribute('resourceId') !== $function->getId()) {
|
||||
throw new AppwriteException(AppwriteException::DEPLOYMENT_NOT_FOUND, 'Deployment not found. Create a deployment before trying to execute a function');
|
||||
}
|
||||
|
||||
if ($deployment->isEmpty()) {
|
||||
throw new AppwriteException(AppwriteException::DEPLOYMENT_NOT_FOUND, 'Deployment not found. Create a deployment before trying to execute a function');
|
||||
}
|
||||
|
||||
/** Check if build has completed */
|
||||
$build = Authorization::skip(fn () => $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')));
|
||||
if ($build->isEmpty()) {
|
||||
throw new AppwriteException(AppwriteException::BUILD_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($build->getAttribute('status') !== 'ready') {
|
||||
throw new AppwriteException(AppwriteException::BUILD_NOT_READY);
|
||||
}
|
||||
|
||||
$permissions = $function->getAttribute('execute');
|
||||
|
||||
if (!(\in_array('any', $permissions)) && (\in_array('guests', $permissions))) {
|
||||
throw new AppwriteException(AppwriteException::USER_UNAUTHORIZED, 'To execute function using domain, execute permissions must include "any" or "guests"');
|
||||
}
|
||||
|
||||
$headers = \array_merge([], $requestHeaders);
|
||||
$headers['x-appwrite-trigger'] = 'http';
|
||||
$headers['x-appwrite-user-id'] = '';
|
||||
$headers['x-appwrite-user-jwt'] = '';
|
||||
$headers['x-appwrite-country-code'] = '';
|
||||
$headers['x-appwrite-continent-code'] = '';
|
||||
$headers['x-appwrite-continent-eu'] = 'false';
|
||||
|
||||
$ip = $headers['x-real-ip'] ?? '';
|
||||
if (!empty($ip)) {
|
||||
$record = $geodb->get($ip);
|
||||
|
||||
if ($record) {
|
||||
$eu = Config::getParam('locale-eu');
|
||||
|
||||
$headers['x-appwrite-country-code'] = $record['country']['iso_code'] ?? '';
|
||||
$headers['x-appwrite-continent-code'] = $record['continent']['code'] ?? '';
|
||||
$headers['x-appwrite-continent-eu'] = (\in_array($record['country']['iso_code'], $eu)) ? 'true' : 'false';
|
||||
}
|
||||
}
|
||||
|
||||
$headersFiltered = [];
|
||||
foreach ($headers as $key => $value) {
|
||||
if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_REQUEST)) {
|
||||
$headersFiltered[] = ['name' => $key, 'value' => $value];
|
||||
}
|
||||
}
|
||||
|
||||
$executionId = ID::unique();
|
||||
|
||||
$execution = new Document([
|
||||
'$id' => $executionId,
|
||||
'$permissions' => [],
|
||||
'functionInternalId' => $function->getInternalId(),
|
||||
'functionId' => $function->getId(),
|
||||
'deploymentInternalId' => $deployment->getInternalId(),
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'trigger' => 'http', // http / schedule / event
|
||||
'status' => 'processing', // waiting / processing / completed / failed
|
||||
'responseStatusCode' => 0,
|
||||
'responseHeaders' => [],
|
||||
'requestPath' => $path,
|
||||
'requestMethod' => $method,
|
||||
'requestHeaders' => $headersFiltered,
|
||||
'errors' => '',
|
||||
'logs' => '',
|
||||
'duration' => 0.0,
|
||||
'search' => implode(' ', [$functionId, $executionId]),
|
||||
]);
|
||||
|
||||
$headers = [
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . \strlen($body),
|
||||
'X-Appwrite-Project: ' . $projectId
|
||||
];
|
||||
$queueForEvents
|
||||
->setParam('functionId', $function->getId())
|
||||
->setParam('executionId', $execution->getId())
|
||||
->setContext('function', $function);
|
||||
|
||||
$ch = \curl_init();
|
||||
\curl_setopt($ch, CURLOPT_URL, "http://localhost/v1/functions/{$functionId}/executions");
|
||||
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
|
||||
\curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
|
||||
\curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
// \curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
\curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
||||
\curl_setopt($ch, CURLOPT_TIMEOUT, 30);
|
||||
$durationStart = \microtime(true);
|
||||
|
||||
$executionResponse = \curl_exec($ch);
|
||||
$statusCode = \curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$error = \curl_error($ch);
|
||||
$errNo = \curl_errno($ch);
|
||||
$vars = [];
|
||||
|
||||
\curl_close($ch);
|
||||
|
||||
if ($errNo !== 0) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_ARGUMENT_INVALID, "Internal error: " . $error);
|
||||
// V2 vars
|
||||
if ($version === 'v2') {
|
||||
$vars = \array_merge($vars, [
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $headers['x-appwrite-trigger'] ?? '',
|
||||
'APPWRITE_FUNCTION_DATA' => $body ?? '',
|
||||
'APPWRITE_FUNCTION_USER_ID' => $headers['x-appwrite-user-id'] ?? '',
|
||||
'APPWRITE_FUNCTION_JWT' => $headers['x-appwrite-user-jwt'] ?? ''
|
||||
]);
|
||||
}
|
||||
|
||||
if ($statusCode >= 400) {
|
||||
$error = \json_decode($executionResponse, true)['message'];
|
||||
throw new AppwriteException(AppwriteException::GENERAL_ARGUMENT_INVALID, "Execution error: " . $error);
|
||||
// Shared vars
|
||||
foreach ($function->getAttribute('varsProject', []) as $var) {
|
||||
$vars[$var->getAttribute('key')] = $var->getAttribute('value', '');
|
||||
}
|
||||
|
||||
$execution = \json_decode($executionResponse, true);
|
||||
// Function vars
|
||||
foreach ($function->getAttribute('vars', []) as $var) {
|
||||
$vars[$var->getAttribute('key')] = $var->getAttribute('value', '');
|
||||
}
|
||||
|
||||
$contentType = 'text/plain';
|
||||
foreach ($execution['responseHeaders'] as $header) {
|
||||
if (\strtolower($header['name']) === 'content-type') {
|
||||
$contentType = $header['value'];
|
||||
// Appwrite vars
|
||||
$vars = \array_merge($vars, [
|
||||
'APPWRITE_FUNCTION_ID' => $functionId,
|
||||
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name'),
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(),
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '',
|
||||
]);
|
||||
|
||||
/** Execute function */
|
||||
$executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST'));
|
||||
try {
|
||||
$version = $function->getAttribute('version', 'v2');
|
||||
$command = $runtime['startCommand'];
|
||||
$command = $version === 'v2' ? '' : 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $command . '"';
|
||||
$executionResponse = $executor->createExecution(
|
||||
projectId: $project->getId(),
|
||||
deploymentId: $deployment->getId(),
|
||||
body: \strlen($body) > 0 ? $body : null,
|
||||
variables: $vars,
|
||||
timeout: $function->getAttribute('timeout', 0),
|
||||
image: $runtime['image'],
|
||||
source: $build->getAttribute('path', ''),
|
||||
entrypoint: $deployment->getAttribute('entrypoint', ''),
|
||||
version: $version,
|
||||
path: $path,
|
||||
method: $method,
|
||||
headers: $headers,
|
||||
runtimeEntrypoint: $command,
|
||||
requestTimeout: 30
|
||||
);
|
||||
|
||||
$headersFiltered = [];
|
||||
foreach ($executionResponse['headers'] as $key => $value) {
|
||||
if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_RESPONSE)) {
|
||||
$headersFiltered[] = ['name' => $key, 'value' => $value];
|
||||
}
|
||||
}
|
||||
|
||||
$response->setHeader($header['name'], $header['value']);
|
||||
/** Update execution status */
|
||||
$status = $executionResponse['statusCode'] >= 400 ? 'failed' : 'completed';
|
||||
$execution->setAttribute('status', $status);
|
||||
$execution->setAttribute('responseStatusCode', $executionResponse['statusCode']);
|
||||
$execution->setAttribute('responseHeaders', $headersFiltered);
|
||||
$execution->setAttribute('logs', $executionResponse['logs']);
|
||||
$execution->setAttribute('errors', $executionResponse['errors']);
|
||||
$execution->setAttribute('duration', $executionResponse['duration']);
|
||||
} catch (\Throwable $th) {
|
||||
$durationEnd = \microtime(true);
|
||||
|
||||
$execution
|
||||
->setAttribute('duration', $durationEnd - $durationStart)
|
||||
->setAttribute('status', 'failed')
|
||||
->setAttribute('responseStatusCode', 500)
|
||||
->setAttribute('errors', $th->getMessage() . '\nError Code: ' . $th->getCode());
|
||||
Console::error($th->getMessage());
|
||||
} finally {
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_EXECUTIONS, 1)
|
||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1)
|
||||
->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000)) // per project
|
||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000)) // per function
|
||||
;
|
||||
}
|
||||
|
||||
if ($function->getAttribute('logging')) {
|
||||
/** @var Document $execution */
|
||||
$execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution));
|
||||
}
|
||||
|
||||
$execution->setAttribute('logs', '');
|
||||
$execution->setAttribute('errors', '');
|
||||
|
||||
$headers = [];
|
||||
foreach (($executionResponse['headers'] ?? []) as $key => $value) {
|
||||
$headers[] = ['name' => $key, 'value' => $value];
|
||||
}
|
||||
|
||||
$execution->setAttribute('responseBody', $executionResponse['body'] ?? '');
|
||||
$execution->setAttribute('responseHeaders', $headers);
|
||||
|
||||
$body = $execution['responseBody'] ?? '';
|
||||
|
||||
$encodingKey = \array_search('x-open-runtimes-encoding', \array_column($execution['responseHeaders'], 'name'));
|
||||
@@ -179,6 +341,15 @@ function router(App $utopia, Database $dbForConsole, SwooleRequest $swooleReques
|
||||
}
|
||||
}
|
||||
|
||||
$contentType = 'text/plain';
|
||||
foreach ($execution['responseHeaders'] as $header) {
|
||||
if (\strtolower($header['name']) === 'content-type') {
|
||||
$contentType = $header['value'];
|
||||
}
|
||||
|
||||
$response->setHeader($header['name'], $header['value']);
|
||||
}
|
||||
|
||||
$response
|
||||
->setContentType($contentType)
|
||||
->setStatusCode($execution['responseStatusCode'] ?? 200)
|
||||
@@ -205,13 +376,17 @@ App::init()
|
||||
->inject('console')
|
||||
->inject('project')
|
||||
->inject('dbForConsole')
|
||||
->inject('getProjectDB')
|
||||
->inject('user')
|
||||
->inject('locale')
|
||||
->inject('localeCodes')
|
||||
->inject('clients')
|
||||
->inject('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) {
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForUsage')
|
||||
->inject('geodb')
|
||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForConsole, callable $getProjectDB, Document $user, Locale $locale, array $localeCodes, array $clients, array $servers, Certificate $queueForCertificates, Event $queueForEvents, Usage $queueForUsage, Reader $geodb) {
|
||||
/*
|
||||
* Appwrite Router
|
||||
*/
|
||||
@@ -220,7 +395,7 @@ App::init()
|
||||
$mainDomain = App::getEnv('_APP_DOMAIN', '');
|
||||
// Only run Router when external domain
|
||||
if ($host !== $mainDomain) {
|
||||
if (router($utopia, $dbForConsole, $swooleRequest, $request, $response)) {
|
||||
if (router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -232,7 +407,9 @@ App::init()
|
||||
Request::setRoute($route);
|
||||
|
||||
if ($route === null) {
|
||||
return $response->setStatusCode(404)->send('Not Found');
|
||||
return $response
|
||||
->setStatusCode(404)
|
||||
->send('Not Found');
|
||||
}
|
||||
|
||||
$requestFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', ''));
|
||||
@@ -425,7 +602,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-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-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-Appwrite-Share-Tables, 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');
|
||||
@@ -511,7 +688,7 @@ App::init()
|
||||
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_KEY_ACCCESS)) > $accessedAt) {
|
||||
$key->setAttribute('accessedAt', DateTime::now());
|
||||
$dbForConsole->updateDocument('keys', $key->getId(), $key);
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||
}
|
||||
|
||||
$sdkValidator = new WhiteList($servers, true);
|
||||
@@ -525,7 +702,7 @@ App::init()
|
||||
/** Update access time as well */
|
||||
$key->setAttribute('accessedAt', Datetime::now());
|
||||
$dbForConsole->updateDocument('keys', $key->getId(), $key);
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -571,7 +748,11 @@ App::options()
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForConsole) {
|
||||
->inject('getProjectDB')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForUsage')
|
||||
->inject('geodb')
|
||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForConsole, callable $getProjectDB, Event $queueForEvents, Usage $queueForUsage, Reader $geodb) {
|
||||
/*
|
||||
* Appwrite Router
|
||||
*/
|
||||
@@ -579,7 +760,7 @@ App::options()
|
||||
$mainDomain = App::getEnv('_APP_DOMAIN', '');
|
||||
// Only run Router when external domain
|
||||
if ($host !== $mainDomain) {
|
||||
if (router($utopia, $dbForConsole, $swooleRequest, $request, $response)) {
|
||||
if (router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -589,7 +770,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-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-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-Appwrite-Share-Tables, 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')
|
||||
@@ -607,10 +788,11 @@ App::error()
|
||||
->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log) {
|
||||
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
$route = $utopia->getRoute();
|
||||
$publish = true;
|
||||
|
||||
if ($error instanceof AppwriteException) {
|
||||
$publish = $error->isPublishable();
|
||||
} else {
|
||||
$publish = $error->getCode() === 0 || $error->getCode() >= 500;
|
||||
}
|
||||
|
||||
if ($logger && ($publish || $error->getCode() === 0)) {
|
||||
@@ -756,10 +938,10 @@ App::error()
|
||||
->setParam('development', App::isDevelopment())
|
||||
->setParam('projectName', $project->getAttribute('name'))
|
||||
->setParam('projectURL', $project->getAttribute('url'))
|
||||
->setParam('message', $error->getMessage())
|
||||
->setParam('type', $type)
|
||||
->setParam('code', $code)
|
||||
->setParam('trace', $trace);
|
||||
->setParam('message', $output['message'] ?? '')
|
||||
->setParam('type', $output['type'] ?? '')
|
||||
->setParam('code', $output['code'] ?? '')
|
||||
->setParam('trace', $output['trace'] ?? []);
|
||||
|
||||
$response->html($layout->render());
|
||||
}
|
||||
|
||||
@@ -407,7 +407,7 @@ App::shutdown()
|
||||
$session = array_shift($sessions);
|
||||
$dbForProject->deleteDocument('sessions', $session->getId());
|
||||
}
|
||||
$dbForProject->deleteCachedDocument('users', $userId);
|
||||
$dbForProject->purgeCachedDocument('users', $userId);
|
||||
});
|
||||
|
||||
App::shutdown()
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
$dbForConsole->createCollection($key, $attributes, $indexes);
|
||||
}
|
||||
|
||||
if ($dbForConsole->getDocument('buckets', 'default')->isEmpty() && !$dbForConsole->exists($dbForConsole->getDefaultDatabase(), 'bucket_1')) {
|
||||
if ($dbForConsole->getDocument('buckets', 'default')->isEmpty() && !$dbForConsole->exists($dbForConsole->getDatabase(), 'bucket_1')) {
|
||||
Console::success('[Setup] - Creating default bucket...');
|
||||
$dbForConsole->createDocument('buckets', new Document([
|
||||
'$id' => ID::custom('default'),
|
||||
|
||||
+138
-133
@@ -12,11 +12,11 @@ if (\file_exists(__DIR__ . '/../vendor/autoload.php')) {
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
}
|
||||
|
||||
ini_set('memory_limit', '512M');
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
ini_set('default_socket_timeout', -1);
|
||||
error_reporting(E_ALL);
|
||||
\ini_set('memory_limit', '512M');
|
||||
\ini_set('display_errors', 1);
|
||||
\ini_set('display_startup_errors', 1);
|
||||
\ini_set('default_socket_timeout', -1);
|
||||
\error_reporting(E_ALL);
|
||||
|
||||
use Appwrite\Event\Migration;
|
||||
use Appwrite\Event\Usage;
|
||||
@@ -34,6 +34,7 @@ use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\URL\URL as AppwriteURL;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Utopia\Cache\Cache;
|
||||
@@ -112,7 +113,7 @@ 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 = 329;
|
||||
const APP_CACHE_BUSTER = 331;
|
||||
const APP_VERSION_STABLE = '1.4.13';
|
||||
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
|
||||
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
|
||||
@@ -142,7 +143,8 @@ const APP_SOCIAL_DEV = 'https://dev.to/appwrite';
|
||||
const APP_SOCIAL_STACKSHARE = 'https://stackshare.io/appwrite';
|
||||
const APP_SOCIAL_YOUTUBE = 'https://www.youtube.com/c/appwrite?sub_confirmation=1';
|
||||
const APP_HOSTNAME_INTERNAL = 'appwrite';
|
||||
// Database Reconnect
|
||||
// Database
|
||||
const DATABASE_SHARED_TABLES = 'database_db_self_hosted_shared_tables';
|
||||
const DATABASE_RECONNECT_SLEEP = 2;
|
||||
const DATABASE_RECONNECT_MAX_ATTEMPTS = 10;
|
||||
// Database Worker Types
|
||||
@@ -195,6 +197,7 @@ const FUNCTION_ALLOWLIST_HEADERS_RESPONSE = ['content-type', 'content-length'];
|
||||
// Usage metrics
|
||||
const METRIC_TEAMS = 'teams';
|
||||
const METRIC_USERS = 'users';
|
||||
const METRIC_MESSAGES = 'messages';
|
||||
const METRIC_SESSIONS = 'sessions';
|
||||
const METRIC_DATABASES = 'databases';
|
||||
const METRIC_COLLECTIONS = 'collections';
|
||||
@@ -653,14 +656,13 @@ $register->set('pools', function () {
|
||||
|
||||
foreach ($connections as $key => $connection) {
|
||||
$type = $connection['type'] ?? '';
|
||||
$dsns = $connection['dsns'] ?? '';
|
||||
$multipe = $connection['multiple'] ?? false;
|
||||
$multiple = $connection['multiple'] ?? false;
|
||||
$schemes = $connection['schemes'] ?? [];
|
||||
$config = [];
|
||||
$dsns = explode(',', $connection['dsns'] ?? '');
|
||||
foreach ($dsns as &$dsn) {
|
||||
$dsn = explode('=', $dsn);
|
||||
$name = ($multipe) ? $key . '_' . $dsn[0] : $key;
|
||||
$name = ($multiple) ? $key . '_' . $dsn[0] : $key;
|
||||
$dsn = $dsn[1] ?? '';
|
||||
$config[] = $name;
|
||||
if (empty($dsn)) {
|
||||
@@ -683,47 +685,38 @@ $register->set('pools', function () {
|
||||
/**
|
||||
* Get Resource
|
||||
*
|
||||
* Creation could be reused accross connection types like database, cache, queue, etc.
|
||||
* Creation could be reused across connection types like database, cache, queue, etc.
|
||||
*
|
||||
* Resource assignment to an adapter will happen below.
|
||||
*/
|
||||
switch ($dsnScheme) {
|
||||
case 'mysql':
|
||||
case 'mariadb':
|
||||
$resource = function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) {
|
||||
return new PDOProxy(function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) {
|
||||
return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, array(
|
||||
PDO::ATTR_TIMEOUT => 3, // Seconds
|
||||
PDO::ATTR_PERSISTENT => true,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed
|
||||
PDO::ATTR_EMULATE_PREPARES => true,
|
||||
PDO::ATTR_STRINGIFY_FETCHES => true
|
||||
));
|
||||
});
|
||||
};
|
||||
break;
|
||||
case 'redis':
|
||||
$resource = function () use ($dsnHost, $dsnPort, $dsnPass) {
|
||||
$redis = new Redis();
|
||||
@$redis->pconnect($dsnHost, (int)$dsnPort);
|
||||
if ($dsnPass) {
|
||||
$redis->auth($dsnPass);
|
||||
}
|
||||
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
|
||||
$resource = match ($dsnScheme) {
|
||||
'mysql',
|
||||
'mariadb' => function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) {
|
||||
return new PDOProxy(function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) {
|
||||
return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, array(
|
||||
PDO::ATTR_TIMEOUT => 3, // Seconds
|
||||
PDO::ATTR_PERSISTENT => true,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => true,
|
||||
PDO::ATTR_STRINGIFY_FETCHES => true
|
||||
));
|
||||
});
|
||||
},
|
||||
'redis' => function () use ($dsnHost, $dsnPort, $dsnPass) {
|
||||
$redis = new Redis();
|
||||
@$redis->pconnect($dsnHost, (int)$dsnPort);
|
||||
if ($dsnPass) {
|
||||
$redis->auth($dsnPass);
|
||||
}
|
||||
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
|
||||
|
||||
return $redis;
|
||||
};
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid scheme");
|
||||
break;
|
||||
}
|
||||
return $redis;
|
||||
},
|
||||
default => throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid scheme"),
|
||||
};
|
||||
|
||||
$pool = new Pool($name, $poolSize, function () use ($type, $resource, $dsn) {
|
||||
// Get Adapter
|
||||
$adapter = null;
|
||||
switch ($type) {
|
||||
case 'database':
|
||||
$adapter = match ($dsn->getScheme()) {
|
||||
@@ -732,7 +725,7 @@ $register->set('pools', function () {
|
||||
default => null
|
||||
};
|
||||
|
||||
$adapter->setDefaultDatabase($dsn->getPath());
|
||||
$adapter->setDatabase($dsn->getPath());
|
||||
break;
|
||||
case 'pubsub':
|
||||
$adapter = $resource();
|
||||
@@ -752,7 +745,6 @@ $register->set('pools', function () {
|
||||
|
||||
default:
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Server error: Missing adapter implementation.");
|
||||
break;
|
||||
}
|
||||
|
||||
return $adapter;
|
||||
@@ -949,24 +941,25 @@ App::setResource('clients', function ($request, $console, $project) {
|
||||
fn ($node) => $node['hostname'],
|
||||
\array_filter(
|
||||
$console->getAttribute('platforms', []),
|
||||
fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB) && isset($node['hostname']) && !empty($node['hostname']))
|
||||
fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB) && !empty($node['hostname']))
|
||||
)
|
||||
);
|
||||
|
||||
$clients = \array_unique(
|
||||
\array_merge(
|
||||
$clientsConsole,
|
||||
\array_map(
|
||||
fn ($node) => $node['hostname'],
|
||||
\array_filter(
|
||||
$project->getAttribute('platforms', []),
|
||||
fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB || $node['type'] === Origin::CLIENT_TYPE_FLUTTER_WEB) && isset($node['hostname']) && !empty($node['hostname']))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$clients = $clientsConsole;
|
||||
$platforms = $project->getAttribute('platforms', []);
|
||||
|
||||
return $clients;
|
||||
foreach ($platforms as $node) {
|
||||
if (
|
||||
isset($node['type']) &&
|
||||
($node['type'] === Origin::CLIENT_TYPE_WEB ||
|
||||
$node['type'] === Origin::CLIENT_TYPE_FLUTTER_WEB) &&
|
||||
!empty($node['hostname'])
|
||||
) {
|
||||
$clients[] = $node['hostname'];
|
||||
}
|
||||
}
|
||||
|
||||
return \array_unique($clients);
|
||||
}, ['request', 'console', 'project']);
|
||||
|
||||
App::setResource('user', function ($mode, $project, $console, $request, $response, $dbForProject, $dbForConsole) {
|
||||
@@ -1138,11 +1131,22 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForConsole,
|
||||
$database = new Database($dbAdapter, $cache);
|
||||
|
||||
$database
|
||||
->setNamespace('_' . $project->getInternalId())
|
||||
->setMetadata('host', \gethostname())
|
||||
->setMetadata('project', $project->getId())
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS);
|
||||
|
||||
if ($project->getAttribute('database') === DATABASE_SHARED_TABLES) {
|
||||
$database
|
||||
->setShareTables(true)
|
||||
->setTenant($project->getInternalId())
|
||||
->setNamespace('');
|
||||
} else {
|
||||
$database
|
||||
->setShareTables(false)
|
||||
->setTenant(null)
|
||||
->setNamespace('_' . $project->getInternalId());
|
||||
}
|
||||
|
||||
return $database;
|
||||
}, ['pools', 'dbForConsole', 'cache', 'project']);
|
||||
|
||||
@@ -1150,8 +1154,7 @@ App::setResource('dbForConsole', function (Group $pools, Cache $cache) {
|
||||
$dbAdapter = $pools
|
||||
->get('console')
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
->getResource();
|
||||
|
||||
$database = new Database($dbAdapter, $cache);
|
||||
|
||||
@@ -1167,22 +1170,35 @@ App::setResource('dbForConsole', function (Group $pools, Cache $cache) {
|
||||
App::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;
|
||||
}
|
||||
|
||||
$databaseName = $project->getAttribute('database');
|
||||
|
||||
if (isset($databases[$databaseName])) {
|
||||
$database = $databases[$databaseName];
|
||||
|
||||
$configure = (function (Database $database) use ($project) {
|
||||
$database
|
||||
->setNamespace('_' . $project->getInternalId())
|
||||
->setMetadata('host', \gethostname())
|
||||
->setMetadata('project', $project->getId())
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS);
|
||||
|
||||
if ($project->getAttribute('database') === DATABASE_SHARED_TABLES) {
|
||||
$database
|
||||
->setShareTables(true)
|
||||
->setTenant($project->getInternalId())
|
||||
->setNamespace('');
|
||||
} else {
|
||||
$database
|
||||
->setShareTables(false)
|
||||
->setTenant(null)
|
||||
->setNamespace('_' . $project->getInternalId());
|
||||
}
|
||||
});
|
||||
|
||||
if (isset($databases[$databaseName])) {
|
||||
$database = $databases[$databaseName];
|
||||
$configure($database);
|
||||
return $database;
|
||||
}
|
||||
|
||||
@@ -1192,19 +1208,10 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
|
||||
->getResource();
|
||||
|
||||
$database = new Database($dbAdapter, $cache);
|
||||
|
||||
$databases[$databaseName] = $database;
|
||||
|
||||
$database
|
||||
->setNamespace('_' . $project->getInternalId())
|
||||
->setMetadata('host', \gethostname())
|
||||
->setMetadata('project', $project->getId())
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS);
|
||||
|
||||
$configure($database);
|
||||
return $database;
|
||||
};
|
||||
|
||||
return $getProjectDB;
|
||||
}, ['pools', 'dbForConsole', 'cache']);
|
||||
|
||||
App::setResource('cache', function (Group $pools) {
|
||||
@@ -1261,62 +1268,60 @@ function getDevice($root): Device
|
||||
Console::warning($e->getMessage() . 'Invalid DSN. Defaulting to Local device.');
|
||||
}
|
||||
|
||||
switch ($device) {
|
||||
case Storage::DEVICE_S3:
|
||||
return new S3($root, $accessKey, $accessSecret, $bucket, $region, $acl);
|
||||
case STORAGE::DEVICE_DO_SPACES:
|
||||
return new DOSpaces($root, $accessKey, $accessSecret, $bucket, $region, $acl);
|
||||
case Storage::DEVICE_BACKBLAZE:
|
||||
return new Backblaze($root, $accessKey, $accessSecret, $bucket, $region, $acl);
|
||||
case Storage::DEVICE_LINODE:
|
||||
return new Linode($root, $accessKey, $accessSecret, $bucket, $region, $acl);
|
||||
case Storage::DEVICE_WASABI:
|
||||
return new Wasabi($root, $accessKey, $accessSecret, $bucket, $region, $acl);
|
||||
case Storage::DEVICE_LOCAL:
|
||||
default:
|
||||
return new Local($root);
|
||||
}
|
||||
return match ($device) {
|
||||
Storage::DEVICE_S3 => new S3($root, $accessKey, $accessSecret, $bucket, $region, $acl),
|
||||
Storage::DEVICE_DO_SPACES => new DOSpaces($root, $accessKey, $accessSecret, $bucket, $region, $acl),
|
||||
Storage::DEVICE_BACKBLAZE => new Backblaze($root, $accessKey, $accessSecret, $bucket, $region, $acl),
|
||||
Storage::DEVICE_LINODE => new Linode($root, $accessKey, $accessSecret, $bucket, $region, $acl),
|
||||
Storage::DEVICE_WASABI => new Wasabi($root, $accessKey, $accessSecret, $bucket, $region, $acl),
|
||||
default => new Local($root),
|
||||
};
|
||||
} else {
|
||||
switch (strtolower(App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL) ?? '')) {
|
||||
case Storage::DEVICE_LOCAL:
|
||||
default:
|
||||
return new Local($root);
|
||||
case Storage::DEVICE_S3:
|
||||
$s3AccessKey = App::getEnv('_APP_STORAGE_S3_ACCESS_KEY', '');
|
||||
$s3SecretKey = App::getEnv('_APP_STORAGE_S3_SECRET', '');
|
||||
$s3Region = App::getEnv('_APP_STORAGE_S3_REGION', '');
|
||||
$s3Bucket = App::getEnv('_APP_STORAGE_S3_BUCKET', '');
|
||||
$s3Acl = 'private';
|
||||
return new S3($root, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl);
|
||||
case Storage::DEVICE_DO_SPACES:
|
||||
$doSpacesAccessKey = App::getEnv('_APP_STORAGE_DO_SPACES_ACCESS_KEY', '');
|
||||
$doSpacesSecretKey = App::getEnv('_APP_STORAGE_DO_SPACES_SECRET', '');
|
||||
$doSpacesRegion = App::getEnv('_APP_STORAGE_DO_SPACES_REGION', '');
|
||||
$doSpacesBucket = App::getEnv('_APP_STORAGE_DO_SPACES_BUCKET', '');
|
||||
$doSpacesAcl = 'private';
|
||||
return new DOSpaces($root, $doSpacesAccessKey, $doSpacesSecretKey, $doSpacesBucket, $doSpacesRegion, $doSpacesAcl);
|
||||
case Storage::DEVICE_BACKBLAZE:
|
||||
$backblazeAccessKey = App::getEnv('_APP_STORAGE_BACKBLAZE_ACCESS_KEY', '');
|
||||
$backblazeSecretKey = App::getEnv('_APP_STORAGE_BACKBLAZE_SECRET', '');
|
||||
$backblazeRegion = App::getEnv('_APP_STORAGE_BACKBLAZE_REGION', '');
|
||||
$backblazeBucket = App::getEnv('_APP_STORAGE_BACKBLAZE_BUCKET', '');
|
||||
$backblazeAcl = 'private';
|
||||
return new Backblaze($root, $backblazeAccessKey, $backblazeSecretKey, $backblazeBucket, $backblazeRegion, $backblazeAcl);
|
||||
case Storage::DEVICE_LINODE:
|
||||
$linodeAccessKey = App::getEnv('_APP_STORAGE_LINODE_ACCESS_KEY', '');
|
||||
$linodeSecretKey = App::getEnv('_APP_STORAGE_LINODE_SECRET', '');
|
||||
$linodeRegion = App::getEnv('_APP_STORAGE_LINODE_REGION', '');
|
||||
$linodeBucket = App::getEnv('_APP_STORAGE_LINODE_BUCKET', '');
|
||||
$linodeAcl = 'private';
|
||||
return new Linode($root, $linodeAccessKey, $linodeSecretKey, $linodeBucket, $linodeRegion, $linodeAcl);
|
||||
case Storage::DEVICE_WASABI:
|
||||
$wasabiAccessKey = App::getEnv('_APP_STORAGE_WASABI_ACCESS_KEY', '');
|
||||
$wasabiSecretKey = App::getEnv('_APP_STORAGE_WASABI_SECRET', '');
|
||||
$wasabiRegion = App::getEnv('_APP_STORAGE_WASABI_REGION', '');
|
||||
$wasabiBucket = App::getEnv('_APP_STORAGE_WASABI_BUCKET', '');
|
||||
$wasabiAcl = 'private';
|
||||
return new Wasabi($root, $wasabiAccessKey, $wasabiSecretKey, $wasabiBucket, $wasabiRegion, $wasabiAcl);
|
||||
}
|
||||
$device = strtolower(App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL) ?? '');
|
||||
|
||||
return match ($device) {
|
||||
Storage::DEVICE_S3 => new S3(
|
||||
$root,
|
||||
App::getEnv('_APP_STORAGE_S3_ACCESS_KEY', ''),
|
||||
App::getEnv('_APP_STORAGE_S3_SECRET', ''),
|
||||
App::getEnv('_APP_STORAGE_S3_BUCKET', ''),
|
||||
App::getEnv('_APP_STORAGE_S3_REGION', ''),
|
||||
'private'
|
||||
),
|
||||
Storage::DEVICE_DO_SPACES => new DOSpaces(
|
||||
$root,
|
||||
App::getEnv('_APP_STORAGE_DO_SPACES_ACCESS_KEY', ''),
|
||||
App::getEnv('_APP_STORAGE_DO_SPACES_SECRET', ''),
|
||||
App::getEnv('_APP_STORAGE_DO_SPACES_BUCKET', ''),
|
||||
App::getEnv('_APP_STORAGE_DO_SPACES_REGION', ''),
|
||||
'private'
|
||||
),
|
||||
Storage::DEVICE_BACKBLAZE => new Backblaze(
|
||||
$root,
|
||||
App::getEnv('_APP_STORAGE_BACKBLAZE_ACCESS_KEY', ''),
|
||||
App::getEnv('_APP_STORAGE_BACKBLAZE_SECRET', ''),
|
||||
App::getEnv('_APP_STORAGE_BACKBLAZE_BUCKET', ''),
|
||||
App::getEnv('_APP_STORAGE_BACKBLAZE_REGION', ''),
|
||||
'private'
|
||||
),
|
||||
Storage::DEVICE_LINODE => new Linode(
|
||||
$root,
|
||||
App::getEnv('_APP_STORAGE_LINODE_ACCESS_KEY', ''),
|
||||
App::getEnv('_APP_STORAGE_LINODE_SECRET', ''),
|
||||
App::getEnv('_APP_STORAGE_LINODE_BUCKET', ''),
|
||||
App::getEnv('_APP_STORAGE_LINODE_REGION', ''),
|
||||
'private'
|
||||
),
|
||||
Storage::DEVICE_WASABI => new Wasabi(
|
||||
$root,
|
||||
App::getEnv('_APP_STORAGE_WASABI_ACCESS_KEY', ''),
|
||||
App::getEnv('_APP_STORAGE_WASABI_SECRET', ''),
|
||||
App::getEnv('_APP_STORAGE_WASABI_BUCKET', ''),
|
||||
App::getEnv('_APP_STORAGE_WASABI_REGION', ''),
|
||||
'private'
|
||||
),
|
||||
default => new Local($root),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ services:
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_MAINTENANCE_INTERVAL
|
||||
- _APP_MAINTENANCE_DELAY
|
||||
- _APP_MAINTENANCE_RETENTION_EXECUTION
|
||||
- _APP_MAINTENANCE_RETENTION_CACHE
|
||||
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||
|
||||
+58
-18
@@ -14,6 +14,7 @@ use Appwrite\Event\Mail;
|
||||
use Appwrite\Event\Migration;
|
||||
use Appwrite\Event\Phone;
|
||||
use Appwrite\Event\Usage;
|
||||
use Appwrite\Event\UsageDump;
|
||||
use Appwrite\Platform\Appwrite;
|
||||
use Swoole\Runtime;
|
||||
use Utopia\App;
|
||||
@@ -62,15 +63,31 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register,
|
||||
}
|
||||
|
||||
$pools = $register->get('pools');
|
||||
$database = $pools
|
||||
|
||||
$adapter = $pools
|
||||
->get($project->getAttribute('database'))
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
->getResource();
|
||||
|
||||
$adapter = new Database($database, $cache);
|
||||
$adapter->setNamespace('_' . $project->getInternalId());
|
||||
return $adapter;
|
||||
$database = new Database($adapter, $cache);
|
||||
|
||||
$database
|
||||
->setMetadata('host', \gethostname())
|
||||
->setMetadata('project', $project->getId());
|
||||
|
||||
if ($project->getAttribute('database') === DATABASE_SHARED_TABLES) {
|
||||
$database
|
||||
->setShareTables(true)
|
||||
->setTenant($project->getInternalId())
|
||||
->setNamespace('');
|
||||
} else {
|
||||
$database
|
||||
->setShareTables(false)
|
||||
->setTenant(null)
|
||||
->setNamespace('_' . $project->getInternalId());
|
||||
}
|
||||
|
||||
return $database;
|
||||
}, ['cache', 'register', 'message', 'dbForConsole']);
|
||||
|
||||
Server::setResource('project', function (Message $message, Database $dbForConsole) {
|
||||
@@ -96,7 +113,19 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForConso
|
||||
|
||||
if (isset($databases[$databaseName])) {
|
||||
$database = $databases[$databaseName];
|
||||
$database->setNamespace('_' . $project->getInternalId());
|
||||
|
||||
if ($project->getAttribute('database') === DATABASE_SHARED_TABLES) {
|
||||
$database
|
||||
->setShareTables(true)
|
||||
->setTenant($project->getInternalId())
|
||||
->setNamespace('');
|
||||
} else {
|
||||
$database
|
||||
->setShareTables(false)
|
||||
->setTenant(null)
|
||||
->setNamespace('_' . $project->getInternalId());
|
||||
}
|
||||
|
||||
return $database;
|
||||
}
|
||||
|
||||
@@ -109,7 +138,17 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForConso
|
||||
|
||||
$databases[$databaseName] = $database;
|
||||
|
||||
$database->setNamespace('_' . $project->getInternalId());
|
||||
if ($project->getAttribute('database') === DATABASE_SHARED_TABLES) {
|
||||
$database
|
||||
->setShareTables(true)
|
||||
->setTenant($project->getInternalId())
|
||||
->setNamespace('');
|
||||
} else {
|
||||
$database
|
||||
->setShareTables(false)
|
||||
->setTenant(null)
|
||||
->setNamespace('_' . $project->getInternalId());
|
||||
}
|
||||
|
||||
return $database;
|
||||
};
|
||||
@@ -146,6 +185,9 @@ Server::setResource('log', fn() => new Log());
|
||||
Server::setResource('queueForUsage', function (Connection $queue) {
|
||||
return new Usage($queue);
|
||||
}, ['queue']);
|
||||
Server::setResource('queueForUsageDump', function (Connection $queue) {
|
||||
return new UsageDump($queue);
|
||||
}, ['queue']);
|
||||
Server::setResource('queue', function (Group $pools) {
|
||||
return $pools->get('queue')->pop()->getResource();
|
||||
}, ['pools']);
|
||||
@@ -231,7 +273,7 @@ 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
|
||||
* - _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');
|
||||
@@ -249,7 +291,6 @@ try {
|
||||
Console::error($e->getMessage() . ', File: ' . $e->getFile() . ', Line: ' . $e->getLine());
|
||||
}
|
||||
|
||||
|
||||
$worker = $platform->getWorker();
|
||||
|
||||
$worker
|
||||
@@ -264,7 +305,8 @@ $worker
|
||||
->inject('error')
|
||||
->inject('logger')
|
||||
->inject('log')
|
||||
->action(function (Throwable $error, ?Logger $logger, Log $log) {
|
||||
->inject('project')
|
||||
->action(function (Throwable $error, ?Logger $logger, Log $log, Document $project) {
|
||||
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
|
||||
if ($error instanceof PDOException) {
|
||||
@@ -280,6 +322,7 @@ $worker
|
||||
$log->setAction('appwrite-queue-' . App::getEnv('QUEUE'));
|
||||
$log->addTag('verboseType', get_class($error));
|
||||
$log->addTag('code', $error->getCode());
|
||||
$log->addTag('projectId', $project->getId() ?? 'n/a');
|
||||
$log->addExtra('file', $error->getFile());
|
||||
$log->addExtra('line', $error->getLine());
|
||||
$log->addExtra('trace', $error->getTraceAsString());
|
||||
@@ -299,12 +342,9 @@ $worker
|
||||
Console::error('[Error] Line: ' . $error->getLine());
|
||||
});
|
||||
|
||||
try {
|
||||
$workerStart = $worker->getWorkerStart();
|
||||
} catch (\Throwable $error) {
|
||||
$worker->workerStart();
|
||||
} finally {
|
||||
Console::info("Worker $workerName started");
|
||||
}
|
||||
$worker->workerStart()
|
||||
->action(function () use ($workerName) {
|
||||
Console::info("Worker $workerName started");
|
||||
});
|
||||
|
||||
$worker->start();
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
php /usr/src/code/app/worker.php usage-dump $@
|
||||
+7
-6
@@ -1,4 +1,5 @@
|
||||
{
|
||||
|
||||
"name": "appwrite/server-ce",
|
||||
"description": "End to end backend server for frontend and mobile apps.",
|
||||
"type": "project",
|
||||
@@ -43,20 +44,20 @@
|
||||
"ext-sockets": "*",
|
||||
"appwrite/php-runtimes": "0.13.*",
|
||||
"appwrite/php-clamav": "2.0.*",
|
||||
"utopia-php/abuse": "0.33.*",
|
||||
"utopia-php/abuse": "0.34.*",
|
||||
"utopia-php/analytics": "0.10.*",
|
||||
"utopia-php/audit": "0.35.*",
|
||||
"utopia-php/audit": "0.36.*",
|
||||
"utopia-php/cache": "0.9.*",
|
||||
"utopia-php/cli": "0.15.*",
|
||||
"utopia-php/config": "0.2.*",
|
||||
"utopia-php/database": "0.45.*",
|
||||
"utopia-php/domains": "0.3.*",
|
||||
"utopia-php/database": "0.45.7",
|
||||
"utopia-php/domains": "0.5.*",
|
||||
"utopia-php/dsn": "0.1.*",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/image": "0.5.*",
|
||||
"utopia-php/image": "0.6.*",
|
||||
"utopia-php/locale": "0.4.*",
|
||||
"utopia-php/logger": "0.3.*",
|
||||
"utopia-php/messaging": "0.2.*",
|
||||
"utopia-php/messaging": "0.3.*",
|
||||
"utopia-php/migration": "0.3.*",
|
||||
"utopia-php/orchestration": "0.9.*",
|
||||
"utopia-php/platform": "0.5.*",
|
||||
|
||||
Generated
+160
-166
@@ -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": "35dcde03d0eb9a0d27de653b9fa038d4",
|
||||
"content-hash": "9ab28ccc7cde35e834aac175d331c346",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -156,11 +156,11 @@
|
||||
},
|
||||
{
|
||||
"name": "appwrite/php-runtimes",
|
||||
"version": "0.13.2",
|
||||
"version": "0.13.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/runtimes.git",
|
||||
"reference": "214a37c2c66e0f2bc9c30fdfde66955d9fd084a1"
|
||||
"reference": "5d93fc578a9a543bcdc9b2c0562d80a51d56c73d"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
@@ -195,7 +195,7 @@
|
||||
"php",
|
||||
"runtimes"
|
||||
],
|
||||
"time": "2023-11-22T15:36:00+00:00"
|
||||
"time": "2024-03-01T14:47:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "chillerlan/php-qrcode",
|
||||
@@ -815,16 +815,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.28.0",
|
||||
"version": "v1.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
|
||||
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
|
||||
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
|
||||
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -832,9 +832,6 @@
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
@@ -878,7 +875,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -894,20 +891,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/abuse",
|
||||
"version": "0.33.0",
|
||||
"version": "0.34.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/abuse.git",
|
||||
"reference": "1ba8d5f2793885cbf779e3b5b9d886968af43d2c"
|
||||
"reference": "c8497650cd3ee0d04fe8a9e6391572262c1d89e0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/1ba8d5f2793885cbf779e3b5b9d886968af43d2c",
|
||||
"reference": "1ba8d5f2793885cbf779e3b5b9d886968af43d2c",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/c8497650cd3ee0d04fe8a9e6391572262c1d89e0",
|
||||
"reference": "c8497650cd3ee0d04fe8a9e6391572262c1d89e0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -941,9 +938,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/abuse/issues",
|
||||
"source": "https://github.com/utopia-php/abuse/tree/0.33.0"
|
||||
"source": "https://github.com/utopia-php/abuse/tree/0.34.1"
|
||||
},
|
||||
"time": "2023-11-01T08:51:33+00:00"
|
||||
"time": "2024-03-05T10:43:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/analytics",
|
||||
@@ -993,16 +990,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/audit",
|
||||
"version": "0.35.0",
|
||||
"version": "0.36.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/audit.git",
|
||||
"reference": "ed9366ef05556da040de7a8b570f4160c7d8ea4a"
|
||||
"reference": "9db48fed0558c33c9ddbb493fe2171844a3f0fd4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/ed9366ef05556da040de7a8b570f4160c7d8ea4a",
|
||||
"reference": "ed9366ef05556da040de7a8b570f4160c7d8ea4a",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/9db48fed0558c33c9ddbb493fe2171844a3f0fd4",
|
||||
"reference": "9db48fed0558c33c9ddbb493fe2171844a3f0fd4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1034,9 +1031,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/audit/issues",
|
||||
"source": "https://github.com/utopia-php/audit/tree/0.35.0"
|
||||
"source": "https://github.com/utopia-php/audit/tree/0.36.1"
|
||||
},
|
||||
"time": "2023-11-01T08:51:29+00:00"
|
||||
"time": "2024-03-05T10:50:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/cache",
|
||||
@@ -1190,16 +1187,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "0.45.5",
|
||||
"version": "0.45.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "0b66a017f817a910acb83e6aea92bccea9571fe6"
|
||||
"reference": "f508c5fcec8e4b2c323a12dd4355a8cb0cc6ad03"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/0b66a017f817a910acb83e6aea92bccea9571fe6",
|
||||
"reference": "0b66a017f817a910acb83e6aea92bccea9571fe6",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/f508c5fcec8e4b2c323a12dd4355a8cb0cc6ad03",
|
||||
"reference": "f508c5fcec8e4b2c323a12dd4355a8cb0cc6ad03",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1207,7 +1204,7 @@
|
||||
"ext-pdo": "*",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/cache": "0.9.*",
|
||||
"utopia-php/framework": "0.*.*",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/mongo": "0.3.*"
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -1240,22 +1237,22 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.45.5"
|
||||
"source": "https://github.com/utopia-php/database/tree/0.45.7"
|
||||
},
|
||||
"time": "2024-01-08T17:08:15+00:00"
|
||||
"time": "2024-03-05T10:28:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
"version": "0.3.2",
|
||||
"version": "0.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/domains.git",
|
||||
"reference": "aaa8c9a96c69ccb397997b1f4f2299c66f77eefb"
|
||||
"reference": "bf07f60326f8389f378ddf6fcde86217e5cfe18c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/domains/zipball/aaa8c9a96c69ccb397997b1f4f2299c66f77eefb",
|
||||
"reference": "aaa8c9a96c69ccb397997b1f4f2299c66f77eefb",
|
||||
"url": "https://api.github.com/repos/utopia-php/domains/zipball/bf07f60326f8389f378ddf6fcde86217e5cfe18c",
|
||||
"reference": "bf07f60326f8389f378ddf6fcde86217e5cfe18c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1300,9 +1297,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/domains/issues",
|
||||
"source": "https://github.com/utopia-php/domains/tree/0.3.2"
|
||||
"source": "https://github.com/utopia-php/domains/tree/0.5.0"
|
||||
},
|
||||
"time": "2023-07-19T16:39:24+00:00"
|
||||
"time": "2024-01-03T22:04:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/dsn",
|
||||
@@ -1353,16 +1350,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/framework",
|
||||
"version": "0.33.1",
|
||||
"version": "0.33.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/http.git",
|
||||
"reference": "b745607aa1875554a0ad52e28f6db918da1ce11c"
|
||||
"reference": "b1423ca3e3b61c6c4c2e619d2cb80672809a19f3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/http/zipball/b745607aa1875554a0ad52e28f6db918da1ce11c",
|
||||
"reference": "b745607aa1875554a0ad52e28f6db918da1ce11c",
|
||||
"url": "https://api.github.com/repos/utopia-php/http/zipball/b1423ca3e3b61c6c4c2e619d2cb80672809a19f3",
|
||||
"reference": "b1423ca3e3b61c6c4c2e619d2cb80672809a19f3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1392,22 +1389,22 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/http/issues",
|
||||
"source": "https://github.com/utopia-php/http/tree/0.33.1"
|
||||
"source": "https://github.com/utopia-php/http/tree/0.33.2"
|
||||
},
|
||||
"time": "2024-01-17T16:48:32+00:00"
|
||||
"time": "2024-01-31T10:35:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/image",
|
||||
"version": "0.5.4",
|
||||
"version": "0.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/image.git",
|
||||
"reference": "ca5f436f9aa22dedaa6648f24f3687733808e336"
|
||||
"reference": "2d74c27e69e65a93cf94a16586598a04fe435bf0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/image/zipball/ca5f436f9aa22dedaa6648f24f3687733808e336",
|
||||
"reference": "ca5f436f9aa22dedaa6648f24f3687733808e336",
|
||||
"url": "https://api.github.com/repos/utopia-php/image/zipball/2d74c27e69e65a93cf94a16586598a04fe435bf0",
|
||||
"reference": "2d74c27e69e65a93cf94a16586598a04fe435bf0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1415,6 +1412,8 @@
|
||||
"php": ">=8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.2.*",
|
||||
"phpstan/phpstan": "1.9.x-dev",
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"vimeo/psalm": "4.13.1"
|
||||
},
|
||||
@@ -1428,12 +1427,6 @@
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Eldad Fux",
|
||||
"email": "eldad@appwrite.io"
|
||||
}
|
||||
],
|
||||
"description": "A simple Image manipulation library",
|
||||
"keywords": [
|
||||
"framework",
|
||||
@@ -1444,9 +1437,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/image/issues",
|
||||
"source": "https://github.com/utopia-php/image/tree/0.5.4"
|
||||
"source": "https://github.com/utopia-php/image/tree/0.6.1"
|
||||
},
|
||||
"time": "2022-05-11T12:30:41+00:00"
|
||||
"time": "2024-02-05T13:31:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/locale",
|
||||
@@ -1554,16 +1547,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/messaging",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/messaging.git",
|
||||
"reference": "2d0f474a106bb1da285f85e105c29b46085d3a43"
|
||||
"reference": "d488223876f88f97bb76fd6681fed0df80558f62"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/2d0f474a106bb1da285f85e105c29b46085d3a43",
|
||||
"reference": "2d0f474a106bb1da285f85e105c29b46085d3a43",
|
||||
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/d488223876f88f97bb76fd6681fed0df80558f62",
|
||||
"reference": "d488223876f88f97bb76fd6681fed0df80558f62",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1596,9 +1589,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/messaging/issues",
|
||||
"source": "https://github.com/utopia-php/messaging/tree/0.2.0"
|
||||
"source": "https://github.com/utopia-php/messaging/tree/0.3.0"
|
||||
},
|
||||
"time": "2023-09-14T20:48:42+00:00"
|
||||
"time": "2023-11-14T21:02:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
@@ -2420,16 +2413,16 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "0.36.2",
|
||||
"version": "0.36.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "0aa67479d75f0e0cb7b60454031534d7f0abaece"
|
||||
"reference": "8d932098009d62d37dda73cfe4ebc11f83e21405"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/0aa67479d75f0e0cb7b60454031534d7f0abaece",
|
||||
"reference": "0aa67479d75f0e0cb7b60454031534d7f0abaece",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/8d932098009d62d37dda73cfe4ebc11f83e21405",
|
||||
"reference": "8d932098009d62d37dda73cfe4ebc11f83e21405",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2465,22 +2458,22 @@
|
||||
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
|
||||
"support": {
|
||||
"issues": "https://github.com/appwrite/sdk-generator/issues",
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/0.36.2"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/0.36.4"
|
||||
},
|
||||
"time": "2024-01-19T01:04:35+00:00"
|
||||
"time": "2024-02-20T16:36:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/deprecations",
|
||||
"version": "1.1.2",
|
||||
"version": "1.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/deprecations.git",
|
||||
"reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931"
|
||||
"reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931",
|
||||
"reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931",
|
||||
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
|
||||
"reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2512,9 +2505,9 @@
|
||||
"homepage": "https://www.doctrine-project.org/",
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/deprecations/issues",
|
||||
"source": "https://github.com/doctrine/deprecations/tree/1.1.2"
|
||||
"source": "https://github.com/doctrine/deprecations/tree/1.1.3"
|
||||
},
|
||||
"time": "2023-09-27T20:04:15+00:00"
|
||||
"time": "2024-01-30T19:34:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
@@ -2771,16 +2764,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v5.0.0",
|
||||
"version": "v5.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc"
|
||||
"reference": "2218c2252c874a4624ab2f613d86ac32d227bc69"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4a21235f7e56e713259a6f76bf4b5ea08502b9dc",
|
||||
"reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/2218c2252c874a4624ab2f613d86ac32d227bc69",
|
||||
"reference": "2218c2252c874a4624ab2f613d86ac32d227bc69",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2823,26 +2816,27 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.0.0"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.0.1"
|
||||
},
|
||||
"time": "2024-01-07T17:17:35+00:00"
|
||||
"time": "2024-02-21T19:24:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phar-io/manifest.git",
|
||||
"reference": "97803eca37d319dfa7826cc2437fc020857acb53"
|
||||
"reference": "54750ef60c58e43759730615a392c31c80e23176"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
|
||||
"reference": "97803eca37d319dfa7826cc2437fc020857acb53",
|
||||
"url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
|
||||
"reference": "54750ef60c58e43759730615a392c31c80e23176",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-phar": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"phar-io/version": "^3.0.1",
|
||||
@@ -2883,9 +2877,15 @@
|
||||
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
|
||||
"support": {
|
||||
"issues": "https://github.com/phar-io/manifest/issues",
|
||||
"source": "https://github.com/phar-io/manifest/tree/2.0.3"
|
||||
"source": "https://github.com/phar-io/manifest/tree/2.0.4"
|
||||
},
|
||||
"time": "2021-07-20T11:28:43+00:00"
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/theseer",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-03T12:33:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/version",
|
||||
@@ -3050,21 +3050,21 @@
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/TypeResolver.git",
|
||||
"reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc"
|
||||
"reference": "153ae662783729388a584b4361f2545e4d841e3c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fad452781b3d774e3337b0c0b245dd8e5a4455fc",
|
||||
"reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c",
|
||||
"reference": "153ae662783729388a584b4361f2545e4d841e3c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/deprecations": "^1.0",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"php": "^7.3 || ^8.0",
|
||||
"phpdocumentor/reflection-common": "^2.0",
|
||||
"phpstan/phpdoc-parser": "^1.13"
|
||||
},
|
||||
@@ -3102,30 +3102,30 @@
|
||||
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
|
||||
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.0"
|
||||
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2"
|
||||
},
|
||||
"time": "2024-01-11T11:49:22+00:00"
|
||||
"time": "2024-02-23T11:10:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "v1.18.0",
|
||||
"version": "v1.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "d4f454f7e1193933f04e6500de3e79191648ed0c"
|
||||
"reference": "67a759e7d8746d501c41536ba40cd9c0a07d6a87"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/d4f454f7e1193933f04e6500de3e79191648ed0c",
|
||||
"reference": "d4f454f7e1193933f04e6500de3e79191648ed0c",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/67a759e7d8746d501c41536ba40cd9c0a07d6a87",
|
||||
"reference": "67a759e7d8746d501c41536ba40cd9c0a07d6a87",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.2 || ^2.0",
|
||||
"php": "^7.2 || 8.0.* || 8.1.* || 8.2.* || 8.3.*",
|
||||
"phpdocumentor/reflection-docblock": "^5.2",
|
||||
"sebastian/comparator": "^3.0 || ^4.0 || ^5.0",
|
||||
"sebastian/recursion-context": "^3.0 || ^4.0 || ^5.0"
|
||||
"sebastian/comparator": "^3.0 || ^4.0 || ^5.0 || ^6.0",
|
||||
"sebastian/recursion-context": "^3.0 || ^4.0 || ^5.0 || ^6.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpspec/phpspec": "^6.0 || ^7.0",
|
||||
@@ -3171,22 +3171,22 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpspec/prophecy/issues",
|
||||
"source": "https://github.com/phpspec/prophecy/tree/v1.18.0"
|
||||
"source": "https://github.com/phpspec/prophecy/tree/v1.19.0"
|
||||
},
|
||||
"time": "2023-12-07T16:22:33+00:00"
|
||||
"time": "2024-02-29T11:52:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpdoc-parser",
|
||||
"version": "1.25.0",
|
||||
"version": "1.26.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
||||
"reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240"
|
||||
"reference": "231e3186624c03d7e7c890ec662b81e6b0405227"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bd84b629c8de41aa2ae82c067c955e06f1b00240",
|
||||
"reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240",
|
||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/231e3186624c03d7e7c890ec662b81e6b0405227",
|
||||
"reference": "231e3186624c03d7e7c890ec662b81e6b0405227",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3218,22 +3218,22 @@
|
||||
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.25.0"
|
||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.26.0"
|
||||
},
|
||||
"time": "2024-01-04T17:06:16+00:00"
|
||||
"time": "2024-02-23T16:05:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "9.2.30",
|
||||
"version": "9.2.31",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089"
|
||||
"reference": "48c34b5d8d983006bd2adc2d0de92963b9155965"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089",
|
||||
"reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965",
|
||||
"reference": "48c34b5d8d983006bd2adc2d0de92963b9155965",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3290,7 +3290,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3298,7 +3298,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-12-22T06:47:57+00:00"
|
||||
"time": "2024-03-02T06:37:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
@@ -3696,16 +3696,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/cli-parser.git",
|
||||
"reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
|
||||
"reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
|
||||
"reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
|
||||
"reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3740,7 +3740,7 @@
|
||||
"homepage": "https://github.com/sebastianbergmann/cli-parser",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/cli-parser/issues",
|
||||
"source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
|
||||
"source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3748,7 +3748,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-09-28T06:08:49+00:00"
|
||||
"time": "2024-03-02T06:27:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit",
|
||||
@@ -3994,16 +3994,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "4.0.5",
|
||||
"version": "4.0.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
|
||||
"reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
|
||||
"reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc",
|
||||
"reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4048,7 +4048,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4056,7 +4056,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-07T05:35:17+00:00"
|
||||
"time": "2024-03-02T06:30:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
@@ -4123,16 +4123,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
"version": "4.0.5",
|
||||
"version": "4.0.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/exporter.git",
|
||||
"reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d"
|
||||
"reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
|
||||
"reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
|
||||
"reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4188,7 +4188,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/exporter/issues",
|
||||
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5"
|
||||
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4196,20 +4196,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-09-14T06:03:37+00:00"
|
||||
"time": "2024-03-02T06:33:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
"version": "5.0.6",
|
||||
"version": "5.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/global-state.git",
|
||||
"reference": "bde739e7565280bda77be70044ac1047bc007e34"
|
||||
"reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34",
|
||||
"reference": "bde739e7565280bda77be70044ac1047bc007e34",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
|
||||
"reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4252,7 +4252,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/global-state/issues",
|
||||
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6"
|
||||
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4260,7 +4260,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-08-02T09:26:13+00:00"
|
||||
"time": "2024-03-02T06:35:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/lines-of-code",
|
||||
@@ -4660,16 +4660,16 @@
|
||||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "3.8.1",
|
||||
"version": "3.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
|
||||
"reference": "14f5fff1e64118595db5408e946f3a22c75807f7"
|
||||
"reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/14f5fff1e64118595db5408e946f3a22c75807f7",
|
||||
"reference": "14f5fff1e64118595db5408e946f3a22c75807f7",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/d63cee4890a8afaf86a22e51ad4d97c91dd4579b",
|
||||
"reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4736,7 +4736,7 @@
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-11T20:47:48+00:00"
|
||||
"time": "2024-02-16T15:06:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "swoole/ide-helper",
|
||||
@@ -4772,16 +4772,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.28.0",
|
||||
"version": "v1.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
|
||||
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
|
||||
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
|
||||
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4795,9 +4795,6 @@
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
@@ -4834,7 +4831,7 @@
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4850,20 +4847,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.28.0",
|
||||
"version": "v1.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "42292d99c55abe617799667f454222c54c60e229"
|
||||
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
|
||||
"reference": "42292d99c55abe617799667f454222c54c60e229",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
|
||||
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4877,9 +4874,6 @@
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
@@ -4917,7 +4911,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4933,7 +4927,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-07-28T09:04:16+00:00"
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "textalk/websocket",
|
||||
@@ -4986,16 +4980,16 @@
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/theseer/tokenizer.git",
|
||||
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
|
||||
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5024,7 +5018,7 @@
|
||||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||
"support": {
|
||||
"issues": "https://github.com/theseer/tokenizer/issues",
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.2"
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -5032,7 +5026,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-20T00:12:19+00:00"
|
||||
"time": "2024-03-03T12:36:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
|
||||
+51
-25
@@ -5,12 +5,12 @@
|
||||
|
||||
x-logging: &x-logging
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-file: '5'
|
||||
max-size: '10m'
|
||||
max-file: "5"
|
||||
max-size: "10m"
|
||||
|
||||
version: '3'
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
traefik:
|
||||
@@ -645,6 +645,7 @@ services:
|
||||
- _APP_MAINTENANCE_RETENTION_AUDIT
|
||||
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
|
||||
- _APP_MAINTENANCE_RETENTION_SCHEDULES
|
||||
- _APP_MAINTENANCE_DELAY
|
||||
|
||||
appwrite-worker-usage:
|
||||
entrypoint: worker-usage
|
||||
@@ -677,6 +678,37 @@ services:
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_USAGE_AGGREGATION_INTERVAL
|
||||
|
||||
appwrite-worker-usage-dump:
|
||||
entrypoint: worker-usage-dump
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-usage-dump
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_USAGE_AGGREGATION_INTERVAL
|
||||
|
||||
appwrite-schedule:
|
||||
entrypoint: schedule
|
||||
<<: *x-logging
|
||||
@@ -857,7 +889,7 @@ services:
|
||||
- MYSQL_DATABASE=${_APP_DB_SCHEMA}
|
||||
- MYSQL_USER=${_APP_DB_USER}
|
||||
- MYSQL_PASSWORD=${_APP_DB_PASS}
|
||||
command: 'mysqld --innodb-flush-method=fsync' # add ' --query_cache_size=0' for DB tests
|
||||
command: "mysqld --innodb-flush-method=fsync" # add ' --query_cache_size=0' for DB tests
|
||||
# command: mv /var/lib/mysql/ib_logfile0 /var/lib/mysql/ib_logfile0.bu && mv /var/lib/mysql/ib_logfile1 /var/lib/mysql/ib_logfile1.bu
|
||||
|
||||
# smtp:
|
||||
@@ -903,15 +935,16 @@ 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
|
||||
# Webgrind - A nice UI for exploring and debugging code-level stuff
|
||||
# Redis Insight - A nice UI for exploring Redis data
|
||||
# Adminer - A nice UI for exploring MariaDB data
|
||||
# GraphQl Explorer - A nice UI for exploring GraphQL API
|
||||
|
||||
maildev: # used mainly for dev tests
|
||||
image: appwrite/mailcatcher:1.0.0
|
||||
container_name: appwrite-mailcatcher
|
||||
<<: *x-logging
|
||||
ports:
|
||||
- '9503:1080'
|
||||
- "9503:1080"
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
@@ -920,7 +953,7 @@ services:
|
||||
container_name: appwrite-requestcatcher
|
||||
<<: *x-logging
|
||||
ports:
|
||||
- '9504:5000'
|
||||
- "9504:5000"
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
@@ -934,21 +967,15 @@ services:
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
# redis-commander:
|
||||
# image: rediscommander/redis-commander:latest
|
||||
# restart: unless-stopped
|
||||
# networks:
|
||||
# - appwrite
|
||||
# environment:
|
||||
# - REDIS_HOSTS=redis
|
||||
# ports:
|
||||
# - "8081:8081"
|
||||
# webgrind:
|
||||
# image: 'jokkedk/webgrind:latest'
|
||||
# volumes:
|
||||
# - './debug:/tmp'
|
||||
# ports:
|
||||
# - '3001:80'
|
||||
redis-insight:
|
||||
image: redis/redisinsight:latest
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
environment:
|
||||
- REDIS_HOSTS=redis
|
||||
ports:
|
||||
- "8081:5540"
|
||||
|
||||
graphql-explorer:
|
||||
container_name: appwrite-graphql-explorer
|
||||
@@ -961,7 +988,6 @@ services:
|
||||
environment:
|
||||
- SERVER_URL=http://localhost/v1/graphql
|
||||
|
||||
|
||||
# Dev Tools End ------------------------------------------------------------------------------------------
|
||||
|
||||
networks:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.create_phone_verification()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.create_recovery(email: 'email@example.com', url: 'https://example.com')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.create_verification(url: 'https://example.com')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.delete_identity(identity_id: '[IDENTITY_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.delete_session(session_id: '[SESSION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.delete_sessions()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.get_prefs()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.get_session(session_id: '[SESSION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.get()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.list_identities()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.list_logs()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.list_sessions()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.update_email(email: 'email@example.com', password: 'password')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.update_name(name: '[NAME]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.update_password(password: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.update_phone_verification(user_id: '[USER_ID]', secret: '[SECRET]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.update_phone(phone: '+12065550100', password: 'password')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.update_prefs(prefs: {})
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.update_recovery(user_id: '[USER_ID]', secret: '[SECRET]', password: 'password', password_again: 'password')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.update_session(session_id: '[SESSION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.update_status()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ account = Account.new(client)
|
||||
|
||||
response = account.update_verification(user_id: '[USER_ID]', secret: '[SECRET]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
||||
|
||||
response = avatars.get_browser(code: 'aa')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
||||
|
||||
response = avatars.get_credit_card(code: 'amex')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
||||
|
||||
response = avatars.get_favicon(url: 'https://example.com')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
||||
|
||||
response = avatars.get_flag(code: 'af')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
||||
|
||||
response = avatars.get_image(url: 'https://example.com')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
||||
|
||||
response = avatars.get_initials()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
||||
|
||||
response = avatars.get_qr(text: '[TEXT]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create_boolean_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create_collection(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', name: '[NAME]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create_datetime_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create_document(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', document_id: '[DOCUMENT_ID]', data: {})
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create_email_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create_enum_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', elements: [], required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create_float_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create_index(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', type: 'key', attributes: [])
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create_integer_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create_ip_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create_relationship_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', related_collection_id: '[RELATED_COLLECTION_ID]', type: 'oneToOne')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create_string_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', size: 1, required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create_url_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.create(database_id: '[DATABASE_ID]', name: '[NAME]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.delete_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.delete_collection(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.delete_document(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', document_id: '[DOCUMENT_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.delete_index(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.delete(database_id: '[DATABASE_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.get_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.get_collection(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.get_document(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', document_id: '[DOCUMENT_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.get_index(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.get(database_id: '[DATABASE_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.list_attributes(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.list_collections(database_id: '[DATABASE_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.list_documents(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.list_indexes(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.list()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.update_boolean_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.update_collection(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', name: '[NAME]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.update_datetime_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
@@ -11,4 +11,4 @@ databases = Databases.new(client)
|
||||
|
||||
response = databases.update_document(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', document_id: '[DOCUMENT_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user