diff --git a/app/config/events.php b/app/config/events.php index db1bbc2434..2bb3862fdf 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -3,98 +3,163 @@ /** * List of publicly accessiable system events */ + +use Appwrite\Utopia\Response; + return [ 'account.create' => [ 'description' => 'This event triggers when the account is created.', + 'model' => Response::MODEL_USER, + 'note' => '', ], 'account.update.email' => [ 'description' => 'This event triggers when the account email address is updated.', + 'model' => Response::MODEL_USER, + 'note' => '', ], 'account.update.name' => [ 'description' => 'This event triggers when the account name is updated.', + 'model' => Response::MODEL_USER, + 'note' => '', ], 'account.update.password' => [ 'description' => 'This event triggers when the account password is updated.', + 'model' => Response::MODEL_USER, + 'note' => '', ], 'account.update.prefs' => [ 'description' => 'This event triggers when the account preferences are updated.', + 'model' => Response::MODEL_USER, + 'note' => '', ], 'account.recovery.create' => [ 'description' => 'This event triggers when the account recovery token is created.', + 'model' => Response::MODEL_TOKEN, + 'note' => 'version >= 0.7', ], 'account.recovery.update' => [ 'description' => 'This event triggers when the account recovery token is validated.', + 'model' => Response::MODEL_TOKEN, + 'note' => 'version >= 0.7', ], 'account.verification.create' => [ 'description' => 'This event triggers when the account verification token is created.', + 'model' => Response::MODEL_TOKEN, + 'note' => 'version >= 0.7', ], 'account.verification.update' => [ 'description' => 'This event triggers when the account verification token is validated.', + 'model' => Response::MODEL_TOKEN, + 'note' => 'version >= 0.7', ], 'account.delete' => [ 'description' => 'This event triggers when the account is deleted.', + 'model' => Response::MODEL_USER, + 'note' => '', ], 'account.sessions.create' => [ 'description' => 'This event triggers when the account session is created.', + 'model' => Response::MODEL_SESSION, + 'note' => '', ], 'account.sessions.delete' => [ 'description' => 'This event triggers when the account session is deleted.', + 'model' => Response::MODEL_SESSION, + 'note' => '', ], 'database.collections.create' => [ 'description' => 'This event triggers when a database collection is created.', + 'model' => Response::MODEL_COLLECTION, + 'note' => '', ], 'database.collections.update' => [ 'description' => 'This event triggers when a database collection is updated.', + 'model' => Response::MODEL_COLLECTION, + 'note' => '', ], 'database.collections.delete' => [ 'description' => 'This event triggers when a database collection is deleted.', + 'model' => Response::MODEL_COLLECTION, + 'note' => '', ], 'database.documents.create' => [ 'description' => 'This event triggers when a database document is created.', + 'model' => Response::MODEL_ANY, + 'note' => '', ], 'database.documents.update' => [ 'description' => 'This event triggers when a database document is updated.', + 'model' => Response::MODEL_ANY, + 'note' => '', ], 'database.documents.delete' => [ 'description' => 'This event triggers when a database document is deleted.', + 'model' => Response::MODEL_ANY, + 'note' => '', ], 'storage.files.create' => [ 'description' => 'This event triggers when a storage file is created.', + 'model' => Response::MODEL_FILE, + 'note' => '', ], 'storage.files.update' => [ 'description' => 'This event triggers when a storage file is updated.', + 'model' => Response::MODEL_FILE, + 'note' => '', ], 'storage.files.delete' => [ 'description' => 'This event triggers when a storage file is deleted.', + 'model' => Response::MODEL_FILE, + 'note' => '', ], 'users.create' => [ 'description' => 'This event triggers when a user is created from the users API.', + 'model' => Response::MODEL_USER, + 'note' => 'version >= 0.7', ], 'users.update.status' => [ 'description' => 'This event triggers when a user status is updated from the users API.', + 'model' => Response::MODEL_USER, + 'note' => 'version >= 0.7', ], 'users.delete' => [ 'description' => 'This event triggers when a user is deleted from users API.', + 'model' => Response::MODEL_USER, + 'note' => 'version >= 0.7', ], 'users.sessions.delete' => [ 'description' => 'This event triggers when a user session is deleted from users API.', + 'model' => Response::MODEL_SESSION, + 'note' => 'version >= 0.7', ], 'teams.create' => [ 'description' => 'This event triggers when a team is created.', + 'model' => Response::MODEL_TEAM, + 'note' => 'version >= 0.7', ], 'teams.update' => [ 'description' => 'This event triggers when a team is updated.', + 'model' => Response::MODEL_TEAM, + 'note' => 'version >= 0.7', ], 'teams.delete' => [ 'description' => 'This event triggers when a team is deleted.', + 'model' => Response::MODEL_TEAM, + 'note' => 'version >= 0.7', ], 'teams.memberships.create' => [ 'description' => 'This event triggers when a team memberships is created.', + 'model' => Response::MODEL_MEMBERSHIP, + 'note' => 'version >= 0.7', ], 'teams.memberships.update.status' => [ 'description' => 'This event triggers when a team memberships status is updated.', + 'model' => Response::MODEL_MEMBERSHIP, + 'note' => 'version >= 0.7', ], 'teams.memberships.delete' => [ 'description' => 'This event triggers when a team memberships is deleted.', + 'model' => Response::MODEL_MEMBERSHIP, + 'note' => 'version >= 0.7', ], ]; \ No newline at end of file diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 55487eee52..eb6bd5ed4d 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -235,7 +235,7 @@ App::delete('/v1/database/collections/:collectionId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_NONE) ->param('collectionId', '', new UID(), 'Collection unique ID.') - ->action(function ($collectionId, $response, $projectDB, $webhooks, $audits) { + ->action(function ($collectionId, $response, $projectDB, $webhooks, $audits, $deletes) { /** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Database\Database $projectDB */ /** @var Appwrite\Event\Event $webhooks */ @@ -250,7 +250,11 @@ App::delete('/v1/database/collections/:collectionId') if (!$projectDB->deleteDocument($collectionId)) { throw new Exception('Failed to remove collection from DB', 500); } - + + $deletes + ->setParam('document', $collection) + ; + $webhooks ->setParam('payload', $response->output($collection, Response::MODEL_COLLECTION)) ; @@ -262,7 +266,7 @@ App::delete('/v1/database/collections/:collectionId') ; $response->noContent(); - }, ['response', 'projectDB', 'webhooks', 'audits']); + }, ['response', 'projectDB', 'webhooks', 'audits', 'deletes']); App::post('/v1/database/collections/:collectionId/documents') ->desc('Create Document') diff --git a/app/init.php b/app/init.php index 3e64c87562..ee4c217bc8 100644 --- a/app/init.php +++ b/app/init.php @@ -37,7 +37,7 @@ const APP_USERAGENT = APP_NAME.'-Server v%s. Please report abuse at %s'; const APP_MODE_DEFAULT = 'default'; const APP_MODE_ADMIN = 'admin'; const APP_PAGING_LIMIT = 12; -const APP_CACHE_BUSTER = 140; +const APP_CACHE_BUSTER = 141; const APP_VERSION_STABLE = '0.7.0'; const APP_STORAGE_UPLOADS = '/storage/uploads'; const APP_STORAGE_FUNCTIONS = '/storage/functions'; diff --git a/app/workers/deletes.php b/app/workers/deletes.php index dbd86dd2d4..14addd2d18 100644 --- a/app/workers/deletes.php +++ b/app/workers/deletes.php @@ -32,7 +32,7 @@ class DeletesV1 $document = new Document($document); - switch ($document->getCollection()) { + switch (strval($document->getCollection())) { case Database::SYSTEM_COLLECTION_PROJECTS: $this->deleteProject($document); break; @@ -42,7 +42,9 @@ class DeletesV1 case Database::SYSTEM_COLLECTION_USERS: $this->deleteUser($document, $projectId); break; - + case Database::SYSTEM_COLLECTION_COLLECTIONS: + $this->deleteDocuments($document, $projectId); + break; default: Console::error('No lazy delete operation available for document of type: '.$document->getCollection()); break; @@ -53,6 +55,16 @@ class DeletesV1 { // ... Remove environment for this job } + + protected function deleteDocuments(Document $document, $projectId) + { + $collectionId = $document->getId(); + + // Delete Documents in the deleted collection + $this->deleteByGroup([ + '$collection='.$collectionId + ], $this->getProjectDB($projectId)); + } protected function deleteProject(Document $document) { @@ -202,4 +214,4 @@ class DeletesV1 return $projectDB; } -} +} \ No newline at end of file diff --git a/public/images/appwrite-footer-dark.svg b/public/images/appwrite-footer-dark.svg index dddc42887c..4e4fbc5e08 100644 --- a/public/images/appwrite-footer-dark.svg +++ b/public/images/appwrite-footer-dark.svg @@ -1 +1,2 @@ - \ No newline at end of file + + \ No newline at end of file diff --git a/public/images/appwrite-footer-light.svg b/public/images/appwrite-footer-light.svg index a6caddbacf..142c03ca0c 100644 --- a/public/images/appwrite-footer-light.svg +++ b/public/images/appwrite-footer-light.svg @@ -1 +1,2 @@ - \ No newline at end of file + + \ No newline at end of file diff --git a/public/images/appwrite-nav.svg b/public/images/appwrite-nav.svg index f416bde648..9a052d4533 100644 --- a/public/images/appwrite-nav.svg +++ b/public/images/appwrite-nav.svg @@ -1 +1,2 @@ - \ No newline at end of file + + \ No newline at end of file diff --git a/public/images/appwrite-white.svg b/public/images/appwrite-white.svg index 3d941c0d8a..b82cfef311 100644 --- a/public/images/appwrite-white.svg +++ b/public/images/appwrite-white.svg @@ -1 +1,2 @@ - \ No newline at end of file + + \ No newline at end of file diff --git a/public/images/appwrite.svg b/public/images/appwrite.svg index 53e6ea421e..7128b7b733 100644 --- a/public/images/appwrite.svg +++ b/public/images/appwrite.svg @@ -1 +1,2 @@ - \ No newline at end of file + + \ No newline at end of file diff --git a/public/images/icon-nav.svg b/public/images/icon-nav.svg index 96ee99bfad..6c91e72a4a 100644 --- a/public/images/icon-nav.svg +++ b/public/images/icon-nav.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/images/icon.svg b/public/images/icon.svg index d26e87d003..00ef5b67f8 100644 --- a/public/images/icon.svg +++ b/public/images/icon.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/tests/e2e/Services/Database/DatabaseCustomServerTest.php b/tests/e2e/Services/Database/DatabaseCustomServerTest.php index dec0b108ef..2f0bdfc766 100644 --- a/tests/e2e/Services/Database/DatabaseCustomServerTest.php +++ b/tests/e2e/Services/Database/DatabaseCustomServerTest.php @@ -5,10 +5,119 @@ namespace Tests\E2E\Services\Database; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; +use Tests\E2E\Client; class DatabaseCustomServerTest extends Scope { use DatabaseBase; use ProjectCustom; use SideServer; + + public function testDeleteCollection() + { + /** + * Test for SUCCESS + */ + + // Create collection + $actors = $this->client->call(Client::METHOD_POST, '/database/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'name' => 'Actors', + 'read' => ['*'], + 'write' => ['role:1', 'role:2'], + 'rules' => [ + [ + 'label' => 'First Name', + 'key' => 'firstName', + 'type' => 'text', + 'default' => '', + 'required' => true, + 'array' => false + ], + [ + 'label' => 'Last Name', + 'key' => 'lastName', + 'type' => 'text', + 'default' => '', + 'required' => true, + 'array' => false + ], + ], + ]); + + $this->assertEquals($actors['headers']['status-code'], 201); + $this->assertEquals($actors['body']['$collection'], 0); + $this->assertEquals($actors['body']['name'], 'Actors'); + $this->assertIsArray($actors['body']['$permissions']); + $this->assertIsArray($actors['body']['$permissions']['read']); + $this->assertIsArray($actors['body']['$permissions']['write']); + $this->assertCount(1, $actors['body']['$permissions']['read']); + $this->assertCount(2, $actors['body']['$permissions']['write']); + + // Add Documents to the collection + $document1 = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actors['body']['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'firstName' => 'Tom', + 'lastName' => 'Holland', + ], + 'read' => ['user:'.$this->getUser()['$id']], + 'write' => ['user:'.$this->getUser()['$id']], + ]); + + $document2 = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actors['body']['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'firstName' => 'Samuel', + 'lastName' => 'Jackson', + ], + 'read' => ['user:'.$this->getUser()['$id']], + 'write' => ['user:'.$this->getUser()['$id']], + ]); + + $this->assertEquals($document1['headers']['status-code'], 201); + $this->assertEquals($document1['body']['$collection'], $actors['body']['$id']); + $this->assertIsArray($document1['body']['$permissions']); + $this->assertIsArray($document1['body']['$permissions']['read']); + $this->assertIsArray($document1['body']['$permissions']['write']); + $this->assertCount(1, $document1['body']['$permissions']['read']); + $this->assertCount(1, $document1['body']['$permissions']['write']); + $this->assertEquals($document1['body']['firstName'], 'Tom'); + $this->assertEquals($document1['body']['lastName'], 'Holland'); + + $this->assertEquals($document2['headers']['status-code'], 201); + $this->assertEquals($document2['body']['$collection'], $actors['body']['$id']); + $this->assertIsArray($document2['body']['$permissions']); + $this->assertIsArray($document2['body']['$permissions']['read']); + $this->assertIsArray($document2['body']['$permissions']['write']); + $this->assertCount(1, $document2['body']['$permissions']['read']); + $this->assertCount(1, $document2['body']['$permissions']['write']); + $this->assertEquals($document2['body']['firstName'], 'Samuel'); + $this->assertEquals($document2['body']['lastName'], 'Jackson'); + + // Delete the actors collection + $response = $this->client->call(Client::METHOD_DELETE, '/database/collections/'.$actors['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], $this->getHeaders())); + + $this->assertEquals($response['headers']['status-code'], 204); + $this->assertEquals($response['body'],""); + + // Try to get the collection and check if it has been deleted + $response = $this->client->call(Client::METHOD_GET, '/database/collections/'.$actors['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'] + ], $this->getHeaders())); + + $this->assertEquals($response['headers']['status-code'], 404); + } } \ No newline at end of file