1
0
Fork 0
mirror of synced 2024-05-19 04:02:34 +12:00
appwrite/app/workers/deletes.php

620 lines
22 KiB
PHP
Raw Normal View History

<?php
use Utopia\App;
2021-07-14 07:24:52 +12:00
use Utopia\Database\Database;
use Utopia\Database\Document;
2021-07-13 09:57:37 +12:00
use Utopia\Database\Query;
2021-07-14 07:24:52 +12:00
use Utopia\Database\Validator\Authorization;
use Appwrite\Resque\Worker;
2022-02-04 14:29:40 +13:00
use Executor\Executor;
2021-01-22 21:28:33 +13:00
use Utopia\Storage\Device\Local;
2020-12-19 03:08:28 +13:00
use Utopia\Abuse\Abuse;
use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\CLI\Console;
use Utopia\Audit\Audit;
require_once __DIR__ . '/../init.php';
2020-12-19 21:08:03 +13:00
2021-01-15 19:02:48 +13:00
Console::title('Deletes V1 Worker');
2021-09-01 21:13:23 +12:00
Console::success(APP_NAME . ' deletes worker v1 has started' . "\n");
2020-12-19 21:08:03 +13:00
class DeletesV1 extends Worker
{
2021-08-27 16:37:15 +12:00
/**
* @var Database
*/
protected $consoleDB = null;
2022-05-16 21:58:17 +12:00
public function getName(): string
{
return "deletes";
}
public function init(): void
{
}
public function run(): void
{
$project = new Document($this->args['project'] ?? []);
2021-06-12 22:07:26 +12:00
$type = $this->args['type'] ?? '';
switch (strval($type)) {
2020-12-19 03:05:15 +13:00
case DELETE_TYPE_DOCUMENT:
$document = new Document($this->args['document'] ?? []);
2021-06-12 22:07:26 +12: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 22:51:49 +12:00
case DELETE_TYPE_DATABASES:
$this->deleteDatabase($document, $project->getId());
break;
2021-10-26 13:14:55 +13:00
case DELETE_TYPE_COLLECTIONS:
$this->deleteCollection($document, $project->getId());
break;
2021-10-26 13:14:55 +13:00
case DELETE_TYPE_PROJECTS:
$this->deleteProject($document);
break;
2021-10-26 13:14:55 +13:00
case DELETE_TYPE_FUNCTIONS:
$this->deleteFunction($document, $project->getId());
break;
case DELETE_TYPE_DEPLOYMENTS:
$this->deleteDeployment($document, $project->getId());
break;
2021-10-26 13:14:55 +13:00
case DELETE_TYPE_USERS:
$this->deleteUser($document, $project->getId());
break;
2021-10-26 13:14:55 +13:00
case DELETE_TYPE_TEAMS:
$this->deleteMemberships($document, $project->getId());
break;
2021-11-07 18:54:28 +13:00
case DELETE_TYPE_BUCKETS:
$this->deleteBucket($document, $project->getId());
2021-07-28 22:09:29 +12:00
break;
default:
2021-09-01 21:13:23 +12:00
Console::error('No lazy delete operation available for document of type: ' . $document->getCollection());
break;
}
2020-12-15 10:26:37 +13:00
break;
2020-12-22 07:15:52 +13:00
2020-12-28 06:57:35 +13:00
case DELETE_TYPE_EXECUTIONS:
$this->deleteExecutionLogs($this->args['timestamp']);
2020-12-22 07:15:52 +13:00
break;
2020-12-19 03:05:15 +13:00
case DELETE_TYPE_AUDIT:
$timestamp = $payload['timestamp'] ?? 0;
$document = new Document($payload['document'] ?? []);
if (!empty($timestamp)) {
$this->deleteAuditLogs($this->args['timestamp']);
}
if (!$document->isEmpty()) {
$this->deleteAuditLogsByResource('document/' . $document->getId(), $project->getId());
}
break;
2020-12-19 03:05:15 +13:00
case DELETE_TYPE_ABUSE:
$this->deleteAbuseLogs($this->args['timestamp']);
break;
2021-02-05 23:57:43 +13:00
case DELETE_TYPE_REALTIME:
$this->deleteRealtimeUsage($this->args['timestamp']);
break;
case DELETE_TYPE_SESSIONS:
$this->deleteExpiredSessions($this->args['timestamp']);
break;
2021-02-05 23:57:43 +13:00
case DELETE_TYPE_CERTIFICATES:
$document = new Document($this->args['document']);
$this->deleteCertificates($document);
break;
2021-09-01 21:13:23 +12:00
case DELETE_TYPE_USAGE:
2021-08-27 23:37:52 +12:00
$this->deleteUsageStats($this->args['timestamp1d'], $this->args['timestamp30m']);
2021-09-06 21:39:36 +12:00
break;
2020-12-19 21:08:03 +13:00
default:
2021-09-01 21:13:23 +12:00
Console::error('No delete operation for type: ' . $type);
2020-12-19 21:08:03 +13:00
break;
2021-09-01 21:13:23 +12:00
}
}
public function shutdown(): void
{
}
2021-09-01 21:13:23 +12: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 22:51:49 +12:00
/**
* @param Document $document database document
* @param string $projectId
*/
protected function deleteDatabase(Document $document, string $projectId): void
{
$databaseId = $document->getId();
$dbForProject = $this->getProjectDB($projectId);
$this->deleteByGroup('database_' . $document->getInternalId(), [], $dbForProject, function ($document) use ($projectId) {
$this->deleteCollection($document, $projectId);
});
$dbForProject->deleteCollection('database_' . $document->getInternalId());
$this->deleteAuditLogsByResource('database/' . $databaseId, $projectId);
}
/**
* @param Document $document teams document
* @param string $projectId
*/
protected function deleteCollection(Document $document, string $projectId): void
{
$collectionId = $document->getId();
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 22:51:49 +12:00
$databaseId = str_replace('database_', '', $document->getCollection());
2021-09-01 21:13:23 +12:00
$dbForProject = $this->getProjectDB($projectId);
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 22:51:49 +12:00
$dbForProject->deleteCollection('database_' . $databaseId . '_collection_' . $document->getInternalId());
$this->deleteByGroup('attributes', [
new Query('collectionId', Query::TYPE_EQUAL, [$collectionId])
], $dbForProject);
$this->deleteByGroup('indexes', [
new Query('collectionId', Query::TYPE_EQUAL, [$collectionId])
], $dbForProject);
$this->deleteAuditLogsByResource('collection/' . $collectionId, $projectId);
}
2021-08-27 23:37:52 +12:00
/**
* @param int $timestamp1d
* @param int $timestamp30m
*/
protected function deleteUsageStats(int $timestamp1d, int $timestamp30m)
2021-09-01 21:13:23 +12:00
{
$this->deleteForProjectIds(function (string $projectId) use ($timestamp1d, $timestamp30m) {
$dbForProject = $this->getProjectDB($projectId);
2021-08-27 23:37:52 +12:00
// Delete Usage stats
$this->deleteByGroup('stats', [
new Query('time', Query::TYPE_LESSER, [$timestamp1d]),
new Query('period', Query::TYPE_EQUAL, ['1d']),
], $dbForProject);
2021-08-27 23:37:52 +12:00
$this->deleteByGroup('stats', [
new Query('time', Query::TYPE_LESSER, [$timestamp30m]),
new Query('period', Query::TYPE_EQUAL, ['30m']),
], $dbForProject);
2021-08-27 23:37:52 +12:00
});
}
2021-07-14 07:24:52 +12:00
/**
* @param Document $document teams document
* @param string $projectId
*/
2021-08-27 16:37:15 +12:00
protected function deleteMemberships(Document $document, string $projectId): void
{
$teamId = $document->getAttribute('teamId', '');
// Delete Memberships
2021-07-14 07:24:52 +12:00
$this->deleteByGroup('memberships', [
new Query('teamId', Query::TYPE_EQUAL, [$teamId])
], $this->getProjectDB($projectId));
}
2021-07-14 07:24:52 +12:00
/**
* @param Document $document project document
*/
2021-08-27 16:37:15 +12:00
protected function deleteProject(Document $document): void
{
2021-07-14 06:44:45 +12:00
$projectId = $document->getId();
// Delete all DBs
$this->getProjectDB($projectId)->delete($projectId);
2021-07-14 06:44:45 +12:00
// Delete all storage directories
2021-09-01 21:13:23 +12:00
$uploads = new Local(APP_STORAGE_UPLOADS . '/app-' . $document->getId());
$cache = new Local(APP_STORAGE_CACHE . '/app-' . $document->getId());
2020-05-27 07:12:40 +12:00
$uploads->delete($uploads->getRoot(), true);
$cache->delete($cache->getRoot(), true);
}
2021-07-14 07:24:52 +12:00
/**
* @param Document $document user document
* @param string $projectId
*/
2021-08-27 16:37:15 +12:00
protected function deleteUser(Document $document, string $projectId): void
{
2021-07-13 09:57:37 +12:00
$userId = $document->getId();
2021-02-20 02:59:36 +13:00
// Delete all sessions of this user from the sessions table and update the sessions field of the user record
$this->deleteByGroup('sessions', [
new Query('userId', Query::TYPE_EQUAL, [$userId])
], $this->getProjectDB($projectId));
2022-04-26 20:52:59 +12:00
$this->getProjectDB($projectId)->deleteCachedDocument('users', $userId);
// Delete Memberships and decrement team membership counts
2021-07-14 07:24:52 +12:00
$this->deleteByGroup('memberships', [
2021-07-13 09:57:37 +12:00
new Query('userId', Query::TYPE_EQUAL, [$userId])
2021-09-01 21:13:23 +12:00
], $this->getProjectDB($projectId), function (Document $document) use ($projectId) {
if ($document->getAttribute('confirm')) { // Count only confirmed members
$teamId = $document->getAttribute('teamId');
$team = $this->getProjectDB($projectId)->getDocument('teams', $teamId);
2021-09-01 21:13:23 +12:00
if (!$team->isEmpty()) {
2022-05-16 21:58:17 +12:00
$team = $this
->getProjectDB($projectId)
->updateDocument(
'teams',
$teamId,
// Ensure that total >= 0
$team->setAttribute('total', \max($team->getAttribute('total', 0) - 1, 0))
);
}
}
});
2022-04-27 23:06:53 +12:00
// Delete tokens
$this->deleteByGroup('tokens', [
new Query('userId', Query::TYPE_EQUAL, [$userId])
], $this->getProjectDB($projectId));
}
2021-07-14 07:24:52 +12:00
/**
* @param int $timestamp
*/
2021-08-27 16:37:15 +12:00
protected function deleteExecutionLogs(int $timestamp): void
2020-12-15 10:26:37 +13:00
{
$this->deleteForProjectIds(function (string $projectId) use ($timestamp) {
$dbForProject = $this->getProjectDB($projectId);
2020-12-15 10:26:37 +13:00
// Delete Executions
2021-07-14 07:24:52 +12:00
$this->deleteByGroup('executions', [
new Query('$createdAt', Query::TYPE_LESSER, [$timestamp])
], $dbForProject);
});
2020-12-15 10:26:37 +13:00
}
/**
* @param int $timestamp
*/
protected function deleteExpiredSessions(int $timestamp): void
{
$this->deleteForProjectIds(function (string $projectId) use ($timestamp) {
$dbForProject = $this->getProjectDB($projectId);
// Delete Sessions
$this->deleteByGroup('sessions', [
new Query('expire', Query::TYPE_LESSER, [$timestamp])
], $dbForProject);
});
}
/**
* @param int $timestamp
*/
protected function deleteRealtimeUsage(int $timestamp): void
{
$this->deleteForProjectIds(function (string $projectId) use ($timestamp) {
$dbForProject = $this->getProjectDB($projectId);
// Delete Dead Realtime Logs
$this->deleteByGroup('realtime', [
new Query('timestamp', Query::TYPE_LESSER, [$timestamp])
], $dbForProject);
});
}
2021-07-14 07:24:52 +12:00
/**
* @param int $timestamp
*/
2021-08-27 16:37:15 +12:00
protected function deleteAbuseLogs(int $timestamp): void
{
2021-09-01 21:13:23 +12:00
if ($timestamp == 0) {
throw new Exception('Failed to delete audit logs. No timestamp provided');
2020-12-19 03:05:15 +13:00
}
$this->deleteForProjectIds(function (string $projectId) use ($timestamp) {
$dbForProject = $this->getProjectDB($projectId);
$timeLimit = new TimeLimit("", 0, 1, $dbForProject);
2021-09-01 21:13:23 +12:00
$abuse = new Abuse($timeLimit);
2020-12-19 03:08:28 +13:00
$status = $abuse->cleanup($timestamp);
if (!$status) {
2021-09-01 21:13:23 +12:00
throw new Exception('Failed to delete Abuse logs for project ' . $projectId);
}
});
}
2021-07-14 07:24:52 +12:00
/**
* @param int $timestamp
*/
2021-08-27 16:37:15 +12:00
protected function deleteAuditLogs(int $timestamp): void
{
2021-09-01 21:13:23 +12:00
if ($timestamp == 0) {
2020-12-19 03:05:15 +13:00
throw new Exception('Failed to delete audit logs. No timestamp provided');
}
$this->deleteForProjectIds(function (string $projectId) use ($timestamp) {
$dbForProject = $this->getProjectDB($projectId);
$audit = new Audit($dbForProject);
2020-12-19 03:05:15 +13:00
$status = $audit->cleanup($timestamp);
if (!$status) {
2021-09-01 21:13:23 +12:00
throw new Exception('Failed to delete Audit logs for project' . $projectId);
}
});
}
/**
* @param int $timestamp
*/
protected function deleteAuditLogsByResource(string $resource, string $projectId): void
{
$dbForProject = $this->getProjectDB($projectId);
$this->deleteByGroup(Audit::COLLECTION, [
new Query('resource', Query::TYPE_EQUAL, [$resource])
], $dbForProject);
}
2021-07-14 07:24:52 +12:00
/**
* @param Document $document function document
* @param string $projectId
*/
2021-08-27 16:37:15 +12:00
protected function deleteFunction(Document $document, string $projectId): void
{
$dbForProject = $this->getProjectDB($projectId);
2022-02-13 11:34:16 +13:00
$functionId = $document->getId();
2022-01-28 13:25:28 +13:00
/**
* Delete Deployments
*/
2022-02-13 11:34:16 +13:00
Console::info("Deleting deployments for function " . $functionId);
$storageFunctions = new Local(APP_STORAGE_FUNCTIONS . '/app-' . $projectId);
$deploymentIds = [];
$this->deleteByGroup('deployments', [
2022-02-13 11:34:16 +13:00
new Query('resourceId', Query::TYPE_EQUAL, [$functionId])
], $dbForProject, function (Document $document) use ($storageFunctions, &$deploymentIds) {
$deploymentIds[] = $document->getId();
if ($storageFunctions->delete($document->getAttribute('path', ''), true)) {
2022-02-01 12:44:55 +13:00
Console::success('Deleted deployment files: ' . $document->getAttribute('path', ''));
} else {
Console::error('Failed to delete deployment files: ' . $document->getAttribute('path', ''));
}
});
/**
* Delete builds
*/
2022-02-13 11:34:16 +13:00
Console::info("Deleting builds for function " . $functionId);
$storageBuilds = new Local(APP_STORAGE_BUILDS . '/app-' . $projectId);
2022-05-16 21:58:17 +12:00
foreach ($deploymentIds as $deploymentId) {
2022-01-29 13:52:06 +13:00
$this->deleteByGroup('builds', [
new Query('deploymentId', Query::TYPE_EQUAL, [$deploymentId])
], $dbForProject, function (Document $document) use ($storageBuilds, $deploymentId) {
2022-01-29 13:52:06 +13:00
if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) {
Console::success('Deleted build files: ' . $document->getAttribute('outputPath', ''));
} else {
Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', ''));
}
});
}
2022-05-24 02:54:50 +12:00
/**
2022-02-13 11:34:16 +13:00
* Delete Executions
2022-05-16 21:58:17 +12:00
*/
2022-02-13 11:34:16 +13:00
Console::info("Deleting executions for function " . $functionId);
$this->deleteByGroup('executions', [
2022-02-13 11:34:16 +13:00
new Query('functionId', Query::TYPE_EQUAL, [$functionId])
], $dbForProject);
/**
* Request executor to delete all deployment containers
*/
2022-02-13 11:34:16 +13:00
Console::info("Requesting executor to delete all deployment containers for function " . $functionId);
$executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST'));
foreach ($deploymentIds as $deploymentId) {
try {
$executor->deleteRuntime($projectId, $deploymentId);
} catch (Throwable $th) {
Console::error($th->getMessage());
}
}
}
/**
* @param Document $document deployment document
* @param string $projectId
*/
protected function deleteDeployment(Document $document, string $projectId): void
{
$dbForProject = $this->getProjectDB($projectId);
$deploymentId = $document->getId();
2022-02-13 11:34:16 +13:00
$functionId = $document->getAttribute('resourceId');
/**
2022-01-29 13:00:25 +13:00
* Delete deployment files
*/
2022-02-13 11:34:16 +13:00
Console::info("Deleting deployment files for deployment " . $deploymentId);
$storageFunctions = new Local(APP_STORAGE_FUNCTIONS . '/app-' . $projectId);
if ($storageFunctions->delete($document->getAttribute('path', ''), true)) {
2022-02-01 12:44:55 +13:00
Console::success('Deleted deployment files: ' . $document->getAttribute('path', ''));
} else {
Console::error('Failed to delete deployment files: ' . $document->getAttribute('path', ''));
}
/**
* Delete builds
*/
2022-02-13 11:34:16 +13:00
Console::info("Deleting builds for deployment " . $deploymentId);
$storageBuilds = new Local(APP_STORAGE_BUILDS . '/app-' . $projectId);
$this->deleteByGroup('builds', [
new Query('deploymentId', Query::TYPE_EQUAL, [$deploymentId])
], $dbForProject, function (Document $document) use ($storageBuilds) {
if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) {
Console::success('Deleted build files: ' . $document->getAttribute('outputPath', ''));
2021-09-01 21:13:23 +12:00
} else {
Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', ''));
}
});
/**
* Request executor to delete the deployment container
*/
2022-02-13 11:34:16 +13:00
Console::info("Requesting executor to delete deployment container for deployment " . $deploymentId);
try {
$executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST'));
$executor->deleteRuntime($projectId, $deploymentId);
} catch (Throwable $th) {
Console::error($th->getMessage());
}
}
2021-07-14 07:24:52 +12:00
/**
* @param Document $document to be deleted
* @param Database $database to delete it from
* @param callable $callback to perform after document is deleted
*
* @return bool
*/
protected function deleteById(Document $document, Database $database, callable $callback = null): bool
{
if ($database->deleteDocument($document->getCollection(), $document->getId())) {
2021-09-01 21:13:23 +12:00
Console::success('Deleted document "' . $document->getId() . '" successfully');
2021-09-01 21:13:23 +12:00
if (is_callable($callback)) {
$callback($document);
}
return true;
2021-09-01 21:13:23 +12:00
} else {
Console::error('Failed to delete document: ' . $document->getId());
return false;
}
}
2021-07-14 07:24:52 +12:00
/**
* @param callable $callback
*/
2021-08-27 16:37:15 +12:00
protected function deleteForProjectIds(callable $callback): void
2020-12-22 07:15:52 +13:00
{
$count = 0;
$chunk = 0;
$limit = 50;
$projects = [];
$sum = $limit;
2020-12-22 07:15:52 +13:00
$executionStart = \microtime(true);
2021-09-01 21:13:23 +12:00
while ($sum === $limit) {
$projects = $this->getConsoleDB()->find('projects', [], $limit, ($chunk * $limit));
2021-08-27 16:37:15 +12:00
$chunk++;
/** @var string[] $projectIds */
2022-05-16 21:58:17 +12:00
$projectIds = array_map(fn (Document $project) => $project->getId(), $projects);
$sum = count($projects);
2021-09-01 21:13:23 +12:00
Console::info('Executing delete function for chunk #' . $chunk . '. Found ' . $sum . ' projects');
foreach ($projectIds as $projectId) {
$callback($projectId);
$count++;
}
}
2020-12-22 07:15:52 +13:00
$executionEnd = \microtime(true);
Console::info("Found {$count} projects " . ($executionEnd - $executionStart) . " seconds");
2020-12-22 07:15:52 +13:00
}
2021-07-13 09:57:37 +12:00
/**
* @param string $collection collectionID
* @param Query[] $queries
2021-07-14 07:24:52 +12:00
* @param Database $database
2021-07-13 09:57:37 +12:00
* @param callable $callback
*/
2021-08-27 16:37:15 +12:00
protected function deleteByGroup(string $collection, array $queries, Database $database, callable $callback = null): void
{
$count = 0;
$chunk = 0;
$limit = 50;
$results = [];
$sum = $limit;
$executionStart = \microtime(true);
2021-09-01 21:13:23 +12:00
while ($sum === $limit) {
$chunk++;
2022-01-29 13:52:06 +13:00
$results = $database->find($collection, $queries, $limit, 0);
$sum = count($results);
2021-09-01 21:13:23 +12:00
Console::info('Deleting chunk #' . $chunk . '. Found ' . $sum . ' documents');
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-14 07:24:52 +12:00
/**
2022-05-24 02:54:50 +12:00
* @param Document $document certificates document
2021-07-14 07:24:52 +12:00
*/
2021-08-27 16:37:15 +12:00
protected function deleteCertificates(Document $document): void
2021-02-05 22:05:26 +13:00
{
$consoleDB = $this->getConsoleDB();
// If domain has certificate generated
2022-05-16 21:58:17 +12:00
if (isset($document['certificateId'])) {
$domainUsingCertificate = $consoleDB->findOne('domains', [
new Query('certificateId', Query::TYPE_EQUAL, [$document['certificateId']])
]);
2022-05-16 21:58:17 +12:00
if (!$domainUsingCertificate) {
$mainDomain = App::getEnv('_APP_DOMAIN_TARGET', '');
2022-05-16 21:58:17 +12:00
if ($mainDomain === $document->getAttribute('domain')) {
$domainUsingCertificate = $mainDomain;
}
}
// If certificate is still used by some domain, mark we can't delete.
// Current domain should not be found, because we only have copy. Original domain is already deleted from database.
2022-05-16 21:58:17 +12:00
if ($domainUsingCertificate) {
Console::warning("Skipping certificate deletion, because a domain is still using it.");
return;
}
}
2021-02-05 23:57:43 +13:00
$domain = $document->getAttribute('domain');
2021-02-05 22:05:26 +13:00
$directory = APP_STORAGE_CERTIFICATES . '/' . $domain;
2021-02-06 00:18:12 +13:00
$checkTraversal = realpath($directory) === $directory;
2021-02-05 22:05:26 +13:00
2021-09-01 21:13:23 +12:00
if ($domain && $checkTraversal && is_dir($directory)) {
// Delete certificate document, so Appwrite is aware of change
2022-05-16 21:58:17 +12:00
if (isset($document['certificateId'])) {
$consoleDB->deleteDocument('certificates', $document['certificateId']);
}
// Delete files, so Traefik is aware of change
2021-09-01 21:13:23 +12:00
array_map('unlink', glob($directory . '/*.*'));
2021-02-05 22:05:26 +13:00
rmdir($directory);
2021-02-05 23:57:43 +13:00
Console::info("Deleted certificate files for {$domain}");
} else {
Console::info("No certificate files found for {$domain}");
2021-02-05 22:05:26 +13:00
}
}
2021-07-18 19:03:48 +12:00
protected function deleteBucket(Document $document, string $projectId)
{
2022-01-27 01:54:18 +13:00
$dbForProject = $this->getProjectDB($projectId);
2022-02-18 14:36:25 +13:00
$dbForProject->deleteCollection('bucket_' . $document->getInternalId());
2021-07-28 22:14:47 +12:00
2022-05-24 02:54:50 +12:00
$device = $this->getDevice(APP_STORAGE_UPLOADS . '/app-' . $projectId);
2022-02-18 14:36:25 +13:00
$device->deletePath($document->getId());
2021-07-18 19:03:48 +12:00
}
2021-09-01 21:13:23 +12:00
}