Merge remote-tracking branch 'origin/1.6.x' into feat-bulk-operations

# Conflicts:
#	composer.lock
This commit is contained in:
Jake Barnby
2025-03-27 18:11:03 +13:00
27 changed files with 296 additions and 525 deletions
+1
View File
@@ -86,6 +86,7 @@ _APP_MAINTENANCE_RETENTION_CACHE=2592000
_APP_MAINTENANCE_RETENTION_EXECUTION=1209600
_APP_MAINTENANCE_RETENTION_ABUSE=86400
_APP_MAINTENANCE_RETENTION_AUDIT=1209600
_APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE=15778800
_APP_USAGE_AGGREGATION_INTERVAL=30
_APP_STATS_RESOURCES_INTERVAL=3600
_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000
+3 -3
View File
@@ -1038,7 +1038,7 @@ return [
'$id' => ID::custom('providerUid'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
'size' => 2048, // Decrease to 128 as in index length?
'signed' => true,
'required' => false,
'default' => null,
@@ -1107,14 +1107,14 @@ return [
'$id' => ID::custom('_key_userInternalId_provider_providerUid'),
'type' => Database::INDEX_UNIQUE,
'attributes' => ['userInternalId', 'provider', 'providerUid'],
'lengths' => [11, 128, 128],
'lengths' => [11, 128, 128], // providerUid is length 2000!
'orders' => [Database::ORDER_ASC, Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_provider_providerUid'),
'type' => Database::INDEX_UNIQUE,
'attributes' => ['provider', 'providerUid'],
'lengths' => [128, 128],
'lengths' => [128, 128], // providerUid is length 2000!
'orders' => [Database::ORDER_ASC, Database::ORDER_ASC],
],
[
+1 -65
View File
@@ -3,72 +3,8 @@
return [
'default' => [
'$id' => 'default',
'name' => 'Frankfurt',
'name' => 'default',
'disabled' => false,
'flag' => 'de',
'default' => true,
],
'fra' => [
'$id' => 'fra',
'name' => 'Frankfurt',
'disabled' => false,
'flag' => 'de',
'default' => true,
],
'nyc' => [
'$id' => 'nyc',
'name' => 'New York',
'disabled' => true,
'flag' => 'us',
'default' => true,
],
'sfo' => [
'$id' => 'sfo',
'name' => 'San Francisco',
'disabled' => true,
'flag' => 'us',
'default' => true,
],
'blr' => [
'$id' => 'blr',
'name' => 'Bengaluru',
'disabled' => true,
'flag' => 'in',
'default' => true,
],
'lon' => [
'$id' => 'lon',
'name' => 'London',
'disabled' => true,
'flag' => 'gb',
'default' => true,
],
'ams' => [
'$id' => 'ams',
'name' => 'Amsterdam',
'disabled' => true,
'flag' => 'nl',
'default' => true,
],
'sgp' => [
'$id' => 'sgp',
'name' => 'Singapore',
'disabled' => true,
'flag' => 'sg',
'default' => true,
],
'tor' => [
'$id' => 'tor',
'name' => 'Toronto',
'disabled' => true,
'flag' => 'ca',
'default' => true,
],
'syd' => [
'$id' => 'syd',
'name' => 'Sydney',
'disabled' => true,
'flag' => 'au',
'default' => true,
],
];
+10 -1
View File
@@ -1048,13 +1048,22 @@ return [
],
[
'name' => '_APP_MAINTENANCE_RETENTION_AUDIT',
'description' => 'IThe maximum duration (in seconds) upto which to retain audit logs. The default value is 1209600 seconds (14 days).',
'description' => 'The maximum duration (in seconds) upto which to retain audit logs. The default value is 1209600 seconds (14 days).',
'introduction' => '0.7.0',
'default' => '1209600',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE',
'description' => 'The maximum duration (in seconds) upto which to retain console audit logs. The default value is 15778800 seconds (6 months).',
'introduction' => '1.6.2',
'default' => '15778800',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_MAINTENANCE_RETENTION_ABUSE',
'description' => 'The maximum duration (in seconds) upto which to retain abuse logs. The default value is 86400 seconds (1 day).',
+4 -4
View File
@@ -3433,7 +3433,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
}
$queueForStatsUsage
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, $operations)
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, max($operations, 1))
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_WRITES), $operations)
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
@@ -3596,7 +3596,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
}
$queueForStatsUsage
->addMetric(METRIC_DATABASES_OPERATIONS_READS, $operations)
->addMetric(METRIC_DATABASES_OPERATIONS_READS, max($operations, 1))
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_READS), $operations);
$response->addHeader('X-Debug-Operations', $operations);
@@ -3737,7 +3737,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
$processDocument($collection, $document);
$queueForStatsUsage
->addMetric(METRIC_DATABASES_OPERATIONS_READS, $operations)
->addMetric(METRIC_DATABASES_OPERATIONS_READS, max($operations, 1))
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_READS), $operations);
$response->addHeader('X-Debug-Operations', $operations);
@@ -4035,7 +4035,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$setCollection($collection, $newDocument);
$queueForStatsUsage
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, $operations)
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, max($operations, 1))
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_WRITES), $operations);
$response->addHeader('X-Debug-Operations', $operations);
+2 -2
View File
@@ -295,7 +295,7 @@ App::post('/v1/functions')
$schedule = Authorization::skip(
fn () => $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'), // Todo replace with projects region
'region' => $project->getAttribute('region'),
'resourceType' => 'function',
'resourceId' => $function->getId(),
'resourceInternalId' => $function->getInternalId(),
@@ -2079,7 +2079,7 @@ App::post('/v1/functions/:functionId/executions')
];
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'),
'region' => $project->getAttribute('region'),
'resourceType' => ScheduleExecutions::getSupportedResource(),
'resourceId' => $execution->getId(),
'resourceInternalId' => $execution->getInternalId(),
+6 -6
View File
@@ -2936,7 +2936,7 @@ App::post('/v1/messaging/messages/email')
break;
case MessageStatus::SCHEDULED:
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'),
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
@@ -3058,7 +3058,7 @@ App::post('/v1/messaging/messages/sms')
break;
case MessageStatus::SCHEDULED:
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'),
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
@@ -3275,7 +3275,7 @@ App::post('/v1/messaging/messages/push')
break;
case MessageStatus::SCHEDULED:
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'),
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
@@ -3661,7 +3661,7 @@ App::patch('/v1/messaging/messages/email/:messageId')
if (\is_null($currentScheduledAt) && !\is_null($scheduledAt)) {
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'),
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
@@ -3862,7 +3862,7 @@ App::patch('/v1/messaging/messages/sms/:messageId')
if (\is_null($currentScheduledAt) && !\is_null($scheduledAt)) {
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'),
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
@@ -4035,7 +4035,7 @@ App::patch('/v1/messaging/messages/push/:messageId')
if (\is_null($currentScheduledAt) && !\is_null($scheduledAt)) {
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'),
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
+4 -1
View File
@@ -615,7 +615,10 @@ App::post('/v1/teams/:teamId/memberships')
$membership = ($isPrivilegedUser || $isAppUser) ?
Authorization::skip(fn () => $dbForProject->createDocument('memberships', $membership)) :
$dbForProject->createDocument('memberships', $membership);
Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
if ($isPrivilegedUser || $isAppUser) {
Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
}
} elseif ($membership->getAttribute('confirm') === false) {
$membership->setAttribute('secret', Auth::hash($secret));
+1
View File
@@ -223,6 +223,7 @@ const METRIC_TOPICS = 'topics';
const METRIC_TARGETS = 'targets';
const METRIC_PROVIDER_TYPE_TARGETS = '{providerType}.targets';
const METRIC_KEYS = 'keys';
const METRIC_DOMAINS = 'domains';
const METRIC_RESOURCE_TYPE_ID_BUILDS = '{resourceType}.{resourceInternalId}.builds';
const METRIC_RESOURCE_TYPE_ID_BUILDS_STORAGE = '{resourceType}.{resourceInternalId}.builds.storage';
const METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS = '{resourceType}.{resourceInternalId}.deployments';
+1 -1
View File
@@ -217,7 +217,7 @@ $register->set('pools', function () {
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_PERSISTENT => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => true,
PDO::ATTR_STRINGIFY_FETCHES => true
+3 -1
View File
@@ -148,6 +148,7 @@ $image = $this->getParam('image', '');
- _APP_MAINTENANCE_RETENTION_CACHE
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES
- _APP_SMS_PROVIDER
@@ -164,7 +165,6 @@ $image = $this->getParam('image', '');
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
- _APP_ASSISTANT_OPENAI_API_KEY
appwrite-console:
<<: *x-logging
container_name: appwrite-console
@@ -341,6 +341,7 @@ $image = $this->getParam('image', '');
- _APP_EXECUTOR_HOST
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_EXECUTION
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
- _APP_EMAIL_CERTIFICATES
@@ -652,6 +653,7 @@ $image = $this->getParam('image', '');
- _APP_MAINTENANCE_RETENTION_CACHE
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES
+8 -7
View File
@@ -16,8 +16,6 @@ use Appwrite\Event\Migration;
use Appwrite\Event\Realtime;
use Appwrite\Event\StatsUsage;
use Appwrite\Event\StatsUsageDump;
/** remove */
/** /remove */
use Appwrite\Event\Webhook;
use Appwrite\Platform\Appwrite;
use Swoole\Runtime;
@@ -215,15 +213,18 @@ Server::setResource('getLogsDB', function (Group $pools, Cache $cache) {
}, ['pools', 'cache']);
Server::setResource('abuseRetention', function () {
return time() - (int) System::getEnv('_APP_MAINTENANCE_RETENTION_ABUSE', 86400);
return time() - (int) System::getEnv('_APP_MAINTENANCE_RETENTION_ABUSE', 86400); // 1 day
});
Server::setResource('auditRetention', function () {
return DateTime::addSeconds(new \DateTime(), -1 * System::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT', 1209600));
});
Server::setResource('auditRetention', function (Document $project) {
if ($project->getId() === 'console') {
return DateTime::addSeconds(new \DateTime(), -1 * System::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE', 15778800)); // 6 months
}
return DateTime::addSeconds(new \DateTime(), -1 * System::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT', 1209600)); // 14 days
}, ['project']);
Server::setResource('executionRetention', function () {
return DateTime::addSeconds(new \DateTime(), -1 * System::getEnv('_APP_MAINTENANCE_RETENTION_EXECUTION', 1209600));
return DateTime::addSeconds(new \DateTime(), -1 * System::getEnv('_APP_MAINTENANCE_RETENTION_EXECUTION', 1209600)); // 14 days
});
Server::setResource('cache', function (Registry $register) {
+3 -3
View File
@@ -51,7 +51,7 @@
"utopia-php/cache": "0.12.*",
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.61.*",
"utopia-php/database": "0.62.*",
"utopia-php/domains": "0.5.*",
"utopia-php/dsn": "0.2.1",
"utopia-php/framework": "0.33.*",
@@ -60,10 +60,10 @@
"utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.6.*",
"utopia-php/messaging": "0.16.*",
"utopia-php/migration": "0.6.*",
"utopia-php/migration": "0.8.*",
"utopia-php/orchestration": "0.9.*",
"utopia-php/platform": "0.7.*",
"utopia-php/pools": "0.5.*",
"utopia-php/pools": "0.7.*",
"utopia-php/preloader": "0.2.*",
"utopia-php/queue": "0.9.*",
"utopia-php/registry": "0.5.*",
Generated
+46 -314
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "54fc27a2c8d4f5ab4959dbc93be319e1",
"content-hash": "d2bec8137dcd84994121f89a29932d31",
"packages": [
{
"name": "adhocore/jwt",
@@ -751,65 +751,6 @@
},
"time": "2025-03-13T21:08:17+00:00"
},
{
"name": "jean85/pretty-package-versions",
"version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/Jean85/pretty-package-versions.git",
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.1.0",
"php": "^7.4|^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.2",
"jean85/composer-provided-replaced-stub-package": "^1.0",
"phpstan/phpstan": "^1.4",
"phpunit/phpunit": "^7.5|^8.5|^9.6",
"vimeo/psalm": "^4.3 || ^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Jean85\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alessandro Lai",
"email": "alessandro.lai85@gmail.com"
}
],
"description": "A library to get pretty versions strings of installed dependencies",
"keywords": [
"composer",
"package",
"release",
"versions"
],
"support": {
"issues": "https://github.com/Jean85/pretty-package-versions/issues",
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0"
},
"time": "2024-11-18T16:19:46+00:00"
},
{
"name": "league/csv",
"version": "9.14.0",
@@ -968,75 +909,6 @@
},
"time": "2023-10-02T10:01:54+00:00"
},
{
"name": "mongodb/mongodb",
"version": "1.10.0",
"source": {
"type": "git",
"url": "https://github.com/mongodb/mongo-php-library.git",
"reference": "b0bbd657f84219212487d01a8ffe93a789e1e488"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/b0bbd657f84219212487d01a8ffe93a789e1e488",
"reference": "b0bbd657f84219212487d01a8ffe93a789e1e488",
"shasum": ""
},
"require": {
"ext-hash": "*",
"ext-json": "*",
"ext-mongodb": "^1.11.0",
"jean85/pretty-package-versions": "^1.2 || ^2.0.1",
"php": "^7.1 || ^8.0",
"symfony/polyfill-php80": "^1.19"
},
"require-dev": {
"doctrine/coding-standard": "^9.0",
"squizlabs/php_codesniffer": "^3.6",
"symfony/phpunit-bridge": "^5.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.10.x-dev"
}
},
"autoload": {
"files": [
"src/functions.php"
],
"psr-4": {
"MongoDB\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Andreas Braun",
"email": "andreas.braun@mongodb.com"
},
{
"name": "Jeremy Mikola",
"email": "jmikola@gmail.com"
}
],
"description": "MongoDB driver library",
"homepage": "https://jira.mongodb.org/browse/PHPLIB",
"keywords": [
"database",
"driver",
"mongodb",
"persistence"
],
"support": {
"issues": "https://github.com/mongodb/mongo-php-library/issues",
"source": "https://github.com/mongodb/mongo-php-library/tree/1.10.0"
},
"time": "2021-10-20T22:22:37+00:00"
},
{
"name": "mustangostang/spyc",
"version": "0.6.3",
@@ -2371,16 +2243,16 @@
},
{
"name": "ramsey/collection",
"version": "2.1.0",
"version": "2.1.1",
"source": {
"type": "git",
"url": "https://github.com/ramsey/collection.git",
"reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109"
"reference": "344572933ad0181accbf4ba763e85a0306a8c5e2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/collection/zipball/3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109",
"reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109",
"url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2",
"reference": "344572933ad0181accbf4ba763e85a0306a8c5e2",
"shasum": ""
},
"require": {
@@ -2441,9 +2313,9 @@
],
"support": {
"issues": "https://github.com/ramsey/collection/issues",
"source": "https://github.com/ramsey/collection/tree/2.1.0"
"source": "https://github.com/ramsey/collection/tree/2.1.1"
},
"time": "2025-03-02T04:48:29+00:00"
"time": "2025-03-22T05:38:12+00:00"
},
{
"name": "ramsey/uuid",
@@ -2932,86 +2804,6 @@
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-php82",
"version": "v1.31.0",
@@ -3705,16 +3497,16 @@
},
{
"name": "utopia-php/database",
"version": "0.61.2",
"version": "0.62.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "349fbdf4bc088f7775c7dfb8b80239a617a88436"
"reference": "65dc51466c12552add10395900cdbb4728da4068"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/349fbdf4bc088f7775c7dfb8b80239a617a88436",
"reference": "349fbdf4bc088f7775c7dfb8b80239a617a88436",
"url": "https://api.github.com/repos/utopia-php/database/zipball/65dc51466c12552add10395900cdbb4728da4068",
"reference": "65dc51466c12552add10395900cdbb4728da4068",
"shasum": ""
},
"require": {
@@ -3722,8 +3514,7 @@
"ext-pdo": "*",
"php": ">=8.1",
"utopia-php/cache": "0.12.*",
"utopia-php/framework": "0.33.*",
"utopia-php/mongo": "0.3.*"
"utopia-php/framework": "0.33.*"
},
"require-dev": {
"fakerphp/faker": "1.23.*",
@@ -3755,9 +3546,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.61.2"
"source": "https://github.com/utopia-php/database/tree/0.62.1"
},
"time": "2025-03-15T11:47:42+00:00"
"time": "2025-03-24T08:27:18+00:00"
},
{
"name": "utopia-php/domains",
@@ -4159,16 +3950,16 @@
},
{
"name": "utopia-php/migration",
"version": "0.6.22",
"version": "0.8.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/migration.git",
"reference": "a0269746bd318ff0993f5aa008675b971689d5b5"
"reference": "aa3b7a508feb7090f487e7bf9cd71f5c92fbc7c1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/a0269746bd318ff0993f5aa008675b971689d5b5",
"reference": "a0269746bd318ff0993f5aa008675b971689d5b5",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/aa3b7a508feb7090f487e7bf9cd71f5c92fbc7c1",
"reference": "aa3b7a508feb7090f487e7bf9cd71f5c92fbc7c1",
"shasum": ""
},
"require": {
@@ -4176,7 +3967,7 @@
"ext-curl": "*",
"ext-openssl": "*",
"php": ">=8.1",
"utopia-php/database": "0.61.*",
"utopia-php/database": "0.62.*",
"utopia-php/dsn": "0.2.*",
"utopia-php/framework": "0.33.*",
"utopia-php/storage": "0.18.*"
@@ -4209,69 +4000,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/migration/issues",
"source": "https://github.com/utopia-php/migration/tree/0.6.22"
"source": "https://github.com/utopia-php/migration/tree/0.8.2"
},
"time": "2025-03-13T07:35:55+00:00"
},
{
"name": "utopia-php/mongo",
"version": "0.3.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/mongo.git",
"reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/mongo/zipball/52326a9a43e2d27ff0c15c48ba746dacbe9a7aee",
"reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee",
"shasum": ""
},
"require": {
"ext-mongodb": "*",
"mongodb/mongodb": "1.10.0",
"php": ">=8.0"
},
"require-dev": {
"fakerphp/faker": "^1.14",
"laravel/pint": "1.2.*",
"phpstan/phpstan": "1.8.*",
"phpunit/phpunit": "^9.4",
"swoole/ide-helper": "4.8.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Utopia\\Mongo\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Eldad Fux",
"email": "eldad@appwrite.io"
},
{
"name": "Wess",
"email": "wess@appwrite.io"
}
],
"description": "A simple library to manage Mongo database",
"keywords": [
"database",
"mongo",
"php",
"upf",
"utopia"
],
"support": {
"issues": "https://github.com/utopia-php/mongo/issues",
"source": "https://github.com/utopia-php/mongo/tree/0.3.1"
},
"time": "2023-09-01T17:25:28+00:00"
"time": "2025-03-24T09:05:31+00:00"
},
{
"name": "utopia-php/orchestration",
@@ -4375,25 +4106,26 @@
},
{
"name": "utopia-php/pools",
"version": "0.5.0",
"version": "0.7.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/pools.git",
"reference": "6f716a213a08db95eda1b5dddfa90983c1834817"
"reference": "ad64d45afda08ec8b29e2642a8d18075964d40bf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/pools/zipball/6f716a213a08db95eda1b5dddfa90983c1834817",
"reference": "6f716a213a08db95eda1b5dddfa90983c1834817",
"url": "https://api.github.com/repos/utopia-php/pools/zipball/ad64d45afda08ec8b29e2642a8d18075964d40bf",
"reference": "ad64d45afda08ec8b29e2642a8d18075964d40bf",
"shasum": ""
},
"require": {
"php": ">=8.0"
"php": ">=8.3",
"utopia-php/telemetry": "0.1.*"
},
"require-dev": {
"laravel/pint": "1.2.*",
"phpstan/phpstan": "1.8.*",
"phpunit/phpunit": "^9.3"
"laravel/pint": "1.*",
"phpstan/phpstan": "1.*",
"phpunit/phpunit": "11.*"
},
"type": "library",
"autoload": {
@@ -4420,9 +4152,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/pools/issues",
"source": "https://github.com/utopia-php/pools/tree/0.5.0"
"source": "https://github.com/utopia-php/pools/tree/0.7.0"
},
"time": "2024-04-19T11:11:54+00:00"
"time": "2025-03-18T03:55:33+00:00"
},
{
"name": "utopia-php/preloader",
@@ -4760,16 +4492,16 @@
},
{
"name": "utopia-php/telemetry",
"version": "0.1.0",
"version": "0.1.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/telemetry.git",
"reference": "d35f2f0632f4ee0be63fb7ace6a94a6adda71a80"
"reference": "437f0021777f0e575dfb9e8a1a081b3aed75e33f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/telemetry/zipball/d35f2f0632f4ee0be63fb7ace6a94a6adda71a80",
"reference": "d35f2f0632f4ee0be63fb7ace6a94a6adda71a80",
"url": "https://api.github.com/repos/utopia-php/telemetry/zipball/437f0021777f0e575dfb9e8a1a081b3aed75e33f",
"reference": "437f0021777f0e575dfb9e8a1a081b3aed75e33f",
"shasum": ""
},
"require": {
@@ -4790,7 +4522,7 @@
"type": "library",
"autoload": {
"psr-4": {
"Utopia\\": "src/"
"Utopia\\Telemetry\\": "src/Telemetry"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -4804,9 +4536,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/telemetry/issues",
"source": "https://github.com/utopia-php/telemetry/tree/0.1.0"
"source": "https://github.com/utopia-php/telemetry/tree/0.1.1"
},
"time": "2024-11-13T10:29:53+00:00"
"time": "2025-03-17T11:57:52+00:00"
},
{
"name": "utopia-php/vcs",
@@ -5043,16 +4775,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "0.40.7",
"version": "0.40.9",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "9e89b0bc4d8e6c81817d27096629f34a149fa873"
"reference": "dbb45a5db22cdc3368fe2573c07ba6088f188fa4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/9e89b0bc4d8e6c81817d27096629f34a149fa873",
"reference": "9e89b0bc4d8e6c81817d27096629f34a149fa873",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/dbb45a5db22cdc3368fe2573c07ba6088f188fa4",
"reference": "dbb45a5db22cdc3368fe2573c07ba6088f188fa4",
"shasum": ""
},
"require": {
@@ -5088,9 +4820,9 @@
"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.40.7"
"source": "https://github.com/appwrite/sdk-generator/tree/0.40.9"
},
"time": "2025-03-12T08:43:55+00:00"
"time": "2025-03-17T18:39:14+00:00"
},
{
"name": "doctrine/annotations",
@@ -8402,7 +8134,7 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
+7 -3
View File
@@ -171,6 +171,7 @@ services:
- _APP_MAINTENANCE_RETENTION_CACHE
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES
- _APP_SMS_PROVIDER
@@ -389,6 +390,8 @@ services:
- _APP_DATABASE_SHARED_TABLES
- _APP_DATABASE_SHARED_TABLES_V1
- _APP_EMAIL_CERTIFICATES
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
appwrite-worker-databases:
entrypoint: worker-databases
@@ -721,6 +724,7 @@ services:
- _APP_MAINTENANCE_RETENTION_CACHE
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES
- _APP_MAINTENANCE_DELAY
@@ -756,7 +760,7 @@ services:
- _APP_LOGGING_CONFIG
- _APP_DATABASE_SHARED_TABLES
- _APP_STATS_RESOURCES_INTERVAL
appwrite-worker-stats-resources:
entrypoint: worker-stats-resources
<<: *x-logging
@@ -787,7 +791,7 @@ services:
- _APP_LOGGING_CONFIG
- _APP_USAGE_AGGREGATION_INTERVAL
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-stats-usage:
entrypoint: worker-stats-usage
<<: *x-logging
@@ -850,7 +854,7 @@ services:
- _APP_USAGE_AGGREGATION_INTERVAL
- _APP_DATABASE_SHARED_TABLES
- _APP_STATS_USAGE_DUAL_WRITING_DBS
appwrite-task-scheduler-functions:
entrypoint: schedule-functions
<<: *x-logging
+1 -1
View File
@@ -6,7 +6,7 @@
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
stopOnFailure="true"
>
<extensions>
<extension class="Appwrite\Tests\TestHook" />
+1 -2
View File
@@ -10,7 +10,6 @@ use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Exception;
use Utopia\Database\Query;
use Utopia\System\System;
class V19 extends Migration
{
@@ -731,7 +730,7 @@ class V19 extends Migration
if (empty($document->getAttribute('scheduleId', null))) {
$schedule = $this->consoleDB->createDocument('schedules', new Document([
'region' => System::getEnv('_APP_REGION', 'default'), // Todo replace with projects region
'region' => $project->getAttribute('region'),
'resourceType' => 'function',
'resourceId' => $document->getId(),
'resourceInternalId' => $document->getInternalId(),
+4 -29
View File
@@ -47,13 +47,15 @@ class Maintenance extends Action
Console::info("[{$time}] Notifying workers with maintenance tasks every {$interval} seconds");
$this->foreachProject($dbForPlatform, function (Document $project) use ($queueForDeletes, $usageStatsRetentionHourly) {
$dbForPlatform->foreach('projects', function (Document $project) use ($queueForDeletes, $usageStatsRetentionHourly) {
$queueForDeletes
->setType(DELETE_TYPE_MAINTENANCE)
->setProject($project)
->setUsageRetentionHourlyDateTime(DateTime::addSeconds(new \DateTime(), -1 * $usageStatsRetentionHourly))
->trigger();
});
}, [
Query::limit(100),
]);
$queueForDeletes
->setType(DELETE_TYPE_MAINTENANCE)
@@ -68,33 +70,6 @@ class Maintenance extends Action
}, $interval, $delay);
}
protected function foreachProject(Database $dbForPlatform, callable $callback): void
{
// TODO: @Meldiron name of this method no longer matches. It does not delete, and it gives whole document
$count = 0;
$chunk = 0;
$limit = 50;
$sum = $limit;
$executionStart = \microtime(true);
while ($sum === $limit) {
$projects = $dbForPlatform->find('projects', [Query::limit($limit), Query::offset($chunk * $limit)]);
$chunk++;
/** @var string[] $projectIds */
$sum = count($projects);
foreach ($projects as $project) {
$callback($project);
$count++;
}
}
$executionEnd = \microtime(true);
Console::info("Found {$count} projects " . ($executionEnd - $executionStart) . " seconds");
}
private function notifyDeleteConnections(Delete $queueForDeletes): void
{
$queueForDeletes
+16 -2
View File
@@ -103,8 +103,15 @@ abstract class ScheduleBase extends Action
$paginationQueries[] = Query::cursorAfter($latestDocument);
}
// Temporarly accepting both 'fra' and 'default'
// When all migrated, only use _APP_REGION with 'default' as default value
$regions = [System::getEnv('_APP_REGION', 'default')];
if (!in_array('default', $regions)) {
$regions[] = 'default';
}
$results = $dbForPlatform->find('schedules', \array_merge($paginationQueries, [
Query::equal('region', [System::getEnv('_APP_REGION', 'default')]),
Query::equal('region', $regions),
Query::equal('resourceType', [static::getSupportedResource()]),
Query::equal('active', [true]),
]));
@@ -153,8 +160,15 @@ abstract class ScheduleBase extends Action
$paginationQueries[] = Query::cursorAfter($latestDocument);
}
// Temporarly accepting both 'fra' and 'default'
// When all migrated, only use _APP_REGION with 'default' as default value
$regions = [System::getEnv('_APP_REGION', 'default')];
if (!in_array('default', $regions)) {
$regions[] = 'default';
}
$results = $dbForPlatform->find('schedules', \array_merge($paginationQueries, [
Query::equal('region', [System::getEnv('_APP_REGION', 'default')]),
Query::equal('region', $regions),
Query::equal('resourceType', [static::getSupportedResource()]),
Query::greaterThanEqual('resourceUpdatedAt', $lastSyncUpdate),
]));
+26 -23
View File
@@ -12,12 +12,12 @@ use Utopia\Database\Exception\Authorization;
use Utopia\Database\Exception\Structure;
use Utopia\Platform\Action;
use Utopia\Queue\Message;
use Utopia\Queue\Result\Commit;
use Utopia\Queue\Result\NoCommit;
use Utopia\System\System;
class Audits extends Action
{
protected const BATCH_SIZE_DEVELOPMENT = 1; // smaller batch size for development
protected const BATCH_SIZE_PRODUCTION = 5_000;
protected const BATCH_AGGREGATION_INTERVAL = 60; // in seconds
private int $lastTriggeredTime = 0;
@@ -27,9 +27,7 @@ class Audits extends Action
protected function getBatchSize(): int
{
return System::getEnv('_APP_ENV', 'development') === 'development'
? self::BATCH_SIZE_DEVELOPMENT
: self::BATCH_SIZE_PRODUCTION;
return intval(System::getEnv('_APP_QUEUE_PREFETCH_COUNT', 1));
}
public static function getName(): string
@@ -57,13 +55,13 @@ class Audits extends Action
* @param Message $message
* @param callable $getProjectDB
* @param Document $project
* @return void
* @return Commit|NoCommit
* @throws Throwable
* @throws \Utopia\Database\Exception
* @throws Authorization
* @throws Structure
*/
public function action(Message $message, callable $getProjectDB, Document $project): void
public function action(Message $message, callable $getProjectDB, Document $project): Commit|NoCommit
{
$payload = $message->getPayload() ?? [];
@@ -119,29 +117,34 @@ class Audits extends Action
// Check if we should process the batch by checking both for the batch size and the elapsed time
$batchSize = $this->getBatchSize();
$shouldProcessBatch = \count($this->logs) >= $batchSize;
if (!$shouldProcessBatch && \count($this->logs) > 0) {
$logCount = array_reduce($this->logs, fn (int $current, $logs) => $current + count($logs), 0);
$shouldProcessBatch = $logCount >= $batchSize;
if (!$shouldProcessBatch && $logCount > 0) {
$shouldProcessBatch = (\time() - $this->lastTriggeredTime) >= self::BATCH_AGGREGATION_INTERVAL;
}
if ($shouldProcessBatch) {
try {
foreach ($this->logs as $internalId => $projectLogs) {
$dbForProject = $getProjectDB($projectLogs['project']);
if (!$shouldProcessBatch) {
return new NoCommit();
}
Console::log('Processing batch with ' . count($projectLogs['logs']) . ' events');
$audit = new Audit($dbForProject);
try {
foreach ($this->logs as $internalId => $projectLogs) {
$dbForProject = $getProjectDB($projectLogs['project']);
$audit->logBatch($projectLogs['logs']);
Console::success('Audit logs processed successfully');
Console::log('Processing batch with ' . count($projectLogs['logs']) . ' events');
$audit = new Audit($dbForProject);
unset($this->logs[$internalId]);
}
} catch (Throwable $e) {
Console::error('Error processing audit logs: ' . $e->getMessage());
} finally {
$this->lastTriggeredTime = time();
$audit->logBatch($projectLogs['logs']);
Console::success('Audit logs processed successfully');
unset($this->logs[$internalId]);
}
return new Commit();
} catch (Throwable $e) {
Console::error('Error processing audit logs: ' . $e->getMessage());
return new NoCommit();
} finally {
$this->lastTriggeredTime = time();
}
}
}
+113 -42
View File
@@ -31,6 +31,8 @@ use Utopia\System\System;
class Deletes extends Action
{
protected array $selects = ['$internalId', '$id', '$collection', '$permissions', '$updatedAt'];
public static function getName(): string
{
return 'deletes';
@@ -180,10 +182,17 @@ class Deletes extends Action
*/
private function deleteSchedules(Database $dbForPlatform, callable $getProjectDB, string $datetime): void
{
// Temporarly accepting both 'fra' and 'default'
// When all migrated, only use _APP_REGION with 'default' as default value
$regions = [System::getEnv('_APP_REGION', 'default')];
if (!in_array('default', $regions)) {
$regions[] = 'default';
}
$this->listByGroup(
'schedules',
[
Query::equal('region', [System::getEnv('_APP_REGION', 'default')]),
Query::equal('region', $regions),
Query::lessThanEqual('resourceUpdatedAt', $datetime),
Query::equal('active', [false]),
],
@@ -248,7 +257,8 @@ class Deletes extends Action
$this->deleteByGroup(
'subscribers',
[
Query::equal('topicInternalId', [$topic->getInternalId()])
Query::equal('topicInternalId', [$topic->getInternalId()]),
Query::orderAsc(),
],
$getProjectDB($project)
);
@@ -269,7 +279,8 @@ class Deletes extends Action
$this->deleteByGroup(
'subscribers',
[
Query::equal('targetInternalId', [$target->getInternalId()])
Query::equal('targetInternalId', [$target->getInternalId()]),
Query::orderAsc(),
],
$dbForProject,
function (Document $subscriber) use ($dbForProject, $target) {
@@ -306,7 +317,8 @@ class Deletes extends Action
$this->deleteByGroup(
'targets',
[
Query::equal('expired', [true])
Query::equal('expired', [true]),
Query::orderAsc(),
],
$getProjectDB($project),
function (Document $target) use ($getProjectDB, $project) {
@@ -320,7 +332,8 @@ class Deletes extends Action
$this->deleteByGroup(
'targets',
[
Query::equal('sessionInternalId', [$session->getInternalId()])
Query::equal('sessionInternalId', [$session->getInternalId()]),
Query::orderAsc(),
],
$getProjectDB($project),
function (Document $target) use ($getProjectDB, $project) {
@@ -347,14 +360,20 @@ class Deletes extends Action
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId)
);
$query[] = Query::equal('resource', [$resource]);
$queries = [
Query::equal('resource', [$resource])
];
if (!empty($resourceType)) {
$query[] = Query::equal('resourceType', [$resourceType]);
$queries[] = Query::equal('resourceType', [$resourceType]);
}
$queries[] = Query::select($this->selects);
$queries[] = Query::orderAsc();
$this->deleteByGroup(
'cache',
$query,
$queries,
$dbForProject,
function (Document $document) use ($cache, $projectId) {
$path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId();
@@ -385,15 +404,16 @@ class Deletes extends Action
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId)
);
$query = [
$queries = [
Query::select($this->selects),
Query::lessThan('accessedAt', $datetime),
Query::orderDesc('accessedAt'),
Query::orderDesc('$internalId'),
Query::orderDesc(),
];
$this->deleteByGroup(
'cache',
$query,
$queries,
$dbForProject,
function (Document $document) use ($cache, $projectId) {
$path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId();
@@ -421,10 +441,11 @@ class Deletes extends Action
// Delete Usage stats from projectDB
$this->deleteByGroup('stats', [
Query::select($this->selects),
Query::equal('period', ['1h']),
Query::lessThan('time', $hourlyUsageRetentionDatetime),
Query::orderDesc('time'),
Query::orderDesc('$internalId'),
Query::equal('period', ['1h']),
Query::orderDesc(),
], $dbForProject);
if ($project->getId() !== 'console') {
@@ -433,10 +454,11 @@ class Deletes extends Action
// Delete Usage stats from logsDB
$this->deleteByGroup('stats', [
Query::select($this->selects),
Query::equal('period', ['1h']),
Query::lessThan('time', $hourlyUsageRetentionDatetime),
Query::orderDesc('time'),
Query::orderDesc('$internalId'),
Query::equal('period', ['1h']),
Query::orderDesc(),
], $dbForLogs);
}
}
@@ -457,7 +479,8 @@ class Deletes extends Action
$this->deleteByGroup(
'memberships',
[
Query::equal('teamInternalId', [$teamInternalId])
Query::equal('teamInternalId', [$teamInternalId]),
Query::orderAsc()
],
$dbForProject,
function (Document $membership) use ($dbForProject) {
@@ -547,7 +570,13 @@ class Deletes extends Action
if ($projectTables || !\in_array($collection->getId(), $projectCollectionIds)) {
$dbForProject->deleteCollection($collection->getId());
} else {
$this->deleteByGroup($collection->getId(), [], database: $dbForProject);
$this->deleteByGroup(
$collection->getId(),
[
Query::orderAsc()
],
database: $dbForProject
);
}
} catch (Throwable $e) {
Console::error('Error deleting '.$collection->getId().' '.$e->getMessage());
@@ -567,58 +596,78 @@ class Deletes extends Action
// Delete Platforms
$this->deleteByGroup('platforms', [
Query::equal('projectInternalId', [$projectInternalId])
Query::equal('projectInternalId', [$projectInternalId]),
Query::orderAsc()
], $dbForPlatform);
// Delete project and function rules
$this->deleteByGroup('rules', [
Query::equal('projectInternalId', [$projectInternalId])
Query::equal('projectInternalId', [$projectInternalId]),
Query::orderAsc()
], $dbForPlatform, function (Document $document) use ($dbForPlatform, $certificates) {
$this->deleteRule($dbForPlatform, $document, $certificates);
});
// Delete Keys
$this->deleteByGroup('keys', [
Query::equal('projectInternalId', [$projectInternalId])
Query::equal('projectInternalId', [$projectInternalId]),
Query::orderAsc()
], $dbForPlatform);
// Delete Webhooks
$this->deleteByGroup('webhooks', [
Query::equal('projectInternalId', [$projectInternalId])
Query::equal('projectInternalId', [$projectInternalId]),
Query::orderAsc()
], $dbForPlatform);
// Delete VCS Installations
$this->deleteByGroup('installations', [
Query::equal('projectInternalId', [$projectInternalId])
Query::equal('projectInternalId', [$projectInternalId]),
Query::orderAsc()
], $dbForPlatform);
// Delete VCS Repositories
$this->deleteByGroup('repositories', [
Query::equal('projectInternalId', [$projectInternalId]),
Query::orderAsc()
], $dbForPlatform);
// Delete VCS comments
$this->deleteByGroup('vcsComments', [
Query::equal('projectInternalId', [$projectInternalId]),
Query::orderAsc()
], $dbForPlatform);
// Delete Schedules (No projectInternalId in this collection)
// Delete Schedules
$this->deleteByGroup('schedules', [
Query::equal('projectId', [$projectId]),
Query::orderAsc()
], $dbForPlatform);
// Delete metadata table
if ($projectTables) {
$dbForProject->deleteCollection(Database::METADATA);
} elseif ($sharedTablesV1) {
$this->deleteByGroup(Database::METADATA, [], $dbForProject);
$this->deleteByGroup(
Database::METADATA,
[
Query::orderAsc()
],
$dbForProject
);
} elseif ($sharedTablesV2) {
$queries = \array_map(
fn ($id) => Query::notEqual('$id', $id),
$projectCollectionIds
);
$this->deleteByGroup(Database::METADATA, $queries, $dbForProject);
$queries[] = Query::orderAsc();
$this->deleteByGroup(
Database::METADATA,
$queries,
$dbForProject
);
}
// Delete all storage directories
@@ -643,14 +692,16 @@ class Deletes extends Action
// Delete all sessions of this user from the sessions table and update the sessions field of the user record
$this->deleteByGroup('sessions', [
Query::equal('userInternalId', [$userInternalId])
Query::equal('userInternalId', [$userInternalId]),
Query::orderAsc()
], $dbForProject);
$dbForProject->purgeCachedDocument('users', $userId);
// Delete Memberships and decrement team membership counts
$this->deleteByGroup('memberships', [
Query::equal('userInternalId', [$userInternalId])
Query::equal('userInternalId', [$userInternalId]),
Query::orderAsc()
], $dbForProject, function (Document $document) use ($dbForProject) {
if ($document->getAttribute('confirm')) { // Count only confirmed members
$teamId = $document->getAttribute('teamId');
@@ -663,19 +714,22 @@ class Deletes extends Action
// Delete tokens
$this->deleteByGroup('tokens', [
Query::equal('userInternalId', [$userInternalId])
Query::equal('userInternalId', [$userInternalId]),
Query::orderAsc()
], $dbForProject);
// Delete identities
$this->deleteByGroup('identities', [
Query::equal('userInternalId', [$userInternalId])
Query::equal('userInternalId', [$userInternalId]),
Query::orderAsc()
], $dbForProject);
// Delete targets
$this->deleteByGroup(
'targets',
[
Query::equal('userInternalId', [$userInternalId])
Query::equal('userInternalId', [$userInternalId]),
Query::orderAsc()
],
$dbForProject,
function (Document $target) use ($getProjectDB, $project) {
@@ -697,9 +751,10 @@ class Deletes extends Action
// Delete Executions
$this->deleteByGroup('executions', [
Query::select($this->selects),
Query::lessThan('$createdAt', $datetime),
Query::orderDesc('$createdAt'),
Query::orderDesc('$internalId'),
Query::orderDesc(),
], $dbForProject);
}
@@ -717,9 +772,10 @@ class Deletes extends Action
// Delete Sessions
$this->deleteByGroup('sessions', [
Query::select($this->selects),
Query::lessThan('$createdAt', $expired),
Query::orderDesc('$createdAt'),
Query::orderDesc('$internalId'),
Query::orderDesc(),
], $dbForProject);
}
@@ -735,14 +791,14 @@ class Deletes extends Action
$this->deleteByGroup('realtime', [
Query::lessThan('timestamp', $datetime),
Query::orderDesc('timestamp'),
Query::orderDesc('$internalId'),
Query::orderAsc(),
], $dbForPlatform);
}
/**
* @param Database $dbForPlatform
* @param callable $getProjectDB
* @param string $datetime
* @param string $auditRetention
* @return void
* @throws Exception
*/
@@ -753,9 +809,10 @@ class Deletes extends Action
try {
$this->deleteByGroup(Audit::COLLECTION, [
Query::select($this->selects),
Query::lessThan('time', $auditRetention),
Query::orderDesc('time'),
Query::orderDesc('$internalId'),
Query::orderAsc(),
], $dbForProject);
} catch (DatabaseException $e) {
Console::error('Failed to delete audit logs for project ' . $projectId . ': ' . $e->getMessage());
@@ -783,9 +840,10 @@ class Deletes extends Action
*/
Console::info("Deleting rules for function " . $functionId);
$this->deleteByGroup('rules', [
Query::equal('resourceType', ['function']),
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('resourceInternalId', [$functionInternalId]),
Query::equal('projectInternalId', [$project->getInternalId()])
Query::equal('resourceType', ['function']),
Query::orderAsc()
], $dbForPlatform, function (Document $document) use ($project, $dbForPlatform, $certificates) {
$this->deleteRule($dbForPlatform, $document, $certificates);
});
@@ -795,8 +853,9 @@ class Deletes extends Action
*/
Console::info("Deleting variables for function " . $functionId);
$this->deleteByGroup('variables', [
Query::equal('resourceInternalId', [$functionInternalId]),
Query::equal('resourceType', ['function']),
Query::equal('resourceInternalId', [$functionInternalId])
Query::orderAsc()
], $dbForProject);
/**
@@ -806,7 +865,8 @@ class Deletes extends Action
$deploymentInternalIds = [];
$this->deleteByGroup('deployments', [
Query::equal('resourceInternalId', [$functionInternalId])
Query::equal('resourceInternalId', [$functionInternalId]),
Query::orderAsc()
], $dbForProject, function (Document $document) use ($deviceForFunctions, &$deploymentInternalIds) {
$deploymentInternalIds[] = $document->getInternalId();
$this->deleteDeploymentFiles($deviceForFunctions, $document);
@@ -819,7 +879,8 @@ class Deletes extends Action
foreach ($deploymentInternalIds as $deploymentInternalId) {
$this->deleteByGroup('builds', [
Query::equal('deploymentInternalId', [$deploymentInternalId])
Query::equal('deploymentInternalId', [$deploymentInternalId]),
Query::orderAsc()
], $dbForProject, function (Document $document) use ($deviceForBuilds) {
$this->deleteBuildFiles($deviceForBuilds, $document);
});
@@ -830,7 +891,9 @@ class Deletes extends Action
*/
Console::info("Deleting executions for function " . $functionId);
$this->deleteByGroup('executions', [
Query::equal('functionInternalId', [$functionInternalId])
Query::select($this->selects),
Query::equal('functionInternalId', [$functionInternalId]),
Query::orderAsc()
], $dbForProject);
/**
@@ -841,12 +904,15 @@ class Deletes extends Action
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('resourceInternalId', [$functionInternalId]),
Query::equal('resourceType', ['function']),
Query::orderAsc()
], $dbForPlatform, function (Document $document) use ($dbForPlatform) {
$providerRepositoryId = $document->getAttribute('providerRepositoryId', '');
$projectInternalId = $document->getAttribute('projectInternalId', '');
$this->deleteByGroup('vcsComments', [
Query::equal('providerRepositoryId', [$providerRepositoryId]),
Query::equal('projectInternalId', [$projectInternalId]),
Query::orderAsc()
], $dbForPlatform);
});
@@ -946,7 +1012,8 @@ class Deletes extends Action
Console::info("Deleting builds for deployment " . $deploymentId);
$this->deleteByGroup('builds', [
Query::equal('deploymentInternalId', [$deploymentInternalId])
Query::equal('deploymentInternalId', [$deploymentInternalId]),
Query::orderAsc()
], $dbForProject, function (Document $document) use ($deviceForBuilds) {
$this->deleteBuildFiles($deviceForBuilds, $document);
});
@@ -974,6 +1041,10 @@ class Deletes extends Action
): void {
$start = \microtime(true);
/**
* deleteDocuments uses a cursor, we need to add a unique order by field or use default
*/
try {
$documents = $database->deleteDocuments($collection, $queries);
} catch (Throwable $th) {
@@ -34,6 +34,9 @@ class Migrations extends Action
protected Document $project;
/**
* @var callable
*/
protected $logError;
public static function getName(): string
@@ -114,6 +114,13 @@ class StatsResources extends Action
$keys = $dbForPlatform->count('keys', [
Query::equal('projectInternalId', [$project->getInternalId()])
]);
$domains = $dbForPlatform->count('rules', [
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('owner', ['']),
]);
$databases = $dbForProject->count('databases');
$buckets = $dbForProject->count('buckets');
$users = $dbForProject->count('users');
@@ -162,6 +169,7 @@ class StatsResources extends Action
METRIC_PROVIDERS => $providers,
METRIC_TOPICS => $topics,
METRIC_KEYS => $keys,
METRIC_DOMAINS => $domains,
METRIC_TARGETS => $targets,
str_replace('{providerType}', MESSAGE_TYPE_EMAIL, METRIC_PROVIDER_TYPE_TARGETS) => $emailTargets,
str_replace('{providerType}', MESSAGE_TYPE_PUSH, METRIC_PROVIDER_TYPE_TARGETS) => $pushTargets,
@@ -71,12 +71,18 @@ class Base extends Queries
'array' => false,
]);
$internalId = new Document([
'key' => '$internalId',
'type' => Database::VAR_STRING,
'array' => false,
]);
$validators = [
new Limit(),
new Offset(),
new Cursor(),
new Filter($attributes, APP_DATABASE_QUERY_MAX_VALUES),
new Order($attributes),
new Order([...$attributes, $internalId]),
];
parent::__construct($validators);
+2 -1
View File
@@ -4,6 +4,7 @@ namespace Tests\E2E\Scopes;
use Tests\E2E\Client;
use Utopia\Database\Helpers\ID;
use Utopia\System\System;
trait ProjectCustom
{
@@ -42,7 +43,7 @@ trait ProjectCustom
'x-appwrite-project' => 'console',
], [
'projectId' => ID::unique(),
'region' => 'default',
'region' => System::getEnv('_APP_REGION', 'default'),
'name' => 'Demo Project',
'teamId' => $team['body']['$id'],
'description' => 'Demo Project Description',
@@ -8,6 +8,7 @@ use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideClient;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Role;
use Utopia\System\System;
class FunctionsCustomClientTest extends Scope
{
@@ -111,7 +112,7 @@ class FunctionsCustomClientTest extends Scope
$this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
$this->assertEquals('8.0', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']);
$this->assertEquals(APP_VERSION_STABLE, $output['APPWRITE_VERSION']);
$this->assertEquals('default', $output['APPWRITE_REGION']);
$this->assertEquals(System::getEnv('_APP_REGION', 'default'), $output['APPWRITE_REGION']);
$this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']);
$this->assertEquals('foobar', $output['APPWRITE_FUNCTION_DATA']);
$this->assertEquals($this->getUser()['$id'], $output['APPWRITE_FUNCTION_USER_ID']);
@@ -221,7 +222,7 @@ class FunctionsCustomClientTest extends Scope
$this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
$this->assertEquals('8.0', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']);
$this->assertEquals(APP_VERSION_STABLE, $output['APPWRITE_VERSION']);
$this->assertEquals('default', $output['APPWRITE_REGION']);
$this->assertEquals(System::getEnv('_APP_REGION', 'default'), $output['APPWRITE_REGION']);
$this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']);
$this->assertEquals('foobar', $output['APPWRITE_FUNCTION_DATA']);
$this->assertEquals($this->getUser()['$id'], $output['APPWRITE_FUNCTION_USER_ID']);
@@ -14,6 +14,7 @@ use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Query;
use Utopia\System\System;
class ProjectsConsoleClientTest extends Scope
{
@@ -49,7 +50,7 @@ class ProjectsConsoleClientTest extends Scope
'projectId' => ID::unique(),
'name' => 'Project Test',
'teamId' => $team['body']['$id'],
'region' => 'default',
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(201, $response['headers']['status-code']);
@@ -89,7 +90,7 @@ class ProjectsConsoleClientTest extends Scope
'projectId' => ID::unique(),
'name' => '',
'teamId' => $team['body']['$id'],
'region' => 'default'
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(400, $response['headers']['status-code']);
@@ -100,7 +101,7 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), [
'projectId' => ID::unique(),
'name' => 'Project Test',
'region' => 'default'
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(401, $response['headers']['status-code']);
@@ -129,7 +130,7 @@ class ProjectsConsoleClientTest extends Scope
'projectId' => $projectId,
'name' => 'Project Duplicate',
'teamId' => $teamId,
'region' => 'default'
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(409, $response['headers']['status-code']);
@@ -178,7 +179,7 @@ class ProjectsConsoleClientTest extends Scope
'projectId' => ID::unique(),
'name' => 'Team 1 Project',
'teamId' => $team1,
'region' => 'default',
'region' => System::getEnv('_APP_REGION', 'default'),
]);
$this->assertEquals(201, $response['headers']['status-code']);
@@ -277,7 +278,7 @@ class ProjectsConsoleClientTest extends Scope
'projectId' => ID::unique(),
'name' => 'Project Test 2',
'teamId' => $team['body']['$id'],
'region' => 'default'
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(201, $response['headers']['status-code']);
@@ -2042,7 +2043,7 @@ class ProjectsConsoleClientTest extends Scope
'projectId' => ID::unique(),
'name' => 'Project Test',
'teamId' => $team['body']['$id'],
'region' => 'default'
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(201, $project['headers']['status-code']);
@@ -2135,7 +2136,7 @@ class ProjectsConsoleClientTest extends Scope
'projectId' => ID::unique(),
'name' => 'Project Test',
'teamId' => $team['body']['$id'],
'region' => 'default'
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(201, $project['headers']['status-code']);
@@ -3749,7 +3750,7 @@ class ProjectsConsoleClientTest extends Scope
'projectId' => ID::unique(),
'name' => 'Amazing Project',
'teamId' => $teamId,
'region' => 'default'
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(201, $project['headers']['status-code']);
@@ -3820,7 +3821,7 @@ class ProjectsConsoleClientTest extends Scope
'projectId' => ID::unique(),
'name' => 'Amazing Project 1',
'teamId' => $teamId,
'region' => 'default'
'region' => System::getEnv('_APP_REGION', 'default')
]);
$project2 = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
@@ -3830,7 +3831,7 @@ class ProjectsConsoleClientTest extends Scope
'projectId' => ID::unique(),
'name' => 'Amazing Project 2',
'teamId' => $teamId,
'region' => 'default'
'region' => System::getEnv('_APP_REGION', 'default')
]);
$project1Id = $project1['body']['$id'];