appwrite/src/Appwrite/Platform/Workers/Deletes.php

1164 lines
43 KiB
PHP
Raw Normal View History

<?php
2023-06-05 16:13:00 +00:00
namespace Appwrite\Platform\Workers;
2022-11-21 14:24:52 +00:00
use Appwrite\Auth\Auth;
2023-08-23 20:19:22 +00:00
use Executor\Executor;
2023-10-01 08:04:12 +00:00
use Throwable;
2023-06-05 16:13:00 +00:00
use Utopia\Abuse\Abuse;
use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\Audit\Audit;
use Utopia\Cache\Adapter\Filesystem;
use Utopia\Cache\Cache;
2021-07-13 19:24:52 +00:00
use Utopia\Database\Database;
2023-06-05 16:13:00 +00:00
use Exception;
use Utopia\App;
use Utopia\CLI\Console;
2022-11-21 14:24:52 +00:00
use Utopia\Database\DateTime;
2023-06-05 16:13:00 +00:00
use Utopia\Database\Document;
use Utopia\Database\Exception\Authorization;
2023-10-01 08:04:12 +00:00
use Utopia\Database\Exception\Conflict;
use Utopia\Database\Exception\Restricted;
use Utopia\Database\Exception\Structure;
2024-01-15 05:26:30 +00:00
use Utopia\Database\Exception as DatabaseException;
2023-06-05 16:13:00 +00:00
use Utopia\Database\Query;
use Utopia\Platform\Action;
use Utopia\Queue\Message;
use Utopia\Storage\Device;
2023-06-05 16:13:00 +00:00
class Deletes extends Action
{
2023-06-05 16:13:00 +00:00
public static function getName(): string
2022-05-16 09:58:17 +00:00
{
2023-06-05 16:13:00 +00:00
return 'deletes';
}
2023-06-05 16:13:00 +00:00
/**
* @throws Exception
*/
public function __construct()
{
2023-06-05 16:13:00 +00:00
$this
->desc('Deletes worker')
->inject('message')
->inject('dbForConsole')
->inject('getProjectDB')
2023-10-01 08:04:12 +00:00
->inject('getFilesDevice')
->inject('getFunctionsDevice')
->inject('getBuildsDevice')
->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));
}
2023-06-05 16:13:00 +00:00
/**
* @throws Exception
2023-10-01 08:04:12 +00:00
* @throws Throwable
2023-06-05 16:13:00 +00:00
*/
2023-10-01 08:04:12 +00:00
public function action(Message $message, Database $dbForConsole, callable $getProjectDB, callable $getFilesDevice, callable $getFunctionsDevice, callable $getBuildsDevice, callable $getCacheDevice): void
{
2023-06-05 16:13:00 +00:00
$payload = $message->getPayload() ?? [];
if (empty($payload)) {
throw new Exception('Missing payload');
}
$type = $payload['type'] ?? '';
$datetime = $payload['datetime'] ?? null;
$hourlyUsageRetentionDatetime = $payload['hourlyUsageRetentionDatetime'] ?? null;
$resource = $payload['resource'] ?? null;
$document = new Document($payload['document'] ?? []);
2023-06-11 14:08:48 +00:00
$project = new Document($payload['project'] ?? []);
2023-06-05 16:13:00 +00:00
switch (strval($type)) {
2020-12-18 14:05:15 +00:00
case DELETE_TYPE_DOCUMENT:
2021-06-12 10:07:26 +00:00
switch ($document->getCollection()) {
Database layer (#3338) * database response model * database collection config * new database scopes * database service update * database execption codes * remove read write permission from database model * updating tests and fixing some bugs * server side tests are now passing * databases api * tests for database endpoint * composer update * fix error * formatting * formatting fixes * get database test * more updates to events and usage * more usage updates * fix delete type * fix test * delete database * more fixes * databaseId in attributes and indexes * more fixes * fix issues * fix index subquery * fix console scope and index query * updating tests as required * fix phpcs errors and warnings * updates to review suggestions * UI progress * ui updates and cleaning up * fix type * rework database events * update tests * update types * event generation fixed * events config updated * updating context to support multiple * realtime updates * fix ids * update context * validator updates * fix naming conflict * fix tests * fix lint errors * fix wprler and realtime tests * fix webhooks test * fix event validator and other tests * formatting fixes * removing leftover var_dumps * remove leftover comment * update usage params * usage metrics updates * update database usage * fix usage * specs update * updates to usage * fix UI and usage * fix lints * internal id fixes * fixes for internal Id * renaming services and related files * rename tests * rename doc link * rename readme * fix test name * tests: fixes for 0.15.x sync Co-authored-by: Torsten Dittmann <torsten.dittmann@googlemail.com>
2022-06-22 10:51:49 +00:00
case DELETE_TYPE_DATABASES:
2023-06-05 16:13:00 +00:00
$this->deleteDatabase($getProjectDB, $document, $project);
Database layer (#3338) * database response model * database collection config * new database scopes * database service update * database execption codes * remove read write permission from database model * updating tests and fixing some bugs * server side tests are now passing * databases api * tests for database endpoint * composer update * fix error * formatting * formatting fixes * get database test * more updates to events and usage * more usage updates * fix delete type * fix test * delete database * more fixes * databaseId in attributes and indexes * more fixes * fix issues * fix index subquery * fix console scope and index query * updating tests as required * fix phpcs errors and warnings * updates to review suggestions * UI progress * ui updates and cleaning up * fix type * rework database events * update tests * update types * event generation fixed * events config updated * updating context to support multiple * realtime updates * fix ids * update context * validator updates * fix naming conflict * fix tests * fix lint errors * fix wprler and realtime tests * fix webhooks test * fix event validator and other tests * formatting fixes * removing leftover var_dumps * remove leftover comment * update usage params * usage metrics updates * update database usage * fix usage * specs update * updates to usage * fix UI and usage * fix lints * internal id fixes * fixes for internal Id * renaming services and related files * rename tests * rename doc link * rename readme * fix test name * tests: fixes for 0.15.x sync Co-authored-by: Torsten Dittmann <torsten.dittmann@googlemail.com>
2022-06-22 10:51:49 +00:00
break;
2021-10-26 00:14:55 +00:00
case DELETE_TYPE_COLLECTIONS:
2023-06-05 16:13:00 +00:00
$this->deleteCollection($getProjectDB, $document, $project);
break;
2021-10-26 00:14:55 +00:00
case DELETE_TYPE_PROJECTS:
2023-10-01 08:04:12 +00:00
$this->deleteProject($dbForConsole, $getProjectDB, $getFilesDevice, $getFunctionsDevice, $getBuildsDevice, $getCacheDevice, $document);
break;
2021-10-26 00:14:55 +00:00
case DELETE_TYPE_FUNCTIONS:
2023-10-01 08:04:12 +00:00
$this->deleteFunction($dbForConsole, $getProjectDB, $getFunctionsDevice, $getBuildsDevice, $document, $project);
break;
case DELETE_TYPE_DEPLOYMENTS:
2023-10-01 08:04:12 +00:00
$this->deleteDeployment($getProjectDB, $getFunctionsDevice, $getBuildsDevice, $document, $project);
break;
2021-10-26 00:14:55 +00:00
case DELETE_TYPE_USERS:
2023-06-05 16:13:00 +00:00
$this->deleteUser($getProjectDB, $document, $project);
break;
2021-10-26 00:14:55 +00:00
case DELETE_TYPE_TEAMS:
2023-10-03 08:40:34 +00:00
$this->deleteMemberships($getProjectDB, $document, $project);
if ($project->getId() === 'console') {
2023-10-03 08:40:34 +00:00
$this->deleteProjectsByTeam($dbForConsole, $getProjectDB, $getFilesDevice, $getFunctionsDevice, $getBuildsDevice, $getCacheDevice, $document);
}
break;
2021-11-07 05:54:28 +00:00
case DELETE_TYPE_BUCKETS:
2023-10-01 08:04:12 +00:00
$this->deleteBucket($getProjectDB, $getFilesDevice, $document, $project);
break;
case DELETE_TYPE_INSTALLATIONS:
2023-10-03 08:40:34 +00:00
$this->deleteInstallation($dbForConsole, $getProjectDB, $document, $project);
break;
2023-03-10 07:42:52 +00:00
case DELETE_TYPE_RULES:
2023-10-17 18:32:38 +00:00
$this->deleteRule($dbForConsole, $document);
2021-07-28 10:09:29 +00:00
break;
default:
if (\str_starts_with($document->getCollection(), 'database_')) {
2023-06-05 16:13:00 +00:00
$this->deleteCollection($getProjectDB, $document, $project);
break;
}
2021-09-01 09:13:23 +00:00
Console::error('No lazy delete operation available for document of type: ' . $document->getCollection());
break;
}
2020-12-14 21:26:37 +00:00
break;
2020-12-21 18:15:52 +00:00
2020-12-27 17:57:35 +00:00
case DELETE_TYPE_EXECUTIONS:
2023-06-05 16:13:00 +00:00
$this->deleteExecutionLogs($dbForConsole, $getProjectDB, $datetime);
2020-12-21 18:15:52 +00:00
break;
2020-12-18 14:05:15 +00:00
case DELETE_TYPE_AUDIT:
2022-07-11 15:12:41 +00:00
if (!empty($datetime)) {
2023-06-05 16:13:00 +00:00
$this->deleteAuditLogs($dbForConsole, $getProjectDB, $datetime);
}
if (!$document->isEmpty()) {
2023-06-05 16:13:00 +00:00
$this->deleteAuditLogsByResource($getProjectDB, 'document/' . $document->getId(), $project);
}
break;
2020-12-18 14:05:15 +00:00
case DELETE_TYPE_ABUSE:
2023-06-05 16:13:00 +00:00
$this->deleteAbuseLogs($dbForConsole, $getProjectDB, $datetime);
break;
2021-02-05 10:57:43 +00:00
case DELETE_TYPE_REALTIME:
2023-10-17 18:32:38 +00:00
$this->deleteRealtimeUsage($dbForConsole, $datetime);
break;
case DELETE_TYPE_SESSIONS:
2023-06-05 16:13:00 +00:00
$this->deleteExpiredSessions($dbForConsole, $getProjectDB);
break;
case DELETE_TYPE_USAGE:
2023-10-01 17:39:26 +00:00
$this->deleteUsageStats($dbForConsole, $getProjectDB, $hourlyUsageRetentionDatetime);
2021-09-06 09:39:36 +00:00
break;
2022-08-15 09:05:41 +00:00
case DELETE_TYPE_CACHE_BY_RESOURCE:
2023-10-01 08:04:12 +00:00
$this->deleteCacheByResource($project, $getProjectDB, $resource);
2022-08-15 09:05:41 +00:00
break;
case DELETE_TYPE_CACHE_BY_TIMESTAMP:
2023-10-01 08:04:12 +00:00
$this->deleteCacheByDate($project, $getProjectDB, $datetime);
2022-07-03 09:36:59 +00:00
break;
2022-11-16 12:51:43 +00:00
case DELETE_TYPE_SCHEDULES:
$this->deleteSchedules($dbForConsole, $getProjectDB, $datetime, $document);
2022-11-16 12:51:43 +00:00
break;
2023-10-25 17:33:23 +00:00
case DELETE_TYPE_TOPIC:
$this->deleteTopic($project, $getProjectDB, $document);
2023-10-17 17:23:26 +00:00
break;
2020-12-19 08:08:03 +00:00
default:
2021-09-01 09:13:23 +00:00
Console::error('No delete operation for type: ' . $type);
2020-12-19 08:08:03 +00:00
break;
2021-09-01 09:13:23 +00:00
}
}
2022-11-16 12:51:43 +00:00
/**
2023-06-05 16:13:00 +00:00
* @param Database $dbForConsole
* @param callable $getProjectDB
* @param string $datetime
2024-01-15 05:26:30 +00:00
* @param Document|null $document
2023-06-05 16:13:00 +00:00
* @return void
* @throws Authorization
2024-01-15 05:26:30 +00:00
* @throws Conflict
* @throws Restricted
* @throws Structure
* @throws DatabaseException
2022-11-16 12:51:43 +00:00
*/
private function deleteSchedules(Database $dbForConsole, callable $getProjectDB, string $datetime, ?Document $document = null): void
2022-11-16 12:51:43 +00:00
{
2022-12-14 08:44:40 +00:00
$this->listByGroup(
2022-11-16 14:31:49 +00:00
'schedules',
[
2022-11-16 12:51:43 +00:00
Query::equal('region', [App::getEnv('_APP_REGION', 'default')]),
2024-01-15 05:26:30 +00:00
Query::equal('resourceType', [$document->getAttribute('resourceType')]),
2022-11-16 12:51:43 +00:00
Query::lessThanEqual('resourceUpdatedAt', $datetime),
Query::equal('active', [false]),
2022-11-16 14:31:49 +00:00
],
2023-06-05 16:13:00 +00:00
$dbForConsole,
function (Document $document) use ($dbForConsole, $getProjectDB) {
$project = $dbForConsole->getDocument('projects', $document->getAttribute('projectId'));
2022-11-16 12:51:43 +00:00
if ($project->isEmpty()) {
$dbForConsole->deleteDocument('schedules', $document->getId());
Console::success('Deleted schedule for deleted project ' . $document->getAttribute('projectId'));
2022-11-16 14:31:49 +00:00
return;
2022-11-16 12:51:43 +00:00
}
2024-01-15 06:00:41 +00:00
$resource = $getProjectDB($project)->getDocument(
$document->getAttribute('resourceCollection'),
$document->getAttribute('resourceId')
);
2022-11-16 12:51:43 +00:00
2024-01-15 06:00:41 +00:00
$delete = true;
switch ($document->getAttribute('resourceType')) {
case 'function':
$delete = $resource->isEmpty();
break;
}
if ($delete) {
2023-06-05 16:13:00 +00:00
$dbForConsole->deleteDocument('schedules', $document->getId());
2024-01-15 06:00:41 +00:00
Console::success('Deleting schedule for ' . $document->getAttribute('resourceType') . ' ' . $document->getAttribute('resourceId'));
2022-11-16 12:51:43 +00:00
}
}
2022-11-16 14:31:49 +00:00
);
2022-11-16 12:51:43 +00:00
}
2023-10-17 17:23:26 +00:00
/**
* @param Document $project
* @param callable $getProjectDB
2023-10-17 17:23:26 +00:00
* @param Document $topic
* @throws Exception
*/
2023-10-25 17:33:23 +00:00
protected function deleteTopic(Document $project, callable $getProjectDB, Document $topic)
2023-10-17 17:23:26 +00:00
{
if ($topic->isEmpty()) {
Console::error('Failed to delete subscribers. Topic not found');
return;
}
$dbForProject = $getProjectDB($project);
2023-10-17 17:23:26 +00:00
$this->deleteByGroup('subscribers', [
Query::equal('topicInternalId', [$topic->getInternalId()])
], $dbForProject);
}
2022-07-03 09:36:59 +00:00
/**
2023-06-13 08:15:38 +00:00
* @param Document $project
2023-06-05 16:13:00 +00:00
* @param callable $getProjectDB
* @param string $resource
2023-10-01 17:39:26 +00:00
* @return void
2023-10-01 08:04:12 +00:00
* @throws Authorization
2022-07-03 09:36:59 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteCacheByResource(Document $project, callable $getProjectDB, string $resource): void
2022-08-15 09:05:41 +00:00
{
2023-06-13 08:15:38 +00:00
$projectId = $project->getId();
2023-10-01 08:04:12 +00:00
$dbForProject = $getProjectDB($project);
2023-06-13 08:15:38 +00:00
$document = $dbForProject->findOne('cache', [Query::equal('resource', [$resource])]);
2022-08-15 09:05:41 +00:00
2023-06-13 10:41:54 +00:00
if ($document) {
$cache = new Cache(
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId)
);
2023-06-13 08:15:38 +00:00
2023-06-13 10:41:54 +00:00
$this->deleteById(
$document,
$dbForProject,
function ($document) use ($cache, $projectId) {
$path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId();
if ($cache->purge($document->getId())) {
Console::success('Deleting cache file: ' . $path);
} else {
Console::error('Failed to delete cache file: ' . $path);
}
2023-06-13 08:15:38 +00:00
}
2023-06-13 10:41:54 +00:00
);
}
2022-08-15 09:05:41 +00:00
}
2023-06-13 08:15:38 +00:00
/**
2023-10-01 08:04:12 +00:00
* Document $project
* @param Document $project
* @param callable $getProjectDB
2023-06-13 08:15:38 +00:00
* @param string $datetime
2023-10-01 08:04:12 +00:00
* @return void
2023-06-13 08:15:38 +00:00
* @throws Exception
*/
2023-10-17 18:32:38 +00:00
private function deleteCacheByDate(Document $project, callable $getProjectDB, string $datetime): void
2022-07-03 09:36:59 +00:00
{
2023-10-01 08:04:12 +00:00
$projectId = $project->getId();
$dbForProject = $getProjectDB($project);
2022-07-03 09:36:59 +00:00
2023-10-01 08:04:12 +00:00
$cache = new Cache(
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId)
);
2023-06-13 08:15:38 +00:00
2023-10-01 08:04:12 +00:00
$query = [
Query::lessThan('accessedAt', $datetime),
];
2023-10-01 08:04:12 +00:00
$this->deleteByGroup(
'cache',
$query,
$dbForProject,
function (Document $document) use ($cache, $projectId) {
$path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId();
if ($cache->purge($document->getId())) {
Console::success('Deleting cache file: ' . $path);
} else {
Console::error('Failed to delete cache file: ' . $path);
2022-07-05 07:37:46 +00:00
}
2023-10-01 08:04:12 +00:00
}
);
2022-07-03 09:36:59 +00:00
}
Database layer (#3338) * database response model * database collection config * new database scopes * database service update * database execption codes * remove read write permission from database model * updating tests and fixing some bugs * server side tests are now passing * databases api * tests for database endpoint * composer update * fix error * formatting * formatting fixes * get database test * more updates to events and usage * more usage updates * fix delete type * fix test * delete database * more fixes * databaseId in attributes and indexes * more fixes * fix issues * fix index subquery * fix console scope and index query * updating tests as required * fix phpcs errors and warnings * updates to review suggestions * UI progress * ui updates and cleaning up * fix type * rework database events * update tests * update types * event generation fixed * events config updated * updating context to support multiple * realtime updates * fix ids * update context * validator updates * fix naming conflict * fix tests * fix lint errors * fix wprler and realtime tests * fix webhooks test * fix event validator and other tests * formatting fixes * removing leftover var_dumps * remove leftover comment * update usage params * usage metrics updates * update database usage * fix usage * specs update * updates to usage * fix UI and usage * fix lints * internal id fixes * fixes for internal Id * renaming services and related files * rename tests * rename doc link * rename readme * fix test name * tests: fixes for 0.15.x sync Co-authored-by: Torsten Dittmann <torsten.dittmann@googlemail.com>
2022-06-22 10:51:49 +00:00
/**
2023-06-05 16:13:00 +00:00
* @param callable $getProjectDB
2023-10-01 08:04:12 +00:00
* @param Document $document
2023-06-13 08:15:38 +00:00
* @param Document $project
2023-10-01 17:39:26 +00:00
* @return void
2023-06-05 16:13:00 +00:00
* @throws Exception
Database layer (#3338) * database response model * database collection config * new database scopes * database service update * database execption codes * remove read write permission from database model * updating tests and fixing some bugs * server side tests are now passing * databases api * tests for database endpoint * composer update * fix error * formatting * formatting fixes * get database test * more updates to events and usage * more usage updates * fix delete type * fix test * delete database * more fixes * databaseId in attributes and indexes * more fixes * fix issues * fix index subquery * fix console scope and index query * updating tests as required * fix phpcs errors and warnings * updates to review suggestions * UI progress * ui updates and cleaning up * fix type * rework database events * update tests * update types * event generation fixed * events config updated * updating context to support multiple * realtime updates * fix ids * update context * validator updates * fix naming conflict * fix tests * fix lint errors * fix wprler and realtime tests * fix webhooks test * fix event validator and other tests * formatting fixes * removing leftover var_dumps * remove leftover comment * update usage params * usage metrics updates * update database usage * fix usage * specs update * updates to usage * fix UI and usage * fix lints * internal id fixes * fixes for internal Id * renaming services and related files * rename tests * rename doc link * rename readme * fix test name * tests: fixes for 0.15.x sync Co-authored-by: Torsten Dittmann <torsten.dittmann@googlemail.com>
2022-06-22 10:51:49 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteDatabase(callable $getProjectDB, Document $document, Document $project): void
Database layer (#3338) * database response model * database collection config * new database scopes * database service update * database execption codes * remove read write permission from database model * updating tests and fixing some bugs * server side tests are now passing * databases api * tests for database endpoint * composer update * fix error * formatting * formatting fixes * get database test * more updates to events and usage * more usage updates * fix delete type * fix test * delete database * more fixes * databaseId in attributes and indexes * more fixes * fix issues * fix index subquery * fix console scope and index query * updating tests as required * fix phpcs errors and warnings * updates to review suggestions * UI progress * ui updates and cleaning up * fix type * rework database events * update tests * update types * event generation fixed * events config updated * updating context to support multiple * realtime updates * fix ids * update context * validator updates * fix naming conflict * fix tests * fix lint errors * fix wprler and realtime tests * fix webhooks test * fix event validator and other tests * formatting fixes * removing leftover var_dumps * remove leftover comment * update usage params * usage metrics updates * update database usage * fix usage * specs update * updates to usage * fix UI and usage * fix lints * internal id fixes * fixes for internal Id * renaming services and related files * rename tests * rename doc link * rename readme * fix test name * tests: fixes for 0.15.x sync Co-authored-by: Torsten Dittmann <torsten.dittmann@googlemail.com>
2022-06-22 10:51:49 +00:00
{
$databaseId = $document->getId();
2023-06-05 16:13:00 +00:00
$dbForProject = $getProjectDB($project);
Database layer (#3338) * database response model * database collection config * new database scopes * database service update * database execption codes * remove read write permission from database model * updating tests and fixing some bugs * server side tests are now passing * databases api * tests for database endpoint * composer update * fix error * formatting * formatting fixes * get database test * more updates to events and usage * more usage updates * fix delete type * fix test * delete database * more fixes * databaseId in attributes and indexes * more fixes * fix issues * fix index subquery * fix console scope and index query * updating tests as required * fix phpcs errors and warnings * updates to review suggestions * UI progress * ui updates and cleaning up * fix type * rework database events * update tests * update types * event generation fixed * events config updated * updating context to support multiple * realtime updates * fix ids * update context * validator updates * fix naming conflict * fix tests * fix lint errors * fix wprler and realtime tests * fix webhooks test * fix event validator and other tests * formatting fixes * removing leftover var_dumps * remove leftover comment * update usage params * usage metrics updates * update database usage * fix usage * specs update * updates to usage * fix UI and usage * fix lints * internal id fixes * fixes for internal Id * renaming services and related files * rename tests * rename doc link * rename readme * fix test name * tests: fixes for 0.15.x sync Co-authored-by: Torsten Dittmann <torsten.dittmann@googlemail.com>
2022-06-22 10:51:49 +00:00
2023-06-05 16:13:00 +00:00
$this->deleteByGroup('database_' . $document->getInternalId(), [], $dbForProject, function ($document) use ($getProjectDB, $project) {
$this->deleteCollection($getProjectDB, $document, $project);
Database layer (#3338) * database response model * database collection config * new database scopes * database service update * database execption codes * remove read write permission from database model * updating tests and fixing some bugs * server side tests are now passing * databases api * tests for database endpoint * composer update * fix error * formatting * formatting fixes * get database test * more updates to events and usage * more usage updates * fix delete type * fix test * delete database * more fixes * databaseId in attributes and indexes * more fixes * fix issues * fix index subquery * fix console scope and index query * updating tests as required * fix phpcs errors and warnings * updates to review suggestions * UI progress * ui updates and cleaning up * fix type * rework database events * update tests * update types * event generation fixed * events config updated * updating context to support multiple * realtime updates * fix ids * update context * validator updates * fix naming conflict * fix tests * fix lint errors * fix wprler and realtime tests * fix webhooks test * fix event validator and other tests * formatting fixes * removing leftover var_dumps * remove leftover comment * update usage params * usage metrics updates * update database usage * fix usage * specs update * updates to usage * fix UI and usage * fix lints * internal id fixes * fixes for internal Id * renaming services and related files * rename tests * rename doc link * rename readme * fix test name * tests: fixes for 0.15.x sync Co-authored-by: Torsten Dittmann <torsten.dittmann@googlemail.com>
2022-06-22 10:51:49 +00:00
});
$dbForProject->deleteCollection('database_' . $document->getInternalId());
2023-06-05 16:13:00 +00:00
$this->deleteAuditLogsByResource($getProjectDB, 'database/' . $databaseId, $project);
Database layer (#3338) * database response model * database collection config * new database scopes * database service update * database execption codes * remove read write permission from database model * updating tests and fixing some bugs * server side tests are now passing * databases api * tests for database endpoint * composer update * fix error * formatting * formatting fixes * get database test * more updates to events and usage * more usage updates * fix delete type * fix test * delete database * more fixes * databaseId in attributes and indexes * more fixes * fix issues * fix index subquery * fix console scope and index query * updating tests as required * fix phpcs errors and warnings * updates to review suggestions * UI progress * ui updates and cleaning up * fix type * rework database events * update tests * update types * event generation fixed * events config updated * updating context to support multiple * realtime updates * fix ids * update context * validator updates * fix naming conflict * fix tests * fix lint errors * fix wprler and realtime tests * fix webhooks test * fix event validator and other tests * formatting fixes * removing leftover var_dumps * remove leftover comment * update usage params * usage metrics updates * update database usage * fix usage * specs update * updates to usage * fix UI and usage * fix lints * internal id fixes * fixes for internal Id * renaming services and related files * rename tests * rename doc link * rename readme * fix test name * tests: fixes for 0.15.x sync Co-authored-by: Torsten Dittmann <torsten.dittmann@googlemail.com>
2022-06-22 10:51:49 +00:00
}
/**
2023-06-05 16:13:00 +00:00
* @param callable $getProjectDB
* @param Document $document teams document
2022-08-13 07:57:04 +00:00
* @param Document $project
2023-10-01 17:39:26 +00:00
* @return void
2023-06-05 16:13:00 +00:00
* @throws Exception
*/
2023-10-17 18:32:38 +00:00
private function deleteCollection(callable $getProjectDB, Document $document, Document $project): void
{
$collectionId = $document->getId();
2023-06-23 11:52:19 +00:00
$collectionInternalId = $document->getInternalId();
$databaseId = $document->getAttribute('databaseId');
$databaseInternalId = $document->getAttribute('databaseInternalId');
2021-09-01 09:13:23 +00:00
2023-06-05 16:13:00 +00:00
$dbForProject = $getProjectDB($project);
$relationships = \array_filter(
$document->getAttribute('attributes'),
fn ($attribute) => $attribute['type'] === Database::VAR_RELATIONSHIP
);
foreach ($relationships as $relationship) {
if (!$relationship['twoWay']) {
continue;
}
$relatedCollection = $dbForProject->getDocument('database_' . $databaseInternalId, $relationship['relatedCollection']);
$dbForProject->deleteDocument('attributes', $databaseInternalId . '_' . $relatedCollection->getInternalId() . '_' . $relationship['twoWayKey']);
$dbForProject->deleteCachedDocument('database_' . $databaseInternalId, $relatedCollection->getId());
$dbForProject->deleteCachedCollection('database_' . $databaseInternalId . '_collection_' . $relatedCollection->getInternalId());
}
$dbForProject->deleteCollection('database_' . $databaseInternalId . '_collection_' . $document->getInternalId());
$this->deleteByGroup('attributes', [
2023-06-23 11:52:19 +00:00
Query::equal('databaseInternalId', [$databaseInternalId]),
Query::equal('collectionInternalId', [$collectionInternalId])
], $dbForProject);
$this->deleteByGroup('indexes', [
2023-06-23 11:52:19 +00:00
Query::equal('databaseInternalId', [$databaseInternalId]),
Query::equal('collectionInternalId', [$collectionInternalId])
], $dbForProject);
2023-06-05 16:13:00 +00:00
$this->deleteAuditLogsByResource($getProjectDB, 'database/' . $databaseId . '/collection/' . $collectionId, $project);
}
2021-08-27 11:37:52 +00:00
/**
2023-06-05 16:13:00 +00:00
* @param Database $dbForConsole
* @param callable $getProjectDB
2022-10-28 08:40:04 +00:00
* @param string $hourlyUsageRetentionDatetime
2023-10-01 17:39:26 +00:00
* @return void
* @throws Exception
2021-08-27 11:37:52 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteUsageStats(Database $dbForConsole, callable $getProjectDB, string $hourlyUsageRetentionDatetime): void
2021-09-01 09:13:23 +00:00
{
2023-06-05 16:13:00 +00:00
$this->deleteForProjectIds($dbForConsole, function (Document $project) use ($getProjectDB, $hourlyUsageRetentionDatetime) {
$dbForProject = $getProjectDB($project);
2021-08-27 11:37:52 +00:00
// Delete Usage stats
$this->deleteByGroup('stats', [
2022-10-28 08:40:04 +00:00
Query::lessThan('time', $hourlyUsageRetentionDatetime),
2022-10-23 04:46:23 +00:00
Query::equal('period', ['1h']),
], $dbForProject);
2021-08-27 11:37:52 +00:00
});
}
2021-07-13 19:24:52 +00:00
/**
2023-06-05 16:13:00 +00:00
* @param callable $getProjectDB
2021-07-13 19:24:52 +00:00
* @param Document $document teams document
2022-08-13 07:57:04 +00:00
* @param Document $project
2023-10-01 17:39:26 +00:00
* @return void
2023-06-05 16:13:00 +00:00
* @throws Exception
2021-07-13 19:24:52 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteMemberships(callable $getProjectDB, Document $document, Document $project): void
2021-08-27 04:37:15 +00:00
{
2023-10-01 08:04:12 +00:00
$dbForProject = $getProjectDB($project);
2023-06-23 11:52:19 +00:00
$teamInternalId = $document->getInternalId();
// Delete Memberships
$this->deleteByGroup(
'memberships',
[
Query::equal('teamInternalId', [$teamInternalId])
],
$dbForProject,
function (Document $membership) use ($dbForProject) {
$userId = $membership->getAttribute('userId');
$dbForProject->deleteCachedDocument('users', $userId);
}
);
}
/**
2023-06-05 16:13:00 +00:00
* @param Database $dbForConsole
2023-10-01 08:04:12 +00:00
* @param Document $document
* @return void
2023-06-05 16:13:00 +00:00
* @throws Authorization
2023-10-01 08:04:12 +00:00
* @throws \Utopia\Database\Exception
* @throws Conflict
* @throws Restricted
* @throws Structure
*/
2023-10-17 18:32:38 +00:00
private function deleteProjectsByTeam(Database $dbForConsole, callable $getProjectDB, callable $getFilesDevice, callable $getFunctionsDevice, callable $getBuildsDevice, callable $getCacheDevice, Document $document): void
{
$projects = $dbForConsole->find('projects', [
Query::equal('teamInternalId', [$document->getInternalId()])
]);
foreach ($projects as $project) {
2023-10-03 08:40:34 +00:00
$this->deleteProject($dbForConsole, $getProjectDB, $getFilesDevice, $getFunctionsDevice, $getBuildsDevice, $getCacheDevice, $project);
$dbForConsole->deleteDocument('projects', $project->getId());
}
}
2021-07-13 19:24:52 +00:00
/**
2023-10-01 08:04:12 +00:00
* @param Database $dbForConsole
* @param callable $getProjectDB
* @param callable $getFilesDevice
* @param callable $getFunctionsDevice
* @param callable $getBuildsDevice
* @param callable $getCacheDevice
* @param Document $document
2023-10-01 17:39:26 +00:00
* @return void
* @throws Exception
2023-10-01 17:39:26 +00:00
* @throws Authorization
* @throws \Utopia\Database\Exception
2021-07-13 19:24:52 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteProject(Database $dbForConsole, callable $getProjectDB, callable $getFilesDevice, callable $getFunctionsDevice, callable $getBuildsDevice, callable $getCacheDevice, Document $document): void
{
2021-07-13 18:44:45 +00:00
$projectId = $document->getId();
2023-04-27 15:37:14 +00:00
$projectInternalId = $document->getInternalId();
// Delete project tables
2023-06-11 10:29:04 +00:00
$dbForProject = $getProjectDB($document);
while (true) {
2023-01-17 04:31:14 +00:00
$collections = $dbForProject->listCollections();
if (empty($collections)) {
break;
}
foreach ($collections as $collection) {
$dbForProject->deleteCollection($collection->getId());
}
}
2023-04-27 15:37:14 +00:00
// Delete Platforms
$this->deleteByGroup('platforms', [
Query::equal('projectInternalId', [$projectInternalId])
], $dbForConsole);
// Delete project and function rules
$this->deleteByGroup('rules', [
2023-04-27 15:37:14 +00:00
Query::equal('projectInternalId', [$projectInternalId])
2023-10-17 18:32:38 +00:00
], $dbForConsole, function (Document $document) use ($dbForConsole) {
$this->deleteRule($dbForConsole, $document);
});
2023-04-27 15:37:14 +00:00
// Delete Keys
$this->deleteByGroup('keys', [
Query::equal('projectInternalId', [$projectInternalId])
], $dbForConsole);
// Delete Webhooks
$this->deleteByGroup('webhooks', [
Query::equal('projectInternalId', [$projectInternalId])
2023-04-27 15:37:14 +00:00
], $dbForConsole);
2023-11-03 09:24:51 +00:00
// Delete VCS Installations
$this->deleteByGroup('installations', [
Query::equal('projectInternalId', [$projectInternalId])
2023-11-03 09:24:51 +00:00
], $dbForConsole);
2023-11-08 21:59:29 +00:00
// Delete VCS Repositories
2023-11-03 09:24:51 +00:00
$this->deleteByGroup('repositories', [
2023-11-03 10:02:50 +00:00
Query::equal('projectInternalId', [$projectInternalId]),
2023-11-08 21:59:29 +00:00
], $dbForConsole);
// Delete VCS commments
$this->deleteByGroup('vcsComments', [
Query::equal('projectInternalId', [$projectInternalId]),
], $dbForConsole);
// Delete metadata tables
try {
$dbForProject->deleteCollection('_metadata');
} catch (Exception) {
// Ignore: deleteCollection tries to delete a metadata entry after the collection is deleted,
// which will throw an exception here because the metadata collection is already deleted.
}
2021-07-13 18:44:45 +00:00
// Delete all storage directories
2023-10-01 08:04:12 +00:00
$uploads = $getFilesDevice($projectId);
$functions = $getFunctionsDevice($projectId);
$builds = $getBuildsDevice($projectId);
$cache = $getCacheDevice($projectId);
2020-05-26 19:12:40 +00:00
$uploads->delete($uploads->getRoot(), true);
2023-01-12 09:42:07 +00:00
$functions->delete($functions->getRoot(), true);
$builds->delete($builds->getRoot(), true);
2020-05-26 19:12:40 +00:00
$cache->delete($cache->getRoot(), true);
}
2021-07-13 19:24:52 +00:00
/**
2023-06-05 16:13:00 +00:00
* @param callable $getProjectDB
2021-07-13 19:24:52 +00:00
* @param Document $document user document
2022-08-13 07:57:04 +00:00
* @param Document $project
2023-10-01 17:39:26 +00:00
* @return void
2023-06-05 16:13:00 +00:00
* @throws Exception
2021-07-13 19:24:52 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteUser(callable $getProjectDB, Document $document, Document $project): void
{
2021-07-12 21:57:37 +00:00
$userId = $document->getId();
2023-06-23 11:52:19 +00:00
$userInternalId = $document->getInternalId();
2023-06-05 16:13:00 +00:00
$dbForProject = $getProjectDB($project);
2022-11-16 19:39:35 +00:00
// Delete all sessions of this user from the sessions table and update the sessions field of the user record
$this->deleteByGroup('sessions', [
2023-06-23 11:52:19 +00:00
Query::equal('userInternalId', [$userInternalId])
2022-11-16 19:39:35 +00:00
], $dbForProject);
2022-11-16 19:39:35 +00:00
$dbForProject->deleteCachedDocument('users', $userId);
// Delete Memberships and decrement team membership counts
2021-07-13 19:24:52 +00:00
$this->deleteByGroup('memberships', [
2023-06-23 11:52:19 +00:00
Query::equal('userInternalId', [$userInternalId])
2022-11-16 19:39:35 +00:00
], $dbForProject, function (Document $document) use ($dbForProject) {
if ($document->getAttribute('confirm')) { // Count only confirmed members
$teamId = $document->getAttribute('teamId');
2022-11-16 19:39:35 +00:00
$team = $dbForProject->getDocument('teams', $teamId);
2021-09-01 09:13:23 +00:00
if (!$team->isEmpty()) {
2022-11-16 19:39:35 +00:00
$team = $dbForProject->updateDocument(
'teams',
$teamId,
// Ensure that total >= 0
$team->setAttribute('total', \max($team->getAttribute('total', 0) - 1, 0))
2022-11-16 19:39:35 +00:00
);
}
}
});
2022-04-27 11:06:53 +00:00
// Delete tokens
$this->deleteByGroup('tokens', [
2023-06-23 11:52:19 +00:00
Query::equal('userInternalId', [$userInternalId])
2022-11-16 19:39:35 +00:00
], $dbForProject);
// Delete identities
$this->deleteByGroup('identities', [
Query::equal('userInternalId', [$userInternalId])
], $dbForProject);
// Delete targets
$this->deleteByGroup('targets', [
Query::equal('userInternalId', [$userInternalId])
], $dbForProject);
}
2021-07-13 19:24:52 +00:00
/**
2023-06-05 16:13:00 +00:00
* @param database $dbForConsole
* @param callable $getProjectDB
2022-07-11 15:12:41 +00:00
* @param string $datetime
2023-10-01 17:39:26 +00:00
* @return void
* @throws Exception
2021-07-13 19:24:52 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteExecutionLogs(database $dbForConsole, callable $getProjectDB, string $datetime): void
2020-12-14 21:26:37 +00:00
{
2023-06-05 16:13:00 +00:00
$this->deleteForProjectIds($dbForConsole, function (Document $project) use ($getProjectDB, $datetime) {
$dbForProject = $getProjectDB($project);
2020-12-14 21:26:37 +00:00
// Delete Executions
2021-07-13 19:24:52 +00:00
$this->deleteByGroup('executions', [
2022-08-11 23:53:52 +00:00
Query::lessThan('$createdAt', $datetime)
], $dbForProject);
});
2020-12-14 21:26:37 +00:00
}
2023-06-05 16:13:00 +00:00
/**
* @param Database $dbForConsole
* @param callable $getProjectDB
* @return void
2023-10-01 08:04:12 +00:00
* @throws Exception|Throwable
2023-06-05 16:13:00 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteExpiredSessions(Database $dbForConsole, callable $getProjectDB): void
{
2022-12-14 08:44:40 +00:00
2023-06-05 16:13:00 +00:00
$this->deleteForProjectIds($dbForConsole, function (Document $project) use ($dbForConsole, $getProjectDB) {
$dbForProject = $getProjectDB($project);
$project = $dbForConsole->getDocument('projects', $project->getId());
2022-12-14 08:44:40 +00:00
$duration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
$expired = DateTime::addSeconds(new \DateTime(), -1 * $duration);
// Delete Sessions
$this->deleteByGroup('sessions', [
2022-11-21 14:24:52 +00:00
Query::lessThan('$createdAt', $expired)
], $dbForProject);
});
}
/**
2023-06-05 16:13:00 +00:00
* @param Database $dbForConsole
2022-07-11 15:12:41 +00:00
* @param string $datetime
2023-10-01 17:39:26 +00:00
* @return void
* @throws Exception
*/
2023-10-17 18:32:38 +00:00
private function deleteRealtimeUsage(Database $dbForConsole, string $datetime): void
{
2023-10-17 18:32:38 +00:00
// Delete Dead Realtime Logs
$this->deleteByGroup('realtime', [
Query::lessThan('timestamp', $datetime)
], $dbForConsole);
}
2021-07-13 19:24:52 +00:00
/**
2023-06-05 16:13:00 +00:00
* @param Database $dbForConsole
* @param callable $getProjectDB
2022-07-11 15:12:41 +00:00
* @param string $datetime
2023-10-01 17:39:26 +00:00
* @return void
2022-07-11 15:12:41 +00:00
* @throws Exception
2021-07-13 19:24:52 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteAbuseLogs(Database $dbForConsole, callable $getProjectDB, string $datetime): void
{
2022-07-11 15:12:41 +00:00
if (empty($datetime)) {
throw new Exception('Failed to delete audit logs. No datetime provided');
2020-12-18 14:05:15 +00:00
}
2023-06-05 16:13:00 +00:00
$this->deleteForProjectIds($dbForConsole, function (Document $project) use ($getProjectDB, $datetime) {
2022-08-13 07:57:04 +00:00
$projectId = $project->getId();
2023-06-05 16:13:00 +00:00
$dbForProject = $getProjectDB($project);
$timeLimit = new TimeLimit("", 0, 1, $dbForProject);
2021-09-01 09:13:23 +00:00
$abuse = new Abuse($timeLimit);
2022-07-19 14:52:06 +00:00
$status = $abuse->cleanup($datetime);
if (!$status) {
2021-09-01 09:13:23 +00:00
throw new Exception('Failed to delete Abuse logs for project ' . $projectId);
}
});
}
2021-07-13 19:24:52 +00:00
/**
2023-06-05 16:13:00 +00:00
* @param Database $dbForConsole
* @param callable $getProjectDB
2022-07-11 15:12:41 +00:00
* @param string $datetime
2023-10-01 17:39:26 +00:00
* @return void
2022-07-11 15:12:41 +00:00
* @throws Exception
2021-07-13 19:24:52 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteAuditLogs(Database $dbForConsole, callable $getProjectDB, string $datetime): void
{
2022-07-11 15:12:41 +00:00
if (empty($datetime)) {
throw new Exception('Failed to delete audit logs. No datetime provided');
2020-12-18 14:05:15 +00:00
}
2022-07-11 15:12:41 +00:00
2023-06-05 16:13:00 +00:00
$this->deleteForProjectIds($dbForConsole, function (Document $project) use ($getProjectDB, $datetime) {
2022-08-13 07:57:04 +00:00
$projectId = $project->getId();
2023-06-05 16:13:00 +00:00
$dbForProject = $getProjectDB($project);
$audit = new Audit($dbForProject);
2022-07-19 14:52:06 +00:00
$status = $audit->cleanup($datetime);
if (!$status) {
2021-09-01 09:13:23 +00:00
throw new Exception('Failed to delete Audit logs for project' . $projectId);
}
});
}
/**
2023-06-05 16:13:00 +00:00
* @param callable $getProjectDB
2022-07-11 15:12:41 +00:00
* @param string $resource
2022-08-13 07:57:04 +00:00
* @param Document $project
2023-10-01 17:39:26 +00:00
* @return void
2023-06-05 16:13:00 +00:00
* @throws Exception
*/
2023-10-17 18:32:38 +00:00
private function deleteAuditLogsByResource(callable $getProjectDB, string $resource, Document $project): void
{
2023-06-05 16:13:00 +00:00
$dbForProject = $getProjectDB($project);
$this->deleteByGroup(Audit::COLLECTION, [
2022-08-11 23:53:52 +00:00
Query::equal('resource', [$resource])
], $dbForProject);
}
2021-07-13 19:24:52 +00:00
/**
2023-06-05 16:13:00 +00:00
* @param callable $getProjectDB
2023-10-01 08:04:12 +00:00
* @param callable $getFunctionsDevice
* @param callable $getBuildsDevice
2021-07-13 19:24:52 +00:00
* @param Document $document function document
2022-08-13 07:57:04 +00:00
* @param Document $project
2023-10-01 17:39:26 +00:00
* @return void
2023-06-05 16:13:00 +00:00
* @throws Exception
2021-07-13 19:24:52 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteFunction(Database $dbForConsole, callable $getProjectDB, callable $getFunctionsDevice, callable $getBuildsDevice, Document $document, Document $project): void
{
2022-08-13 07:57:04 +00:00
$projectId = $project->getId();
2023-06-05 16:13:00 +00:00
$dbForProject = $getProjectDB($project);
2022-02-12 22:34:16 +00:00
$functionId = $document->getId();
2023-06-23 11:52:19 +00:00
$functionInternalId = $document->getInternalId();
2022-01-28 00:25:28 +00:00
2023-02-22 15:07:34 +00:00
/**
2023-07-31 06:47:47 +00:00
* Delete rules
2023-02-22 15:07:34 +00:00
*/
2023-07-31 06:47:47 +00:00
Console::info("Deleting rules for function " . $functionId);
2023-03-08 18:30:01 +00:00
$this->deleteByGroup('rules', [
2023-02-22 15:07:34 +00:00
Query::equal('resourceType', ['function']),
2023-06-23 11:52:19 +00:00
Query::equal('resourceInternalId', [$functionInternalId]),
2023-02-22 15:07:34 +00:00
Query::equal('projectInternalId', [$project->getInternalId()])
2023-10-01 08:04:12 +00:00
], $dbForConsole, function (Document $document) use ($project, $dbForConsole) {
2023-10-17 18:32:38 +00:00
$this->deleteRule($dbForConsole, $document);
2023-03-10 12:20:24 +00:00
});
2023-02-22 15:07:34 +00:00
2022-09-19 11:53:34 +00:00
/**
* Delete Variables
*/
Console::info("Deleting variables for function " . $functionId);
$this->deleteByGroup('variables', [
2023-03-11 16:06:02 +00:00
Query::equal('resourceType', ['function']),
2023-06-23 11:52:19 +00:00
Query::equal('resourceInternalId', [$functionInternalId])
2022-09-19 11:53:34 +00:00
], $dbForProject);
/**
* Delete Deployments
*/
2022-02-12 22:34:16 +00:00
Console::info("Deleting deployments for function " . $functionId);
2023-10-18 17:21:39 +00:00
$functionsStorage = $getFunctionsDevice($projectId);
2023-06-23 11:52:19 +00:00
$deploymentInternalIds = [];
$this->deleteByGroup('deployments', [
2023-06-23 11:52:19 +00:00
Query::equal('resourceInternalId', [$functionInternalId])
2023-10-18 17:21:39 +00:00
], $dbForProject, function (Document $document) use ($functionsStorage, &$deploymentInternalIds) {
2023-06-23 11:52:19 +00:00
$deploymentInternalIds[] = $document->getInternalId();
2023-10-18 17:21:39 +00:00
$this->deleteDeploymentFiles($functionsStorage, $document);
});
/**
* Delete builds
*/
2022-02-12 22:34:16 +00:00
Console::info("Deleting builds for function " . $functionId);
2023-10-18 17:21:39 +00:00
$buildsStorage = $getBuildsDevice($projectId);
2023-06-23 11:52:19 +00:00
foreach ($deploymentInternalIds as $deploymentInternalId) {
2022-01-29 00:52:06 +00:00
$this->deleteByGroup('builds', [
2023-06-23 11:52:19 +00:00
Query::equal('deploymentInternalId', [$deploymentInternalId])
2023-10-18 17:21:39 +00:00
], $dbForProject, function (Document $document) use ($buildsStorage) {
$this->deleteBuildFiles($buildsStorage, $document);
2022-01-29 00:52:06 +00:00
});
}
2022-05-23 14:54:50 +00:00
/**
2022-02-12 22:34:16 +00:00
* Delete Executions
2022-05-16 09:58:17 +00:00
*/
2022-02-12 22:34:16 +00:00
Console::info("Deleting executions for function " . $functionId);
$this->deleteByGroup('executions', [
2023-06-23 11:52:19 +00:00
Query::equal('functionInternalId', [$functionInternalId])
], $dbForProject);
/**
* Delete VCS Repositories and VCS Comments
*/
Console::info("Deleting VCS repositories and comments linked to function " . $functionId);
$this->deleteByGroup('repositories', [
2023-11-14 11:38:09 +00:00
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('resourceInternalId', [$functionInternalId]),
Query::equal('resourceType', ['function']),
], $dbForConsole, function (Document $document) use ($dbForConsole) {
$providerRepositoryId = $document->getAttribute('providerRepositoryId', '');
2023-11-14 13:11:54 +00:00
$projectInternalId = $document->getAttribute('projectInternalId', '');
$this->deleteByGroup('vcsComments', [
Query::equal('providerRepositoryId', [$providerRepositoryId]),
2023-11-14 13:11:54 +00:00
Query::equal('projectInternalId', [$projectInternalId]),
], $dbForConsole);
});
2023-03-14 11:13:03 +00:00
/**
* Request executor to delete all deployment containers
*/
Console::info("Requesting executor to delete all deployment containers for function " . $functionId);
2023-10-02 14:02:48 +00:00
$this->deleteRuntimes($getProjectDB, $document, $project);
}
2023-10-17 18:32:38 +00:00
/**
* @param Device $device
* @param Document $deployment
* @return void
*/
private function deleteDeploymentFiles(Device $device, Document $deployment): void
{
$deploymentId = $deployment->getId();
$deploymentPath = $deployment->getAttribute('path', '');
if (empty($deploymentPath)) {
Console::info("No deployment files for deployment " . $deploymentId);
return;
}
Console::info("Deleting deployment files for deployment " . $deploymentId);
try {
if ($device->delete($deploymentPath, true)) {
Console::success('Deleted deployment files: ' . $deploymentPath);
} else {
Console::error('Failed to delete deployment files: ' . $deploymentPath);
}
} catch (\Throwable $th) {
Console::error('Failed to delete deployment files: ' . $deploymentPath);
Console::error('[Error] Type: ' . get_class($th));
Console::error('[Error] Message: ' . $th->getMessage());
Console::error('[Error] File: ' . $th->getFile());
Console::error('[Error] Line: ' . $th->getLine());
}
}
2023-10-17 18:32:38 +00:00
/**
* @param Device $device
* @param Document $build
* @return void
*/
private function deleteBuildFiles(Device $device, Document $build): void
{
$buildId = $build->getId();
$buildPath = $build->getAttribute('path', '');
if (empty($buildPath)) {
Console::info("No build files for build " . $buildId);
return;
}
try {
if ($device->delete($buildPath, true)) {
Console::success('Deleted build files: ' . $buildPath);
} else {
Console::error('Failed to delete build files: ' . $buildPath);
}
} catch (\Throwable $th) {
Console::error('Failed to delete deployment files: ' . $buildPath);
Console::error('[Error] Type: ' . get_class($th));
Console::error('[Error] Message: ' . $th->getMessage());
Console::error('[Error] File: ' . $th->getFile());
Console::error('[Error] Line: ' . $th->getLine());
}
}
/**
2023-06-05 16:13:00 +00:00
* @param callable $getProjectDB
2023-10-01 08:04:12 +00:00
* @param callable $getFunctionsDevice
* @param callable $getBuildsDevice
* @param Document $document
2022-08-13 07:57:04 +00:00
* @param Document $project
2023-10-01 17:39:26 +00:00
* @return void
2023-06-05 16:13:00 +00:00
* @throws Exception
*/
2023-10-17 18:32:38 +00:00
private function deleteDeployment(callable $getProjectDB, callable $getFunctionsDevice, callable $getBuildsDevice, Document $document, Document $project): void
{
2022-08-13 07:57:04 +00:00
$projectId = $project->getId();
2023-06-05 16:13:00 +00:00
$dbForProject = $getProjectDB($project);
$deploymentId = $document->getId();
2023-06-23 11:52:19 +00:00
$deploymentInternalId = $document->getInternalId();
/**
2022-01-29 00:00:25 +00:00
* Delete deployment files
*/
2023-10-18 17:21:39 +00:00
$functionsStorage = $getFunctionsDevice($projectId);
$this->deleteDeploymentFiles($functionsStorage, $document);
/**
* Delete builds
*/
2022-02-12 22:34:16 +00:00
Console::info("Deleting builds for deployment " . $deploymentId);
2023-10-18 17:21:39 +00:00
$buildsStorage = $getBuildsDevice($projectId);
$this->deleteByGroup('builds', [
2023-06-23 11:52:19 +00:00
Query::equal('deploymentInternalId', [$deploymentInternalId])
2023-10-18 17:21:39 +00:00
], $dbForProject, function (Document $document) use ($buildsStorage) {
$this->deleteBuildFiles($buildsStorage, $document);
});
2023-03-14 11:13:03 +00:00
/**
* Request executor to delete all deployment containers
*/
Console::info("Requesting executor to delete deployment container for deployment " . $deploymentId);
2023-10-01 17:39:26 +00:00
$this->deleteRuntimes($getProjectDB, $document, $project);
}
2021-07-13 19:24:52 +00:00
/**
* @param Document $document to be deleted
* @param Database $database to delete it from
* @param callable|null $callback to perform after document is deleted
2023-10-17 18:32:38 +00:00
* @return void
2021-07-13 19:24:52 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteById(Document $document, Database $database, callable $callback = null): void
{
if ($database->deleteDocument($document->getCollection(), $document->getId())) {
2021-09-01 09:13:23 +00:00
Console::success('Deleted document "' . $document->getId() . '" successfully');
2021-09-01 09:13:23 +00:00
if (is_callable($callback)) {
$callback($document);
}
2021-09-01 09:13:23 +00:00
} else {
Console::error('Failed to delete document: ' . $document->getId());
}
}
2021-07-13 19:24:52 +00:00
/**
2023-06-05 16:13:00 +00:00
* @param Database $dbForConsole
2021-07-13 19:24:52 +00:00
* @param callable $callback
* @throws Exception
2021-07-13 19:24:52 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteForProjectIds(database $dbForConsole, callable $callback): void
2020-12-21 18:15:52 +00:00
{
2022-12-14 08:44:40 +00:00
// 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);
2021-09-01 09:13:23 +00:00
while ($sum === $limit) {
2023-06-05 16:13:00 +00:00
$projects = $dbForConsole->find('projects', [Query::limit($limit), Query::offset($chunk * $limit)]);
2021-08-27 04:37:15 +00:00
$chunk++;
/** @var string[] $projectIds */
$sum = count($projects);
2021-09-01 09:13:23 +00:00
Console::info('Executing delete function for chunk #' . $chunk . '. Found ' . $sum . ' projects');
foreach ($projects as $project) {
$callback($project);
$count++;
}
}
2020-12-21 18:15:52 +00:00
$executionEnd = \microtime(true);
Console::info("Found {$count} projects " . ($executionEnd - $executionStart) . " seconds");
2020-12-21 18:15:52 +00:00
}
/**
* @param string $collection collectionID
* @param array $queries
* @param Database $database
* @param callable|null $callback
2023-10-01 17:39:26 +00:00
* @return void
* @throws Exception
*/
2023-10-17 18:32:38 +00:00
private function deleteByGroup(string $collection, array $queries, Database $database, callable $callback = null): void
{
$count = 0;
$chunk = 0;
$limit = 50;
$sum = $limit;
$executionStart = \microtime(true);
2023-06-05 16:13:00 +00:00
while ($sum === $limit) {
$chunk++;
2023-06-05 16:13:00 +00:00
$results = $database->find($collection, \array_merge([Query::limit($limit)], $queries));
2023-06-05 16:13:00 +00:00
$sum = count($results);
2023-06-05 16:13:00 +00:00
Console::info('Deleting chunk #' . $chunk . '. Found ' . $sum . ' documents');
2023-06-05 16:13:00 +00:00
foreach ($results as $document) {
$this->deleteById($document, $database, $callback);
$count++;
}
}
$executionEnd = \microtime(true);
Console::info("Deleted {$count} document by group in " . ($executionEnd - $executionStart) . " seconds");
}
2021-07-12 21:57:37 +00:00
/**
* @param string $collection collectionID
* @param Query[] $queries
2021-07-13 19:24:52 +00:00
* @param Database $database
2023-06-05 16:13:00 +00:00
* @param callable|null $callback
2023-10-01 17:39:26 +00:00
* @return void
2023-06-05 16:13:00 +00:00
* @throws Exception
2021-07-12 21:57:37 +00:00
*/
2023-10-17 18:32:38 +00:00
private function listByGroup(string $collection, array $queries, Database $database, callable $callback = null): void
{
$count = 0;
$chunk = 0;
$limit = 50;
$results = [];
$sum = $limit;
$cursor = null;
$executionStart = \microtime(true);
2021-09-01 09:13:23 +00:00
while ($sum === $limit) {
$chunk++;
$mergedQueries = \array_merge([Query::limit($limit)], $queries);
if ($cursor instanceof Document) {
$mergedQueries[] = Query::cursorAfter($cursor);
}
$results = $database->find($collection, $mergedQueries);
2022-01-29 00:52:06 +00:00
$sum = count($results);
if ($sum > 0) {
$cursor = $results[$sum - 1];
}
foreach ($results as $document) {
2022-12-14 08:44:40 +00:00
if (is_callable($callback)) {
$callback($document);
}
$count++;
}
}
$executionEnd = \microtime(true);
2022-12-14 08:44:40 +00:00
Console::info("Listed {$count} document by group in " . ($executionEnd - $executionStart) . " seconds");
}
2021-07-13 19:24:52 +00:00
/**
2023-06-05 16:13:00 +00:00
* @param Database $dbForConsole
2023-03-10 07:42:52 +00:00
* @param Document $document rule document
2023-10-01 17:39:26 +00:00
* @return void
2021-07-13 19:24:52 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteRule(Database $dbForConsole, Document $document): void
2021-02-05 09:05:26 +00:00
{
2021-02-05 10:57:43 +00:00
$domain = $document->getAttribute('domain');
2021-02-05 09:05:26 +00:00
$directory = APP_STORAGE_CERTIFICATES . '/' . $domain;
2021-02-05 11:18:12 +00:00
$checkTraversal = realpath($directory) === $directory;
2021-02-05 09:05:26 +00:00
2023-03-10 07:42:52 +00:00
if ($checkTraversal && is_dir($directory)) {
// Delete files, so Traefik is aware of change
2021-09-01 09:13:23 +00:00
array_map('unlink', glob($directory . '/*.*'));
2021-02-05 09:05:26 +00:00
rmdir($directory);
2021-02-05 10:57:43 +00:00
Console::info("Deleted certificate files for {$domain}");
} else {
Console::info("No certificate files found for {$domain}");
2021-02-05 09:05:26 +00:00
}
2023-03-10 07:42:52 +00:00
// Delete certificate document, so Appwrite is aware of change
if (isset($document['certificateId'])) {
2023-10-01 08:04:12 +00:00
$dbForConsole->deleteDocument('certificates', $document['certificateId']);
2023-03-10 07:42:52 +00:00
}
2021-02-05 09:05:26 +00:00
}
2021-07-18 07:03:48 +00:00
2023-06-05 16:13:00 +00:00
/**
* @param callable $getProjectDB
2023-10-01 08:04:12 +00:00
* @param callable $getFilesDevice
2023-06-05 16:13:00 +00:00
* @param Document $document
* @param Document $project
* @return void
*/
2023-10-17 18:32:38 +00:00
private function deleteBucket(callable $getProjectDB, callable $getFilesDevice, Document $document, Document $project): void
2021-07-18 07:03:48 +00:00
{
2022-08-13 07:57:04 +00:00
$projectId = $project->getId();
2023-06-05 16:13:00 +00:00
$dbForProject = $getProjectDB($project);
2022-02-18 01:36:25 +00:00
$dbForProject->deleteCollection('bucket_' . $document->getInternalId());
2021-07-28 10:14:47 +00:00
2023-10-01 08:04:12 +00:00
$device = $getFilesDevice($projectId);
2022-05-23 14:54:50 +00:00
2022-02-18 01:36:25 +00:00
$device->deletePath($document->getId());
2021-07-18 07:03:48 +00:00
}
2023-03-14 11:13:03 +00:00
2023-10-01 08:04:12 +00:00
/**
* @param Database $dbForConsole
* @param callable $getProjectDB
* @param Document $document
* @param Document $project
* @return void
2023-10-01 17:39:26 +00:00
* @throws Exception
2023-10-01 08:04:12 +00:00
*/
2023-10-17 18:32:38 +00:00
private function deleteInstallation(Database $dbForConsole, callable $getProjectDB, Document $document, Document $project): void
{
2023-10-01 08:04:12 +00:00
$dbForProject = $getProjectDB($project);
$this->listByGroup('functions', [
Query::equal('installationInternalId', [$document->getInternalId()])
], $dbForProject, function ($function) use ($dbForProject, $dbForConsole) {
2023-07-30 19:10:25 +00:00
$dbForConsole->deleteDocument('repositories', $function->getAttribute('repositoryId'));
$function = $function
->setAttribute('installationId', '')
->setAttribute('installationInternalId', '')
->setAttribute('providerRepositoryId', '')
->setAttribute('providerBranch', '')
->setAttribute('providerSilentMode', false)
->setAttribute('providerRootDirectory', '')
->setAttribute('repositoryId', '')
->setAttribute('repositoryInternalId', '');
$dbForProject->updateDocument('functions', $function->getId(), $function);
});
}
2023-10-01 08:04:12 +00:00
/**
* @param callable $getProjectDB
* @param ?Document $function
* @param Document $project
2023-10-01 17:39:26 +00:00
* @return void
2023-10-01 08:04:12 +00:00
* @throws Exception
*/
2023-10-17 18:32:38 +00:00
private function deleteRuntimes(callable $getProjectDB, ?Document $function, Document $project): void
2023-03-14 19:31:23 +00:00
{
2023-03-14 11:13:03 +00:00
$executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST'));
2023-10-01 08:04:12 +00:00
$deleteByFunction = function (Document $function) use ($getProjectDB, $project, $executor) {
2023-03-14 11:13:03 +00:00
$this->listByGroup(
'deployments',
[
Query::equal('resourceInternalId', [$function->getInternalId()]),
Query::equal('resourceType', ['functions']),
],
2023-10-01 08:04:12 +00:00
$getProjectDB($project),
2023-03-14 11:13:03 +00:00
function (Document $deployment) use ($project, $executor) {
$deploymentId = $deployment->getId();
try {
$executor->deleteRuntime($project->getId(), $deploymentId);
Console::info("Runtime for deployment {$deploymentId} deleted.");
} catch (Throwable $th) {
Console::warning("Runtime for deployment {$deploymentId} skipped:");
Console::error('[Error] Type: ' . get_class($th));
Console::error('[Error] Message: ' . $th->getMessage());
Console::error('[Error] File: ' . $th->getFile());
Console::error('[Error] Line: ' . $th->getLine());
}
}
);
};
2023-03-14 19:31:23 +00:00
if ($function !== null) {
2023-03-14 11:13:03 +00:00
// Delete function runtimes
$deleteByFunction($function);
} else {
// Delete all project runtimes
$this->listByGroup(
'functions',
[],
2023-10-01 08:04:12 +00:00
$getProjectDB($project),
2023-03-14 11:13:03 +00:00
function (Document $function) use ($deleteByFunction) {
$deleteByFunction($function);
}
);
}
}
2021-09-01 09:13:23 +00:00
}