Merge pull request #7120 from appwrite/chore-sync-main

Chore sync main
This commit is contained in:
Jake Barnby 2023-11-13 17:09:45 +13:00 committed by GitHub
commit e2aa06ed84
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 244 additions and 69 deletions

2
.gitmodules vendored
View file

@ -1,4 +1,4 @@
[submodule "app/console"] [submodule "app/console"]
path = app/console path = app/console
url = https://github.com/appwrite/console url = https://github.com/appwrite/console
branch = 3.2.5 branch = 3.2.6

View file

@ -1,3 +1,22 @@
# Version 1.4.11
## Miscellaneous
* Update database by @abnegate in [#7111](https://github.com/appwrite/appwrite/pull/7111)
# Version 1.4.10
## Bug fixes
* Handle cases where password history could contain NULLs [#7092](https://github.com/appwrite/appwrite/pull/7092)
* Missing functionId error on create execution [#7091](https://github.com/appwrite/appwrite/pull/7091)
* Ensure usage endpoints don't throw 500 when usage is disabled [#7087](https://github.com/appwrite/appwrite/pull/7087)
* Missing sessionId error when deleting all user sessions [#7085](https://github.com/appwrite/appwrite/pull/7085)
* Domain validation in Create Proxy rule results in 500 error [#7084](https://github.com/appwrite/appwrite/pull/7084)
* Fix optional services [#7078](https://github.com/appwrite/appwrite/pull/7078)
* Fix regression from worker refactor [#7074](https://github.com/appwrite/appwrite/pull/7074)
* Use getQueueSize() in the Health service's get X queue endpoints [#7073](https://github.com/appwrite/appwrite/pull/7073)
* Delete linked VCS repos and comments [#7066](https://github.com/appwrite/appwrite/pull/7066)
# Version 1.4.9 # Version 1.4.9
## Bug fixes ## Bug fixes

View file

@ -66,7 +66,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \ --volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \ --entrypoint="install" \
appwrite/appwrite:1.4.9 appwrite/appwrite:1.4.11
``` ```
### Windows ### Windows
@ -78,7 +78,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^ --volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^ --volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^ --entrypoint="install" ^
appwrite/appwrite:1.4.9 appwrite/appwrite:1.4.11
``` ```
#### PowerShell #### PowerShell
@ -88,7 +88,7 @@ docker run -it --rm `
--volume /var/run/docker.sock:/var/run/docker.sock ` --volume /var/run/docker.sock:/var/run/docker.sock `
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ` --volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
--entrypoint="install" ` --entrypoint="install" `
appwrite/appwrite:1.4.9 appwrite/appwrite:1.4.11
``` ```
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。 运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。

View file

@ -76,7 +76,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \ --volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \ --entrypoint="install" \
appwrite/appwrite:1.4.9 appwrite/appwrite:1.4.11
``` ```
### Windows ### Windows
@ -88,7 +88,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^ --volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^ --volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^ --entrypoint="install" ^
appwrite/appwrite:1.4.9 appwrite/appwrite:1.4.11
``` ```
#### PowerShell #### PowerShell
@ -98,7 +98,7 @@ docker run -it --rm `
--volume /var/run/docker.sock:/var/run/docker.sock ` --volume /var/run/docker.sock:/var/run/docker.sock `
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ` --volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
--entrypoint="install" ` --entrypoint="install" `
appwrite/appwrite:1.4.9 appwrite/appwrite:1.4.11
``` ```
Once the Docker installation is complete, go to http://localhost to access the Appwrite console from your browser. Please note that on non-Linux native hosts, the server might take a few minutes to start after completing the installation. Once the Docker installation is complete, go to http://localhost to access the Appwrite console from your browser. Please note that on non-Linux native hosts, the server might take a few minutes to start after completing the installation.

View file

@ -170,7 +170,7 @@ return [
'docs' => false, 'docs' => false,
'docsUrl' => '', 'docsUrl' => '',
'tests' => false, 'tests' => false,
'optional' => true, 'optional' => false,
'icon' => '', 'icon' => '',
], ],
'functions' => [ 'functions' => [
@ -196,7 +196,7 @@ return [
'docs' => true, 'docs' => true,
'docsUrl' => 'https://appwrite.io/docs/proxy', 'docsUrl' => 'https://appwrite.io/docs/proxy',
'tests' => false, 'tests' => false,
'optional' => true, 'optional' => false,
'icon' => '/images/services/proxy.png', 'icon' => '/images/services/proxy.png',
], ],
'mock' => [ 'mock' => [
@ -248,7 +248,7 @@ return [
'docs' => true, 'docs' => true,
'docsUrl' => 'https://appwrite.io/docs/migrations', 'docsUrl' => 'https://appwrite.io/docs/migrations',
'tests' => true, 'tests' => true,
'optional' => true, 'optional' => false,
'icon' => '/images/services/migrations.png', 'icon' => '/images/services/migrations.png',
], ],
'messaging' => [ 'messaging' => [

@ -1 +1 @@
Subproject commit 9810ce85812ca26c95b7d35196848c92e8ba813d Subproject commit f7c34a1b37d53dd5f28c83b4e12a4e68fcd9b484

View file

@ -3632,7 +3632,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
App::get('/v1/databases/usage') App::get('/v1/databases/usage')
->desc('Get usage stats for the database') ->desc('Get usage stats for the database')
->groups(['api', 'database']) ->groups(['api', 'database', 'usage'])
->label('scope', 'collections.read') ->label('scope', 'collections.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases') ->label('sdk.namespace', 'databases')
@ -3750,7 +3750,7 @@ App::get('/v1/databases/usage')
App::get('/v1/databases/:databaseId/usage') App::get('/v1/databases/:databaseId/usage')
->desc('Get usage stats for the database') ->desc('Get usage stats for the database')
->groups(['api', 'database']) ->groups(['api', 'database', 'usage'])
->label('scope', 'collections.read') ->label('scope', 'collections.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases') ->label('sdk.namespace', 'databases')
@ -3860,7 +3860,7 @@ App::get('/v1/databases/:databaseId/usage')
App::get('/v1/databases/:databaseId/collections/:collectionId/usage') App::get('/v1/databases/:databaseId/collections/:collectionId/usage')
->alias('/v1/database/:collectionId/usage', ['databaseId' => 'default']) ->alias('/v1/database/:collectionId/usage', ['databaseId' => 'default'])
->desc('Get usage stats for a collection') ->desc('Get usage stats for a collection')
->groups(['api', 'database']) ->groups(['api', 'database', 'usage'])
->label('scope', 'collections.read') ->label('scope', 'collections.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases') ->label('sdk.namespace', 'databases')

View file

@ -1658,6 +1658,8 @@ App::post('/v1/functions/:functionId/executions')
->setJWT($jwt) ->setJWT($jwt)
->setProject($project) ->setProject($project)
->setUser($user) ->setUser($user)
->setParam('functionId', $function->getId())
->setParam('executionId', $execution->getId())
->trigger(); ->trigger();
return $response return $response

View file

@ -348,7 +348,7 @@ App::get('/v1/health/queue/webhooks')
->inject('response') ->inject('response')
->action(function (Connection $queue, Response $response) { ->action(function (Connection $queue, Response $response) {
$client = new Client(Event::WEBHOOK_QUEUE_NAME, $queue); $client = new Client(Event::WEBHOOK_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE); $response->dynamic(new Document([ 'size' => $client->getQueueSize() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']); }, ['response']);
App::get('/v1/health/queue/logs') App::get('/v1/health/queue/logs')
@ -366,7 +366,7 @@ App::get('/v1/health/queue/logs')
->inject('response') ->inject('response')
->action(function (Connection $queue, Response $response) { ->action(function (Connection $queue, Response $response) {
$client = new Client(Event::AUDITS_QUEUE_NAME, $queue); $client = new Client(Event::AUDITS_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE); $response->dynamic(new Document([ 'size' => $client->getQueueSize() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']); }, ['response']);
App::get('/v1/health/queue/certificates') App::get('/v1/health/queue/certificates')
@ -384,7 +384,7 @@ App::get('/v1/health/queue/certificates')
->inject('response') ->inject('response')
->action(function (Connection $queue, Response $response) { ->action(function (Connection $queue, Response $response) {
$client = new Client(Event::CERTIFICATES_QUEUE_NAME, $queue); $client = new Client(Event::CERTIFICATES_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE); $response->dynamic(new Document([ 'size' => $client->getQueueSize() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']); }, ['response']);
App::get('/v1/health/queue/builds') App::get('/v1/health/queue/builds')
@ -402,7 +402,7 @@ App::get('/v1/health/queue/builds')
->inject('response') ->inject('response')
->action(function (Connection $queue, Response $response) { ->action(function (Connection $queue, Response $response) {
$client = new Client(Event::BUILDS_QUEUE_NAME, $queue); $client = new Client(Event::BUILDS_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE); $response->dynamic(new Document([ 'size' => $client->getQueueSize() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']); }, ['response']);
App::get('/v1/health/queue/databases') App::get('/v1/health/queue/databases')
@ -421,7 +421,7 @@ App::get('/v1/health/queue/databases')
->inject('response') ->inject('response')
->action(function (string $name, Connection $queue, Response $response) { ->action(function (string $name, Connection $queue, Response $response) {
$client = new Client($name, $queue); $client = new Client($name, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE); $response->dynamic(new Document([ 'size' => $client->getQueueSize() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']); }, ['response']);
App::get('/v1/health/queue/deletes') App::get('/v1/health/queue/deletes')
@ -439,7 +439,7 @@ App::get('/v1/health/queue/deletes')
->inject('response') ->inject('response')
->action(function (Connection $queue, Response $response) { ->action(function (Connection $queue, Response $response) {
$client = new Client(Event::DELETE_QUEUE_NAME, $queue); $client = new Client(Event::DELETE_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE); $response->dynamic(new Document([ 'size' => $client->getQueueSize() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']); }, ['response']);
App::get('/v1/health/queue/mails') App::get('/v1/health/queue/mails')
@ -457,7 +457,7 @@ App::get('/v1/health/queue/mails')
->inject('response') ->inject('response')
->action(function (Connection $queue, Response $response) { ->action(function (Connection $queue, Response $response) {
$client = new Client(Event::MAILS_QUEUE_NAME, $queue); $client = new Client(Event::MAILS_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE); $response->dynamic(new Document([ 'size' => $client->getQueueSize() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']); }, ['response']);
App::get('/v1/health/queue/messaging') App::get('/v1/health/queue/messaging')
@ -475,7 +475,7 @@ App::get('/v1/health/queue/messaging')
->inject('response') ->inject('response')
->action(function (Connection $queue, Response $response) { ->action(function (Connection $queue, Response $response) {
$client = new Client(Event::MESSAGING_QUEUE_NAME, $queue); $client = new Client(Event::MESSAGING_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE); $response->dynamic(new Document([ 'size' => $client->getQueueSize() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']); }, ['response']);
App::get('/v1/health/queue/migrations') App::get('/v1/health/queue/migrations')
@ -493,7 +493,7 @@ App::get('/v1/health/queue/migrations')
->inject('response') ->inject('response')
->action(function (Connection $queue, Response $response) { ->action(function (Connection $queue, Response $response) {
$client = new Client(Event::MIGRATIONS_QUEUE_NAME, $queue); $client = new Client(Event::MIGRATIONS_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE); $response->dynamic(new Document([ 'size' => $client->getQueueSize() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']); }, ['response']);
App::get('/v1/health/queue/functions') App::get('/v1/health/queue/functions')
@ -511,7 +511,7 @@ App::get('/v1/health/queue/functions')
->inject('response') ->inject('response')
->action(function (Connection $queue, Response $response) { ->action(function (Connection $queue, Response $response) {
$client = new Client(Event::FUNCTIONS_QUEUE_NAME, $queue); $client = new Client(Event::FUNCTIONS_QUEUE_NAME, $queue);
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE); $response->dynamic(new Document([ 'size' => $client->getQueueSize() ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']); }, ['response']);
App::get('/v1/health/storage/local') App::get('/v1/health/storage/local')

View file

@ -87,7 +87,11 @@ App::post('/v1/proxy/rules')
$resourceInternalId = $function->getInternalId(); $resourceInternalId = $function->getInternalId();
} }
$domain = new Domain($domain); try {
$domain = new Domain($domain);
} catch (\Exception) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Domain may not start with http:// or https://.');
}
$ruleId = ID::unique(); $ruleId = ID::unique();
$rule = new Document([ $rule = new Document([

View file

@ -86,7 +86,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
'status' => true, 'status' => true,
'labels' => [], 'labels' => [],
'password' => $password, 'password' => $password,
'passwordHistory' => is_null($password) && $passwordHistory === 0 ? [] : [$password], 'passwordHistory' => is_null($password) || $passwordHistory === 0 ? [] : [$password],
'passwordUpdate' => (!empty($password)) ? DateTime::now() : null, 'passwordUpdate' => (!empty($password)) ? DateTime::now() : null,
'hash' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO : $hash, 'hash' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO : $hash,
'hashOptions' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO_OPTIONS : $hashOptionsObject + ['type' => $hash], 'hashOptions' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO_OPTIONS : $hashOptionsObject + ['type' => $hash],
@ -1321,7 +1321,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
App::delete('/v1/users/:userId/sessions') App::delete('/v1/users/:userId/sessions')
->desc('Delete user sessions') ->desc('Delete user sessions')
->groups(['api', 'users']) ->groups(['api', 'users'])
->label('event', 'users.[userId].sessions.[sessionId].delete') ->label('event', 'users.[userId].sessions.delete')
->label('scope', 'users.write') ->label('scope', 'users.write')
->label('audits.event', 'session.delete') ->label('audits.event', 'session.delete')
->label('audits.resource', 'user/{user.$id}') ->label('audits.resource', 'user/{user.$id}')

View file

@ -554,3 +554,11 @@ App::shutdown()
->submit(); ->submit();
} }
}); });
App::init()
->groups(['usage'])
->action(function () {
if (App::getEnv('_APP_USAGE_STATS', 'enabled') !== 'enabled') {
throw new Exception(Exception::GENERAL_USAGE_DISABLED);
}
});

View file

@ -105,8 +105,8 @@ const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return
const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours
const APP_USER_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_UPDATE = 24 * 60 * 60; // 24 hours
const APP_CACHE_BUSTER = 515; const APP_CACHE_BUSTER = 516;
const APP_VERSION_STABLE = '1.4.9'; const APP_VERSION_STABLE = '1.4.11';
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email'; const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum'; const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
const APP_DATABASE_ATTRIBUTE_IP = 'ip'; const APP_DATABASE_ATTRIBUTE_IP = 'ip';

View file

@ -43,13 +43,13 @@
"ext-sockets": "*", "ext-sockets": "*",
"appwrite/php-runtimes": "0.13.*", "appwrite/php-runtimes": "0.13.*",
"appwrite/php-clamav": "2.0.*", "appwrite/php-clamav": "2.0.*",
"utopia-php/abuse": "0.32.*", "utopia-php/abuse": "0.33.*",
"utopia-php/analytics": "0.10.*", "utopia-php/analytics": "0.10.*",
"utopia-php/audit": "0.34.*", "utopia-php/audit": "0.35.*",
"utopia-php/cache": "0.8.*", "utopia-php/cache": "0.8.*",
"utopia-php/cli": "0.15.*", "utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*", "utopia-php/config": "0.2.*",
"utopia-php/database": "0.44.*", "utopia-php/database": "0.45.*",
"utopia-php/domains": "0.3.*", "utopia-php/domains": "0.3.*",
"utopia-php/dsn": "0.1.*", "utopia-php/dsn": "0.1.*",
"utopia-php/framework": "0.31.0", "utopia-php/framework": "0.31.0",

42
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "9afc62ce9c6ba587b9c028e11494e026", "content-hash": "69bc2e21a65b78344393706b39d789b4",
"packages": [ "packages": [
{ {
"name": "adhocore/jwt", "name": "adhocore/jwt",
@ -1615,23 +1615,23 @@
}, },
{ {
"name": "utopia-php/abuse", "name": "utopia-php/abuse",
"version": "0.32.0", "version": "0.33.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/utopia-php/abuse.git", "url": "https://github.com/utopia-php/abuse.git",
"reference": "9717ffb2d7711f3fd621bb6df3edf5724c08ea78" "reference": "1ba8d5f2793885cbf779e3b5b9d886968af43d2c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/9717ffb2d7711f3fd621bb6df3edf5724c08ea78", "url": "https://api.github.com/repos/utopia-php/abuse/zipball/1ba8d5f2793885cbf779e3b5b9d886968af43d2c",
"reference": "9717ffb2d7711f3fd621bb6df3edf5724c08ea78", "reference": "1ba8d5f2793885cbf779e3b5b9d886968af43d2c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-curl": "*", "ext-curl": "*",
"ext-pdo": "*", "ext-pdo": "*",
"php": ">=8.0", "php": ">=8.0",
"utopia-php/database": "0.44.*" "utopia-php/database": "0.45.*"
}, },
"require-dev": { "require-dev": {
"laravel/pint": "1.5.*", "laravel/pint": "1.5.*",
@ -1658,9 +1658,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/utopia-php/abuse/issues", "issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.32.0" "source": "https://github.com/utopia-php/abuse/tree/0.33.0"
}, },
"time": "2023-10-18T07:28:55+00:00" "time": "2023-11-01T08:51:33+00:00"
}, },
{ {
"name": "utopia-php/analytics", "name": "utopia-php/analytics",
@ -1710,21 +1710,21 @@
}, },
{ {
"name": "utopia-php/audit", "name": "utopia-php/audit",
"version": "0.34.0", "version": "0.35.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/utopia-php/audit.git", "url": "https://github.com/utopia-php/audit.git",
"reference": "cf34cc3f9f20da4e574a9be4517e1a11025a858f" "reference": "ed9366ef05556da040de7a8b570f4160c7d8ea4a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/cf34cc3f9f20da4e574a9be4517e1a11025a858f", "url": "https://api.github.com/repos/utopia-php/audit/zipball/ed9366ef05556da040de7a8b570f4160c7d8ea4a",
"reference": "cf34cc3f9f20da4e574a9be4517e1a11025a858f", "reference": "ed9366ef05556da040de7a8b570f4160c7d8ea4a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.0", "php": ">=8.0",
"utopia-php/database": "0.44.*" "utopia-php/database": "0.45.*"
}, },
"require-dev": { "require-dev": {
"laravel/pint": "1.5.*", "laravel/pint": "1.5.*",
@ -1751,9 +1751,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/utopia-php/audit/issues", "issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.34.0" "source": "https://github.com/utopia-php/audit/tree/0.35.0"
}, },
"time": "2023-10-18T07:43:25+00:00" "time": "2023-11-01T08:51:29+00:00"
}, },
{ {
"name": "utopia-php/cache", "name": "utopia-php/cache",
@ -1906,16 +1906,16 @@
}, },
{ {
"name": "utopia-php/database", "name": "utopia-php/database",
"version": "0.44.4", "version": "0.45.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/utopia-php/database.git", "url": "https://github.com/utopia-php/database.git",
"reference": "b0c3fd8ecfedc3646d7780f2d6b38955a66baf48" "reference": "0e76f996439b80794ab73c2fffdb51ebd6676e4b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/b0c3fd8ecfedc3646d7780f2d6b38955a66baf48", "url": "https://api.github.com/repos/utopia-php/database/zipball/0e76f996439b80794ab73c2fffdb51ebd6676e4b",
"reference": "b0c3fd8ecfedc3646d7780f2d6b38955a66baf48", "reference": "0e76f996439b80794ab73c2fffdb51ebd6676e4b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1956,9 +1956,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/utopia-php/database/issues", "issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.44.4" "source": "https://github.com/utopia-php/database/tree/0.45.1"
}, },
"time": "2023-10-26T07:08:12+00:00" "time": "2023-11-01T08:30:19+00:00"
}, },
{ {
"name": "utopia-php/domains", "name": "utopia-php/domains",

View file

@ -44,7 +44,7 @@ class PasswordHistory extends Password
public function isValid($value): bool public function isValid($value): bool
{ {
foreach ($this->history as $hash) { foreach ($this->history as $hash) {
if (Auth::passwordVerify($value, $hash, $this->algo, $this->algoOptions)) { if (!empty($hash) && Auth::passwordVerify($value, $hash, $this->algo, $this->algoOptions)) {
return false; return false;
} }
} }

View file

@ -74,6 +74,8 @@ abstract class Migration
'1.4.7' => 'V19', '1.4.7' => 'V19',
'1.4.8' => 'V19', '1.4.8' => 'V19',
'1.4.9' => 'V19', '1.4.9' => 'V19',
'1.4.10' => 'V19',
'1.4.11' => 'V19',
]; ];
/** /**

View file

@ -46,7 +46,7 @@ class Deletes extends Action
->inject('getFunctionsDevice') ->inject('getFunctionsDevice')
->inject('getBuildsDevice') ->inject('getBuildsDevice')
->inject('getCacheDevice') ->inject('getCacheDevice')
->callback(fn($message, $dbForConsole, callable $getProjectDB, callable $getFilesDevice, callable $getFunctionsDevice, callable $getBuildsDevice, callable $getCacheDevice) => $this->action($message, $dbForConsole, $getProjectDB, $getFilesDevice, $getFunctionsDevice, $getBuildsDevice, $getCacheDevice)); ->callback(fn ($message, $dbForConsole, callable $getProjectDB, callable $getFilesDevice, callable $getFunctionsDevice, callable $getBuildsDevice, callable $getCacheDevice) => $this->action($message, $dbForConsole, $getProjectDB, $getFilesDevice, $getFunctionsDevice, $getBuildsDevice, $getCacheDevice));
} }
/** /**
@ -182,7 +182,8 @@ class Deletes extends Action
$project = $dbForConsole->getDocument('projects', $document->getAttribute('projectId')); $project = $dbForConsole->getDocument('projects', $document->getAttribute('projectId'));
if ($project->isEmpty()) { if ($project->isEmpty()) {
Console::warning('Unable to delete schedule for function ' . $document->getAttribute('resourceId')); $dbForConsole->deleteDocument('schedules', $document->getId());
Console::success('Deleted schedule for deleted project ' . $document->getAttribute('projectId'));
return; return;
} }
@ -473,6 +474,21 @@ class Deletes extends Action
Query::equal('projectInternalId', [$projectInternalId]) Query::equal('projectInternalId', [$projectInternalId])
], $dbForConsole); ], $dbForConsole);
// Delete VCS Installations
$this->deleteByGroup('installations', [
Query::equal('projectInternalId', [$projectInternalId])
], $dbForConsole);
// Delete VCS Repositories
$this->deleteByGroup('repositories', [
Query::equal('projectInternalId', [$projectInternalId]),
], $dbForConsole);
// Delete VCS commments
$this->deleteByGroup('vcsComments', [
Query::equal('projectInternalId', [$projectInternalId]),
], $dbForConsole);
// Delete metadata tables // Delete metadata tables
try { try {
$dbForProject->deleteCollection('_metadata'); $dbForProject->deleteCollection('_metadata');
@ -711,7 +727,7 @@ class Deletes extends Action
$this->deleteDeploymentFiles($functionsStorage, $document); $this->deleteDeploymentFiles($functionsStorage, $document);
}); });
/** /**
* Delete builds * Delete builds
*/ */
Console::info("Deleting builds for function " . $functionId); Console::info("Deleting builds for function " . $functionId);
@ -732,6 +748,22 @@ class Deletes extends Action
Query::equal('functionInternalId', [$functionInternalId]) Query::equal('functionInternalId', [$functionInternalId])
], $dbForProject); ], $dbForProject);
/**
* Delete VCS Repositories and VCS Comments
*/
Console::info("Deleting VCS repositories and comments linked to function " . $functionId);
$this->deleteByGroup('repositories', [
Query::equal('resourceInternalId', [$functionInternalId]),
Query::equal('resourceType', ['function']),
], $dbForConsole, function (Document $document) use ($dbForConsole) {
$providerRepositoryId = $document->getAttribute('providerRepositoryId', '');
$projectId = $document->getAttribute('projectId', '');
$this->deleteByGroup('vcsComments', [
Query::equal('providerRepositoryId', [$providerRepositoryId]),
Query::equal('projectId', [$projectId]),
], $dbForConsole);
});
/** /**
* Request executor to delete all deployment containers * Request executor to delete all deployment containers
*/ */
@ -943,17 +975,28 @@ class Deletes extends Action
$count = 0; $count = 0;
$chunk = 0; $chunk = 0;
$limit = 50; $limit = 50;
$results = [];
$sum = $limit; $sum = $limit;
$cursor = null;
$executionStart = \microtime(true); $executionStart = \microtime(true);
while ($sum === $limit) { while ($sum === $limit) {
$chunk++; $chunk++;
$results = $database->find($collection, \array_merge([Query::limit($limit)], $queries)); $mergedQueries = \array_merge([Query::limit($limit)], $queries);
if ($cursor instanceof Document) {
$mergedQueries[] = Query::cursorAfter($cursor);
}
$results = $database->find($collection, $mergedQueries);
$sum = count($results); $sum = count($results);
if ($sum > 0) {
$cursor = $results[$sum - 1];
}
foreach ($results as $document) { foreach ($results as $document) {
if (is_callable($callback)) { if (is_callable($callback)) {
$callback($document); $callback($document);

View file

@ -25,7 +25,7 @@ class Webhooks extends Action
$this $this
->desc('Webhooks worker') ->desc('Webhooks worker')
->inject('message') ->inject('message')
->callback(fn($message) => $this->action($message)); ->callback(fn ($message) => $this->action($message));
} }
/** /**
@ -48,7 +48,7 @@ class Webhooks extends Action
foreach ($project->getAttribute('webhooks', []) as $webhook) { foreach ($project->getAttribute('webhooks', []) as $webhook) {
if (array_intersect($webhook->getAttribute('events', []), $events)) { if (array_intersect($webhook->getAttribute('events', []), $events)) {
$this->execute($events, $webhookPayload, $webhook, $user, $project); $this->execute($events, $webhookPayload, $webhook, $user, $project);
} }
} }
@ -78,7 +78,9 @@ class Webhooks extends Action
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); \curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
\curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); \curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
\curl_setopt($ch, CURLOPT_HEADER, 0); \curl_setopt($ch, CURLOPT_HEADER, 0);
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); \curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
\curl_setopt($ch, CURLOPT_TIMEOUT, 15);
\curl_setopt($ch, CURLOPT_MAXFILESIZE, 5242880);
\curl_setopt($ch, CURLOPT_USERAGENT, \sprintf( \curl_setopt($ch, CURLOPT_USERAGENT, \sprintf(
APP_USERAGENT, APP_USERAGENT,
App::getEnv('_APP_VERSION', 'UNKNOWN'), App::getEnv('_APP_VERSION', 'UNKNOWN'),
@ -88,16 +90,17 @@ class Webhooks extends Action
$ch, $ch,
CURLOPT_HTTPHEADER, CURLOPT_HTTPHEADER,
[ [
'Content-Type: application/json', 'Content-Type: application/json',
'Content-Length: ' . \strlen($payload), 'Content-Length: ' . \strlen($payload),
'X-' . APP_NAME . '-Webhook-Id: ' . $webhook->getId(), 'X-' . APP_NAME . '-Webhook-Id: ' . $webhook->getId(),
'X-' . APP_NAME . '-Webhook-Events: ' . implode(',', $events), 'X-' . APP_NAME . '-Webhook-Events: ' . implode(',', $events),
'X-' . APP_NAME . '-Webhook-Name: ' . $webhook->getAttribute('name', ''), 'X-' . APP_NAME . '-Webhook-Name: ' . $webhook->getAttribute('name', ''),
'X-' . APP_NAME . '-Webhook-User-Id: ' . $user->getId(), 'X-' . APP_NAME . '-Webhook-User-Id: ' . $user->getId(),
'X-' . APP_NAME . '-Webhook-Project-Id: ' . $project->getId(), 'X-' . APP_NAME . '-Webhook-Project-Id: ' . $project->getId(),
'X-' . APP_NAME . '-Webhook-Signature: ' . $signature, 'X-' . APP_NAME . '-Webhook-Signature: ' . $signature,
] ]
); );
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
if (!$webhook->getAttribute('security', true)) { if (!$webhook->getAttribute('security', true)) {
\curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); \curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

View file

@ -1606,6 +1606,100 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(false, $response['body']['authPersonalDataCheck']); $this->assertEquals(false, $response['body']['authPersonalDataCheck']);
} }
public function testUpdateProjectServicesAll(): void
{
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
]), [
'teamId' => ID::unique(),
'name' => 'Project Test',
]);
$this->assertEquals(201, $team['headers']['status-code']);
$this->assertNotEmpty($team['body']['$id']);
$project = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
]), [
'projectId' => ID::unique(),
'name' => 'Project Test',
'teamId' => $team['body']['$id'],
'region' => 'default'
]);
$this->assertEquals(201, $project['headers']['status-code']);
$this->assertNotEmpty($project['body']['$id']);
$id = $project['body']['$id'];
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service/all', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
]), [
'status' => false,
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
]));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$matches = [];
$pattern = '/serviceStatusFor.*/';
foreach ($response['body'] as $key => $value) {
if (\preg_match($pattern, $key)) {
\var_dump('Matched key: ' . $key);
$matches[$key] = $value;
}
}
foreach ($matches as $value) {
$this->assertFalse($value);
}
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/service/all', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
]), [
'status' => true,
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
]));
$this->assertEquals(200, $response['headers']['status-code']);
$matches = [];
foreach ($response['body'] as $key => $value) {
if (\preg_match($pattern, $key)) {
$matches[$key] = $value;
}
}
foreach ($matches as $value) {
$this->assertTrue($value);
}
}
public function testUpdateProjectServiceStatusAdmin(): array public function testUpdateProjectServiceStatusAdmin(): array
{ {