diff --git a/.env b/.env index 6ea21eed9d..f77083a035 100644 --- a/.env +++ b/.env @@ -87,7 +87,7 @@ _APP_LOGGING_PROVIDER= _APP_LOGGING_CONFIG= _APP_GRAPHQL_MAX_BATCH_SIZE=10 _APP_GRAPHQL_MAX_COMPLEXITY=250 -_APP_GRAPHQL_MAX_DEPTH=3 +_APP_GRAPHQL_MAX_DEPTH=4 _APP_DOCKER_HUB_USERNAME= _APP_DOCKER_HUB_PASSWORD= _APP_VCS_GITHUB_APP_NAME= diff --git a/app/config/collections.php b/app/config/collections.php index f310c91211..7e715baa2c 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1722,28 +1722,6 @@ $commonCollections = [ '$id' => ID::custom('subscribers'), 'name' => 'Subscribers', 'attributes' => [ - [ - '$id' => ID::custom('userId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], - [ - '$id' => ID::custom('userInternalId'), - 'type' => Database::VAR_STRING, - 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, - 'required' => true, - 'default' => null, - 'array' => false, - 'filters' => [], - ], [ '$id' => ID::custom('targetId'), 'type' => Database::VAR_STRING, @@ -1790,20 +1768,6 @@ $commonCollections = [ ], ], 'indexes' => [ - [ - '$id' => ID::custom('_key_userId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['userId'], - 'lengths' => [], - 'orders' => [], - ], - [ - '$id' => ID::custom('_key_userInternalId'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['userInternalId'], - 'lengths' => [], - 'orders' => [], - ], [ '$id' => ID::custom('_key_targetId'), 'type' => Database::INDEX_KEY, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 536ebaf408..f13b037b02 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -54,31 +54,57 @@ App::post('/v1/messaging/providers/mailgun') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Email(), 'Sender email address.') - ->param('apiKey', '', new Text(0), 'Mailgun API Key.') - ->param('domain', '', new Text(0), 'Mailgun Domain.') - ->param('isEuRegion', false, new Boolean(), 'Set as EU region.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Email(), 'Sender email address.', true) + ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) + ->param('domain', '', new Text(0), 'Mailgun Domain.', true) + ->param('isEuRegion', null, new Boolean(), 'Set as EU region.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $apiKey, string $domain, bool $isEuRegion, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $apiKey, string $domain, ?bool $isEuRegion, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if ($isEuRegion === true || $isEuRegion === false) { + $credentials['isEuRegion'] = $isEuRegion; + } + + if (!empty($apiKey)) { + $credentials['apiKey'] = $apiKey; + } + + if (!empty($domain)) { + $credentials['domain'] = $domain; + } + + if ( + $enabled === true && + \array_key_exists('isEuRegion', $credentials) && + \array_key_exists('apiKey', $credentials) && + \array_key_exists('domain', $credentials) && + \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'mailgun', 'type' => 'email', 'enabled' => $enabled, - 'credentials' => [ - 'apiKey' => $apiKey, - 'domain' => $domain, - 'isEuRegion' => $isEuRegion, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $options, ]); try { @@ -111,26 +137,45 @@ App::post('/v1/messaging/providers/sendgrid') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Email(), 'Sender email address.') - ->param('apiKey', '', new Text(0), 'Sendgrid API key.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Email(), 'Sender email address.', true) + ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $apiKey, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $apiKey, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if (!empty($apiKey)) { + $credentials['apiKey'] = $apiKey; + } + + if ( + $enabled === true + && \array_key_exists('apiKey', $credentials) + && \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'sendgrid', 'type' => 'email', 'enabled' => $enabled, - 'credentials' => [ - 'apiKey' => $apiKey, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $options, ]); try { @@ -163,28 +208,51 @@ App::post('/v1/messaging/providers/msg91') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') - ->param('senderId', '', new Text(0), 'Msg91 Sender ID.') - ->param('authKey', '', new Text(0), 'Msg91 Auth Key.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) + ->param('senderId', '', new Text(0), 'Msg91 Sender ID.', true) + ->param('authKey', '', new Text(0), 'Msg91 Auth Key.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $senderId, string $authKey, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $senderId, string $authKey, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if (!empty($senderId)) { + $credentials['senderId'] = $senderId; + } + + if (!empty($authKey)) { + $credentials['authKey'] = $authKey; + } + + if ( + $enabled === true + && \array_key_exists('senderId', $credentials) + && \array_key_exists('authKey', $credentials) + && \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'msg91', 'type' => 'sms', 'enabled' => $enabled, - 'credentials' => [ - 'senderId' => $senderId, - 'authKey' => $authKey, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $options, ]); try { @@ -217,28 +285,51 @@ App::post('/v1/messaging/providers/telesign') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') - ->param('username', '', new Text(0), 'Telesign username.') - ->param('password', '', new Text(0), 'Telesign password.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) + ->param('username', '', new Text(0), 'Telesign username.', true) + ->param('password', '', new Text(0), 'Telesign password.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $username, string $password, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $username, string $password, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if (!empty($username)) { + $credentials['username'] = $username; + } + + if (!empty($password)) { + $credentials['password'] = $password; + } + + if ( + $enabled === true + && \array_key_exists('username', $credentials) + && \array_key_exists('password', $credentials) + && \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'telesign', 'type' => 'sms', 'enabled' => $enabled, - 'credentials' => [ - 'username' => $username, - 'password' => $password, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $options, ]); try { @@ -271,28 +362,51 @@ App::post('/v1/messaging/providers/textmagic') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') - ->param('username', '', new Text(0), 'Textmagic username.') - ->param('apiKey', '', new Text(0), 'Textmagic apiKey.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) + ->param('username', '', new Text(0), 'Textmagic username.', true) + ->param('apiKey', '', new Text(0), 'Textmagic apiKey.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $username, string $apiKey, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $username, string $apiKey, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if (!empty($username)) { + $credentials['username'] = $username; + } + + if (!empty($apiKey)) { + $credentials['apiKey'] = $apiKey; + } + + if ( + $enabled === true + && \array_key_exists('username', $credentials) + && \array_key_exists('apiKey', $credentials) + && \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'textmagic', 'type' => 'sms', 'enabled' => $enabled, - 'credentials' => [ - 'username' => $username, - 'apiKey' => $apiKey, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $options, ]); try { @@ -325,28 +439,51 @@ App::post('/v1/messaging/providers/twilio') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') - ->param('accountSid', '', new Text(0), 'Twilio account secret ID.') - ->param('authToken', '', new Text(0), 'Twilio authentication token.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) + ->param('accountSid', '', new Text(0), 'Twilio account secret ID.', true) + ->param('authToken', '', new Text(0), 'Twilio authentication token.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $accountSid, string $authToken, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $accountSid, string $authToken, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if (!empty($accountSid)) { + $credentials['accountSid'] = $accountSid; + } + + if (!empty($authToken)) { + $credentials['authToken'] = $authToken; + } + + if ( + $enabled === true + && \array_key_exists('accountSid', $credentials) + && \array_key_exists('authToken', $credentials) + && \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'twilio', 'type' => 'sms', 'enabled' => $enabled, - 'credentials' => [ - 'accountSid' => $accountSid, - 'authToken' => $authToken, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $from, ]); try { @@ -379,28 +516,51 @@ App::post('/v1/messaging/providers/vonage') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') - ->param('apiKey', '', new Text(0), 'Vonage API key.') - ->param('apiSecret', '', new Text(0), 'Vonage API secret.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) + ->param('apiKey', '', new Text(0), 'Vonage API key.', true) + ->param('apiSecret', '', new Text(0), 'Vonage API secret.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $from, string $apiKey, string $apiSecret, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $from, string $apiKey, string $apiSecret, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $options = []; + + if (!empty($from)) { + $options ['from'] = $from; + } + + $credentials = []; + + if (!empty($apiKey)) { + $credentials['apiKey'] = $apiKey; + } + + if (!empty($apiSecret)) { + $credentials['apiSecret'] = $apiSecret; + } + + if ( + $enabled === true + && \array_key_exists('apiKey', $credentials) + && \array_key_exists('apiSecret', $credentials) + && \array_key_exists('from', $options) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'vonage', 'type' => 'sms', 'enabled' => $enabled, - 'credentials' => [ - 'apiKey' => $apiKey, - 'apiSecret' => $apiSecret, - ], - 'options' => [ - 'from' => $from, - ] + 'credentials' => $credentials, + 'options' => $options, ]); try { @@ -433,22 +593,33 @@ App::post('/v1/messaging/providers/fcm') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('serverKey', '', new Text(0), 'FCM server key.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', true) + ->param('serverKey', '', new Text(0), 'FCM server key.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $serverKey, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $serverKey, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $credentials = []; + + if (!empty($serverKey)) { + $credentials['serverKey'] = $serverKey; + } + + if ($enabled === true && \array_key_exists('serverKey', $credentials)) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'fcm', 'type' => 'push', 'enabled' => $enabled, - 'credentials' => [ - 'serverKey' => $serverKey, - ], + 'credentials' => $credentials ]); try { @@ -481,30 +652,60 @@ App::post('/v1/messaging/providers/apns') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', '', new Text(128), 'Provider name.') - ->param('authKey', '', new Text(0), 'APNS authentication key.') - ->param('authKeyId', '', new Text(0), 'APNS authentication key ID.') - ->param('teamId', '', new Text(0), 'APNS team ID.') - ->param('bundleId', '', new Text(0), 'APNS bundle ID.') - ->param('endpoint', '', new Text(0), 'APNS endpoint.') - ->param('enabled', true, new Boolean(), 'Set as enabled.', 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) + ->param('bundleId', '', new Text(0), 'APNS bundle ID.', true) + ->param('endpoint', '', new Text(0), 'APNS endpoint.', true) + ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + + $credentials = []; + + if (!empty($authKey)) { + $credentials['authKey'] = $authKey; + } + + if (!empty($authKeyId)) { + $credentials['authKeyId'] = $authKeyId; + } + + if (!empty($teamId)) { + $credentials['teamId'] = $teamId; + } + + if (!empty($bundleId)) { + $credentials['bundleId'] = $bundleId; + } + + if (!empty($endpoint)) { + $credentials['endpoint'] = $endpoint; + } + + if ( + $enabled === true + && \array_key_exists('authKey', $credentials) + && \array_key_exists('authKeyId', $credentials) + && \array_key_exists('teamId', $credentials) + && \array_key_exists('bundleId', $credentials) + && \array_key_exists('endpoint', $credentials) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider = new Document([ '$id' => $providerId, 'name' => $name, 'provider' => 'apns', 'type' => 'push', 'enabled' => $enabled, - 'credentials' => [ - 'authKey' => $authKey, - 'authKeyId' => $authKeyId, - 'teamId' => $teamId, - 'bundleId' => $bundleId, - 'endpoint' => $endpoint, - ], + 'credentials' => $credentials, ]); try { @@ -717,10 +918,6 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if ($isEuRegion === true || $isEuRegion === false) { @@ -737,6 +934,21 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true && + \array_key_exists('isEuRegion', $credentials) && + \array_key_exists('apiKey', $credentials) && + \array_key_exists('domain', $credentials) && + \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -790,16 +1002,25 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - if (!empty($apiKey)) { $provider->setAttribute('credentials', [ 'apiKey' => $apiKey, ]); } + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('apiKey', $provider->getAttribute('credentials')) + && \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -854,10 +1075,6 @@ App::patch('/v1/messaging/providers/msg91/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if (!empty($senderId)) { @@ -870,6 +1087,20 @@ App::patch('/v1/messaging/providers/msg91/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('senderId', $credentials) + && \array_key_exists('authKey', $credentials) + && \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -924,10 +1155,6 @@ App::patch('/v1/messaging/providers/telesign/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if (!empty($username)) { @@ -940,6 +1167,21 @@ App::patch('/v1/messaging/providers/telesign/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('username', $credentials) + && \array_key_exists('password', $credentials) + && \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -994,10 +1236,6 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if (!empty($username)) { @@ -1010,6 +1248,21 @@ App::patch('/v1/messaging/providers/textmagic/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('username', $credentials) + && \array_key_exists('apiKey', $credentials) + && \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -1064,10 +1317,6 @@ App::patch('/v1/messaging/providers/twilio/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if (!empty($accountSid)) { @@ -1080,6 +1329,21 @@ App::patch('/v1/messaging/providers/twilio/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('accountSid', $credentials) + && \array_key_exists('authToken', $credentials) + && \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -1134,10 +1398,6 @@ App::patch('/v1/messaging/providers/vonage/:providerId') ]); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if (!empty($apiKey)) { @@ -1150,6 +1410,21 @@ App::patch('/v1/messaging/providers/vonage/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('apiKey', $credentials) + && \array_key_exists('apiSecret', $credentials) + && \array_key_exists('from', $provider->getAttribute('options')) + ) { + $enabled = true; + } else { + $enabled = false; + } + + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -1196,14 +1471,20 @@ App::patch('/v1/messaging/providers/fcm/:providerId') $provider->setAttribute('name', $name); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - if (!empty($serverKey)) { $provider->setAttribute('credentials', ['serverKey' => $serverKey]); } + if ($enabled === true || $enabled === false) { + if ($enabled === true && \array_key_exists('serverKey', $provider->getAttribute('credentials'))) { + $enabled = true; + } else { + $enabled = false; + } + + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -1255,10 +1536,6 @@ App::patch('/v1/messaging/providers/apns/:providerId') $provider->setAttribute('name', $name); } - if ($enabled === true || $enabled === false) { - $provider->setAttribute('enabled', $enabled); - } - $credentials = $provider->getAttribute('credentials'); if (!empty($authKey)) { @@ -1283,6 +1560,23 @@ App::patch('/v1/messaging/providers/apns/:providerId') $provider->setAttribute('credentials', $credentials); + if ($enabled === true || $enabled === false) { + if ( + $enabled === true + && \array_key_exists('authKey', $credentials) + && \array_key_exists('authKeyId', $credentials) + && \array_key_exists('teamId', $credentials) + && \array_key_exists('bundleId', $credentials) + && \array_key_exists('endpoint', $credentials) + ) { + $enabled = true; + } else { + $enabled = false; + } + + $provider->setAttribute('enabled', $enabled); + } + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); $queueForEvents @@ -1652,10 +1946,8 @@ App::post('/v1/messaging/topics/:topicId/subscribers') '$id' => $subscriberId, '$permissions' => [ Permission::read(Role::user($user->getId())), - Permission::delete(Role::user($target->getAttribute('userId'))), + Permission::delete(Role::user($user->getId())), ], - 'userId' => $user->getId(), - 'userInternalId' => $user->getInternalId(), 'topicId' => $topicId, 'topicInternalId' => $topic->getInternalId(), 'targetId' => $targetId, @@ -1673,7 +1965,9 @@ App::post('/v1/messaging/topics/:topicId/subscribers') ->setParam('topicId', $topic->getId()) ->setParam('subscriberId', $subscriber->getId()); - $subscriber->setAttribute('userName', $user->getAttribute('name')); + $subscriber + ->setAttribute('target', $target) + ->setAttribute('userName', $user->getAttribute('name')); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -1725,9 +2019,11 @@ App::get('/v1/messaging/topics/:topicId/subscribers') $subscribers = batch(\array_map(function (Document $subscriber) use ($dbForProject) { return function () use ($subscriber, $dbForProject) { - $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $subscriber->getAttribute('userId'))); + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); + $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); return $subscriber + ->setAttribute('target', $target) ->setAttribute('userName', $user->getAttribute('name')); }; }, $subscribers)); @@ -1851,9 +2147,12 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId') throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); } - $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $subscriber->getAttribute('userId'))); + $target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'))); + $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); - $subscriber->setAttribute('userName', $user->getAttribute('name')); + $subscriber + ->setAttribute('target', $target) + ->setAttribute('userName', $user->getAttribute('name')); $response ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 0862f0b8fa..8488d8a9e4 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -144,7 +144,11 @@ class Messaging extends Action if ($internalProvider->getId() === $providerId) { $provider = $internalProvider; } else { - $provider = $dbForProject->getDocument('providers', $providerId); + $provider = $dbForProject->getDocument('providers', $providerId, [Query::equal('enabled', [true])]); + + if ($provider->isEmpty()) { + $provider = $internalProvider; + } } $providers[] = $provider; diff --git a/src/Appwrite/Utopia/Response/Model/Subscriber.php b/src/Appwrite/Utopia/Response/Model/Subscriber.php index 5080b44333..e699df876c 100644 --- a/src/Appwrite/Utopia/Response/Model/Subscriber.php +++ b/src/Appwrite/Utopia/Response/Model/Subscriber.php @@ -34,11 +34,20 @@ class Subscriber extends Model 'default' => '', 'example' => '259125845563242502', ]) - ->addRule('userId', [ - 'type' => self::TYPE_STRING, - 'description' => 'User ID.', - 'default' => '', - 'example' => '5e5ea5c16897e', + ->addRule('target', [ + 'type' => Response::MODEL_TARGET, + 'description' => 'Target.', + 'default' => [], + 'example' => [ + '$id' => '259125845563242502', + '$createdAt' => self::TYPE_DATETIME_EXAMPLE, + '$updatedAt' => self::TYPE_DATETIME_EXAMPLE, + 'providerType' => 'email', + 'providerId' => '259125845563242502', + 'name' => 'ageon-app-email', + 'identifier' => 'random-mail@email.org', + 'userId' => '5e5ea5c16897e', + ], ]) ->addRule('userName', [ 'type' => self::TYPE_STRING, diff --git a/src/Appwrite/Utopia/Response/Model/Target.php b/src/Appwrite/Utopia/Response/Model/Target.php index f6346f409a..a92d1b34ca 100644 --- a/src/Appwrite/Utopia/Response/Model/Target.php +++ b/src/Appwrite/Utopia/Response/Model/Target.php @@ -28,6 +28,12 @@ class Target extends Model 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ]) + ->addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'Target Name.', + 'default' => '', + 'example' => 'Aegon apple token', + ]) ->addRule('userId', [ 'type' => self::TYPE_STRING, 'description' => 'User ID.', diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 3777d67b73..6939e6a9b5 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -2044,9 +2044,16 @@ trait Base return 'mutation createSubscriber($subscriberId: String!, $targetId: String!, $topicId: String!) { messagingCreateSubscriber(subscriberId: $subscriberId, targetId: $targetId, topicId: $topicId) { _id - userId targetId topicId + userName + target { + _id + userId + name + providerType + identifier + } } }'; case self::$LIST_SUBSCRIBERS: @@ -2055,9 +2062,16 @@ trait Base total subscribers { _id - userId targetId topicId + userName + target { + _id + userId + name + providerType + identifier + } } } }'; @@ -2065,9 +2079,16 @@ trait Base return 'query getSubscriber($topicId: String!, $subscriberId: String!) { messagingGetSubscriber(topicId: $topicId, subscriberId: $subscriberId) { _id - userId targetId topicId + userName + target { + _id + userId + name + providerType + identifier + } } }'; case self::$DELETE_SUBSCRIBER: diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index e3ca99f2ac..d1a084cfc1 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -430,7 +430,7 @@ class MessagingTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['topicId'], $topicId); $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['targetId'], $targetId); - $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['userId'], $userId); + $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['target']['userId'], $userId); return $response['body']['data']['messagingCreateSubscriber']; } @@ -454,9 +454,9 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['topicId'], $subscriber['topicId']); - $this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['targetId'], $subscriber['targetId']); - $this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['userId'], $subscriber['userId']); + $this->assertEquals($subscriber['topicId'], $response['body']['data']['messagingListSubscribers']['subscribers'][0]['topicId']); + $this->assertEquals($subscriber['targetId'], $response['body']['data']['messagingListSubscribers']['subscribers'][0]['targetId']); + $this->assertEquals($subscriber['target']['userId'], $response['body']['data']['messagingListSubscribers']['subscribers'][0]['target']['userId']); $this->assertEquals(1, \count($response['body']['data']['messagingListSubscribers']['subscribers'])); } @@ -487,7 +487,7 @@ class MessagingTest extends Scope $this->assertEquals($subscriberId, $response['body']['data']['messagingGetSubscriber']['_id']); $this->assertEquals($topicId, $response['body']['data']['messagingGetSubscriber']['topicId']); $this->assertEquals($subscriber['targetId'], $response['body']['data']['messagingGetSubscriber']['targetId']); - $this->assertEquals($subscriber['userId'], $response['body']['data']['messagingGetSubscriber']['userId']); + $this->assertEquals($subscriber['target']['userId'], $response['body']['data']['messagingGetSubscriber']['target']['userId']); } /** diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 37a581b088..690e503e77 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -333,7 +333,8 @@ trait MessagingBase ]); $this->assertEquals(201, $response['headers']['status-code']); - $this->assertEquals($target['body']['userId'], $response['body']['userId']); + $this->assertEquals($target['body']['userId'], $response['body']['target']['userId']); + $this->assertEquals($target['body']['providerType'], $response['body']['target']['providerType']); $topic = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['$id'], [ 'content-type' => 'application/json', @@ -350,7 +351,9 @@ trait MessagingBase 'topicId' => $topic['body']['$id'], 'targetId' => $target['body']['$id'], 'userId' => $target['body']['userId'], - 'subscriberId' => $response['body']['$id'] + 'subscriberId' => $response['body']['$id'], + 'identifier' => $target['body']['identifier'], + 'providerType' => $target['body']['providerType'], ]; } @@ -368,7 +371,9 @@ trait MessagingBase $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($data['topicId'], $response['body']['topicId']); $this->assertEquals($data['targetId'], $response['body']['targetId']); - $this->assertEquals($data['userId'], $response['body']['userId']); + $this->assertEquals($data['userId'], $response['body']['target']['userId']); + $this->assertEquals($data['providerType'], $response['body']['target']['providerType']); + $this->assertEquals($data['identifier'], $response['body']['target']['identifier']); } /** @@ -384,7 +389,9 @@ trait MessagingBase $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, $response['body']['total']); - $this->assertEquals($data['userId'], $response['body']['subscribers'][0]['userId']); + $this->assertEquals($data['userId'], $response['body']['subscribers'][0]['target']['userId']); + $this->assertEquals($data['providerType'], $response['body']['subscribers'][0]['target']['providerType']); + $this->assertEquals($data['identifier'], $response['body']['subscribers'][0]['target']['identifier']); $this->assertEquals(\count($response['body']['subscribers']), $response['body']['total']); return $data;