diff --git a/CHANGES.md b/CHANGES.md index 20fa479c6f..e61a2a4c08 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## Bugs - Fix license detection for Flutter and Dart SDKs [#4435](https://github.com/appwrite/appwrite/pull/4435) +- Fix missing realtime event for create function deployment [#4574](https://github.com/appwrite/appwrite/pull/4574) - Fix missing status, buildStderr and buildStderr from get deployment response [#4611](https://github.com/appwrite/appwrite/pull/4611) # Version 1.0.4 diff --git a/SECURITY.md b/SECURITY.md index 89aa610910..d0e4c98f1b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,9 +4,9 @@ | Version | Supported | | ------- | ------------------ | -| <= 0.10 | :x: | -| 0.11.x | :white_check_mark: | -| 0.12.x | :white_check_mark: | +| <= 0.14 | :x: | +| 0.15.x | :white_check_mark: | +| 1.0.x | :white_check_mark: | ## Reporting a Vulnerability diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 0159939039..9b83c6dfce 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -5,7 +5,6 @@ use Appwrite\Auth\Auth; use Appwrite\Auth\Validator\Password; use Appwrite\Auth\Validator\Phone; use Appwrite\Detector\Detector; -use Appwrite\Event\Audit; use Appwrite\Event\Event; use Appwrite\Event\Mail; use Appwrite\Event\Phone as EventPhone; @@ -39,7 +38,6 @@ use Utopia\Database\Validator\UID; use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; -use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -141,7 +139,7 @@ App::post('/v1/account') App::post('/v1/account/sessions/email') ->alias('/v1/account/sessions') - ->desc('Create Account Session with Email') + ->desc('Create Email Session') ->groups(['api', 'account', 'auth']) ->label('event', 'users.[userId].sessions.[sessionId].create') ->label('scope', 'public') @@ -255,7 +253,7 @@ App::post('/v1/account/sessions/email') }); App::get('/v1/account/sessions/oauth2/:provider') - ->desc('Create Account Session with OAuth2') + ->desc('Create OAuth2 Session') ->groups(['api', 'account']) ->label('error', __DIR__ . '/../../views/general/error.phtml') ->label('scope', 'public') @@ -1223,7 +1221,7 @@ App::post('/v1/account/sessions/anonymous') }); App::post('/v1/account/jwt') - ->desc('Create Account JWT') + ->desc('Create JWT') ->groups(['api', 'account', 'auth']) ->label('scope', 'account') ->label('auth.type', 'jwt') @@ -1310,7 +1308,7 @@ App::get('/v1/account/prefs') }); App::get('/v1/account/sessions') - ->desc('List Account Sessions') + ->desc('List Sessions') ->groups(['api', 'account']) ->label('scope', 'account') ->label('usage.metric', 'users.{scope}.requests.read') @@ -1345,7 +1343,7 @@ App::get('/v1/account/sessions') }); App::get('/v1/account/logs') - ->desc('List Account Logs') + ->desc('List Logs') ->groups(['api', 'account']) ->label('scope', 'account') ->label('usage.metric', 'users.{scope}.requests.read') @@ -1406,7 +1404,7 @@ App::get('/v1/account/logs') }); App::get('/v1/account/sessions/:sessionId') - ->desc('Get Session By ID') + ->desc('Get Session') ->groups(['api', 'account']) ->label('scope', 'account') ->label('usage.metric', 'users.{scope}.requests.read') @@ -1446,7 +1444,7 @@ App::get('/v1/account/sessions/:sessionId') }); App::patch('/v1/account/name') - ->desc('Update Account Name') + ->desc('Update Name') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.name') ->label('scope', 'account') @@ -1477,7 +1475,7 @@ App::patch('/v1/account/name') }); App::patch('/v1/account/password') - ->desc('Update Account Password') + ->desc('Update Password') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.password') ->label('scope', 'account') @@ -1517,7 +1515,7 @@ App::patch('/v1/account/password') }); App::patch('/v1/account/email') - ->desc('Update Account Email') + ->desc('Update Email') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.email') ->label('scope', 'account') @@ -1569,7 +1567,7 @@ App::patch('/v1/account/email') }); App::patch('/v1/account/phone') - ->desc('Update Account Phone') + ->desc('Update Phone') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.phone') ->label('scope', 'account') @@ -1617,7 +1615,7 @@ App::patch('/v1/account/phone') }); App::patch('/v1/account/prefs') - ->desc('Update Account Preferences') + ->desc('Update Preferences') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.prefs') ->label('scope', 'account') @@ -1646,7 +1644,7 @@ App::patch('/v1/account/prefs') }); App::patch('/v1/account/status') - ->desc('Update Account Status') + ->desc('Update Status') ->groups(['api', 'account']) ->label('event', 'users.[userId].update.status') ->label('scope', 'account') @@ -1681,7 +1679,7 @@ App::patch('/v1/account/status') }); App::delete('/v1/account/sessions/:sessionId') - ->desc('Delete Account Session') + ->desc('Delete Session') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].delete') @@ -1752,7 +1750,7 @@ App::delete('/v1/account/sessions/:sessionId') }); App::patch('/v1/account/sessions/:sessionId') - ->desc('Update Session (Refresh Tokens)') + ->desc('Update OAuth Session (Refresh Tokens)') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].update') @@ -1834,7 +1832,7 @@ App::patch('/v1/account/sessions/:sessionId') }); App::delete('/v1/account/sessions') - ->desc('Delete All Account Sessions') + ->desc('Delete Sessions') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].sessions.[sessionId].delete') @@ -1886,8 +1884,6 @@ App::delete('/v1/account/sessions') $dbForProject->deleteCachedDocument('users', $user->getId()); - $numOfSessions = count($sessions); - $events ->setParam('userId', $user->getId()) ->setParam('sessionId', $session->getId()); diff --git a/src/Appwrite/Messaging/Adapter/Realtime.php b/src/Appwrite/Messaging/Adapter/Realtime.php index 9151a5c0b5..dddbc59e7f 100644 --- a/src/Appwrite/Messaging/Adapter/Realtime.php +++ b/src/Appwrite/Messaging/Adapter/Realtime.php @@ -321,7 +321,7 @@ class Realtime extends Adapter } } elseif ($parts[2] === 'deployments') { $channels[] = 'console'; - + $projectId = 'console'; $roles = [Role::team($project->getAttribute('teamId'))->toString()]; } diff --git a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php index efcfe95f53..500b3d48be 100644 --- a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php +++ b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php @@ -2,16 +2,19 @@ namespace Tests\E2E\Services\Realtime; +use CURLFile; use Tests\E2E\Client; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\SideConsole; +use Tests\E2E\Services\Functions\FunctionsBase; use Utopia\Database\ID; use Utopia\Database\Permission; use Utopia\Database\Role; class RealtimeConsoleClientTest extends Scope { + use FunctionsBase; use RealtimeBase; use ProjectCustom; use SideConsole; @@ -425,4 +428,78 @@ class RealtimeConsoleClientTest extends Scope $client->close(); } + + public function testCreateDeployment() + { + $response1 = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'functionId' => ID::unique(), + 'name' => 'Test', + 'runtime' => 'php-8.0', + 'events' => [ + 'users.*.create', + 'users.*.delete', + ], + 'schedule' => '0 0 1 1 *', + 'timeout' => 10, + ]); + + $functionId = $response1['body']['$id'] ?? ''; + + $this->assertEquals(201, $response1['headers']['status-code']); + + + $projectId = 'console'; + + $client = $this->getWebsocket(['console'], [ + 'origin' => 'http://localhost', + 'cookie' => 'a_session_console=' . $this->getRoot()['session'], + ], $projectId); + + $response = json_decode($client->receive(), true); + + $this->assertArrayHasKey('type', $response); + $this->assertArrayHasKey('data', $response); + $this->assertEquals('connected', $response['type']); + $this->assertNotEmpty($response['data']); + $this->assertCount(1, $response['data']['channels']); + $this->assertContains('console', $response['data']['channels']); + $this->assertNotEmpty($response['data']['user']); + + /** + * Test Create Deployment + */ + + $folder = 'php'; + $code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz"; + $this->packageCode($folder); + + $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'entrypoint' => 'index.php', + 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), + ]); + + $deploymentId = $deployment['body']['$id'] ?? ''; + + $this->assertEquals(202, $deployment['headers']['status-code']); + + $response = json_decode($client->receive(), true); + + $this->assertArrayHasKey('type', $response); + $this->assertArrayHasKey('data', $response); + $this->assertEquals('event', $response['type']); + $this->assertNotEmpty($response['data']); + $this->assertArrayHasKey('timestamp', $response['data']); + $this->assertCount(1, $response['data']['channels']); + $this->assertContains('console', $response['data']['channels']); + $this->assertContains("functions.{$functionId}.deployments.{$deploymentId}.create", $response['data']['events']); + $this->assertNotEmpty($response['data']['payload']); + + $client->close(); + } }