From 06daa544e892b6e8b2975a4226d3045d7fc1c96a Mon Sep 17 00:00:00 2001 From: prateek banga Date: Mon, 30 Oct 2023 23:37:57 +0530 Subject: [PATCH] review changes --- app/config/collections.php | 42 ++- app/config/errors.php | 5 + app/controllers/api/account.php | 8 +- app/controllers/api/messaging.php | 294 ++++++++++++++---- app/controllers/api/teams.php | 4 +- composer.lock | 2 +- src/Appwrite/Extend/Exception.php | 1 + src/Appwrite/Platform/Workers/Messaging.php | 43 ++- .../Database/Validator/Queries/Messages.php | 4 +- .../Database/Validator/Queries/Providers.php | 2 +- .../Utopia/Response/Model/Message.php | 22 +- .../Utopia/Response/Model/Provider.php | 2 +- .../Account/AccountCustomClientTest.php | 5 +- tests/e2e/Services/GraphQL/AccountTest.php | 1 - tests/e2e/Services/GraphQL/Base.php | 112 ++++--- tests/e2e/Services/GraphQL/MessagingTest.php | 24 +- .../e2e/Services/Messaging/MessagingBase.php | 24 +- 17 files changed, 421 insertions(+), 174 deletions(-) diff --git a/app/config/collections.php b/app/config/collections.php index 54b6b3bec..cf21df2eb 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1417,7 +1417,7 @@ $commonCollections = [ 'filters' => [], ], [ - '$id' => ID::custom('default'), + '$id' => ID::custom('internal'), 'type' => Database::VAR_BOOLEAN, 'signed' => true, 'size' => 0, @@ -1495,16 +1495,16 @@ $commonCollections = [ 'orders' => [Database::ORDER_ASC], ], [ - '$id' => ID::custom('_key_default'), + '$id' => ID::custom('_key_internal'), 'type' => Database::INDEX_KEY, - 'attributes' => ['default'], + 'attributes' => ['internal'], 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], [ - '$id' => ID::custom('_key_default_type'), + '$id' => ID::custom('_key_internal_type'), 'type' => Database::INDEX_KEY, - 'attributes' => ['default','type'], + 'attributes' => ['internal','type'], 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], @@ -1557,13 +1557,35 @@ $commonCollections = [ 'filters' => ['json'], ], [ - '$id' => ID::custom('to'), + '$id' => ID::custom('topics'), 'type' => Database::VAR_STRING, 'format' => '', - 'size' => 65535, + 'size' => 21845, 'signed' => true, - 'required' => true, - 'default' => null, + 'required' => false, + 'default' => [], + 'array' => true, + 'filters' => [], + ], + [ + '$id' => ID::custom('users'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 21845, + 'signed' => true, + 'required' => false, + 'default' => [], + 'array' => true, + 'filters' => [], + ], + [ + '$id' => ID::custom('targets'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 21845, + 'signed' => true, + 'required' => false, + 'default' => [], 'array' => true, 'filters' => [], ], @@ -1601,7 +1623,7 @@ $commonCollections = [ 'filters' => [], ], [ - '$id' => ID::custom('deliveredTo'), + '$id' => ID::custom('deliveredTotal'), 'type' => Database::VAR_INTEGER, 'format' => '', 'size' => 0, diff --git a/app/config/errors.php b/app/config/errors.php index 50c59b23e..931d24d65 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -790,6 +790,11 @@ return [ 'description' => 'Message with the requested ID could not be found.', 'code' => 404, ], + Exception::MESSAGE_MISSING_TARGET => [ + 'name' => Exception::MESSAGE_MISSING_TARGET, + 'description' => 'Message with the requested ID is missing a target (Topics or Users or Targets).', + 'code' => 400, + ], Exception::MESSAGE_ALREADY_SENT => [ 'name' => Exception::MESSAGE_ALREADY_SENT, 'description' => 'Message with the requested ID has already been sent.', diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 4c7411d97..faa862360 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1241,7 +1241,7 @@ App::post('/v1/account/sessions/phone') ->inject('locale') ->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale) { $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])); if ($provider === false || $provider->isEmpty()) { @@ -1347,7 +1347,7 @@ App::post('/v1/account/sessions/phone') $messageDoc = $dbForProject->createDocument('messages', new Document([ '$id' => $token->getId(), - 'to' => [$target->getId()], + 'targets' => [$target->getId()], 'data' => [ 'content' => $message, ], @@ -2914,7 +2914,7 @@ App::post('/v1/account/verification/phone') ->inject('locale') ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Document $project, Locale $locale) { $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])); if ($provider === false || $provider->isEmpty()) { @@ -2980,7 +2980,7 @@ App::post('/v1/account/verification/phone') $messageDoc = $dbForProject->createDocument('messages', new Document([ '$id' => $verification->getId(), - 'to' => [$target->getId()], + 'targets' => [$target->getId()], 'data' => [ 'content' => $message, ], diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 1dbb371a7..567c8e2cd 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -69,14 +69,14 @@ App::post('/v1/messaging/providers/mailgun') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['email']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -127,14 +127,14 @@ App::post('/v1/messaging/providers/sendgrid') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -187,14 +187,14 @@ App::post('/v1/messaging/providers/msg91') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -247,14 +247,14 @@ App::post('/v1/messaging/providers/telesign') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -307,14 +307,14 @@ App::post('/v1/messaging/providers/textmagic') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -367,14 +367,14 @@ App::post('/v1/messaging/providers/twilio') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -427,14 +427,14 @@ App::post('/v1/messaging/providers/vonage') ] ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -481,14 +481,14 @@ App::post('/v1/messaging/providers/fcm') ], ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['push']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -543,14 +543,14 @@ App::post('/v1/messaging/providers/apns') ], ]); - // Check if a default provider exists, if not, set this one as default + // Check if a internal provider exists, if not, set this one as internal if ( empty($dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['push']) ])) ) { - $provider->setAttribute('default', true); + $provider->setAttribute('internal', true); } try { @@ -647,13 +647,14 @@ App::patch('/v1/messaging/providers/mailgun/: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('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('isEuRegion', null, new Boolean(), 'Set as eu region.', true) ->param('from', '', new Text(256), 'Sender email address.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, ?bool $isEuRegion, string $from, string $apiKey, string $domain, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -680,6 +681,10 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if ($isEuRegion === true || $isEuRegion === false) { @@ -698,6 +703,15 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -718,11 +732,12 @@ App::patch('/v1/messaging/providers/sendgrid/: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('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) ->param('from', '', new Text(256), 'Sender email address.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $apiKey, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -749,6 +764,10 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + if (!empty($apiKey)) { $provider->setAttribute('credentials', [ 'apiKey' => $apiKey, @@ -757,6 +776,15 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -777,12 +805,13 @@ App::patch('/v1/messaging/providers/msg91/: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('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('senderId', '', new Text(0), 'Msg91 Sender ID.', true) ->param('authKey', '', new Text(0), 'Msg91 Auth Key.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $senderId, string $authKey, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $senderId, string $authKey, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -809,6 +838,10 @@ App::patch('/v1/messaging/providers/msg91/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($senderId)) { @@ -823,6 +856,15 @@ App::patch('/v1/messaging/providers/msg91/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -843,12 +885,13 @@ App::patch('/v1/messaging/providers/telesign/: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('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('username', '', new Text(0), 'Telesign username.', true) ->param('password', '', new Text(0), 'Telesign password.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $password, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $username, string $password, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -875,6 +918,10 @@ App::patch('/v1/messaging/providers/telesign/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($username)) { @@ -889,6 +936,15 @@ App::patch('/v1/messaging/providers/telesign/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -909,12 +965,13 @@ 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('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('username', '', new Text(0), 'Textmagic username.', true) ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $apiKey, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $username, string $apiKey, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -941,6 +998,10 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($username)) { @@ -955,6 +1016,15 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -975,12 +1045,13 @@ App::patch('/v1/messaging/providers/twilio/: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('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('accountSid', null, new Text(0), 'Twilio account secret ID.', true) ->param('authToken', null, new Text(0), 'Twilio authentication token.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $accountSid, string $authToken, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $accountSid, string $authToken, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1007,6 +1078,10 @@ App::patch('/v1/messaging/providers/twilio/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($accountSid)) { @@ -1021,6 +1096,15 @@ App::patch('/v1/messaging/providers/twilio/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1041,12 +1125,13 @@ App::patch('/v1/messaging/providers/vonage/: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('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('apiKey', '', new Text(0), 'Vonage API key.', true) ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) ->param('from', '', new Text(256), 'Sender number.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $apiSecret, string $from, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $apiKey, string $apiSecret, string $from, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1073,6 +1158,10 @@ App::patch('/v1/messaging/providers/vonage/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($apiKey)) { @@ -1087,6 +1176,15 @@ App::patch('/v1/messaging/providers/vonage/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1107,10 +1205,11 @@ App::patch('/v1/messaging/providers/fcm/: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('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('serverKey', '', new Text(0), 'FCM Server Key.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $serverKey, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $serverKey, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1131,12 +1230,25 @@ App::patch('/v1/messaging/providers/fcm/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + if (!empty($serverKey)) { $provider->setAttribute('credentials', ['serverKey' => $serverKey]); } $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1158,6 +1270,7 @@ App::patch('/v1/messaging/providers/apns/: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('internal', null, new Boolean(), 'Set as internal. Internal providers are used in services other than Messaging service such as Authentication service', true) ->param('authKey', '', new Text(0), 'APNS authentication key.', true) ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.', true) ->param('teamId', '', new Text(0), 'APNS team ID.', true) @@ -1165,7 +1278,7 @@ App::patch('/v1/messaging/providers/apns/:providerId') ->param('endpoint', '', new Text(0), 'APNS endpoint.', true) ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1186,6 +1299,10 @@ App::patch('/v1/messaging/providers/apns/:providerId') $provider->setAttribute('enabled', $enabled); } + if ($internal === true) { + $provider->setAttribute('internal', $internal); + } + $credentials = $provider->getAttribute('credentials'); if (!empty($authKey)) { @@ -1212,6 +1329,15 @@ App::patch('/v1/messaging/providers/apns/:providerId') $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + if ($internal === true) { + $internalProvider = $dbForProject->findOne('providers', [ + 'internal' => true, + 'type' => 'email', + ]); + $internalProvider->setAttribute('internal', false); + $dbForProject->updateDocument('providers', $internalProvider->getId(), $internalProvider); + } + $response ->dynamic($provider, Response::MODEL_PROVIDER); }); @@ -1620,9 +1746,11 @@ App::post('/v1/messaging/messages/email') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message 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('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), '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('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', 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) @@ -1631,12 +1759,18 @@ App::post('/v1/messaging/messages/email') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $to, string $subject, string $content, string $description, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, string $description, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { + throw new Exception(Exception::MESSAGE_MISSING_TARGET); + } + $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, - 'to' => $to, + 'topics' => $topics, + 'users' => $users, + 'targets' => $targets, 'description' => $description, 'data' => [ 'subject' => $subject, @@ -1673,8 +1807,10 @@ App::post('/v1/messaging/messages/sms') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message 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('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('content', '', new Text(64230), 'SMS Content.') + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', 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('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) @@ -1682,12 +1818,18 @@ App::post('/v1/messaging/messages/sms') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $to, string $content, string $description, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $content, array $topics, array $users, array $targets, string $description, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { + throw new Exception(Exception::MESSAGE_MISSING_TARGET); + } + $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, - 'to' => $to, + 'topics' => $topics, + 'users' => $users, + 'targets' => $targets, 'description' => $description, 'data' => [ 'content' => $content, @@ -1722,9 +1864,11 @@ App::post('/v1/messaging/messages/push') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new CustomId(), 'Message 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('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('title', '', new Text(256), 'Title for push notification.') ->param('body', '', new Text(64230), 'Body for push notification.') + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('data', null, new JSON(), 'Additional Data for push notification.', true) ->param('action', '', new Text(256), 'Action for push notification.', true) @@ -1739,9 +1883,13 @@ App::post('/v1/messaging/messages/push') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $to, string $title, string $body, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { + throw new Exception(Exception::MESSAGE_MISSING_TARGET); + } + $pushData = [ 'title' => $title, 'body' => $body, @@ -1777,7 +1925,9 @@ App::post('/v1/messaging/messages/push') $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, - 'to' => $to, + 'topics' => $topics, + 'users' => $users, + 'targets' => $targets, 'description' => $description, 'deliveryTime' => $deliveryTime, 'data' => $pushData, @@ -1878,7 +2028,9 @@ App::patch('/v1/messaging/messages/email/:messageId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('subject', '', new Text(998), 'Email Subject.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.', true) @@ -1889,7 +2041,7 @@ App::patch('/v1/messaging/messages/email/:messageId') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $to, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, array $topics, array $users, array $targets, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -1904,8 +2056,16 @@ App::patch('/v1/messaging/messages/email/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } - if (\count($to) > 0) { - $message->setAttribute('to', $to); + if (\count($topics) > 0) { + $message->setAttribute('topics', $topics); + } + + if (\count($users) > 0) { + $message->setAttribute('users', $users); + } + + if (\count($targets) > 0) { + $message->setAttribute('targets', $targets); } $data = $message->getAttribute('data'); @@ -1965,7 +2125,9 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.', true) ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) @@ -1974,7 +2136,7 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $to, string $description, string $content, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, array $topics, array $users, array $targets, string $description, string $content, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -1989,8 +2151,16 @@ App::patch('/v1/messaging/messages/sms/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } - if (\count($to) > 0) { - $message->setAttribute('to', $to); + if (\count($topics) > 0) { + $message->setAttribute('topics', $topics); + } + + if (\count($users) > 0) { + $message->setAttribute('users', $users); + } + + if (\count($targets) > 0) { + $message->setAttribute('targets', $targets); } $data = $message->getAttribute('data'); @@ -2042,7 +2212,9 @@ App::patch('/v1/messaging/messages/push/:messageId') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') - ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('title', '', new Text(256), 'Title for push notification.', true) ->param('body', '', new Text(64230), 'Body for push notification.', true) @@ -2058,7 +2230,7 @@ App::patch('/v1/messaging/messages/push/:messageId') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, array $to, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, array $topics, array $users, array $targets, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2073,8 +2245,16 @@ App::patch('/v1/messaging/messages/push/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } - if (\count($to) > 0) { - $message->setAttribute('to', $to); + if (\count($topics) > 0) { + $message->setAttribute('topics', $topics); + } + + if (\count($users) > 0) { + $message->setAttribute('users', $users); + } + + if (\count($targets) > 0) { + $message->setAttribute('targets', $targets); } $pushData = $message->getAttribute('data'); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index da2261fd5..a0975634d 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -633,7 +633,7 @@ App::post('/v1/teams/:teamId/memberships') ; } elseif (!empty($phone)) { $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ - Query::equal('default', [true]), + Query::equal('internal', [true]), Query::equal('type', ['sms']) ])); @@ -662,7 +662,7 @@ App::post('/v1/teams/:teamId/memberships') $messageDoc = $dbForProject->createDocument('messages', new Document([ // Here membership ID is used as message ID so that it can be used in test cases to verify the message '$id' => $membership->getId(), - 'to' => [$target->getId()], + 'targets' => [$target->getId()], 'data' => [ 'content' => $message, ], diff --git a/composer.lock b/composer.lock index 66e5e5a11..560dfe7b2 100644 --- a/composer.lock +++ b/composer.lock @@ -5822,5 +5822,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 8d6dc6d29..cef64ffce 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -241,6 +241,7 @@ class Exception extends \Exception /** Message */ public const MESSAGE_NOT_FOUND = 'message_not_found'; + public const MESSAGE_MISSING_TARGET = 'message_missing_target'; public const MESSAGE_ALREADY_SENT = 'message_already_sent'; public const MESSAGE_ALREADY_SCHEDULED = 'message_already_scheduled'; diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 5ca5ebfc6..a56c98b5e 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -10,6 +10,7 @@ use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; use Utopia\Messaging\Adapters\SMS as SMSAdapter; use Utopia\Messaging\Adapters\SMS\Mock; use Utopia\Messaging\Adapters\SMS\Msg91; @@ -70,25 +71,33 @@ class Messaging extends Action private function processMessage(Database $dbForProject, Document $message): void { - $recipientsId = $message->getAttribute('to', []); + $topicsId = $message->getAttribute('topics', []); + $targetsId = $message->getAttribute('targets', []); + $usersId = $message->getAttribute('users', []); /** * @var Document[] $recipients */ $recipients = []; - $topics = $dbForProject->find('topics', [Query::equal('$id', $recipientsId)]); - foreach ($topics as $topic) { - $recipients = \array_merge($recipients, $topic->getAttribute('targets')); + if (\count($topicsId) > 0) { + $topics = $dbForProject->find('topics', [Query::equal('$id', $topicsId)]); + foreach ($topics as $topic) { + $recipients = \array_merge($recipients, $topic->getAttribute('targets')); + } } - $users = $dbForProject->find('users', [Query::equal('$id', $recipientsId)]); - foreach ($users as $user) { - $recipients = \array_merge($recipients, $user->getAttribute('targets')); + if (\count($usersId) > 0) { + $users = $dbForProject->find('users', [Query::equal('$id', $usersId)]); + foreach ($users as $user) { + $recipients = \array_merge($recipients, $user->getAttribute('targets')); + } } - $targets = $dbForProject->find('targets', [Query::equal('$id', $recipientsId)]); - $recipients = \array_merge($recipients, $targets); + if (\count($targetsId) > 0) { + $targets = $dbForProject->find('targets', [Query::equal('$id', $targetsId)]); + $recipients = \array_merge($recipients, $targets); + } $providers = []; foreach ($recipients as $recipient) { @@ -104,7 +113,7 @@ class Messaging extends Action */ $results = batch(\array_map(function ($providerId) use ($providers, $message, $dbForProject) { return function () use ($providerId, $providers, $message, $dbForProject) { - $provider = $dbForProject->getDocument('providers', $providerId); + $provider = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId)); $identifiers = $providers[$providerId]; $adapter = match ($provider->getAttribute('type')) { 'sms' => $this->sms($provider), @@ -118,7 +127,7 @@ class Messaging extends Action $results = batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex) { return function () use ($batch, $message, $provider, $adapter, $batchIndex) { - $deliveredTo = 0; + $deliveredTotal = 0; $deliveryErrors = []; $messageData = clone $message; $messageData->setAttribute('to', $batch); @@ -130,13 +139,13 @@ class Messaging extends Action }; try { $adapter->send($data); - $deliveredTo += \count($batch); + $deliveredTotal += \count($batch); } catch (\Exception $e) { $deliveryErrors[] = 'Failed sending to targets ' . $batchIndex + 1 . '-' . \count($batch) . ' with error: ' . $e->getMessage(); } finally { $batchIndex++; return [ - 'deliveredTo' => $deliveredTo, + 'deliveredTotal' => $deliveredTotal, 'deliveryErrors' => $deliveryErrors, ]; } @@ -149,10 +158,10 @@ class Messaging extends Action $results = array_merge(...$results); - $deliveredTo = 0; + $deliveredTotal = 0; $deliveryErrors = []; foreach ($results as $result) { - $deliveredTo += $result['deliveredTo']; + $deliveredTotal += $result['deliveredTotal']; $deliveryErrors = \array_merge($deliveryErrors, $result['deliveryErrors']); } $message->setAttribute('deliveryErrors', $deliveryErrors); @@ -162,8 +171,8 @@ class Messaging extends Action } else { $message->setAttribute('status', 'sent'); } - $message->setAttribute('to', $recipientsId); - $message->setAttribute('deliveredTo', $deliveredTo); + $message->removeAttribute('to'); + $message->setAttribute('deliveredTotal', $deliveredTotal); $message->setAttribute('deliveredAt', DateTime::now()); $dbForProject->updateDocument('messages', $message->getId(), $message); diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php index 4bff13ae1..dd043474a 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Messages.php @@ -5,7 +5,9 @@ namespace Appwrite\Utopia\Database\Validator\Queries; class Messages extends Base { public const ALLOWED_ATTRIBUTES = [ - 'to', + 'topics', + 'users', + 'targets', 'providerId', 'deliveredAt', 'deliveredTo', diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php index 1fd6c9e9f..7760acbda 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Providers.php @@ -8,7 +8,7 @@ class Providers extends Base 'name', 'provider', 'type', - 'default', + 'internal', 'enabled', ]; diff --git a/src/Appwrite/Utopia/Response/Model/Message.php b/src/Appwrite/Utopia/Response/Model/Message.php index 609aa4022..7816c4bf5 100644 --- a/src/Appwrite/Utopia/Response/Model/Message.php +++ b/src/Appwrite/Utopia/Response/Model/Message.php @@ -17,12 +17,26 @@ class Message extends Any 'default' => '', 'example' => '5e5ea5c16897e', ]) - ->addRule('to', [ + ->addRule('topics', [ 'type' => self::TYPE_STRING, - 'description' => 'Message recipients.', + 'description' => 'Topic IDs set as recipients.', 'default' => '', 'array' => true, - 'example' => ['user-1'], + 'example' => ['5e5ea5c16897e'], + ]) + ->addRule('users', [ + 'type' => self::TYPE_STRING, + 'description' => 'User IDs set as recipients.', + 'default' => '', + 'array' => true, + 'example' => ['5e5ea5c16897e'], + ]) + ->addRule('targets', [ + 'type' => self::TYPE_STRING, + 'description' => 'Target IDs set as recipients.', + 'default' => '', + 'array' => true, + 'example' => ['5e5ea5c16897e'], ]) ->addRule('deliveryTime', [ 'type' => self::TYPE_DATETIME, @@ -46,7 +60,7 @@ class Message extends Any 'array' => true, 'example' => ['Failed to send message to target 5e5ea5c16897e: Credentials not valid.'], ]) - ->addRule('deliveredTo', [ + ->addRule('deliveredTotal', [ 'type' => self::TYPE_INTEGER, 'description' => 'Number of recipients the message was delivered to.', 'default' => 0, diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php index 552e9783e..ba522951e 100644 --- a/src/Appwrite/Utopia/Response/Model/Provider.php +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -28,7 +28,7 @@ class Provider extends Model 'default' => '', 'example' => 'mailgun', ]) - ->addRule('default', [ + ->addRule('internal', [ 'type' => self::TYPE_BOOLEAN, 'description' => 'Is this a pre-configured provider instance?', 'default' => false, diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 7f4cb84b0..c138f4049 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -762,7 +762,6 @@ class AccountCustomClientTest extends Scope 'name' => 'Sms provider', 'senderId' => $senderId, 'authKey' => $authKey, - 'default' => true, 'from' => $from, ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -810,7 +809,7 @@ class AccountCustomClientTest extends Scope ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); @@ -1040,7 +1039,7 @@ class AccountCustomClientTest extends Scope ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); return \array_merge($data, [ diff --git a/tests/e2e/Services/GraphQL/AccountTest.php b/tests/e2e/Services/GraphQL/AccountTest.php index 801be808c..e42fe1bc6 100644 --- a/tests/e2e/Services/GraphQL/AccountTest.php +++ b/tests/e2e/Services/GraphQL/AccountTest.php @@ -142,7 +142,6 @@ class AccountTest extends Scope 'from' => $from, 'senderId' => $senderId, 'authKey' => $authKey, - 'default' => true, ], ]; diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index bf6ae84f7..45fc14849 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -1790,7 +1790,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1801,7 +1801,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1812,7 +1812,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1823,7 +1823,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1834,7 +1834,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1845,7 +1845,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1856,7 +1856,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1867,7 +1867,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1878,7 +1878,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1891,7 +1891,7 @@ trait Base name provider type - default + internal enabled } } @@ -1903,7 +1903,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1914,7 +1914,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1925,7 +1925,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1936,7 +1936,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1947,7 +1947,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1958,7 +1958,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1969,7 +1969,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1980,7 +1980,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -1991,7 +1991,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -2002,7 +2002,7 @@ trait Base name provider type - default + internal enabled } }'; @@ -2087,40 +2087,46 @@ trait Base } }'; case self::$CREATE_EMAIL: - return 'mutation createEmail($messageId: String!, $to: [String!]!, $subject: String!, $content: String!, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { - messagingCreateEmail(messageId: $messageId, to: $to, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { + return 'mutation createEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String!, $content: String!, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { + messagingCreateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } }'; case self::$CREATE_SMS: - return 'mutation createSMS($messageId: String!, $to: [String!]!, $content: String!, $status: String, $description: String, $deliveryTime: String) { - messagingCreateSMS(messageId: $messageId, to: $to, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation createSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String!, $status: String, $description: String, $deliveryTime: String) { + messagingCreateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } }'; case self::$CREATE_PUSH_NOTIFICATION: - return 'mutation createPushNotification($messageId: String!, $to: [String!]!, $title: String!, $body: String!, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { - messagingCreatePushNotification(messageId: $messageId, to: $to, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation createPushNotification($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $title: String!, $body: String!, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { + messagingCreatePushNotification(messageId: $messageId, topics: $topics, users: $users, targets: $targets, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } @@ -2131,11 +2137,13 @@ trait Base total messages { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } @@ -2145,50 +2153,58 @@ trait Base return 'query getMessage($messageId: String!) { messagingGetMessage(messageId: $messageId) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } }'; case self::$UPDATE_EMAIL: - return 'mutation updateEmail($messageId: String!, $to: [String!], $subject: String, $content: String, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { - messagingUpdateEmail(messageId: $messageId, to: $to, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { + return 'mutation updateEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String, $content: String, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { + messagingUpdateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } }'; case self::$UPDATE_SMS: - return 'mutation updateSMS($messageId: String!, $to: [String!], $content: String, $status: String, $description: String, $deliveryTime: String) { - messagingUpdateSMS(messageId: $messageId, to: $to, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation updateSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String, $status: String, $description: String, $deliveryTime: String) { + messagingUpdateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } }'; case self::$UPDATE_PUSH_NOTIFICATION: - return 'mutation updatePushNotification($messageId: String!, $to: [String!], $title: String, $body: String, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { - messagingUpdatePushNotification(messageId: $messageId, to: $to, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { + return 'mutation updatePushNotification($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $title: String, $body: String, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { + messagingUpdatePushNotification(messageId: $messageId, topics: $topics, users: $users, targets: $targets, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { _id - to + topics + users + targets deliveryTime deliveredAt deliveryErrors - deliveredTo + deliveredTotal status description } diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 82f697f7e..004f7b2ec 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -631,7 +631,7 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), - 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'subject' => 'Khali beats Undertaker', 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', ], @@ -660,7 +660,7 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); return $message['body']['data']['messagingGetMessage']; @@ -777,7 +777,7 @@ class MessagingTest extends Scope 'variables' => [ 'messageId' => ID::unique(), 'status' => 'draft', - 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'subject' => 'Khali beats Undertaker', 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', ], @@ -822,7 +822,7 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); } @@ -931,7 +931,7 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), - 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'content' => '454665', ], ]; @@ -959,7 +959,7 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); return $message['body']['data']['messagingGetMessage']; } @@ -1073,7 +1073,7 @@ class MessagingTest extends Scope 'variables' => [ 'messageId' => ID::unique(), 'status' => 'draft', - 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'content' => '345463', ], ]; @@ -1117,7 +1117,7 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); } @@ -1222,7 +1222,7 @@ class MessagingTest extends Scope 'query' => $query, 'variables' => [ 'messageId' => ID::unique(), - 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'title' => 'Push Notification Title', 'body' => 'Push Notifiaction Body', ], @@ -1251,7 +1251,7 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); return $message['body']['data']['messagingGetMessage']; @@ -1361,7 +1361,7 @@ class MessagingTest extends Scope 'variables' => [ 'messageId' => ID::unique(), 'status' => 'draft', - 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']], 'title' => 'Push Notification Title', 'body' => 'Push Notifiaction Body', ], @@ -1406,7 +1406,7 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); } } diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 01138c641..b3a075d57 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -486,7 +486,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'messageId' => ID::unique(), - 'to' => [$topic['body']['$id']], + 'topics' => [$topic['body']['$id']], 'subject' => 'Khali beats Undertaker', 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', ]); @@ -503,7 +503,7 @@ trait MessagingBase ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); return $message; @@ -605,7 +605,7 @@ trait MessagingBase ], [ 'messageId' => ID::unique(), 'status' => 'draft', - 'to' => [$topic['body']['$id']], + 'topics' => [$topic['body']['$id']], 'subject' => 'Khali beats Undertaker', 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', ]); @@ -632,7 +632,7 @@ trait MessagingBase ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); } @@ -717,7 +717,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'messageId' => ID::unique(), - 'to' => [$topic['body']['$id']], + 'topics' => [$topic['body']['$id']], 'content' => '064763', ]); @@ -733,7 +733,7 @@ trait MessagingBase ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); return $message; @@ -833,7 +833,7 @@ trait MessagingBase ], [ 'messageId' => ID::unique(), 'status' => 'draft', - 'to' => [$topic['body']['$id']], + 'topics' => [$topic['body']['$id']], 'content' => '047487', ]); @@ -859,7 +859,7 @@ trait MessagingBase ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); } @@ -940,7 +940,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ 'messageId' => ID::unique(), - 'to' => [$topic['body']['$id']], + 'topics' => [$topic['body']['$id']], 'title' => 'Test-Notification', 'body' => 'Test-Notification-Body', ]); @@ -957,7 +957,7 @@ trait MessagingBase ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); return $message; @@ -1053,7 +1053,7 @@ trait MessagingBase ], [ 'messageId' => ID::unique(), 'status' => 'draft', - 'to' => [$topic['body']['$id']], + 'topics' => [$topic['body']['$id']], 'title' => 'Test-Notification', 'body' => 'Test-Notification-Body', ]); @@ -1080,7 +1080,7 @@ trait MessagingBase ]); $this->assertEquals(200, $message['headers']['status-code']); - $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); } }