1
0
Fork 0
mirror of synced 2024-06-14 08:44:49 +12:00

removes internal provider

This commit is contained in:
prateek banga 2023-11-16 01:30:47 +05:30
parent 2aa8391c5e
commit c24664f5d9
14 changed files with 209 additions and 474 deletions

View file

@ -1416,17 +1416,6 @@ $commonCollections = [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('internal'),
'type' => Database::VAR_BOOLEAN,
'signed' => true,
'size' => 0,
'format' => '',
'filters' => [],
'required' => false,
'default' => false,
'array' => false,
],
[
'$id' => ID::custom('enabled'),
'type' => Database::VAR_BOOLEAN,
@ -1495,16 +1484,9 @@ $commonCollections = [
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_internal'),
'$id' => ID::custom('_key_enabled_type'),
'type' => Database::INDEX_KEY,
'attributes' => ['internal'],
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_internal_type'),
'type' => Database::INDEX_KEY,
'attributes' => ['internal','type'],
'attributes' => ['enabled','type'],
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],

View file

@ -781,11 +781,6 @@ return [
'description' => 'Provider with the requested ID is of incorrect type: ',
'code' => 400,
],
Exception::PROVIDER_INTERNAL_UPDATE_DISABLED => [
'name' => Exception::PROVIDER_INTERNAL_UPDATE_DISABLED,
'description' => 'Provider with the requested ID cannot be disabled.',
'code' => 400,
],
/** Topic Errors */
Exception::TOPIC_NOT_FOUND => [

View file

@ -440,7 +440,7 @@ return [
'variables' => [
[
'name' => '_APP_SMS_PROVIDER',
'description' => "Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'.\n\nEnsure `[USER]` and `[SECRET]` are URL encoded if they contain any non-alphanumeric characters.\n\nAvailable providers are twilio, text-magic, telesign, msg91, and vonage.",
'description' => "Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'.\n\nEnsure `[USER]` and `[SECRET]` are URL encoded if they contain any non-alphanumeric characters.\n\nAvailable providers are twilio, textmagic, telesign, msg91, and vonage.",
'introduction' => '0.15.0',
'default' => '',
'required' => false,

View file

@ -1260,12 +1260,7 @@ App::post('/v1/account/sessions/phone')
->inject('queueForMessaging')
->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('internal', [true]),
Query::equal('type', ['sms'])
]));
if ($provider === false || $provider->isEmpty()) {
if (empty(App::getEnv('_APP_SMS_PROVIDER'))) {
throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured');
}
@ -1351,35 +1346,18 @@ App::post('/v1/account/sessions/phone')
$message = $message->setParam('{{token}}', $secret);
$message = $message->render();
$target = $dbForProject->findOne('targets', [
Query::equal('identifier', [$phone]),
]);
if (!$target || $target->isEmpty()) {
$target = $dbForProject->createDocument('targets', new Document([
'$permissions' => [
Permission::read(Role::any()),
Permission::update(Role::user($user->getId())),
Permission::delete(Role::user($user->getId())),
],
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'providerType' => 'sms',
'identifier' => $phone,
]));
$dbForProject->deleteCachedDocument('users', $user->getId());
}
$messageDoc = $dbForProject->createDocument('messages', new Document([
$messageDoc = new Document([
'$id' => $token->getId(),
'targets' => [$target->getId()],
'data' => [
'content' => $message,
],
]));
]);
$queueForMessaging
->setMessageId($messageDoc->getId())
->setMessage($messageDoc)
->setRecipients([$phone])
->setProviderType('SMS')
->setProject($project)
->trigger();
@ -2964,12 +2942,7 @@ App::post('/v1/account/verification/phone')
->inject('project')
->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('internal', [true]),
Query::equal('type', ['sms'])
]));
if ($provider === false || $provider->isEmpty()) {
if (empty(App::getEnv('_APP_SMS_PROVIDER'))) {
throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured');
}
@ -3015,35 +2988,17 @@ App::post('/v1/account/verification/phone')
$message = $message->setParam('{{token}}', $secret);
$message = $message->render();
$target = $dbForProject->findOne('targets', [
Query::equal('identifier', [$user->getAttribute('phone')]),
]);
if (!$target || $target->isEmpty()) {
$target = $dbForProject->createDocument('targets', new Document([
'$permissions' => [
Permission::read(Role::any()),
Permission::update(Role::user($user->getId())),
Permission::delete(Role::user($user->getId())),
],
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'providerType' => 'sms',
'identifier' => $user->getAttribute('phone'),
]));
$dbForProject->deleteCachedDocument('users', $user->getId());
}
$messageDoc = $dbForProject->createDocument('messages', new Document([
$messageDoc = new Document([
'$id' => $verification->getId(),
'targets' => [$target->getId()],
'data' => [
'content' => $message,
],
]));
]);
$queueForMessaging
->setMessageId($messageDoc->getId())
->setMessage($messageDoc)
->setRecipients([$user->getAttribute('phone')])
->setProviderType('SMS')
->setProject($project)
->trigger();

View file

@ -79,16 +79,6 @@ App::post('/v1/messaging/providers/mailgun')
]
]);
// Check if a internal provider exists, if not, set this one as internal
if (
empty($dbForProject->findOne('providers', [
Query::equal('internal', [true]),
Query::equal('type', ['email'])
]))
) {
$provider->setAttribute('internal', true);
}
try {
$provider = $dbForProject->createDocument('providers', $provider);
} catch (DuplicateException) {
@ -141,16 +131,6 @@ App::post('/v1/messaging/providers/sendgrid')
]
]);
// Check if a internal provider exists, if not, set this one as internal
if (
empty($dbForProject->findOne('providers', [
Query::equal('internal', [true]),
Query::equal('type', ['sms'])
]))
) {
$provider->setAttribute('internal', true);
}
try {
$provider = $dbForProject->createDocument('providers', $provider);
} catch (DuplicateException) {
@ -205,16 +185,6 @@ App::post('/v1/messaging/providers/msg91')
]
]);
// Check if a internal provider exists, if not, set this one as internal
if (
empty($dbForProject->findOne('providers', [
Query::equal('internal', [true]),
Query::equal('type', ['sms'])
]))
) {
$provider->setAttribute('internal', true);
}
try {
$provider = $dbForProject->createDocument('providers', $provider);
} catch (DuplicateException) {
@ -269,16 +239,6 @@ App::post('/v1/messaging/providers/telesign')
]
]);
// Check if a internal provider exists, if not, set this one as internal
if (
empty($dbForProject->findOne('providers', [
Query::equal('internal', [true]),
Query::equal('type', ['sms'])
]))
) {
$provider->setAttribute('internal', true);
}
try {
$provider = $dbForProject->createDocument('providers', $provider);
} catch (DuplicateException) {
@ -333,16 +293,6 @@ App::post('/v1/messaging/providers/textmagic')
]
]);
// Check if a internal provider exists, if not, set this one as internal
if (
empty($dbForProject->findOne('providers', [
Query::equal('internal', [true]),
Query::equal('type', ['sms'])
]))
) {
$provider->setAttribute('internal', true);
}
try {
$provider = $dbForProject->createDocument('providers', $provider);
} catch (DuplicateException) {
@ -397,16 +347,6 @@ App::post('/v1/messaging/providers/twilio')
]
]);
// Check if a internal provider exists, if not, set this one as internal
if (
empty($dbForProject->findOne('providers', [
Query::equal('internal', [true]),
Query::equal('type', ['sms'])
]))
) {
$provider->setAttribute('internal', true);
}
try {
$provider = $dbForProject->createDocument('providers', $provider);
} catch (DuplicateException) {
@ -461,16 +401,6 @@ App::post('/v1/messaging/providers/vonage')
]
]);
// Check if a internal provider exists, if not, set this one as internal
if (
empty($dbForProject->findOne('providers', [
Query::equal('internal', [true]),
Query::equal('type', ['sms'])
]))
) {
$provider->setAttribute('internal', true);
}
try {
$provider = $dbForProject->createDocument('providers', $provider);
} catch (DuplicateException) {
@ -519,16 +449,6 @@ App::post('/v1/messaging/providers/fcm')
],
]);
// Check if a internal provider exists, if not, set this one as internal
if (
empty($dbForProject->findOne('providers', [
Query::equal('internal', [true]),
Query::equal('type', ['push'])
]))
) {
$provider->setAttribute('internal', true);
}
try {
$provider = $dbForProject->createDocument('providers', $provider);
} catch (DuplicateException) {
@ -585,16 +505,6 @@ App::post('/v1/messaging/providers/apns')
],
]);
// Check if a internal provider exists, if not, set this one as internal
if (
empty($dbForProject->findOne('providers', [
Query::equal('internal', [true]),
Query::equal('type', ['push'])
]))
) {
$provider->setAttribute('internal', true);
}
try {
$provider = $dbForProject->createDocument('providers', $provider);
} catch (DuplicateException) {
@ -776,7 +686,6 @@ 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)
@ -784,7 +693,7 @@ App::patch('/v1/messaging/providers/mailgun/:providerId')
->inject('queueForEvents')
->inject('dbForProject')
->inject('response')
->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, ?bool $isEuRegion, string $from, string $apiKey, string $domain, Event $queueForEvents, Database $dbForProject, Response $response) {
->action(function (string $providerId, string $name, ?bool $enabled, ?bool $isEuRegion, string $from, string $apiKey, string $domain, Event $queueForEvents, Database $dbForProject, Response $response) {
$provider = $dbForProject->getDocument('providers', $providerId);
if ($provider->isEmpty()) {
@ -806,14 +715,7 @@ App::patch('/v1/messaging/providers/mailgun/:providerId')
]);
}
if ($internal === true) {
$provider->setAttribute('internal', $internal);
}
if ($enabled === true || $enabled === false) {
if ($provider->getAttribute('internal') === true && $enabled === false) {
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
}
$provider->setAttribute('enabled', $enabled);
}
@ -835,15 +737,6 @@ 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);
}
$queueForEvents
->setParam('providerId', $provider->getId());
@ -868,13 +761,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('queueForEvents')
->inject('dbForProject')
->inject('response')
->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $apiKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) {
->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) {
$provider = $dbForProject->getDocument('providers', $providerId);
if ($provider->isEmpty()) {
@ -896,14 +788,7 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId')
]);
}
if ($internal === true) {
$provider->setAttribute('internal', $internal);
}
if ($enabled === true || $enabled === false) {
if ($provider->getAttribute('internal') === true && $enabled === false) {
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
}
$provider->setAttribute('enabled', $enabled);
}
@ -915,15 +800,6 @@ 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);
}
$queueForEvents
->setParam('providerId', $provider->getId());
@ -948,14 +824,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('queueForEvents')
->inject('dbForProject')
->inject('response')
->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $senderId, string $authKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) {
->action(function (string $providerId, string $name, ?bool $enabled, string $senderId, string $authKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) {
$provider = $dbForProject->getDocument('providers', $providerId);
if ($provider->isEmpty()) {
@ -977,14 +852,7 @@ App::patch('/v1/messaging/providers/msg91/:providerId')
]);
}
if ($internal === true) {
$provider->setAttribute('internal', $internal);
}
if ($enabled === true || $enabled === false) {
if ($provider->getAttribute('internal') === true && $enabled === false) {
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
}
$provider->setAttribute('enabled', $enabled);
}
@ -1002,15 +870,6 @@ 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);
}
$queueForEvents
->setParam('providerId', $provider->getId());
@ -1035,14 +894,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('queueForEvents')
->inject('dbForProject')
->inject('response')
->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $username, string $password, string $from, Event $queueForEvents, Database $dbForProject, Response $response) {
->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $password, string $from, Event $queueForEvents, Database $dbForProject, Response $response) {
$provider = $dbForProject->getDocument('providers', $providerId);
if ($provider->isEmpty()) {
@ -1064,14 +922,7 @@ App::patch('/v1/messaging/providers/telesign/:providerId')
]);
}
if ($internal === true) {
$provider->setAttribute('internal', $internal);
}
if ($enabled === true || $enabled === false) {
if ($provider->getAttribute('internal') === true && $enabled === false) {
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
}
$provider->setAttribute('enabled', $enabled);
}
@ -1089,15 +940,6 @@ 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);
}
$queueForEvents
->setParam('providerId', $provider->getId());
@ -1122,14 +964,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('queueForEvents')
->inject('dbForProject')
->inject('response')
->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $username, string $apiKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) {
->action(function (string $providerId, string $name, ?bool $enabled, string $username, string $apiKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) {
$provider = $dbForProject->getDocument('providers', $providerId);
if ($provider->isEmpty()) {
@ -1151,14 +992,7 @@ App::patch('/v1/messaging/providers/textmagic/:providerId')
]);
}
if ($internal === true) {
$provider->setAttribute('internal', $internal);
}
if ($enabled === true || $enabled === false) {
if ($provider->getAttribute('internal') === true && $enabled === false) {
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
}
$provider->setAttribute('enabled', $enabled);
}
@ -1176,15 +1010,6 @@ 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);
}
$queueForEvents
->setParam('providerId', $provider->getId());
@ -1209,14 +1034,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('queueForEvents')
->inject('dbForProject')
->inject('response')
->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $accountSid, string $authToken, string $from, Event $queueForEvents, Database $dbForProject, Response $response) {
->action(function (string $providerId, string $name, ?bool $enabled, string $accountSid, string $authToken, string $from, Event $queueForEvents, Database $dbForProject, Response $response) {
$provider = $dbForProject->getDocument('providers', $providerId);
if ($provider->isEmpty()) {
@ -1238,14 +1062,7 @@ App::patch('/v1/messaging/providers/twilio/:providerId')
]);
}
if ($internal === true) {
$provider->setAttribute('internal', $internal);
}
if ($enabled === true || $enabled === false) {
if ($provider->getAttribute('internal') === true && $enabled === false) {
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
}
$provider->setAttribute('enabled', $enabled);
}
@ -1263,15 +1080,6 @@ 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);
}
$queueForEvents
->setParam('providerId', $provider->getId());
@ -1296,14 +1104,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('queueForEvents')
->inject('dbForProject')
->inject('response')
->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $apiKey, string $apiSecret, string $from, Event $queueForEvents, Database $dbForProject, Response $response) {
->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $apiSecret, string $from, Event $queueForEvents, Database $dbForProject, Response $response) {
$provider = $dbForProject->getDocument('providers', $providerId);
if ($provider->isEmpty()) {
@ -1325,14 +1132,7 @@ App::patch('/v1/messaging/providers/vonage/:providerId')
]);
}
if ($internal === true) {
$provider->setAttribute('internal', $internal);
}
if ($enabled === true || $enabled === false) {
if ($provider->getAttribute('internal') === true && $enabled === false) {
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
}
$provider->setAttribute('enabled', $enabled);
}
@ -1350,15 +1150,6 @@ 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);
}
$queueForEvents
->setParam('providerId', $provider->getId());
@ -1383,12 +1174,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('queueForEvents')
->inject('dbForProject')
->inject('response')
->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $serverKey, Event $queueForEvents, Database $dbForProject, Response $response) {
->action(function (string $providerId, string $name, ?bool $enabled, string $serverKey, Event $queueForEvents, Database $dbForProject, Response $response) {
$provider = $dbForProject->getDocument('providers', $providerId);
if ($provider->isEmpty()) {
@ -1404,14 +1194,7 @@ App::patch('/v1/messaging/providers/fcm/:providerId')
$provider->setAttribute('name', $name);
}
if ($internal === true) {
$provider->setAttribute('internal', $internal);
}
if ($enabled === true || $enabled === false) {
if ($provider->getAttribute('internal') === true && $enabled === false) {
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
}
$provider->setAttribute('enabled', $enabled);
}
@ -1421,15 +1204,6 @@ App::patch('/v1/messaging/providers/fcm/: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);
}
$queueForEvents
->setParam('providerId', $provider->getId());
@ -1455,7 +1229,6 @@ 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)
@ -1464,7 +1237,7 @@ App::patch('/v1/messaging/providers/apns/:providerId')
->inject('queueForEvents')
->inject('dbForProject')
->inject('response')
->action(function (string $providerId, string $name, ?bool $enabled, ?bool $internal, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Event $queueForEvents, Database $dbForProject, Response $response) {
->action(function (string $providerId, string $name, ?bool $enabled, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Event $queueForEvents, Database $dbForProject, Response $response) {
$provider = $dbForProject->getDocument('providers', $providerId);
if ($provider->isEmpty()) {
@ -1480,14 +1253,7 @@ App::patch('/v1/messaging/providers/apns/:providerId')
$provider->setAttribute('name', $name);
}
if ($internal === true) {
$provider->setAttribute('internal', $internal);
}
if ($enabled === true || $enabled === false) {
if ($provider->getAttribute('internal') === true && $enabled === false) {
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
}
$provider->setAttribute('enabled', $enabled);
}
@ -1517,15 +1283,6 @@ 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);
}
$queueForEvents
->setParam('providerId', $provider->getId());

View file

@ -628,12 +628,7 @@ App::post('/v1/teams/:teamId/memberships')
->trigger()
;
} elseif (!empty($phone)) {
$provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [
Query::equal('internal', [true]),
Query::equal('type', ['sms'])
]));
if ($provider === false || $provider->isEmpty()) {
if (empty(App::getEnv('_APP_SMS_PROVIDER'))) {
throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured');
}
@ -647,27 +642,17 @@ App::post('/v1/teams/:teamId/memberships')
$message = $message->setParam('{{token}}', $url);
$message = $message->render();
$target = $dbForProject->createDocument('targets', new Document([
'userId' => $invitee->getId(),
'userInternalId' => $invitee->getInternalId(),
'providerType' => 'sms',
'identifier' => $phone,
]));
$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(),
'targets' => [$target->getId()],
$messageDoc = new Document([
'$id' => ID::unique(),
'data' => [
'content' => $message,
],
'providerId' => $provider->getId(),
'providerInternalId' => $provider->getInternalId(),
'deliveryTime' => Datetime::now(),
]));
]);
$queueForMessaging
->setMessageId($messageDoc->getId())
->setMessage($messageDoc)
->setRecipients([$phone])
->setProviderType('SMS')
->setProject($project)
->trigger();
}

View file

@ -582,6 +582,8 @@ services:
- _APP_DB_PASS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG
- _APP_SMS_FROM
- _APP_SMS_PROVIDER
appwrite-worker-migrations:
entrypoint: worker-migrations

View file

@ -9,7 +9,11 @@ use Utopia\Queue\Client;
class Messaging extends Event
{
protected ?string $messageId = null;
private ?string $deliveryTime = null;
protected ?Document $message = null;
protected ?array $recipients = null;
protected ?string $deliveryTime = null;
protected ?string $providerType = null;
public function __construct(protected Connection $connection)
{
@ -20,6 +24,52 @@ class Messaging extends Event
->setClass(Event::MESSAGING_CLASS_NAME);
}
/**
* Sets recipient for the messaging event.
*
* @param string[] $recipients
* @return self
*/
public function setRecipients(array $recipients): self
{
$this->recipients = $recipients;
return $this;
}
/**
* Returns set recipient for messaging event.
*
* @return string[]
*/
public function getRecipient(): array
{
return $this->recipients;
}
/**
* Sets message document for the messaging event.
*
* @param Document $message
* @return self
*/
public function setMessage(Document $message): self
{
$this->message = $message;
return $this;
}
/**
* Returns message document for the messaging event.
*
* @return string
*/
public function getMessage(): Document
{
return $this->message;
}
/**
* Sets message ID for the messaging event.
*
@ -43,6 +93,29 @@ class Messaging extends Event
return $this->messageId;
}
/**
* Sets provider type for the messaging event.
*
* @param string $providerType
* @return self
*/
public function setProviderType(string $providerType): self
{
$this->providerType = $providerType;
return $this;
}
/**
* Returns set provider type for the messaging event.
*
* @return string
*/
public function getProviderType(): string
{
return $this->providerType;
}
/**
* Sets Delivery time for the messaging event.
*
@ -92,6 +165,9 @@ class Messaging extends Event
'project' => $this->project,
'user' => $this->user,
'messageId' => $this->messageId,
'message' => $this->message,
'recipients' => $this->recipients,
'providerType' => $this->providerType,
]);
}
}
}

View file

@ -3,7 +3,10 @@
namespace Appwrite\Platform\Workers;
use Appwrite\Extend\Exception;
use Utopia\App;
use Utopia\CLI\Console;
use Utopia\Database\Helpers\ID;
use Utopia\DSN\DSN;
use Utopia\Platform\Action;
use Utopia\Queue\Message;
use Utopia\Database\Database;
@ -63,11 +66,19 @@ class Messaging extends Action
return;
}
$message = $dbForProject->getDocument('messages', $payload['messageId']);
if (!\is_null($payload['message']) && !\is_null($payload['recipients'])) {
if ($payload['providerType'] === 'SMS') {
$this->processInternalSMSMessage(new Document($payload['message']), $payload['recipients']);
}
} else {
$message = $dbForProject->getDocument('messages', $payload['messageId']);
$this->processMessage($dbForProject, $message);
$this->processMessage($dbForProject, $message);
}
}
private function processMessage(Database $dbForProject, Document $message): void
{
$topicsId = $message->getAttribute('topics', []);
@ -99,7 +110,7 @@ class Messaging extends Action
}
$internalProvider = $dbForProject->findOne('providers', [
Query::equal('internal', [true]),
Query::equal('enabled', [true]),
Query::equal('type', [$recipients[0]->getAttribute('providerType')]),
]);
@ -215,6 +226,74 @@ class Messaging extends Action
$dbForProject->updateDocument('messages', $message->getId(), $message);
}
private function processInternalSMSMessage(Document $message, array $recipients): void
{
if(empty(App::getEnv('_APP_SMS_PROVIDER')) || empty(App::getEnv('_APP_SMS_FROM'))) {
Console::info('Skipped SMS processing. No Phone configuration has been set.');
return;
}
$smsDSN = new DSN(App::getEnv('_APP_SMS_PROVIDER'));
$host = $smsDSN->getHost();
$password = $smsDSN->getPassword();
$user = $smsDSN->getUser();
$from = App::getEnv('_APP_SMS_FROM');
$provider = new Document([
'$id' => ID::unique(),
'provider' => $host,
'type' => 'sms',
'name' => 'Internal SMS',
'enabled' => true,
'credentials' => match ($host) {
'twilio' => [
'accountSid' => $user,
'authToken' => $password
],
'textmagic' => [
'username' => $user,
'apiKey' => $password
],
'telesign' => [
'username' => $user,
'password' => $password
],
'msg91' => [
'senderId' => $user,
'authKey' => $password
],
'vonage' => [
'apiKey' => $user,
'apiSecret' => $password
],
default => null
},
'options' => [
'from' => $from
]
]);
$adapter = $this->sms($provider);
$maxBatchSize = $adapter->getMaxMessagesPerRequest();
$batches = \array_chunk($recipients, $maxBatchSize);
$batchIndex = 0;
batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex) {
return function () use ($batch, $message, $provider, $adapter, $batchIndex) {
$message->setAttribute('to', $batch);
$data = $this->buildSMSMessage($message, $provider);
try {
$adapter->send($data);
} catch (\Exception $e) {
Console::error('Failed sending to targets ' . $batchIndex + 1 . '-' . \count($batch) . ' with error: ' . $e->getMessage());
}
};
}, $batches));
}
public function shutdown(): void
{
}
@ -225,7 +304,7 @@ class Messaging extends Action
return match ($provider->getAttribute('provider')) {
'mock' => new Mock('username', 'password'),
'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']),
'text-magic' => new TextMagic($credentials['username'], $credentials['apiKey']),
'textmagic' => new TextMagic($credentials['username'], $credentials['apiKey']),
'telesign' => new Telesign($credentials['username'], $credentials['password']),
'msg91' => new Msg91($credentials['senderId'], $credentials['authKey']),
'vonage' => new Vonage($credentials['apiKey'], $credentials['apiSecret']),

View file

@ -8,7 +8,6 @@ class Providers extends Base
'name',
'provider',
'type',
'internal',
'enabled',
];

View file

@ -40,12 +40,6 @@ class Provider extends Model
'default' => '',
'example' => 'mailgun',
])
->addRule('internal', [
'type' => self::TYPE_BOOLEAN,
'description' => 'Is this a pre-configured provider instance?',
'default' => false,
'example' => true,
])
->addRule('enabled', [
'type' => self::TYPE_BOOLEAN,
'description' => 'Is provider enabled?',

View file

@ -744,33 +744,8 @@ class AccountCustomClientTest extends Scope
public function testCreatePhone(): array
{
if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) {
$this->markTestSkipped('SMS DSN not provided');
}
$number = '+123456789';
$smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'));
$to = $smsDSN->getParam('to');
$from = $smsDSN->getParam('from');
$authKey = $smsDSN->getPassword();
$senderId = $smsDSN->getUser();
if (empty($to) || empty($from) || empty($authKey) || empty($senderId)) {
$this->markTestSkipped('SMS provider not configured');
}
$number = $to;
$response = $this->client->call(Client::METHOD_POST, '/messaging/providers/msg91', \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]), [
'providerId' => ID::unique(),
'name' => 'Sms provider',
'senderId' => $senderId,
'authKey' => $authKey,
'from' => $from,
]);
$this->assertEquals(201, $response['headers']['status-code']);
/**
* Test for SUCCESS
*/
@ -781,7 +756,6 @@ class AccountCustomClientTest extends Scope
]), [
'userId' => ID::unique(),
'phone' => $number,
'from' => $from,
]);
$this->assertEquals(201, $response['headers']['status-code']);
@ -807,19 +781,17 @@ class AccountCustomClientTest extends Scope
\sleep(5);
$message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $messageId, [
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$smsRequest = $this->getLastRequest();
$this->assertEquals(200, $message['headers']['status-code']);
$this->assertEquals(1, $message['body']['deliveredTotal']);
$this->assertEquals(0, \count($message['body']['deliveryErrors']));
$this->assertEquals('http://request-catcher:5000/mock-sms', $smsRequest['url']);
$this->assertEquals('Appwrite Mock Message Sender', $smsRequest['headers']['User-Agent']);
$this->assertEquals('username', $smsRequest['headers']['X-Username']);
$this->assertEquals('password', $smsRequest['headers']['X-Key']);
$this->assertEquals('POST', $smsRequest['method']);
$this->assertEquals('+123456789', $smsRequest['data']['from']);
$this->assertEquals($number, $smsRequest['data']['to']);
$data['token'] = $message['body']['data']['content'];
$data['token'] = $smsRequest['data']['message'];
$data['id'] = $userId;
$data['number'] = $number;
@ -1018,8 +990,6 @@ class AccountCustomClientTest extends Scope
public function testPhoneVerification(array $data): array
{
$session = $data['session'] ?? '';
$smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'));
$from = $smsDSN->getParam('from');
/**
* Test for SUCCESS
@ -1030,28 +1000,19 @@ class AccountCustomClientTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
]), ['from' => $from]);
]));
$this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEmpty($response['body']['secret']);
$this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['expire']));
\sleep(3);
\sleep(2);
$message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $response['body']['$id'], [
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(200, $message['headers']['status-code']);
$this->assertEquals(1, $message['body']['deliveredTotal']);
$this->assertEquals(0, \count($message['body']['deliveryErrors']));
$smsRequest = $this->getLastRequest();
return \array_merge($data, [
'token' => $message['body']['data']['content']
'token' => $smsRequest['data']['secret']
]);
}

View file

@ -124,38 +124,7 @@ class AccountTest extends Scope
*/
public function testCreatePhoneVerification(): array
{
if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) {
$this->markTestSkipped('SMS DSN not provided');
}
$smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'));
$to = $smsDSN->getParam('to');
$from = $smsDSN->getParam('from');
$authKey = $smsDSN->getPassword();
$senderId = $smsDSN->getUser();
if (empty($to) || empty($from) || empty($authKey) || empty($senderId)) {
$this->markTestSkipped('SMS provider not configured');
}
$projectId = $this->getProject()['$id'];
$query = $this->getQuery(self::$CREATE_MSG91_PROVIDER);
$graphQLPayload = [
'query' => $query,
'variables' => [
'providerId' => ID::unique(),
'name' => 'Sms Provider',
'from' => $from,
'senderId' => $senderId,
'authKey' => $authKey,
],
];
$response = $this->client->call(Client::METHOD_POST, '/graphql', [
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
'x-appwrite-key' => $this->getProject()['apiKey'],
], $graphQLPayload);
$query = $this->getQuery(self::$CREATE_PHONE_VERIFICATION);
$graphQLPayload = [

View file

@ -1796,7 +1796,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1807,7 +1806,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1818,7 +1816,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1829,7 +1826,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1840,7 +1836,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1851,7 +1846,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1862,7 +1856,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1873,7 +1866,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1884,7 +1876,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1897,7 +1888,7 @@ trait Base
name
provider
type
internal
enabled
}
}
@ -1909,7 +1900,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1920,7 +1910,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1931,7 +1920,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1942,7 +1930,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1953,7 +1940,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1964,7 +1950,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1975,7 +1960,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1986,7 +1970,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -1997,7 +1980,6 @@ trait Base
name
provider
type
internal
enabled
}
}';
@ -2008,7 +1990,6 @@ trait Base
name
provider
type
internal
enabled
}
}';