From fd4a81c4fc3fe7288d93080e39a2a7eb2a5fa3f8 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 25 Oct 2023 23:03:23 +0530 Subject: [PATCH 1/4] made review changes --- app/config/collections.php | 4 +- app/config/events.php | 33 ++-- app/controllers/api/account.php | 26 +-- app/controllers/api/avatars.php | 4 +- app/controllers/api/messaging.php | 178 +++++++++--------- app/controllers/api/projects.php | 8 +- app/controllers/api/teams.php | 5 +- app/controllers/api/users.php | 8 +- app/init.php | 9 +- docs/tutorials/add-oauth2-provider.md | 6 +- src/Appwrite/Migration/Version/V15.php | 2 +- src/Appwrite/Migration/Version/V16.php | 12 +- src/Appwrite/Platform/Workers/Deletes.php | 40 +++- src/Appwrite/Platform/Workers/Messaging.php | 7 - .../Database/Validator/Queries/Messages.php | 3 +- src/Appwrite/Utopia/Response/Filters/V13.php | 4 +- src/Appwrite/Utopia/Response/Filters/V16.php | 6 +- .../Utopia/Response/Model/Project.php | 10 +- .../Projects/ProjectsConsoleClientTest.php | 6 +- .../unit/Utopia/Response/Filters/V16Test.php | 6 +- 20 files changed, 201 insertions(+), 176 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index bf2dd07975..8f4edef99f 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -5,7 +5,7 @@ use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Helpers\ID; -$providers = Config::getParam('authProviders', []); +$providers = Config::getParam('oAuthProviders', []); $auth = Config::getParam('auth', []); /** @@ -4008,7 +4008,7 @@ $consoleCollections = array_merge([ 'filters' => ['json'], ], [ - '$id' => ID::custom('authProviders'), + '$id' => ID::custom('oAuthProviders'), 'type' => Database::VAR_STRING, 'format' => '', 'size' => 16384, diff --git a/app/config/events.php b/app/config/events.php index b07d356470..8a89402184 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -261,29 +261,28 @@ return [ 'update' => [ '$description' => 'This event triggers when a message is updated.', ], - 'topics' => [ - '$model' => Response::MODEL_TOPIC, + ], + 'topics' => [ + '$model' => Response::MODEL_TOPIC, + '$resource' => true, + '$description' => 'This event triggers on any topic event.', + 'create' => [ + '$description' => 'This event triggers when a provider is created.', + ], + 'delete' => [ + '$description' => 'This event triggers when a provider is deleted.' + ], + 'subscribers' => [ + '$model' => Response::MODEL_SUBSCRIBER, '$resource' => true, - '$description' => 'This event triggers on any topic event.', + '$description' => 'This event triggers on any subscriber event.', 'create' => [ - '$description' => 'This event triggers when a provider is created.', + '$description' => 'This event triggers when a subscriber is created.', ], 'delete' => [ - '$description' => 'This event triggers when a provider is deleted.' - ], - 'subscribers' => [ - '$model' => Response::MODEL_SUBSCRIBER, - '$resource' => true, - '$description' => 'This event triggers on any subscriber event.', - 'create' => [ - '$description' => 'This event triggers when a subscriber is created.', - ], - 'delete' => [ - '$description' => 'This event triggers when a subscriber is deleted.' - ], + '$description' => 'This event triggers when a subscriber is deleted.' ], ], - ], 'providers' => [ '$model' => Response::MODEL_PROVIDER, diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 175c239b8e..f119d33414 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -299,7 +299,7 @@ App::get('/v1/account/sessions/oauth2/:provider') ->label('sdk.methodType', 'webAuth') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('authProviders'), fn($node) => (!$node['mock'])))) . '.') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn($node) => (!$node['mock'])))) . '.') ->param('success', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) ->param('failure', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) ->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) @@ -311,14 +311,14 @@ App::get('/v1/account/sessions/oauth2/:provider') $protocol = $request->getProtocol(); $callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId(); - $providerEnabled = $project->getAttribute('authProviders', [])[$provider . 'Enabled'] ?? false; + $providerEnabled = $project->getAttribute('oAuthProviders', [])[$provider . 'Enabled'] ?? false; if (!$providerEnabled) { throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please enable the provider from your ' . APP_NAME . ' console to continue.'); } - $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; + $appId = $project->getAttribute('oAuthProviders', [])[$provider . 'Appid'] ?? ''; + $appSecret = $project->getAttribute('oAuthProviders', [])[$provider . 'Secret'] ?? '{}'; if (!empty($appSecret) && isset($appSecret['version'])) { $key = App::getEnv('_APP_OPENSSL_KEY_V' . $appSecret['version']); @@ -358,7 +358,7 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->label('scope', 'public') ->label('docs', false) ->param('projectId', '', new Text(1024), 'Project ID.') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 provider.') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 provider.') ->param('code', '', new Text(2048, 0), 'OAuth2 code. This is a temporary code that the will be later exchanged for an access token.', true) ->param('state', '', new Text(2048), 'Login state params.', true) ->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true) @@ -391,7 +391,7 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId') ->label('origin', '*') ->label('docs', false) ->param('projectId', '', new Text(1024), 'Project ID.') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 provider.') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 provider.') ->param('code', '', new Text(2048, 0), 'OAuth2 code. This is a temporary code that the will be later exchanged for an access token.', true) ->param('state', '', new Text(2048), 'Login state params.', true) ->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true) @@ -430,7 +430,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->label('docs', false) ->label('usage.metric', 'sessions.{scope}.requests.create') ->label('usage.params', ['provider:{request.provider}']) - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'OAuth2 provider.') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 provider.') ->param('code', '', new Text(2048, 0), 'OAuth2 code. This is a temporary code that the will be later exchanged for an access token.', true) ->param('state', '', new Text(2048), 'OAuth2 state params.', true) ->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true) @@ -448,9 +448,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId(); $defaultState = ['success' => $project->getAttribute('url', ''), 'failure' => '']; $validateURL = new URL(); - $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; - $providerEnabled = $project->getAttribute('authProviders', [])[$provider . 'Enabled'] ?? false; + $appId = $project->getAttribute('oAuthProviders', [])[$provider . 'Appid'] ?? ''; + $appSecret = $project->getAttribute('oAuthProviders', [])[$provider . 'Secret'] ?? '{}'; + $providerEnabled = $project->getAttribute('oAuthProviders', [])[$provider . 'Enabled'] ?? false; $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); @@ -458,7 +458,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED); } - $providers = Config::getParam('authProviders'); + $providers = Config::getParam('oAuthProviders'); $providerName = $providers[$provider]['name'] ?? ''; /** @var Appwrite\Auth\OAuth2 $oauth2 */ @@ -2296,8 +2296,8 @@ App::patch('/v1/account/sessions/:sessionId') $provider = $session->getAttribute('provider'); $refreshToken = $session->getAttribute('providerRefreshToken'); - $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; + $appId = $project->getAttribute('oAuthProviders', [])[$provider . 'Appid'] ?? ''; + $appSecret = $project->getAttribute('oAuthProviders', [])[$provider . 'Secret'] ?? '{}'; $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index e0d967eb00..b6395774e9 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -84,8 +84,8 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro $accessTokenExpiry = $gitHubSession->getAttribute('providerAccessTokenExpiry'); $refreshToken = $gitHubSession->getAttribute('providerRefreshToken'); - $appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? ''; - $appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}'; + $appId = $project->getAttribute('oAuthProviders', [])[$provider . 'Appid'] ?? ''; + $appSecret = $project->getAttribute('oAuthProviders', [])[$provider . 'Secret'] ?? '{}'; $className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider); diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 3bf7561a49..20989da623 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -3,6 +3,7 @@ use Appwrite\Event\Delete; use Appwrite\Event\Messaging; use Appwrite\Extend\Exception; +use Appwrite\Network\Validator\Email; use Appwrite\Permission; use Appwrite\Role; use Appwrite\Utopia\Database\Validator\CustomId; @@ -27,9 +28,9 @@ use Utopia\Validator\Text; use Utopia\Validator\WhiteList; App::post('/v1/messaging/providers/mailgun') - ->desc('Create Mailgun Provider') + ->desc('Create Mailgun provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -41,15 +42,14 @@ App::post('/v1/messaging/providers/mailgun') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('isEuRegion', false, new Boolean(), 'Set as EU region.', true) - ->param('from', '', new Text(256), 'Sender Email Address.') + ->param('from', '', new Email(), 'Sender Email Address.') ->param('apiKey', '', new Text(0), 'Mailgun API Key.') ->param('domain', '', new Text(0), 'Mailgun Domain.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ @@ -57,7 +57,6 @@ App::post('/v1/messaging/providers/mailgun') 'name' => $name, 'provider' => 'mailgun', 'type' => 'email', - 'default' => $default, 'enabled' => $enabled, 'search' => $providerId . ' ' . $name . ' ' . 'mailgun' . ' ' . 'email', 'credentials' => [ @@ -92,9 +91,9 @@ App::post('/v1/messaging/providers/mailgun') }); App::post('/v1/messaging/providers/sendgrid') - ->desc('Create Sendgrid Provider') + ->desc('Create Sendgrid provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -106,19 +105,17 @@ App::post('/v1/messaging/providers/sendgrid') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $apiKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'sendgrid', 'type' => 'email', - 'default' => $default, 'enabled' => $enabled, 'options' => [], 'search' => $providerId . ' ' . $name . ' ' . 'sendgrid' . ' ' . 'email', @@ -149,9 +146,9 @@ App::post('/v1/messaging/providers/sendgrid') }); App::post('/v1/messaging/providers/msg91') - ->desc('Create Msg91 Provider') + ->desc('Create Msg91 provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -163,14 +160,13 @@ App::post('/v1/messaging/providers/msg91') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('from', '', new Text(256), 'Sender Number.') ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $from, string $senderId, string $authKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $from, string $senderId, string $authKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -178,7 +174,6 @@ App::post('/v1/messaging/providers/msg91') 'provider' => 'msg91', 'type' => 'sms', 'search' => $providerId . ' ' . $name . ' ' . 'msg91' . ' ' . 'sms', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'senderId' => $senderId, @@ -211,9 +206,9 @@ App::post('/v1/messaging/providers/msg91') }); App::post('/v1/messaging/providers/telesign') - ->desc('Create Telesign Provider') + ->desc('Create Telesign provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -225,13 +220,12 @@ App::post('/v1/messaging/providers/telesign') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('username', '', new Text(0), 'Telesign username.') ->param('password', '', new Text(0), 'Telesign password.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $username, string $password, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -239,7 +233,6 @@ App::post('/v1/messaging/providers/telesign') 'provider' => 'telesign', 'type' => 'sms', 'search' => $providerId . ' ' . $name . ' ' . 'telesign' . ' ' . 'sms', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'username' => $username, @@ -269,27 +262,26 @@ App::post('/v1/messaging/providers/telesign') }); App::post('/v1/messaging/providers/textmagic') - ->desc('Create Textmagic Provider') + ->desc('Create TextMagic provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'createTextmagicProvider') + ->label('sdk.method', 'createTextMagicProvider') ->label('sdk.description', '/docs/references/messaging/create-textmagic-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('username', '', new Text(0), 'Textmagic username.') - ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') + ->param('username', '', new Text(0), 'TextMagic username.') + ->param('apiKey', '', new Text(0), 'TextMagic apiKey.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -297,7 +289,6 @@ App::post('/v1/messaging/providers/textmagic') 'provider' => 'text-magic', 'type' => 'sms', 'search' => $providerId . ' ' . $name . ' ' . 'text-magic' . ' ' . 'sms', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'username' => $username, @@ -327,9 +318,9 @@ App::post('/v1/messaging/providers/textmagic') }); App::post('/v1/messaging/providers/twilio') - ->desc('Create Twilio Provider') + ->desc('Create Twilio provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -341,13 +332,12 @@ App::post('/v1/messaging/providers/twilio') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') ->param('authToken', '', new Text(0), 'Twilio authentication token.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $accountSid, string $authToken, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -355,7 +345,6 @@ App::post('/v1/messaging/providers/twilio') 'provider' => 'twilio', 'type' => 'sms', 'search' => $providerId . ' ' . $name . ' ' . 'twilio' . ' ' . 'sms', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'accountSid' => $accountSid, @@ -385,9 +374,9 @@ App::post('/v1/messaging/providers/twilio') }); App::post('/v1/messaging/providers/vonage') - ->desc('Create Vonage Provider') + ->desc('Create Vonage provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -399,13 +388,12 @@ App::post('/v1/messaging/providers/vonage') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Vonage API key.') ->param('apiSecret', '', new Text(0), 'Vonage API secret.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -413,7 +401,6 @@ App::post('/v1/messaging/providers/vonage') 'provider' => 'vonage', 'type' => 'sms', 'search' => $providerId . ' ' . $name . ' ' . 'vonage' . ' ' . 'sms', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'apiKey' => $apiKey, @@ -443,9 +430,9 @@ App::post('/v1/messaging/providers/vonage') }); App::post('/v1/messaging/providers/fcm') - ->desc('Create FCM Provider') + ->desc('Create FCM provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -457,9 +444,8 @@ App::post('/v1/messaging/providers/fcm') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) - ->param('serverKey', '', new Text(0), 'FCM Server Key.') + ->param('serverKey', '', new Text(0), 'FCM server key.') ->inject('dbForProject') ->inject('response') ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $serverKey, Database $dbForProject, Response $response) { @@ -470,7 +456,6 @@ App::post('/v1/messaging/providers/fcm') 'provider' => 'fcm', 'type' => 'push', 'search' => $providerId . ' ' . $name . ' ' . 'fcm' . ' ' . 'push', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'serverKey' => $serverKey, @@ -499,9 +484,9 @@ App::post('/v1/messaging/providers/fcm') }); App::post('/v1/messaging/providers/apns') - ->desc('Create APNS Provider') + ->desc('Create APNS provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.create') + ->label('audits.event', 'provider.create') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -513,7 +498,6 @@ App::post('/v1/messaging/providers/apns') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('default', false, new Boolean(), 'Set as default provider.', true) ->param('enabled', true, new Boolean(), 'Set as enabled.', true) ->param('authKey', '', new Text(0), 'APNS authentication key.') ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') @@ -530,7 +514,6 @@ App::post('/v1/messaging/providers/apns') 'provider' => 'apns', 'type' => 'push', 'search' => $providerId . ' ' . $name . ' ' . 'apns' . ' ' . 'push', - 'default' => $default, 'enabled' => $enabled, 'credentials' => [ 'authKey' => $authKey, @@ -563,7 +546,7 @@ App::post('/v1/messaging/providers/apns') }); App::get('/v1/messaging/providers') - ->desc('List Providers') + ->desc('List providers') ->groups(['api', 'messaging']) ->label('scope', 'providers.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -574,11 +557,16 @@ App::get('/v1/messaging/providers') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROVIDER_LIST) ->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) + ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('dbForProject') ->inject('response') ->action(function (array $queries, Database $dbForProject, Response $response) { $queries = Query::parseQueries($queries); + if (!empty($search)) { + $queries[] = Query::search('search', $search); + } + // Get cursor document if there was a cursor query $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); $cursor = reset($cursor); @@ -594,15 +582,14 @@ App::get('/v1/messaging/providers') $cursor->setValue($cursorDocument); } - $filterQueries = Query::groupByType($queries)['filters']; $response->dynamic(new Document([ - 'total' => $dbForProject->count('providers', $filterQueries, APP_LIMIT_COUNT), 'providers' => $dbForProject->find('providers', $queries), + 'total' => $dbForProject->count('providers', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_PROVIDER_LIST); }); App::get('/v1/messaging/providers/:providerId') - ->desc('Get Provider') + ->desc('Get provider') ->groups(['api', 'messaging']) ->label('scope', 'providers.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -626,9 +613,9 @@ App::get('/v1/messaging/providers/:providerId') }); App::patch('/v1/messaging/providers/mailgun/:providerId') - ->desc('Update Mailgun Provider') + ->desc('Update Mailgun provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -697,9 +684,9 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') }); App::patch('/v1/messaging/providers/sendgrid/:providerId') - ->desc('Update Sendgrid Provider') + ->desc('Update Sendgrid provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -749,9 +736,9 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') }); App::patch('/v1/messaging/providers/msg91/:providerId') - ->desc('Update Msg91 Provider') + ->desc('Update Msg91 provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -808,9 +795,9 @@ App::patch('/v1/messaging/providers/msg91/:providerId') }); App::patch('/v1/messaging/providers/telesign/:providerId') - ->desc('Update Telesign Provider') + ->desc('Update Telesign provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -867,14 +854,14 @@ App::patch('/v1/messaging/providers/telesign/:providerId') }); App::patch('/v1/messaging/providers/textmagic/:providerId') - ->desc('Update Textmagic Provider') + ->desc('Update TextMagic provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') - ->label('sdk.method', 'updateTextmagicProvider') + ->label('sdk.method', 'updateTextMagicProvider') ->label('sdk.description', '/docs/references/messaging/update-textmagic-provider.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) @@ -882,8 +869,8 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('username', '', new Text(0), 'Textmagic username.', true) - ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) + ->param('username', '', new Text(0), 'TextMagic username.', true) + ->param('apiKey', '', new Text(0), 'TextMagic apiKey.', true) ->inject('dbForProject') ->inject('response') ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $apiKey, Database $dbForProject, Response $response) { @@ -926,9 +913,9 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') }); App::patch('/v1/messaging/providers/twilio/:providerId') - ->desc('Update Twilio Provider') + ->desc('Update Twilio provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -985,9 +972,9 @@ App::patch('/v1/messaging/providers/twilio/:providerId') }); App::patch('/v1/messaging/providers/vonage/:providerId') - ->desc('Update Vonage Provider') + ->desc('Update Vonage provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -1044,9 +1031,9 @@ App::patch('/v1/messaging/providers/vonage/:providerId') }); App::patch('/v1/messaging/providers/fcm/:providerId') - ->desc('Update FCM Provider') + ->desc('Update FCM provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -1095,9 +1082,9 @@ App::patch('/v1/messaging/providers/fcm/:providerId') App::patch('/v1/messaging/providers/apns/:providerId') - ->desc('Update APNS Provider') + ->desc('Update APNS provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.update') + ->label('audits.event', 'provider.update') ->label('audits.resource', 'providers/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -1169,7 +1156,7 @@ App::patch('/v1/messaging/providers/apns/:providerId') }); App::delete('/v1/messaging/providers/:providerId') - ->desc('Delete Provider') + ->desc('Delete provider') ->groups(['api', 'messaging']) ->label('audits.event', 'providers.delete') ->label('audits.resource', 'providers/{request.id}') @@ -1182,15 +1169,20 @@ App::delete('/v1/messaging/providers/:providerId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_NONE) ->param('providerId', '', new UID(), 'Provider ID.') + ->inject('queueForDeletes') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, Database $dbForProject, Response $response) { + ->action(function (string $providerId, Delete $queueForDeletes, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); } + $queueForDeletes + ->setType(DELETE_TYPE_PROVIDER) + ->setDocument($provider); + $dbForProject->deleteDocument('providers', $provider->getId()); $response @@ -1259,11 +1251,16 @@ App::get('/v1/messaging/topics') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TOPIC_LIST) ->param('queries', [], new Topics(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Topics::ALLOWED_ATTRIBUTES), true) + ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('dbForProject') ->inject('response') - ->action(function (array $queries, Database $dbForProject, Response $response) { + ->action(function (array $queries, string $search, Database $dbForProject, Response $response) { $queries = Query::parseQueries($queries); + if (!empty($search)) { + $queries[] = Query::search('search', $search); + } + // Get cursor document if there was a cursor query $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); $cursor = reset($cursor); @@ -1279,10 +1276,9 @@ App::get('/v1/messaging/topics') $cursor->setValue($cursorDocument[0]); } - $filterQueries = Query::groupByType($queries)['filters']; $response->dynamic(new Document([ - 'total' => $dbForProject->count('topics', $filterQueries, APP_LIMIT_COUNT), 'topics' => $dbForProject->find('topics', $queries), + 'total' => $dbForProject->count('topics', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_TOPIC_LIST); }); @@ -1379,7 +1375,7 @@ App::delete('/v1/messaging/topics/:topicId') $dbForProject->deleteDocument('topics', $topicId); $queueForDeletes - ->setType(DELETE_TYPE_SUBSCRIBERS) + ->setType(DELETE_TYPE_TOPIC) ->setDocument($topic); $response @@ -1388,7 +1384,7 @@ App::delete('/v1/messaging/topics/:topicId') }); App::post('/v1/messaging/topics/:topicId/subscribers') - ->desc('Adds a Subscriber to a Topic.') + ->desc('Adds a subscriber to a topic.') ->groups(['api', 'messaging']) ->label('audits.event', 'subscribers.create') ->label('audits.resource', 'subscribers/{response.$id}') @@ -1485,12 +1481,10 @@ App::get('/v1/messaging/topics/:topicId/subscribers') $cursor->setValue($cursorDocument); } - $filterQueries = Query::groupByType($queries)['filters']; - $response ->dynamic(new Document([ 'subscribers' => $dbForProject->find('subscribers', $queries), - 'total' => $dbForProject->count('subscribers', $filterQueries, APP_LIMIT_COUNT), + 'total' => $dbForProject->count('subscribers', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_SUBSCRIBER_LIST); }); @@ -1527,7 +1521,7 @@ App::get('/v1/messaging/topics/:topicId/subscriber/:subscriberId') }); App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') - ->desc('Delete a Subscriber from a Topic.') + ->desc('Delete a subscriber from a topic.') ->groups(['api', 'messaging']) ->label('audits.event', 'subscribers.delete') ->label('audits.resource', 'subscribers/{request.subscriberId}') @@ -1581,7 +1575,7 @@ App::post('/v1/messaging/messages/email') ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('subject', '', new Text(998), 'Email Subject.') ->param('content', '', new Text(64230), 'Email Content.') - ->param('description', '', new Text(256), 'Description for Message.', true) + ->param('description', '', new Text(256), 'Description for message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) @@ -1795,7 +1789,7 @@ App::post('/v1/messaging/messages/push') }); App::get('/v1/messaging/messages') - ->desc('List Messages') + ->desc('List messages') ->groups(['api', 'messaging']) ->label('scope', 'messages.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -1806,11 +1800,16 @@ App::get('/v1/messaging/messages') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE_LIST) ->param('queries', [], new Messages(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true) + ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('dbForProject') ->inject('response') - ->action(function (array $queries, Database $dbForProject, Response $response) { + ->action(function (array $queries, string $search, Database $dbForProject, Response $response) { $queries = Query::parseQueries($queries); + if (!empty($search)) { + $queries[] = Query::search('search', $search); + } + // Get cursor document if there was a cursor query $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); $cursor = reset($cursor); @@ -1826,15 +1825,14 @@ App::get('/v1/messaging/messages') $cursor->setValue($cursorDocument); } - $filterQueries = Query::groupByType($queries)['filters']; $response->dynamic(new Document([ - 'total' => $dbForProject->count('messages', $filterQueries, APP_LIMIT_COUNT), 'messages' => $dbForProject->find('messages', $queries), + 'total' => $dbForProject->count('messages', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_MESSAGE_LIST); }); App::get('/v1/messaging/messages/:messageId') - ->desc('Get Message') + ->desc('Get a message') ->groups(['api', 'messaging']) ->label('scope', 'messages.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index a5f3b76608..de9cc82b84 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -164,7 +164,7 @@ App::post('/v1/projects') 'legalTaxId' => ID::custom($legalTaxId), 'services' => new stdClass(), 'platforms' => null, - 'authProviders' => [], + 'oAuthProviders' => [], 'webhooks' => null, 'keys' => null, 'auths' => $auths, @@ -613,7 +613,7 @@ App::patch('/v1/projects/:projectId/oauth2') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('authProviders')), true), 'Provider Name') + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'Provider Name') ->param('appId', null, new Text(256), 'Provider app ID. Max length: 256 chars.', true) ->param('secret', null, new text(512), 'Provider secret key. Max length: 512 chars.', true) ->param('enabled', null, new Boolean(), 'Provider status. Set to \'false\' to disable new session creation.', true) @@ -627,7 +627,7 @@ App::patch('/v1/projects/:projectId/oauth2') throw new Exception(Exception::PROJECT_NOT_FOUND); } - $providers = $project->getAttribute('authProviders', []); + $providers = $project->getAttribute('oAuthProviders', []); if ($appId !== null) { $providers[$provider . 'Appid'] = $appId; @@ -641,7 +641,7 @@ App::patch('/v1/projects/:projectId/oauth2') $providers[$provider . 'Enabled'] = $enabled; } - $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('authProviders', $providers)); + $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('oAuthProviders', $providers)); $response->dynamic($project, Response::MODEL_PROJECT); }); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index f600eb9aa5..da2261fd50 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -380,7 +380,6 @@ App::post('/v1/teams/:teamId/memberships') ->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.') ->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) // TODO add our own built-in confirm page ->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true) - ->param('from', '', new Text(128), 'Sender of the message. It can be alphanumeric (Ex: MyCompany20). Restrictions may apply depending of the destination.', true) ->inject('response') ->inject('project') ->inject('user') @@ -389,7 +388,7 @@ App::post('/v1/teams/:teamId/memberships') ->inject('queueForMails') ->inject('queueForMessaging') ->inject('queueForEvents') - ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, string $from, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents) { + ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents) { $isAPIKey = Auth::isAppUser(Authorization::getRoles()); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); @@ -634,7 +633,7 @@ App::post('/v1/teams/:teamId/memberships') ; } elseif (!empty($phone)) { $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('default', [true, false]), + Query::equal('default', [true]), Query::equal('type', ['sms']) ])); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index ac545ba329..7c9253684e 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -382,7 +382,7 @@ App::post('/v1/users/scrypt-modified') App::post('/v1/users/:userId/targets') ->desc('Create User Target') ->groups(['api', 'users']) - ->label('audits.event', 'users.targets.create') + ->label('audits.event', 'target.create') ->label('audits.resource', 'target/response.$id') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) @@ -1201,7 +1201,7 @@ App::patch('/v1/users/:userId/prefs') App::patch('/v1/users/:userId/targets/:targetId/identifier') ->desc('Update user target\'s identifier') ->groups(['api', 'users']) - ->label('audits.event', 'users.targets.update') + ->label('audits.event', 'target.update') ->label('audits.resource', 'target/{response.$id}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) @@ -1376,7 +1376,7 @@ App::delete('/v1/users/:userId') App::delete('/v1/users/:userId/targets/:targetId') ->desc('Delete user target') ->groups(['api', 'users']) - ->label('audits.event', 'users.targets.delete') + ->label('audits.event', 'target.delete') ->label('audits.resource', 'target/{request.$targetId}') ->label('scope', 'targets.write') ->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN]) @@ -1455,7 +1455,7 @@ App::get('/v1/users/usage') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_USAGE_USERS) ->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true) - ->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(fn ($value) => "oauth-" . $value, \array_keys(Config::getParam('authProviders', [])))), true), 'Provider Name.', true) + ->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(fn ($value) => "oauth-" . $value, \array_keys(Config::getParam('oAuthProviders', [])))), true), 'Provider Name.', true) ->inject('response') ->inject('dbForProject') ->inject('register') diff --git a/app/init.php b/app/init.php index 2513d713f5..136ecd25cb 100644 --- a/app/init.php +++ b/app/init.php @@ -168,7 +168,8 @@ const DELETE_TYPE_SESSIONS = 'sessions'; const DELETE_TYPE_CACHE_BY_TIMESTAMP = 'cacheByTimeStamp'; const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource'; const DELETE_TYPE_SCHEDULES = 'schedules'; -const DELETE_TYPE_SUBSCRIBERS = 'subscribers'; +const DELETE_TYPE_PROVIDER = 'provider'; +const DELETE_TYPE_TOPIC = 'topic'; // Compression type const COMPRESSION_TYPE_NONE = 'none'; const COMPRESSION_TYPE_GZIP = 'gzip'; @@ -233,7 +234,7 @@ App::setMode(App::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION)); Config::load('events', __DIR__ . '/config/events.php'); Config::load('auth', __DIR__ . '/config/auth.php'); Config::load('errors', __DIR__ . '/config/errors.php'); -Config::load('authProviders', __DIR__ . '/config/authProviders.php'); +Config::load('oAuthProviders', __DIR__ . '/config/oAuthProviders.php'); Config::load('platforms', __DIR__ . '/config/platforms.php'); Config::load('collections', __DIR__ . '/config/collections.php'); Config::load('runtimes', __DIR__ . '/config/runtimes.php'); @@ -531,6 +532,7 @@ Database::addFilter( return Authorization::skip(fn() => $database ->find('targets', [ Query::equal('userInternalId', [$document->getInternalId()]), + Query::limit(APP_LIMIT_SUBQUERY) ])); } ); @@ -546,6 +548,7 @@ Database::addFilter( $database ->find('subscribers', [ Query::equal('topicInternalId', [$document->getInternalId()]), + Query::limit(1000000) ]) )); if (\count($targetIds) > 0) { @@ -1128,7 +1131,7 @@ App::setResource('console', function () { ], 'authWhitelistEmails' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [], 'authWhitelistIPs' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [], - 'authProviders' => [ + 'oAuthProviders' => [ 'githubEnabled' => true, 'githubSecret' => App::getEnv('_APP_CONSOLE_GITHUB_SECRET', ''), 'githubAppid' => App::getEnv('_APP_CONSOLE_GITHUB_APP_ID', '') diff --git a/docs/tutorials/add-oauth2-provider.md b/docs/tutorials/add-oauth2-provider.md index 6481c64162..ab33f70cb2 100644 --- a/docs/tutorials/add-oauth2-provider.md +++ b/docs/tutorials/add-oauth2-provider.md @@ -37,7 +37,7 @@ Finally, you will need to create a `feat-XXX-YYY-oauth` branch based on the `mas The first step in adding a new OAuth2 provider is to add it to the list of providers located at: ``` -app/config/authProviders.php +app/config/oAuthProviders.php ``` Make sure to fill in all data needed and that your provider array key name: @@ -45,7 +45,7 @@ Make sure to fill in all data needed and that your provider array key name: - is in [`camelCase`](https://en.wikipedia.org/wiki/Camel_case) format for sentence, but lowercase for names. `github` must be all lowercased, but `paypalSandbox` should have uppercase S - has no spaces or special characters -> Please make sure to keep the list of providers in `authProviders.php` in the alphabetical order A-Z. +> Please make sure to keep the list of providers in `oAuthProviders.php` in the alphabetical order A-Z. ### 2.2 Add Provider Logo @@ -199,7 +199,7 @@ If you need any help with the contribution, feel free to head over to [our Disco If your OAuth provider requires special configuration apart from `clientId` and `clientSecret` you can create a custom form. Currently this is being realized through putting all custom fields as JSON into the `clientSecret` field to keep the project API stable. You can implement your custom form following these steps: -1. Add your custom form in `app/views/console/users/oauth/[PROVIDER].phtml`. Below is a template you can use. Add the filename to `app/config/authProviders.php`. +1. Add your custom form in `app/views/console/users/oauth/[PROVIDER].phtml`. Below is a template you can use. Add the filename to `app/config/oAuthProviders.php`. ```php "oauth-" . $value, - \array_keys(Config::getParam('authProviders', [])) + \array_keys(Config::getParam('oAuthProviders', [])) ) ); diff --git a/src/Appwrite/Migration/Version/V16.php b/src/Appwrite/Migration/Version/V16.php index bee2236dfb..49f244598e 100644 --- a/src/Appwrite/Migration/Version/V16.php +++ b/src/Appwrite/Migration/Version/V16.php @@ -124,23 +124,23 @@ class V16 extends Migration /** * Enable OAuth providers with data */ - $authProviders = $document->getAttribute('authProviders', []); + $oAuthProviders = $document->getAttribute('oAuthProviders', []); - foreach (Config::getParam('authProviders') as $provider => $value) { + foreach (Config::getParam('oAuthProviders') as $provider => $value) { if (!$value['enabled']) { continue; } - if (($authProviders[$provider . 'Appid'] ?? false) && ($authProviders[$provider . 'Secret'] ?? false)) { - if (array_key_exists($provider . 'Enabled', $authProviders)) { + if (($oAuthProviders[$provider . 'Appid'] ?? false) && ($oAuthProviders[$provider . 'Secret'] ?? false)) { + if (array_key_exists($provider . 'Enabled', $oAuthProviders)) { continue; } - $authProviders[$provider . 'Enabled'] = true; + $oAuthProviders[$provider . 'Enabled'] = true; } } - $document->setAttribute('authProviders', $authProviders); + $document->setAttribute('oAuthProviders', $oAuthProviders); break; } diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index cf2b359deb..6f33679aca 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -150,8 +150,11 @@ class Deletes extends Action case DELETE_TYPE_SCHEDULES: $this->deleteSchedules($dbForConsole, $getProjectDB, $datetime); break; - case DELETE_TYPE_SUBSCRIBERS: - $this->deleteSubscribers($project, $getProjectDB, $document); + case DELETE_TYPE_PROVIDER: + $this->deleteProvider($project, $getProjectDB, $document); + break; + case DELETE_TYPE_TOPIC: + $this->deleteTopic($project, $getProjectDB, $document); break; default: Console::error('No delete operation for type: ' . $type); @@ -196,13 +199,44 @@ class Deletes extends Action ); } + /** + * @param Document $project + * @param callable $getProjectDB + * @param Document $provider + * @throws Exception + */ + protected function deleteProvider(Document $project, callable $getProjectDB, Document $provider) + { + if ($provider->isEmpty()) { + Console::error('Failed to delete topics, subscribers and messages. Provider not found'); + return; + } + + $dbForProject = $getProjectDB($project); + $topics = $dbForProject->find('topics', [Query::equal('providerInternalId', [$provider->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY)]); + + $this->deleteByGroup('topics', [ + Query::equal('providerInternalId', [$provider->getInternalId()]) + ], $dbForProject); + + foreach ($topics as $topic) { + $this->deleteByGroup('subscribers', [ + Query::equal('topicInternalId', [$topic->getInternalId()]) + ], $dbForProject); + } + + $this->deleteByGroup('messages', [ + Query::equal('providerInternalId', [$provider->getInternalId()]) + ], $dbForProject); + } + /** * @param Document $project * @param callable $getProjectDB * @param Document $topic * @throws Exception */ - protected function deleteSubscribers(Document $project, callable $getProjectDB, Document $topic) + protected function deleteTopic(Document $project, callable $getProjectDB, Document $topic) { if ($topic->isEmpty()) { Console::error('Failed to delete subscribers. Topic not found'); diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index d87fb05532..b542dccaf2 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -31,13 +31,6 @@ use function Swoole\Coroutine\batch; class Messaging extends Action { - protected ?SMSAdapter $sms = null; - protected ?PushAdapter $push = null; - protected ?EmailAdapter $email = null; - - protected ?Database $dbForProject = null; - - public static function getName(): string { return "messaging"; diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php index d21aa5de1b..4bff13ae19 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php @@ -12,8 +12,7 @@ class Messages extends Base 'deliveryErrors', 'status', 'description', - 'data', - 'search' + 'data' ]; /** diff --git a/src/Appwrite/Utopia/Response/Filters/V13.php b/src/Appwrite/Utopia/Response/Filters/V13.php index d48473593e..04f9782915 100644 --- a/src/Appwrite/Utopia/Response/Filters/V13.php +++ b/src/Appwrite/Utopia/Response/Filters/V13.php @@ -60,8 +60,8 @@ class V13 extends Filter protected function parseProject($content) { - $content['providers'] = $content['authProviders']; - unset($content['authProviders']); + $content['providers'] = $content['oAuthProviders']; + unset($content['oAuthProviders']); return $content; } diff --git a/src/Appwrite/Utopia/Response/Filters/V16.php b/src/Appwrite/Utopia/Response/Filters/V16.php index 66cf650a78..609f118f6e 100644 --- a/src/Appwrite/Utopia/Response/Filters/V16.php +++ b/src/Appwrite/Utopia/Response/Filters/V16.php @@ -88,9 +88,9 @@ class V16 extends Filter protected function parseProject(array $content) { - foreach ($content['authProviders'] ?? [] as $i => $provider) { - $content['authProviders'][$i]['name'] = \ucfirst($provider['key']); - unset($content['authProviders'][$i]['key']); + foreach ($content['oAuthProviders'] ?? [] as $i => $provider) { + $content['oAuthProviders'][$i]['name'] = \ucfirst($provider['key']); + unset($content['oAuthProviders'][$i]['key']); } $content['domains'] = []; diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php index 807c1fb574..6bab4401d7 100644 --- a/src/Appwrite/Utopia/Response/Model/Project.php +++ b/src/Appwrite/Utopia/Response/Model/Project.php @@ -138,7 +138,7 @@ class Project extends Model 'default' => false, 'example' => true, ]) - ->addRule('authProviders', [ + ->addRule('oAuthProviders', [ 'type' => Response::MODEL_AUTH_PROVIDER, 'description' => 'List of Auth Providers.', 'default' => [], @@ -328,9 +328,9 @@ class Project extends Model $document->setAttribute('auth' . ucfirst($key), $value); } - // Providers - $providers = Config::getParam('authProviders', []); - $providerValues = $document->getAttribute('authProviders', []); + // OAuth Providers + $providers = Config::getParam('oAuthProviders', []); + $providerValues = $document->getAttribute('oAuthProviders', []); $projectProviders = []; foreach ($providers as $key => $provider) { @@ -348,7 +348,7 @@ class Project extends Model ]); } - $document->setAttribute('authProviders', $projectProviders); + $document->setAttribute('oAuthProviders', $projectProviders); return $document; } diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index eefc766b94..83e136fab4 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -794,7 +794,7 @@ class ProjectsConsoleClientTest extends Scope public function testUpdateProjectOAuth($data): array { $id = $data['projectId'] ?? ''; - $providers = require('app/config/authProviders.php'); + $providers = require('app/config/oAuthProviders.php'); /** * Test for SUCCESS @@ -825,7 +825,7 @@ class ProjectsConsoleClientTest extends Scope foreach ($providers as $key => $provider) { $asserted = false; - foreach ($response['body']['authProviders'] as $responseProvider) { + foreach ($response['body']['oAuthProviders'] as $responseProvider) { if ($responseProvider['key'] === $key) { $this->assertEquals('AppId-' . ucfirst($key), $responseProvider['appId']); $this->assertEquals('Secret-' . ucfirst($key), $responseProvider['secret']); @@ -867,7 +867,7 @@ class ProjectsConsoleClientTest extends Scope $i = 0; foreach ($providers as $key => $provider) { $asserted = false; - foreach ($response['body']['authProviders'] as $responseProvider) { + foreach ($response['body']['oAuthProviders'] as $responseProvider) { if ($responseProvider['key'] === $key) { // On first provider, test enabled=false $this->assertEquals($i !== 0, $responseProvider['enabled']); diff --git a/tests/unit/Utopia/Response/Filters/V16Test.php b/tests/unit/Utopia/Response/Filters/V16Test.php index 96c615f452..2078559b61 100644 --- a/tests/unit/Utopia/Response/Filters/V16Test.php +++ b/tests/unit/Utopia/Response/Filters/V16Test.php @@ -154,9 +154,9 @@ class V16Test extends TestCase public function projectProvider(): array { return [ - 'authProviders' => [ + 'oAuthProviders' => [ [ - 'authProviders' => [ + 'oAuthProviders' => [ [ 'key' => 'github', 'name' => 'GitHub', @@ -167,7 +167,7 @@ class V16Test extends TestCase ], ], [ - 'authProviders' => [ + 'oAuthProviders' => [ [ 'name' => 'Github', 'appId' => 'client_id', From 887eeef5856c2715c65c0dc317875dea5c36d47b Mon Sep 17 00:00:00 2001 From: prateek banga Date: Wed, 25 Oct 2023 23:09:38 +0530 Subject: [PATCH 2/4] review changes --- app/controllers/api/messaging.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 20989da623..c0e8f7215a 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -448,7 +448,7 @@ App::post('/v1/messaging/providers/fcm') ->param('serverKey', '', new Text(0), 'FCM server key.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $serverKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $serverKey, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, @@ -506,7 +506,7 @@ App::post('/v1/messaging/providers/apns') ->param('endpoint', '', new Text(0), 'APNS endpoint.') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, bool $default, bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $provider = new Document([ '$id' => $providerId, From 34b3ed68ee0f1aa6606ca82a585518cf286e9b17 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Thu, 26 Oct 2023 12:37:39 +0530 Subject: [PATCH 3/4] adds total count for subscribers in topics model --- app/config/collections.php | 13 ++++++++- app/controllers/api/messaging.php | 5 ++-- composer.lock | 2 +- src/Appwrite/Utopia/Response/Model/Topic.php | 6 ++++ .../e2e/Services/Messaging/MessagingBase.php | 28 +++++++++++++++++-- 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 8f4edef99f..4f492471d6 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1629,7 +1629,7 @@ $commonCollections = [ 'size' => 0, 'signed' => true, 'required' => false, - 'default' => null, + 'default' => 0, 'array' => false, 'filters' => [], ], @@ -1719,6 +1719,17 @@ $commonCollections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('total'), + 'type' => Database::VAR_INTEGER, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => 0, + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('targets'), 'type' => Database::VAR_STRING, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 830e2aef3f..4a2bc34776 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1491,7 +1491,7 @@ App::post('/v1/messaging/topics/:topicId/subscribers') try { $subscriber = $dbForProject->createDocument('subscribers', $subscriber); - $dbForProject->deleteCachedDocument('topics', $topicId); + Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('topics', $topicId, 'total', 1)); } catch (DuplicateException) { throw new Exception(Exception::SUBSCRIBER_ALREADY_EXISTS); } @@ -1610,8 +1610,9 @@ App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') if ($subscriber->isEmpty() || $subscriber->getAttribute('topicId') !== $topicId) { throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); } + $subscriber = $dbForProject->deleteDocument('subscribers', $subscriberId); - $dbForProject->deleteCachedDocument('topics', $topicId); + Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute('topics', $topicId, 'total', 1)); $response ->setStatusCode(Response::STATUS_CODE_NOCONTENT) diff --git a/composer.lock b/composer.lock index 7212a951a4..9ef16ead55 100644 --- a/composer.lock +++ b/composer.lock @@ -5822,5 +5822,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/src/Appwrite/Utopia/Response/Model/Topic.php b/src/Appwrite/Utopia/Response/Model/Topic.php index 3a6e832f5c..6d76faf6f4 100644 --- a/src/Appwrite/Utopia/Response/Model/Topic.php +++ b/src/Appwrite/Utopia/Response/Model/Topic.php @@ -28,6 +28,12 @@ class Topic extends Model 'default' => '', 'example' => 'events', ]) + ->addRule('total', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Total count of subscribers subscribed to topic.', + 'default' => 0, + 'example' => 100, + ]) ->addRule('description', [ 'type' => self::TYPE_STRING, 'description' => 'Description of the topic.', diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index c7804d7f89..765bd91ede 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -288,6 +288,7 @@ trait MessagingBase $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('android-app', $response['body']['name']); $this->assertEquals('updated-description', $response['body']['description']); + $this->assertEquals(0, $response['body']['total']); } /** @@ -311,12 +312,23 @@ trait MessagingBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'subscriberId' => 'unique()', + 'subscriberId' => ID::unique(), 'targetId' => $target['body']['$id'], ]); $this->assertEquals(201, $response['headers']['status-code']); + + $topic = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertEquals(200, $topic['headers']['status-code']); + $this->assertEquals('android-app', $topic['body']['name']); + $this->assertEquals('updated-description', $topic['body']['description']); + $this->assertEquals(1, $topic['body']['total']); + return [ - 'topicId' => $topic['$id'], + 'topicId' => $topic['body']['$id'], 'targetId' => $target['body']['$id'], 'subscriberId' => $response['body']['$id'] ]; @@ -361,7 +373,19 @@ trait MessagingBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); + $this->assertEquals(204, $response['headers']['status-code']); + + $topic = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $data['topicId'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $topic['headers']['status-code']); + $this->assertEquals('android-app', $topic['body']['name']); + $this->assertEquals('updated-description', $topic['body']['description']); + $this->assertEquals(0, $topic['body']['total']); } /** From c2cd544948a3d831740e509ce7bd931221c66d98 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 26 Oct 2023 13:46:45 +0530 Subject: [PATCH 4/4] review changes --- app/config/events.php | 7 +- app/controllers/api/messaging.php | 91 +++++++++++------------ app/init.php | 4 +- src/Appwrite/Platform/Workers/Deletes.php | 34 --------- 4 files changed, 50 insertions(+), 86 deletions(-) diff --git a/app/config/events.php b/app/config/events.php index 8a89402184..b0db9090fb 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -267,10 +267,13 @@ return [ '$resource' => true, '$description' => 'This event triggers on any topic event.', 'create' => [ - '$description' => 'This event triggers when a provider is created.', + '$description' => 'This event triggers when a topic is created.', + ], + 'update' => [ + '$description' => 'This event triggers when a topic is updated.', ], 'delete' => [ - '$description' => 'This event triggers when a provider is deleted.' + '$description' => 'This event triggers when a topic is deleted.' ], 'subscribers' => [ '$model' => Response::MODEL_SUBSCRIBER, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 4a2bc34776..e1057a0885 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -31,7 +31,7 @@ App::post('/v1/messaging/providers/mailgun') ->desc('Create Mailgun provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -94,7 +94,7 @@ App::post('/v1/messaging/providers/sendgrid') ->desc('Create Sendgrid provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -152,7 +152,7 @@ App::post('/v1/messaging/providers/msg91') ->desc('Create Msg91 provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -212,7 +212,7 @@ App::post('/v1/messaging/providers/telesign') ->desc('Create Telesign provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -272,7 +272,7 @@ App::post('/v1/messaging/providers/textmagic') ->desc('Create TextMagic provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -332,7 +332,7 @@ App::post('/v1/messaging/providers/twilio') ->desc('Create Twilio provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -392,7 +392,7 @@ App::post('/v1/messaging/providers/vonage') ->desc('Create Vonage provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -452,7 +452,7 @@ App::post('/v1/messaging/providers/fcm') ->desc('Create FCM provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -506,7 +506,7 @@ App::post('/v1/messaging/providers/apns') ->desc('Create APNS provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.create') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -635,7 +635,7 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ->desc('Update Mailgun provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -706,7 +706,7 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ->desc('Update Sendgrid provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -765,7 +765,7 @@ App::patch('/v1/messaging/providers/msg91/:providerId') ->desc('Update Msg91 provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -831,7 +831,7 @@ App::patch('/v1/messaging/providers/telesign/:providerId') ->desc('Update Telesign provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -897,7 +897,7 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ->desc('Update TextMagic provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -963,7 +963,7 @@ App::patch('/v1/messaging/providers/twilio/:providerId') ->desc('Update Twilio provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1029,7 +1029,7 @@ App::patch('/v1/messaging/providers/vonage/:providerId') ->desc('Update Vonage provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1095,7 +1095,7 @@ App::patch('/v1/messaging/providers/fcm/:providerId') ->desc('Update FCM provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1146,7 +1146,7 @@ App::patch('/v1/messaging/providers/apns/:providerId') ->desc('Update APNS provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.update') - ->label('audits.resource', 'providers/{response.$id}') + ->label('audits.resource', 'provider/{response.$id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1219,8 +1219,8 @@ App::patch('/v1/messaging/providers/apns/:providerId') App::delete('/v1/messaging/providers/:providerId') ->desc('Delete provider') ->groups(['api', 'messaging']) - ->label('audits.event', 'providers.delete') - ->label('audits.resource', 'providers/{request.id}') + ->label('audits.event', 'provider.delete') + ->label('audits.resource', 'provider/{request.id}') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1230,20 +1230,15 @@ App::delete('/v1/messaging/providers/:providerId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_NONE) ->param('providerId', '', new UID(), 'Provider ID.') - ->inject('queueForDeletes') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, Delete $queueForDeletes, Database $dbForProject, Response $response) { + ->action(function (string $providerId, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); } - $queueForDeletes - ->setType(DELETE_TYPE_PROVIDER) - ->setDocument($provider); - $dbForProject->deleteDocument('providers', $provider->getId()); $response @@ -1254,8 +1249,8 @@ App::delete('/v1/messaging/providers/:providerId') App::post('/v1/messaging/topics') ->desc('Create a topic.') ->groups(['api', 'messaging']) - ->label('audits.event', 'topics.create') - ->label('audits.resource', 'topics/{response.$id}') + ->label('audits.event', 'topic.create') + ->label('audits.resource', 'topic/{response.$id}') ->label('scope', 'topics.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1373,8 +1368,8 @@ App::get('/v1/messaging/topics/:topicId') App::patch('/v1/messaging/topics/:topicId') ->desc('Update a topic.') ->groups(['api', 'messaging']) - ->label('audits.event', 'topics.update') - ->label('audits.resource', 'topics/{response.$id}') + ->label('audits.event', 'topic.update') + ->label('audits.resource', 'topic/{response.$id}') ->label('scope', 'topics.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1412,8 +1407,8 @@ App::patch('/v1/messaging/topics/:topicId') App::delete('/v1/messaging/topics/:topicId') ->desc('Delete a topic.') ->groups(['api', 'messaging']) - ->label('audits.event', 'topics.delete') - ->label('audits.resource', 'topics/{request.topicId}') + ->label('audits.event', 'topic.delete') + ->label('audits.resource', 'topic/{request.topicId}') ->label('scope', 'topics.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1447,8 +1442,8 @@ App::delete('/v1/messaging/topics/:topicId') App::post('/v1/messaging/topics/:topicId/subscribers') ->desc('Adds a subscriber to a topic.') ->groups(['api', 'messaging']) - ->label('audits.event', 'subscribers.create') - ->label('audits.resource', 'subscribers/{response.$id}') + ->label('audits.event', 'subscriber.create') + ->label('audits.resource', 'subscriber/{response.$id}') ->label('scope', 'subscribers.write') ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1584,8 +1579,8 @@ App::get('/v1/messaging/topics/:topicId/subscriber/:subscriberId') App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') ->desc('Delete a subscriber from a topic.') ->groups(['api', 'messaging']) - ->label('audits.event', 'subscribers.delete') - ->label('audits.resource', 'subscribers/{request.subscriberId}') + ->label('audits.event', 'subscriber.delete') + ->label('audits.resource', 'subscriber/{request.subscriberId}') ->label('scope', 'subscribers.write') ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1622,8 +1617,8 @@ App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') App::post('/v1/messaging/messages/email') ->desc('Create an email.') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.create') - ->label('audits.resource', 'messages/{response.$id}') + ->label('audits.event', 'message.create') + ->label('audits.resource', 'message/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1688,8 +1683,8 @@ App::post('/v1/messaging/messages/email') App::post('/v1/messaging/messages/sms') ->desc('Create an SMS.') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.create') - ->label('audits.resource', 'messages/{response.$id}') + ->label('audits.event', 'message.create') + ->label('audits.resource', 'message/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1751,8 +1746,8 @@ App::post('/v1/messaging/messages/sms') App::post('/v1/messaging/messages/push') ->desc('Create a push notification.') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.create') - ->label('audits.resource', 'messages/{response.$id}') + ->label('audits.event', 'message.create') + ->label('audits.resource', 'message/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -1920,8 +1915,8 @@ App::get('/v1/messaging/messages/:messageId') App::patch('/v1/messaging/messages/email/:messageId') ->desc('Update an email.') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.update') - ->label('audits.resource', 'messages/{response.$id}') + ->label('audits.event', 'message.update') + ->label('audits.resource', 'message/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -2007,8 +2002,8 @@ App::patch('/v1/messaging/messages/email/:messageId') App::patch('/v1/messaging/messages/sms/:messageId') ->desc('Update an SMS.') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.update') - ->label('audits.resource', 'messages/{response.$id}') + ->label('audits.event', 'message.update') + ->label('audits.resource', 'message/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') @@ -2084,8 +2079,8 @@ App::patch('/v1/messaging/messages/sms/:messageId') App::patch('/v1/messaging/messages/push/:messageId') ->desc('Update a push notification.') ->groups(['api', 'messaging']) - ->label('audits.event', 'messages.update') - ->label('audits.resource', 'messages/{response.$id}') + ->label('audits.event', 'message.update') + ->label('audits.resource', 'message/{response.$id}') ->label('scope', 'messages.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) ->label('sdk.namespace', 'messaging') diff --git a/app/init.php b/app/init.php index 136ecd25cb..a60dcb2079 100644 --- a/app/init.php +++ b/app/init.php @@ -98,6 +98,7 @@ const APP_LIMIT_COMPRESSION = 20000000; //20MB const APP_LIMIT_ARRAY_PARAMS_SIZE = 100; // Default maximum of how many elements can there be in API parameter that expects array value const APP_LIMIT_ARRAY_ELEMENT_SIZE = 4096; // Default maximum length of element in array parameter represented by maximum URL length. const APP_LIMIT_SUBQUERY = 1000; +const APP_LIMIT_SUBSCRIBERS_SUBQUERY = 1000000; const APP_LIMIT_WRITE_RATE_DEFAULT = 60; // Default maximum write rate per rate period const APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT = 60; // Default maximum write rate period in seconds const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return in list API calls @@ -168,7 +169,6 @@ const DELETE_TYPE_SESSIONS = 'sessions'; const DELETE_TYPE_CACHE_BY_TIMESTAMP = 'cacheByTimeStamp'; const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource'; const DELETE_TYPE_SCHEDULES = 'schedules'; -const DELETE_TYPE_PROVIDER = 'provider'; const DELETE_TYPE_TOPIC = 'topic'; // Compression type const COMPRESSION_TYPE_NONE = 'none'; @@ -548,7 +548,7 @@ Database::addFilter( $database ->find('subscribers', [ Query::equal('topicInternalId', [$document->getInternalId()]), - Query::limit(1000000) + Query::limit(APP_LIMIT_SUBSCRIBERS_SUBQUERY) ]) )); if (\count($targetIds) > 0) { diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 6f33679aca..a22f7840f7 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -150,9 +150,6 @@ class Deletes extends Action case DELETE_TYPE_SCHEDULES: $this->deleteSchedules($dbForConsole, $getProjectDB, $datetime); break; - case DELETE_TYPE_PROVIDER: - $this->deleteProvider($project, $getProjectDB, $document); - break; case DELETE_TYPE_TOPIC: $this->deleteTopic($project, $getProjectDB, $document); break; @@ -199,37 +196,6 @@ class Deletes extends Action ); } - /** - * @param Document $project - * @param callable $getProjectDB - * @param Document $provider - * @throws Exception - */ - protected function deleteProvider(Document $project, callable $getProjectDB, Document $provider) - { - if ($provider->isEmpty()) { - Console::error('Failed to delete topics, subscribers and messages. Provider not found'); - return; - } - - $dbForProject = $getProjectDB($project); - $topics = $dbForProject->find('topics', [Query::equal('providerInternalId', [$provider->getInternalId()]), Query::limit(APP_LIMIT_SUBQUERY)]); - - $this->deleteByGroup('topics', [ - Query::equal('providerInternalId', [$provider->getInternalId()]) - ], $dbForProject); - - foreach ($topics as $topic) { - $this->deleteByGroup('subscribers', [ - Query::equal('topicInternalId', [$topic->getInternalId()]) - ], $dbForProject); - } - - $this->deleteByGroup('messages', [ - Query::equal('providerInternalId', [$provider->getInternalId()]) - ], $dbForProject); - } - /** * @param Document $project * @param callable $getProjectDB