From e7dca6b2d5cbd61611a88160448c811faeea042a Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 5 Dec 2023 15:01:32 +0100 Subject: [PATCH 01/18] adds uniform logic for worker and extra params for email --- app/controllers/api/messaging.php | 132 ++++++++++++++++---- composer.json | 2 +- composer.lock | 70 ++++++----- src/Appwrite/Platform/Workers/Messaging.php | 104 +++++++++++---- 4 files changed, 230 insertions(+), 78 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index f0cb4dd966..8e217b25ca 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -54,21 +54,38 @@ 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.', true) + ->param('fromName', '', new Text(128), 'Sender Name.') + ->param('fromEmail', '', new Email(), 'Sender email address.') ->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) + ->param('replyToName', '', new Text(128), 'Name set in the Reply To field for the mail. Default value is Sender Name. Reply to name must have reply to email as well.', true) + ->param('replyToEmail', '', new Text(128), 'Email set in the Reply To field for the mail. Default value is Sender Email. Reply to email must have reply to name as well.', true) + ->param('cc', [], new ArrayList(new Email()), 'Array of email addresses to be added as CC.', true) + ->param('bcc', [], new ArrayList(new Email()), 'Array of email addresses to be added as BCC.', 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 $fromName, string $fromEmail, string $apiKey, string $domain, ?bool $isEuRegion, ?bool $enabled, string $replyToName, string $replyToEmail, array $cc, array $bcc, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $options = []; + $options = [ + 'fromName' => $fromName, + 'fromEmail' => $fromEmail, + ]; - if (!empty($from)) { - $options ['from'] = $from; + if (!empty($replyToName) && !empty($replyToEmail)) { + $options['replyToName'] = $replyToName; + $options['replyToEmail'] = $replyToEmail; + } + + if (!empty($cc)) { + $options['cc'] = $cc; + } + + if (!empty($bcc)) { + $options['bcc'] = $bcc; } $credentials = []; @@ -137,19 +154,36 @@ 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.', true) + ->param('fromName', '', new Text(128), 'Sender Name.') + ->param('fromEmail', '', new Email(), 'Sender email address.') ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('replyToName', '', new Text(128), 'Name set in the Reply To field for the mail. Default value is Sender Name.', true) + ->param('replyToEmail', '', new Text(128), 'Email set in the Reply To field for the mail. Default value is Sender Email.', true) + ->param('cc', [], new ArrayList(new Email()), 'Array of email addresses to be added as CC.', true) + ->param('bcc', [], new ArrayList(new Email()), 'Array of email addresses to be added as BCC.', 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 $fromName, string $fromEmail, string $apiKey, ?bool $enabled, string $replyToName, string $replyToEmail, array $cc, array $bcc, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; - $options = []; + $options = [ + 'fromName' => $fromName, + 'fromEmail' => $fromEmail, + ]; - if (!empty($from)) { - $options ['from'] = $from; + if (!empty($replyToName) && !empty($replyToEmail)) { + $options['replyToName'] = $replyToName; + $options['replyToEmail'] = $replyToEmail; + } + + if (!empty($cc)) { + $options['cc'] = $cc; + } + + if (!empty($bcc)) { + $options['bcc'] = $bcc; } $credentials = []; @@ -890,13 +924,18 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('isEuRegion', null, new Boolean(), 'Set as EU region.', true) - ->param('from', '', new Email(), 'Sender email address.', true) + ->param('fromName', '', new Text(128), 'Sender Name.', true) + ->param('fromEmail', '', new Email(), 'Sender email address.', true) + ->param('replyToName', '', new Text(128), 'Name set in the Reply To field for the mail. Default value is Sender Name.', true) + ->param('replyToEmail', '', new Text(128), 'Email set in the Reply To field for the mail. Default value is Sender Email.', true) + ->param('cc', [], new ArrayList(new Email()), 'Array of email addresses to be added as CC.', true) + ->param('bcc', [], new ArrayList(new Email()), 'Array of email addresses to be added as BCC.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?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 $fromName, string $fromEmail, string $replyToName, string $replyToEmail, array $cc, array $bcc, string $apiKey, string $domain, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -912,12 +951,34 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') $provider->setAttribute('name', $name); } - if (!empty($from)) { - $provider->setAttribute('options', [ - 'from' => $from, - ]); + $options = $provider->getAttribute('options'); + + if (!empty($fromName)) { + $options['fromName'] = $fromName; } + if (!empty($fromEmail)) { + $options['fromEmail'] = $fromEmail; + } + + if (!empty($replyToName)) { + $options['replyToName'] = $replyToName; + } + + if (!empty($replyToEmail)) { + $options['replyToEmail'] = $replyToEmail; + } + + if (\count($cc) > 0) { + $options['cc'] = $cc; + } + + if (\count($bcc) > 0) { + $options['bcc'] = $bcc; + } + + $provider->setAttribute('options', $options); + $credentials = $provider->getAttribute('credentials'); if ($isEuRegion === true || $isEuRegion === false) { @@ -976,11 +1037,16 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ->param('name', '', new Text(128), 'Provider name.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) - ->param('from', '', new Email(), 'Sender email address.', true) + ->param('fromName', '', new Text(128), 'Sender Name.', true) + ->param('fromEmail', '', new Email(), 'Sender email address.', true) + ->param('replyToName', '', new Text(128), 'Name set in the Reply To field for the mail. Default value is Sender Name.', true) + ->param('replyToEmail', '', new Text(128), 'Email set in the Reply To field for the mail. Default value is Sender Email.', true) + ->param('cc', [], new ArrayList(new Email()), 'Array of email addresses to be added as CC.', true) + ->param('bcc', [], new ArrayList(new Email()), 'Array of email addresses to be added as BCC.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $from, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, array $cc, array $bcc, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -996,12 +1062,34 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') $provider->setAttribute('name', $name); } - if (!empty($from)) { - $provider->setAttribute('options', [ - 'from' => $from, - ]); + $options = $provider->getAttribute('options'); + + if (!empty($fromName)) { + $options['fromName'] = $fromName; } + if (!empty($fromEmail)) { + $options['fromEmail'] = $fromEmail; + } + + if (!empty($replyToName)) { + $options['replyToName'] = $replyToName; + } + + if (!empty($replyToEmail)) { + $options['replyToEmail'] = $replyToEmail; + } + + if (\count($cc) > 0) { + $options['cc'] = $cc; + } + + if (\count($bcc) > 0) { + $options['bcc'] = $bcc; + } + + $provider->setAttribute('options', $options); + if (!empty($apiKey)) { $provider->setAttribute('credentials', [ 'apiKey' => $apiKey, diff --git a/composer.json b/composer.json index a24feca83b..9dbb59a94a 100644 --- a/composer.json +++ b/composer.json @@ -56,7 +56,7 @@ "utopia-php/image": "0.5.*", "utopia-php/locale": "0.4.*", "utopia-php/logger": "0.3.*", - "utopia-php/messaging": "0.2.*", + "utopia-php/messaging": "0.6.*", "utopia-php/migration": "0.3.*", "utopia-php/orchestration": "0.9.*", "utopia-php/platform": "0.5.*", diff --git a/composer.lock b/composer.lock index 16f44a6357..b865d57a86 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "69bc2e21a65b78344393706b39d789b4", + "content-hash": "f5b11b64b696e0a17222fdaa81350c4c", "packages": [ { "name": "adhocore/jwt", @@ -402,16 +402,16 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.8.0", + "version": "7.8.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9" + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/1110f66a6530a40fe7aea0378fe608ee2b2248f9", - "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", "shasum": "" }, "require": { @@ -426,11 +426,11 @@ "psr/http-client-implementation": "1.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", + "bamarni/composer-bin-plugin": "^1.8.2", "ext-curl": "*", "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.29 || ^9.5.23", + "phpunit/phpunit": "^8.5.36 || ^9.6.15", "psr/log": "^1.1 || ^2.0 || ^3.0" }, "suggest": { @@ -508,7 +508,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.8.0" + "source": "https://github.com/guzzle/guzzle/tree/7.8.1" }, "funding": [ { @@ -524,28 +524,28 @@ "type": "tidelift" } ], - "time": "2023-08-27T10:20:53+00:00" + "time": "2023-12-03T20:35:24+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "111166291a0f8130081195ac4556a5587d7f1b5d" + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/111166291a0f8130081195ac4556a5587d7f1b5d", - "reference": "111166291a0f8130081195ac4556a5587d7f1b5d", + "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.36 || ^9.6.15" }, "type": "library", "extra": { @@ -591,7 +591,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.1" + "source": "https://github.com/guzzle/promises/tree/2.0.2" }, "funding": [ { @@ -607,20 +607,20 @@ "type": "tidelift" } ], - "time": "2023-08-03T15:11:55+00:00" + "time": "2023-12-03T20:19:20+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.6.1", + "version": "2.6.2", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727" + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/be45764272e8873c72dbe3d2edcfdfcc3bc9f727", - "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", "shasum": "" }, "require": { @@ -634,9 +634,9 @@ "psr/http-message-implementation": "1.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", + "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" + "phpunit/phpunit": "^8.5.36 || ^9.6.15" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -707,7 +707,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.6.1" + "source": "https://github.com/guzzle/psr7/tree/2.6.2" }, "funding": [ { @@ -723,7 +723,7 @@ "type": "tidelift" } ], - "time": "2023-08-27T10:13:57+00:00" + "time": "2023-12-03T20:05:35+00:00" }, { "name": "influxdb/influxdb-php", @@ -2270,16 +2270,16 @@ }, { "name": "utopia-php/messaging", - "version": "0.2.0", + "version": "0.6.0", "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "2d0f474a106bb1da285f85e105c29b46085d3a43" + "reference": "a3ebf9d0714e760cfa36f9c5de75c7c0f31c4024" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/2d0f474a106bb1da285f85e105c29b46085d3a43", - "reference": "2d0f474a106bb1da285f85e105c29b46085d3a43", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/a3ebf9d0714e760cfa36f9c5de75c7c0f31c4024", + "reference": "a3ebf9d0714e760cfa36f9c5de75c7c0f31c4024", "shasum": "" }, "require": { @@ -2287,9 +2287,11 @@ "php": ">=8.0.0" }, "require-dev": { - "laravel/pint": "^1.2", + "ext-openssl": "*", + "laravel/pint": "1.13.*", "phpmailer/phpmailer": "6.8.*", - "phpunit/phpunit": "9.6.*" + "phpstan/phpstan": "1.10.*", + "phpunit/phpunit": "9.6.10" }, "type": "library", "autoload": { @@ -2312,9 +2314,9 @@ ], "support": { "issues": "https://github.com/utopia-php/messaging/issues", - "source": "https://github.com/utopia-php/messaging/tree/0.2.0" + "source": "https://github.com/utopia-php/messaging/tree/0.6.0" }, - "time": "2023-09-14T20:48:42+00:00" + "time": "2023-12-05T11:08:43+00:00" }, { "name": "utopia-php/migration", @@ -5823,5 +5825,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 8f945e947f..345da552ab 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -13,22 +13,23 @@ use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\Messaging\Adapters\SMS as SMSAdapter; -use Utopia\Messaging\Adapters\SMS\Mock; -use Utopia\Messaging\Adapters\SMS\Msg91; -use Utopia\Messaging\Adapters\SMS\Telesign; -use Utopia\Messaging\Adapters\SMS\Textmagic; -use Utopia\Messaging\Adapters\SMS\Twilio; -use Utopia\Messaging\Adapters\SMS\Vonage; -use Utopia\Messaging\Adapters\Push as PushAdapter; -use Utopia\Messaging\Adapters\Push\APNS; -use Utopia\Messaging\Adapters\Push\FCM; -use Utopia\Messaging\Adapters\Email as EmailAdapter; -use Utopia\Messaging\Adapters\Email\Mailgun; -use Utopia\Messaging\Adapters\Email\SendGrid; +use Utopia\Messaging\Adapter\Email as EmailAdapter; +use Utopia\Messaging\Adapter\Email\Mailgun; +use Utopia\Messaging\Adapter\Email\Sendgrid; +use Utopia\Messaging\Adapter\Push as PushAdapter; +use Utopia\Messaging\Adapter\Push\APNS; +use Utopia\Messaging\Adapter\Push\FCM; +use Utopia\Messaging\Adapter\SMS as SMSAdapter; +use Utopia\Messaging\Adapter\SMS\Mock; +use Utopia\Messaging\Adapter\SMS\Msg91; +use Utopia\Messaging\Adapter\SMS\Telesign; +use Utopia\Messaging\Adapter\SMS\Textmagic; +use Utopia\Messaging\Adapter\SMS\Twilio; +use Utopia\Messaging\Adapter\SMS\Vonage; use Utopia\Messaging\Messages\Email; use Utopia\Messaging\Messages\Push; use Utopia\Messaging\Messages\SMS; +use Utopia\Messaging\Response; use function Swoole\Coroutine\batch; @@ -169,8 +170,8 @@ class Messaging extends Action $batches = \array_chunk($identifiers, $maxBatchSize); $batchIndex = 0; - $results = batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex) { - return function () use ($batch, $message, $provider, $adapter, $batchIndex) { + $results = batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex, $dbForProject) { + return function () use ($batch, $message, $provider, $adapter, $batchIndex, $dbForProject) { $deliveredTotal = 0; $deliveryErrors = []; $messageData = clone $message; @@ -184,8 +185,24 @@ class Messaging extends Action }; try { - $adapter->send($data); - $deliveredTotal += \count($batch); + $response = new Response($provider->getAttribute('type')); + $response->fromArray(\json_decode($adapter->send($data))); + + $deliveredTotal += $response->getDeliveredTo(); + $details[] = $response->getDetails(); + foreach ($details as $detail) { + if ($detail['status'] === 'failure') { + $deliveryErrors[] = `Failed sending to target {$detail['recipient']} with error: {$detail['error']}`; + } + + // Deleting push targets when token has expired. + if ($detail['error'] === 'Expired token.') { + $target = $dbForProject->findOne('targets', [Query::equal('identifier', [$detail['recipient']])]); + if ($target instanceof Document && !$target->isEmpty()) { + $dbForProject->deleteDocument('targets', $target->getId()); + } + } + } } catch (\Exception $e) { $deliveryErrors[] = 'Failed sending to targets ' . $batchIndex + 1 . '-' . \count($batch) . ' with error: ' . $e->getMessage(); } finally { @@ -313,7 +330,7 @@ class Messaging extends Action 'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']), 'textmagic' => new Textmagic($credentials['username'], $credentials['apiKey']), 'telesign' => new Telesign($credentials['username'], $credentials['password']), - 'msg91' => new Msg91($credentials['senderId'], $credentials['authKey']), + 'msg91' => new Msg91($credentials['senderId'], $credentials['authKey'], $credentials['templateId']), 'vonage' => new Vonage($credentials['apiKey'], $credentials['apiSecret']), default => null }; @@ -323,6 +340,7 @@ class Messaging extends Action { $credentials = $provider->getAttribute('credentials'); return match ($provider->getAttribute('provider')) { + 'mock' => new Mock('username', 'password'), 'apns' => new APNS( $credentials['authKey'], $credentials['authKeyId'], @@ -339,21 +357,65 @@ class Messaging extends Action { $credentials = $provider->getAttribute('credentials'); return match ($provider->getAttribute('provider')) { + 'mock' => new Mock('username', 'password'), 'mailgun' => new Mailgun($credentials['apiKey'], $credentials['domain'], $credentials['isEuRegion']), - 'sendgrid' => new SendGrid($credentials['apiKey']), + 'sendgrid' => new Sendgrid($credentials['apiKey']), default => null }; } private function buildEmailMessage(Document $message, Document $provider): Email { - $from = $provider['options']['from']; + $fromName = $provider['options']['fromName']; + $fromEmail = $provider['options']['fromEmail']; + $replyToEmail = null; + $replyToName = null; + $cc = null; + $bcc = null; + + if (isset($provider['options']['replyToName']) && isset($provider['options']['replyToEmail'])) { + $replyToName = $provider['options']['replyToName']; + $replyToEmail = $provider['options']['replyToEmail']; + } + + if (isset($provider['options']['cc'])) { + foreach ($provider['options']['cc'] as $ccEmail) { + if (is_array($cc)) { + $cc[] = [ + 'email' => $ccEmail, + ]; + } else { + $cc = [ + [ + 'email' => $ccEmail, + ] + ]; + } + } + } + + if (isset($provider['options']['bcc'])) { + foreach ($provider['options']['bcc'] as $bccEmail) { + if (is_array($bcc)) { + $bcc[] = [ + 'email' => $bccEmail, + ]; + } else { + $bcc = [ + [ + 'email' => $bccEmail, + ] + ]; + } + } + } + $to = $message['to']; $subject = $message['data']['subject']; $content = $message['data']['content']; $html = $message['data']['html']; - return new Email($to, $subject, $content, $from, null, $html); + return new Email($to, $subject, $content, $fromName, $fromEmail, $replyToName, $replyToEmail, $cc, $bcc, html: $html); } private function buildSMSMessage(Document $message, Document $provider): SMS From 194bbbb3508fb92a101f8b544986fe6d33fd9ab4 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 5 Dec 2023 19:24:55 +0100 Subject: [PATCH 02/18] review changes --- app/controllers/api/messaging.php | 82 +++++++------------ src/Appwrite/Platform/Workers/Messaging.php | 8 +- tests/e2e/Services/GraphQL/Base.php | 16 ++-- tests/e2e/Services/GraphQL/UsersTest.php | 3 +- .../e2e/Services/Messaging/MessagingBase.php | 9 +- 5 files changed, 48 insertions(+), 70 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 8e217b25ca..3e784d29b7 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -60,10 +60,8 @@ App::post('/v1/messaging/providers/mailgun') ->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) - ->param('replyToName', '', new Text(128), 'Name set in the Reply To field for the mail. Default value is Sender Name. Reply to name must have reply to email as well.', true) - ->param('replyToEmail', '', new Text(128), 'Email set in the Reply To field for the mail. Default value is Sender Email. Reply to email must have reply to name as well.', true) - ->param('cc', [], new ArrayList(new Email()), 'Array of email addresses to be added as CC.', true) - ->param('bcc', [], new ArrayList(new Email()), 'Array of email addresses to be added as BCC.', true) + ->param('replyToName', '', new Text(128), 'Name set in the reply to field for the mail. Default value is sender name. Reply to name must have reply to email as well.', true) + ->param('replyToEmail', '', new Text(128), 'Email set in the reply to field for the mail. Default value is sender email. Reply to email must have reply to name as well.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') @@ -80,14 +78,6 @@ App::post('/v1/messaging/providers/mailgun') $options['replyToEmail'] = $replyToEmail; } - if (!empty($cc)) { - $options['cc'] = $cc; - } - - if (!empty($bcc)) { - $options['bcc'] = $bcc; - } - $credentials = []; if ($isEuRegion === true || $isEuRegion === false) { @@ -158,14 +148,12 @@ App::post('/v1/messaging/providers/sendgrid') ->param('fromEmail', '', new Email(), 'Sender email address.') ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) - ->param('replyToName', '', new Text(128), 'Name set in the Reply To field for the mail. Default value is Sender Name.', true) - ->param('replyToEmail', '', new Text(128), 'Email set in the Reply To field for the mail. Default value is Sender Email.', true) - ->param('cc', [], new ArrayList(new Email()), 'Array of email addresses to be added as CC.', true) - ->param('bcc', [], new ArrayList(new Email()), 'Array of email addresses to be added as BCC.', true) + ->param('replyToName', '', new Text(128), 'Name set in the reply to field for the mail. Default value is sender name.', true) + ->param('replyToEmail', '', new Text(128), 'Email set in the reply to field for the mail. Default value is sender email.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $fromName, string $fromEmail, string $apiKey, ?bool $enabled, string $replyToName, string $replyToEmail, array $cc, array $bcc, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $fromName, string $fromEmail, string $apiKey, ?bool $enabled, string $replyToName, string $replyToEmail, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $options = [ @@ -178,14 +166,6 @@ App::post('/v1/messaging/providers/sendgrid') $options['replyToEmail'] = $replyToEmail; } - if (!empty($cc)) { - $options['cc'] = $cc; - } - - if (!empty($bcc)) { - $options['bcc'] = $bcc; - } - $credentials = []; if (!empty($apiKey)) { @@ -926,16 +906,14 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ->param('isEuRegion', null, new Boolean(), 'Set as EU region.', true) ->param('fromName', '', new Text(128), 'Sender Name.', true) ->param('fromEmail', '', new Email(), 'Sender email address.', true) - ->param('replyToName', '', new Text(128), 'Name set in the Reply To field for the mail. Default value is Sender Name.', true) - ->param('replyToEmail', '', new Text(128), 'Email set in the Reply To field for the mail. Default value is Sender Email.', true) - ->param('cc', [], new ArrayList(new Email()), 'Array of email addresses to be added as CC.', true) - ->param('bcc', [], new ArrayList(new Email()), 'Array of email addresses to be added as BCC.', true) + ->param('replyToName', '', new Text(128), 'Name set in the reply to field for the mail. Default value is sender name.', true) + ->param('replyToEmail', '', new Text(128), 'Email set in the reply to field for the mail. Default value is sender email.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $isEuRegion, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, array $cc, array $bcc, string $apiKey, string $domain, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $isEuRegion, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, string $apiKey, string $domain, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -969,14 +947,6 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') $options['replyToEmail'] = $replyToEmail; } - if (\count($cc) > 0) { - $options['cc'] = $cc; - } - - if (\count($bcc) > 0) { - $options['bcc'] = $bcc; - } - $provider->setAttribute('options', $options); $credentials = $provider->getAttribute('credentials'); @@ -1041,12 +1011,10 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') ->param('fromEmail', '', new Email(), 'Sender email address.', true) ->param('replyToName', '', new Text(128), 'Name set in the Reply To field for the mail. Default value is Sender Name.', true) ->param('replyToEmail', '', new Text(128), 'Email set in the Reply To field for the mail. Default value is Sender Email.', true) - ->param('cc', [], new ArrayList(new Email()), 'Array of email addresses to be added as CC.', true) - ->param('bcc', [], new ArrayList(new Email()), 'Array of email addresses to be added as BCC.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, array $cc, array $bcc, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1080,14 +1048,6 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId') $options['replyToEmail'] = $replyToEmail; } - if (\count($cc) > 0) { - $options['cc'] = $cc; - } - - if (\count($bcc) > 0) { - $options['bcc'] = $bcc; - } - $provider->setAttribute('options', $options); if (!empty($apiKey)) { @@ -2315,9 +2275,11 @@ App::post('/v1/messaging/messages/email') ->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('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('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 target IDs.', true) + ->param('cc', [], new ArrayList(new Email()), 'Array of email addresses to be added as CC.', true) + ->param('bcc', [], new ArrayList(new Email()), 'Array of email addresses to be added as BCC.', true) ->param('description', '', new Text(256), 'Description for message.', true) ->param('status', 'processing', new WhiteList(['draft', 'canceled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) @@ -2327,7 +2289,7 @@ App::post('/v1/messaging/messages/email') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, string $description, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, string $description, array $cc, array $bcc, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { @@ -2357,6 +2319,8 @@ App::post('/v1/messaging/messages/email') 'subject' => $subject, 'content' => $content, 'html' => $html, + 'cc' => $cc, + 'bcc' => $bcc, ], 'status' => $status, ])); @@ -2715,13 +2679,15 @@ App::patch('/v1/messaging/messages/email/:messageId') ->param('content', '', new Text(64230), 'Email Content.', true) ->param('status', '', new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) + ->param('cc', [], new ArrayList(new Email()), 'Array of email addresses to be added as CC.', true) + ->param('bcc', [], new ArrayList(new Email()), 'Array of email addresses to be added as BCC.', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $subject, string $description, string $content, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, 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, array $cc, array $bcc, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2774,6 +2740,14 @@ App::patch('/v1/messaging/messages/email/:messageId') $data['html'] = $html; } + if (count($cc) > 0) { + $data['cc'] = $cc; + } + + if (count($bcc) > 0) { + $data['bcc'] = $bcc; + } + $message->setAttribute('data', $data); if (!empty($description)) { diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 345da552ab..0686088def 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -378,8 +378,8 @@ class Messaging extends Action $replyToEmail = $provider['options']['replyToEmail']; } - if (isset($provider['options']['cc'])) { - foreach ($provider['options']['cc'] as $ccEmail) { + if (\count($message['data']['cc']) > 0) { + foreach ($message['data']['cc'] as $ccEmail) { if (is_array($cc)) { $cc[] = [ 'email' => $ccEmail, @@ -394,8 +394,8 @@ class Messaging extends Action } } - if (isset($provider['options']['bcc'])) { - foreach ($provider['options']['bcc'] as $bccEmail) { + if (\count($message['data']['bcc'])) { + foreach ($message['data']['bcc'] as $bccEmail) { if (is_array($bcc)) { $bcc[] = [ 'email' => $bccEmail, diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 2854d0bf42..2593a58e1a 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -1790,8 +1790,8 @@ trait Base } }'; case self::$CREATE_MAILGUN_PROVIDER: - return 'mutation createMailgunProvider($providerId: String!, $name: String!, $domain: String!, $apiKey: String!, $from: String!, $isEuRegion: Boolean!) { - messagingCreateMailgunProvider(providerId: $providerId, name: $name, domain: $domain, apiKey: $apiKey, from: $from, isEuRegion: $isEuRegion) { + return 'mutation createMailgunProvider($providerId: String!, $name: String!, $domain: String!, $apiKey: String!, $fromName: String!, $fromEmail: String!, $isEuRegion: Boolean!, $replyToName: String, $replyToEmail: String) { + messagingCreateMailgunProvider(providerId: $providerId, name: $name, domain: $domain, apiKey: $apiKey, fromName: $fromName, fromEmail: $fromEmail, isEuRegion: $isEuRegion, replyToName: $replyToName, replyToEmail: $replyToEmail) { _id name provider @@ -1800,8 +1800,8 @@ trait Base } }'; case self::$CREATE_SENDGRID_PROVIDER: - return 'mutation createSendgridProvider($providerId: String!, $name: String!, $from: String!, $apiKey: String!) { - messagingCreateSendgridProvider(providerId: $providerId, name: $name, from: $from, apiKey: $apiKey) { + return 'mutation createSendgridProvider($providerId: String!, $name: String!, $fromName: String!, $fromEmail: String!, $apiKey: String!, $replyToName: String, $replyToEmail: String) { + messagingCreateSendgridProvider(providerId: $providerId, name: $name, fromName: $fromName, fromEmail: $fromEmail, apiKey: $apiKey, replyToName: $replyToName, replyToEmail: $replyToEmail) { _id name provider @@ -2098,8 +2098,8 @@ trait Base } }'; case self::$CREATE_EMAIL: - return 'mutation createEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String!, $content: String!, $status: String, $description: String, $html: Boolean, $scheduledAt: String) { - messagingCreateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, scheduledAt: $scheduledAt) { + return 'mutation createEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String!, $content: String!, $status: String, $description: String, $html: Boolean, $cc: [String], $bcc: [String], $scheduledAt: String) { + messagingCreateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, cc: $cc, bcc: $bcc, scheduledAt: $scheduledAt) { _id topics users @@ -2178,8 +2178,8 @@ trait Base } }'; case self::$UPDATE_EMAIL: - return 'mutation updateEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String, $content: String, $status: String, $description: String, $html: Boolean, $scheduledAt: String) { - messagingUpdateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, scheduledAt: $scheduledAt) { + return 'mutation updateEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String, $content: String, $status: String, $description: String, $html: Boolean, $cc: [String], $bcc: [String], $scheduledAt: String) { + messagingUpdateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, cc: $cc, bcc: $bcc, scheduledAt: $scheduledAt) { _id topics users diff --git a/tests/e2e/Services/GraphQL/UsersTest.php b/tests/e2e/Services/GraphQL/UsersTest.php index 1dac9123a9..d243a45a4a 100644 --- a/tests/e2e/Services/GraphQL/UsersTest.php +++ b/tests/e2e/Services/GraphQL/UsersTest.php @@ -60,7 +60,8 @@ class UsersTest extends Scope 'name' => 'Mailgun1', 'apiKey' => 'api-key', 'domain' => 'domain', - 'from' => 'from@domain.com', + 'fromName' => 'sender name', + 'fromEmail' => 'from@domain.com', 'isEuRegion' => false, ], ]; diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 690e503e77..04fa9f4f22 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -23,7 +23,8 @@ trait MessagingBase 'name' => 'Mailgun1', 'apiKey' => 'my-apikey', 'domain' => 'my-domain', - 'from' => 'sender-email@my-domain.com', + 'fromName' => 'sender name', + 'fromEmail' => 'sender-email@my-domain.com', 'isEuRegion' => false, ], 'twilio' => [ @@ -552,7 +553,8 @@ trait MessagingBase $emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN')); $to = $emailDSN->getParam('to'); - $from = $emailDSN->getParam('from'); + $fromName = $emailDSN->getParam('fromName'); + $fromEmail = $emailDSN->getParam('fromEmail'); $isEuRegion = $emailDSN->getParam('isEuRegion'); $apiKey = $emailDSN->getPassword(); $domain = $emailDSN->getUser(); @@ -572,7 +574,8 @@ trait MessagingBase 'apiKey' => $apiKey, 'domain' => $domain, 'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN), - 'from' => $from + 'fromName' => $fromName, + 'fromEmail' => $fromEmail ]); $this->assertEquals(201, $provider['headers']['status-code']); From 6d357d617dd6dd6a93fc22ec55ea240f733c4c46 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 11 Dec 2023 23:37:32 +0000 Subject: [PATCH 03/18] Add a flag to install and upgrade commands to not start Appwrite This can be useful for cases where the developer only wants the files to be generated and doesn't want to start Appwrite. --- src/Appwrite/Platform/Tasks/Install.php | 14 +++++++++----- src/Appwrite/Platform/Tasks/Upgrade.php | 8 +++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php index eb419ade11..8591f4bcc3 100644 --- a/src/Appwrite/Platform/Tasks/Install.php +++ b/src/Appwrite/Platform/Tasks/Install.php @@ -8,6 +8,7 @@ use Appwrite\Docker\Env; use Appwrite\Utopia\View; use Utopia\CLI\Console; use Utopia\Config\Config; +use Utopia\Validator\Boolean; use Utopia\Validator\Text; use Utopia\Platform\Action; @@ -29,10 +30,11 @@ class Install extends Action ->param('organization', 'appwrite', new Text(0), 'Docker Registry organization', true) ->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true) ->param('interactive', 'Y', new Text(1), 'Run an interactive session', true) - ->callback(fn ($httpPort, $httpsPort, $organization, $image, $interactive) => $this->action($httpPort, $httpsPort, $organization, $image, $interactive)); + ->param('noStart', false, new Boolean(true), 'Run an interactive session', true) + ->callback(fn ($httpPort, $httpsPort, $organization, $image, $interactive, $noStart) => $this->action($httpPort, $httpsPort, $organization, $image, $interactive, $noStart)); } - public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive): void + public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive, bool $noStart): void { $config = Config::getParam('variables'); $defaultHTTPPort = '80'; @@ -220,9 +222,11 @@ class Install extends Action } } - Console::log("Running \"docker compose up -d --remove-orphans --renew-anon-volumes\""); - - $exit = Console::execute("$env docker compose --project-directory $this->path up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr); + $exit = 0; + if (!$noStart) { + Console::log("Running \"docker compose up -d --remove-orphans --renew-anon-volumes\""); + $exit = Console::execute("$env docker compose --project-directory $this->path up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr); + } if ($exit !== 0) { $message = 'Failed to install Appwrite dockers'; diff --git a/src/Appwrite/Platform/Tasks/Upgrade.php b/src/Appwrite/Platform/Tasks/Upgrade.php index e3f0458394..1f3e148a82 100644 --- a/src/Appwrite/Platform/Tasks/Upgrade.php +++ b/src/Appwrite/Platform/Tasks/Upgrade.php @@ -3,6 +3,7 @@ namespace Appwrite\Platform\Tasks; use Utopia\CLI\Console; +use Utopia\Validator\Boolean; use Utopia\Validator\Text; class Upgrade extends Install @@ -21,10 +22,11 @@ class Upgrade extends Install ->param('organization', 'appwrite', new Text(0), 'Docker Registry organization', true) ->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true) ->param('interactive', 'Y', new Text(1), 'Run an interactive session', true) - ->callback(fn ($httpPort, $httpsPort, $organization, $image, $interactive) => $this->action($httpPort, $httpsPort, $organization, $image, $interactive)); + ->param('noStart', false, new Boolean(true), 'Run an interactive session', true) + ->callback(fn ($httpPort, $httpsPort, $organization, $image, $interactive, $noStart) => $this->action($httpPort, $httpsPort, $organization, $image, $interactive, $noStart)); } - public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive): void + public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive, bool $noStart): void { // Check for previous installation $data = @file_get_contents($this->path . '/docker-compose.yml'); @@ -37,6 +39,6 @@ class Upgrade extends Install Console::log(' └── docker-compose.yml'); Console::exit(1); } - parent::action($httpPort, $httpsPort, $organization, $image, $interactive); + parent::action($httpPort, $httpsPort, $organization, $image, $interactive, $noStart); } } From 7b99fab51215826c210c7079e4caea8a6369a857 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Fri, 15 Dec 2023 03:19:24 +1300 Subject: [PATCH 04/18] Use targets for cc/bcc --- app/controllers/api/messaging.php | 72 ++++++++++------- composer.json | 2 +- composer.lock | 14 ++-- src/Appwrite/Platform/Workers/Messaging.php | 85 ++++++++------------- 4 files changed, 87 insertions(+), 86 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 9519f25d95..354dae4c86 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -2278,8 +2278,8 @@ App::post('/v1/messaging/messages/email') ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs.', true) ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of User IDs.', true) ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Targets IDs.', true) - ->param('cc', [], new ArrayList(new Email()), 'Array of email addresses to be added as CC.', true) - ->param('bcc', [], new ArrayList(new Email()), 'Array of email addresses to be added as BCC.', true) + ->param('cc', [], new ArrayList(new UID()), 'Array of target IDs to be added as CC.', true) + ->param('bcc', [], new ArrayList(new UID()), 'Array of target IDs to be added as BCC.', true) ->param('description', '', new Text(256), 'Description for message.', true) ->param('status', 'processing', new WhiteList(['draft', 'canceled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) @@ -2290,22 +2290,30 @@ App::post('/v1/messaging/messages/email') ->inject('queueForMessaging') ->inject('response') ->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, string $description, array $cc, array $bcc, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { - $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + $messageId = $messageId == 'unique()' + ? ID::unique() + : $messageId; if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { throw new Exception(Exception::MESSAGE_MISSING_TARGET); } - foreach ($targets as $target) { - $targetDocument = $dbForProject->getDocument('targets', $target); + $mergedTargets = \array_merge($targets, $cc, $bcc); - if ($targetDocument->isEmpty()) { + $foundTargets = $dbForProject->find('targets', [ + Query::equal('$id', $mergedTargets), + Query::equal('providerType', [MESSAGE_TYPE_EMAIL]), + Query::limit(\count($mergedTargets)), + ]); + + if (\count($foundTargets) !== \count($mergedTargets)) { + throw new Exception(Exception::MESSAGE_TARGET_NOT_EMAIL); + } + + foreach ($foundTargets as $target) { + if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); } - - if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_EMAIL) { - throw new Exception(Exception::MESSAGE_TARGET_NOT_EMAIL . ' ' . $targetDocument->getId()); - } } $message = $dbForProject->createDocument('messages', new Document([ @@ -2368,22 +2376,28 @@ App::post('/v1/messaging/messages/sms') ->inject('queueForMessaging') ->inject('response') ->action(function (string $messageId, string $content, array $topics, array $users, array $targets, string $description, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { - $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + $messageId = $messageId == 'unique()' + ? ID::unique() + : $messageId; if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { throw new Exception(Exception::MESSAGE_MISSING_TARGET); } - foreach ($targets as $target) { - $targetDocument = $dbForProject->getDocument('targets', $target); + $foundTargets = $dbForProject->find('targets', [ + Query::equal('$id', $targets), + Query::equal('providerType', [MESSAGE_TYPE_SMS]), + Query::limit(\count($targets)), + ]); - if ($targetDocument->isEmpty()) { + if (\count($foundTargets) !== \count($targets)) { + throw new Exception(Exception::MESSAGE_TARGET_NOT_SMS); + } + + foreach ($foundTargets as $target) { + if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); } - - if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_SMS) { - throw new Exception(Exception::MESSAGE_TARGET_NOT_SMS . ' ' . $targetDocument->getId()); - } } $message = $dbForProject->createDocument('messages', new Document([ @@ -2450,22 +2464,28 @@ App::post('/v1/messaging/messages/push') ->inject('queueForMessaging') ->inject('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 $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { - $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + $messageId = $messageId == 'unique()' + ? ID::unique() + : $messageId; if (\count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) { throw new Exception(Exception::MESSAGE_MISSING_TARGET); } - foreach ($targets as $target) { - $targetDocument = $dbForProject->getDocument('targets', $target); + $foundTargets = $dbForProject->find('targets', [ + Query::equal('$id', $targets), + Query::equal('providerType', [MESSAGE_TYPE_PUSH]), + Query::limit(\count($targets)), + ]); - if ($targetDocument->isEmpty()) { + if (\count($foundTargets) !== \count($targets)) { + throw new Exception(Exception::MESSAGE_TARGET_NOT_PUSH); + } + + foreach ($foundTargets as $target) { + if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); } - - if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_PUSH) { - throw new Exception(Exception::MESSAGE_TARGET_NOT_PUSH . ' ' . $targetDocument->getId()); - } } $pushData = []; diff --git a/composer.json b/composer.json index 29f3bcdec2..1ad0b055b5 100644 --- a/composer.json +++ b/composer.json @@ -56,7 +56,7 @@ "utopia-php/image": "0.5.*", "utopia-php/locale": "0.4.*", "utopia-php/logger": "0.3.*", - "utopia-php/messaging": "0.6.*", + "utopia-php/messaging": "0.7.*", "utopia-php/migration": "0.3.*", "utopia-php/orchestration": "0.9.*", "utopia-php/platform": "0.5.*", diff --git a/composer.lock b/composer.lock index f40521b414..fb10836c9b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7041499af2e7b23795d8ef82c9d7a072", + "content-hash": "ec8d49765c3f6ccc5759c5eab267f326", "packages": [ { "name": "adhocore/jwt", @@ -2270,16 +2270,16 @@ }, { "name": "utopia-php/messaging", - "version": "0.6.0", + "version": "0.7.0", "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "a3ebf9d0714e760cfa36f9c5de75c7c0f31c4024" + "reference": "b2d4b0334412390e839d250b848ff0f3466f7a55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/a3ebf9d0714e760cfa36f9c5de75c7c0f31c4024", - "reference": "a3ebf9d0714e760cfa36f9c5de75c7c0f31c4024", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/b2d4b0334412390e839d250b848ff0f3466f7a55", + "reference": "b2d4b0334412390e839d250b848ff0f3466f7a55", "shasum": "" }, "require": { @@ -2314,9 +2314,9 @@ ], "support": { "issues": "https://github.com/utopia-php/messaging/issues", - "source": "https://github.com/utopia-php/messaging/tree/0.6.0" + "source": "https://github.com/utopia-php/messaging/tree/0.7.0" }, - "time": "2023-12-05T11:08:43+00:00" + "time": "2023-12-05T13:47:36+00:00" }, { "name": "utopia-php/migration", diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 0686088def..e04bace4c1 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -63,7 +63,7 @@ class Messaging extends Action $payload = $message->getPayload() ?? []; if (empty($payload)) { - Console::error('Payload arg not found'); + Console::error('Payload not found.'); return; } @@ -85,14 +85,14 @@ class Messaging extends Action $usersId = $message->getAttribute('users', []); /** - * @var Document[] $recipients - */ + * @var Document[] $recipients + */ $recipients = []; if (\count($topicsId) > 0) { $topics = $dbForProject->find('topics', [Query::equal('$id', $topicsId)]); foreach ($topics as $topic) { - $targets = \array_filter($topic->getAttribute('targets'), fn (Document $target) => $target->getAttribute('providerType') === $message->getAttribute('providerType')); + $targets = \array_filter($topic->getAttribute('targets'), fn(Document $target) => $target->getAttribute('providerType') === $message->getAttribute('providerType')); $recipients = \array_merge($recipients, $targets); } } @@ -100,7 +100,7 @@ class Messaging extends Action if (\count($usersId) > 0) { $users = $dbForProject->find('users', [Query::equal('$id', $usersId)]); foreach ($users as $user) { - $targets = \array_filter($user->getAttribute('targets'), fn (Document $target) => $target->getAttribute('providerType') === $message->getAttribute('providerType')); + $targets = \array_filter($user->getAttribute('targets'), fn(Document $target) => $target->getAttribute('providerType') === $message->getAttribute('providerType')); $recipients = \array_merge($recipients, $targets); } } @@ -116,13 +116,13 @@ class Messaging extends Action ]); /** - * @var array> $identifiersByProviderId - */ + * @var array> $identifiersByProviderId + */ $identifiersByProviderId = []; /** - * @var Document[] $providers - */ + * @var Document[] $providers + */ $providers = []; foreach ($recipients as $recipient) { $providerId = $recipient->getAttribute('providerId'); @@ -140,12 +140,10 @@ class Messaging extends Action } /** - * @var array[] $results - */ + * @var array[] $results + */ $results = batch(\array_map(function ($providerId) use ($identifiersByProviderId, $providers, $primaryProvider, $message, $dbForProject) { return function () use ($providerId, $identifiersByProviderId, $providers, $primaryProvider, $message, $dbForProject) { - $provider = new Document(); - if ($primaryProvider->getId() === $providerId) { $provider = $primaryProvider; } else { @@ -156,13 +154,12 @@ class Messaging extends Action } } - $providers[] = $provider; $identifiers = $identifiersByProviderId[$providerId]; $adapter = match ($provider->getAttribute('type')) { MESSAGE_TYPE_SMS => $this->sms($provider), MESSAGE_TYPE_PUSH => $this->push($provider), - MESSAGE_TYPE_EMAIL => $this->email($provider), + MESSAGE_TYPE_EMAIL => $this->email($provider), default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) }; @@ -170,7 +167,7 @@ class Messaging extends Action $batches = \array_chunk($identifiers, $maxBatchSize); $batchIndex = 0; - $results = batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex, $dbForProject) { + return batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex, $dbForProject) { return function () use ($batch, $message, $provider, $adapter, $batchIndex, $dbForProject) { $deliveredTotal = 0; $deliveryErrors = []; @@ -180,7 +177,7 @@ class Messaging extends Action $data = match ($provider->getAttribute('type')) { MESSAGE_TYPE_SMS => $this->buildSMSMessage($messageData, $provider), MESSAGE_TYPE_PUSH => $this->buildPushMessage($messageData), - MESSAGE_TYPE_EMAIL => $this->buildEmailMessage($messageData, $provider), + MESSAGE_TYPE_EMAIL => $this->buildEmailMessage($dbForProject, $messageData, $provider), default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE) }; @@ -214,8 +211,6 @@ class Messaging extends Action } }; }, $batches)); - - return $results; }; }, \array_keys($identifiersByProviderId))); @@ -364,58 +359,44 @@ class Messaging extends Action }; } - private function buildEmailMessage(Document $message, Document $provider): Email + private function buildEmailMessage(Database $dbForProject, Document $message, Document $provider): Email { $fromName = $provider['options']['fromName']; $fromEmail = $provider['options']['fromEmail']; $replyToEmail = null; $replyToName = null; - $cc = null; - $bcc = null; if (isset($provider['options']['replyToName']) && isset($provider['options']['replyToEmail'])) { $replyToName = $provider['options']['replyToName']; $replyToEmail = $provider['options']['replyToEmail']; } - if (\count($message['data']['cc']) > 0) { - foreach ($message['data']['cc'] as $ccEmail) { - if (is_array($cc)) { - $cc[] = [ - 'email' => $ccEmail, - ]; - } else { - $cc = [ - [ - 'email' => $ccEmail, - ] - ]; - } + $data = $message['data'] ?? []; + $ccTargets = $data['cc'] ?? []; + $bccTargets = $data['bcc'] ?? []; + $cc = []; + $bcc = []; + + if (\count($ccTargets) > 0) { + $ccTargets = $dbForProject->find('targets', [Query::equal('identifier', $ccTargets)]); + foreach ($ccTargets as $ccTarget) { + $cc[] = ['email' => $ccTarget['identifier']]; } } - if (\count($message['data']['bcc'])) { - foreach ($message['data']['bcc'] as $bccEmail) { - if (is_array($bcc)) { - $bcc[] = [ - 'email' => $bccEmail, - ]; - } else { - $bcc = [ - [ - 'email' => $bccEmail, - ] - ]; - } + if (\count($bccTargets) > 0) { + $bccTargets = $dbForProject->find('targets', [Query::equal('identifier', $bccTargets)]); + foreach ($bccTargets as $bccTarget) { + $bcc[] = ['email' => $bccTarget['identifier']]; } } $to = $message['to']; - $subject = $message['data']['subject']; - $content = $message['data']['content']; - $html = $message['data']['html']; + $subject = $data['subject']; + $content = $data['content']; + $html = $data['html']; - return new Email($to, $subject, $content, $fromName, $fromEmail, $replyToName, $replyToEmail, $cc, $bcc, html: $html); + return new Email($to, $subject, $content, $fromName, $fromEmail, $replyToName, $replyToEmail, $cc, $bcc, null, $html); } private function buildSMSMessage(Document $message, Document $provider): SMS From 4e26bdb5dfb840e17361246c7143ad76179f7b1d Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Fri, 15 Dec 2023 03:45:51 +1300 Subject: [PATCH 05/18] Update update route params --- app/controllers/api/messaging.php | 155 ++++++++++++++++-------------- 1 file changed, 85 insertions(+), 70 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 354dae4c86..b01ab4b7a3 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -31,6 +31,7 @@ use Utopia\Database\Validator\UID; use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; +use Utopia\Validator\Integer; use Utopia\Validator\JSON; use Utopia\Validator\Text; use MaxMind\Db\Reader; @@ -2694,20 +2695,20 @@ App::patch('/v1/messaging/messages/email/:messageId') ->param('topics', null, new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs.', true) ->param('users', null, new ArrayList(new Text(Database::LENGTH_KEY)), 'List of User IDs.', true) ->param('targets', null, new ArrayList(new Text(Database::LENGTH_KEY)), '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) - ->param('status', '', new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) - ->param('html', false, new Boolean(), 'Is content of type HTML', true) - ->param('cc', [], new ArrayList(new Email()), 'Array of email addresses to be added as CC.', true) - ->param('bcc', [], new ArrayList(new Email()), 'Array of email addresses to be added as BCC.', true) + ->param('subject', null, new Text(998), 'Email Subject.', true) + ->param('description', null, new Text(256), 'Description for Message.', true) + ->param('content', null, new Text(64230), 'Email Content.', true) + ->param('status', null, new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) + ->param('html', null, new Boolean(), 'Is content of type HTML', true) + ->param('cc', null, new ArrayList(new UID()), 'Array of target IDs to be added as CC.', true) + ->param('bcc', null, new ArrayList(new UID()), 'Array of target IDs to be added as BCC.', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $subject, string $description, string $content, string $status, bool $html, array $cc, array $bcc, ?string $scheduledAt, Event $queueForEvents, 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, ?array $cc, ?array $bcc, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2718,7 +2719,7 @@ App::patch('/v1/messaging/messages/email/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } - if (!is_null($message->getAttribute('scheduledAt')) && $message->getAttribute('scheduledAt') < new \DateTime()) { + if (!\is_null($message->getAttribute('scheduledAt')) && $message->getAttribute('scheduledAt') < new \DateTime()) { throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } @@ -2730,51 +2731,57 @@ App::patch('/v1/messaging/messages/email/:messageId') $message->setAttribute('users', $users); } - if (!\is_null($targets)) { - foreach ($targets as $target) { - $targetDocument = $dbForProject->getDocument('targets', $target); + if (!\is_null($targets) || !\is_null($cc) || !\is_null($bcc)) { + $mergedTargets = \array_merge(...\array_filter([$targets, $cc, $bcc])); - if ($targetDocument->isEmpty()) { + $foundTargets = $dbForProject->find('targets', [ + Query::equal('$id', $mergedTargets), + Query::equal('providerType', [MESSAGE_TYPE_EMAIL]), + Query::limit(\count($mergedTargets)), + ]); + if (\count($foundTargets) !== \count($mergedTargets)) { + throw new Exception(Exception::MESSAGE_TARGET_NOT_EMAIL); + } + foreach ($foundTargets as $target) { + if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); } - - if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_EMAIL) { - throw new Exception(Exception::MESSAGE_TARGET_NOT_EMAIL . ' ' . $targetDocument->getId()); - } } - - $message->setAttribute('targets', $targets); } $data = $message->getAttribute('data'); - if (!empty($subject)) { + if (!\is_null($targets)) { + $message->setAttribute('targets', $targets); + } + + if (!\is_null($subject)) { $data['subject'] = $subject; } - if (!empty($content)) { + if (!\is_null($content)) { $data['content'] = $content; } - if (!empty($html)) { + if (!\is_null($html)) { $data['html'] = $html; } - if (count($cc) > 0) { + if (!\is_null($cc)) { $data['cc'] = $cc; } - if (count($bcc) > 0) { + if (!\is_null($bcc)) { $data['bcc'] = $bcc; } $message->setAttribute('data', $data); - if (!empty($description)) { + if (!\is_null($description)) { $message->setAttribute('description', $description); } - if (!empty($status)) { + if (!\is_null($status)) { $message->setAttribute('status', $status); } @@ -2816,16 +2823,16 @@ App::patch('/v1/messaging/messages/sms/:messageId') ->param('topics', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) ->param('users', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) ->param('targets', null, 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', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) + ->param('description', null, new Text(256), 'Description for Message.', true) + ->param('content', null, new Text(64230), 'Email Content.', true) + ->param('status', null, new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, string $description, string $content, string $status, ?string $scheduledAt, Event $queueForEvents, 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 $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2849,16 +2856,20 @@ App::patch('/v1/messaging/messages/sms/:messageId') } if (!\is_null($targets)) { - foreach ($targets as $target) { - $targetDocument = $dbForProject->getDocument('targets', $target); + $foundTargets = $dbForProject->find('targets', [ + Query::equal('$id', $targets), + Query::equal('providerType', [MESSAGE_TYPE_SMS]), + Query::limit(\count($targets)), + ]); - if ($targetDocument->isEmpty()) { + if (\count($foundTargets) !== \count($targets)) { + throw new Exception(Exception::MESSAGE_TARGET_NOT_SMS); + } + + foreach ($foundTargets as $target) { + if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); } - - if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_SMS) { - throw new Exception(Exception::MESSAGE_TARGET_NOT_SMS . ' ' . $targetDocument->getId()); - } } $message->setAttribute('targets', $targets); @@ -2866,17 +2877,17 @@ App::patch('/v1/messaging/messages/sms/:messageId') $data = $message->getAttribute('data'); - if (!empty($content)) { + if (!\is_null($content)) { $data['content'] = $content; } $message->setAttribute('data', $data); - if (!empty($status)) { + if (!\is_null($status)) { $message->setAttribute('status', $status); } - if (!empty($description)) { + if (!\is_null($description)) { $message->setAttribute('description', $description); } @@ -2918,24 +2929,24 @@ App::patch('/v1/messaging/messages/push/:messageId') ->param('topics', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) ->param('users', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) ->param('targets', null, 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) + ->param('description', null, new Text(256), 'Description for Message.', true) + ->param('title', null, new Text(256), 'Title for push notification.', true) + ->param('body', null, new Text(64230), 'Body for push notification.', true) ->param('data', null, new JSON(), 'Additional Data for push notification.', true) - ->param('action', '', new Text(256), 'Action for push notification.', true) - ->param('icon', '', new Text(256), 'Icon for push notification. Available only for Android and Web Platform.', true) - ->param('sound', '', new Text(256), 'Sound for push notification. Available only for Android and IOS Platform.', true) - ->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true) - ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) - ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) - ->param('status', '', new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) + ->param('action', null, new Text(256), 'Action for push notification.', true) + ->param('icon', null, new Text(256), 'Icon for push notification. Available only for Android and Web platforms.', true) + ->param('sound', null, new Text(256), 'Sound for push notification. Available only for Android and iOS platforms.', true) + ->param('color', null, new Text(256), 'Color for push notification. Available only for Android platforms.', true) + ->param('tag', null, new Text(256), 'Tag for push notification. Available only for Android platforms.', true) + ->param('badge', null, new Integer(), 'Badge for push notification. Available only for iOS platforms.', true) + ->param('status', null, new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft, cancelled, or processing.', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('project') ->inject('queueForMessaging') ->inject('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 $scheduledAt, Event $queueForEvents, 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, ?int $badge, ?string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $message = $dbForProject->getDocument('messages', $messageId); if ($message->isEmpty()) { @@ -2959,16 +2970,20 @@ App::patch('/v1/messaging/messages/push/:messageId') } if (!\is_null($targets)) { - foreach ($targets as $target) { - $targetDocument = $dbForProject->getDocument('targets', $target); + $foundTargets = $dbForProject->find('targets', [ + Query::equal('$id', $targets), + Query::equal('providerType', [MESSAGE_TYPE_PUSH]), + Query::limit(\count($targets)), + ]); - if ($targetDocument->isEmpty()) { + if (\count($foundTargets) !== \count($targets)) { + throw new Exception(Exception::MESSAGE_TARGET_NOT_PUSH); + } + + foreach ($foundTargets as $target) { + if ($target->isEmpty()) { throw new Exception(Exception::USER_TARGET_NOT_FOUND); } - - if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_PUSH) { - throw new Exception(Exception::MESSAGE_TARGET_NOT_PUSH . ' ' . $targetDocument->getId()); - } } $message->setAttribute('targets', $targets); @@ -2976,53 +2991,53 @@ App::patch('/v1/messaging/messages/push/:messageId') $pushData = $message->getAttribute('data'); - if ($title) { + if (!\is_null($title)) { $pushData['title'] = $title; } - if ($body) { + if (!\is_null($body)) { $pushData['body'] = $body; } - if (!is_null($data)) { + if (!\is_null($data)) { $pushData['data'] = $data; } - if ($action) { + if (!\is_null($action)) { $pushData['action'] = $action; } - if ($icon) { + if (!\is_null($icon)) { $pushData['icon'] = $icon; } - if ($sound) { + if (!\is_null($sound)) { $pushData['sound'] = $sound; } - if ($color) { + if (!\is_null($color)) { $pushData['color'] = $color; } - if ($tag) { + if (!\is_null($tag)) { $pushData['tag'] = $tag; } - if ($badge) { + if (!\is_null($badge)) { $pushData['badge'] = $badge; } $message->setAttribute('data', $pushData); - if (!empty($status)) { + if (!\is_null($status)) { $message->setAttribute('status', $status); } - if (!empty($description)) { + if (!\is_null($description)) { $message->setAttribute('description', $description); } - if (!is_null($scheduledAt)) { + if (!\is_null($scheduledAt)) { $message->setAttribute('scheduledAt', $scheduledAt); } From 8fc3f99a8e3ecaab57a7c04c3a172e7d0d4bf621 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Fri, 15 Dec 2023 19:55:50 +1300 Subject: [PATCH 06/18] Update messaging lib --- composer.json | 2 +- composer.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 1ad0b055b5..b92557d235 100644 --- a/composer.json +++ b/composer.json @@ -56,7 +56,7 @@ "utopia-php/image": "0.5.*", "utopia-php/locale": "0.4.*", "utopia-php/logger": "0.3.*", - "utopia-php/messaging": "0.7.*", + "utopia-php/messaging": "0.8.*", "utopia-php/migration": "0.3.*", "utopia-php/orchestration": "0.9.*", "utopia-php/platform": "0.5.*", diff --git a/composer.lock b/composer.lock index fb10836c9b..803678ff49 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ec8d49765c3f6ccc5759c5eab267f326", + "content-hash": "359b1e3bd27ac7362c6f8d145e64ae36", "packages": [ { "name": "adhocore/jwt", @@ -2270,24 +2270,24 @@ }, { "name": "utopia-php/messaging", - "version": "0.7.0", + "version": "0.8.0", "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "b2d4b0334412390e839d250b848ff0f3466f7a55" + "reference": "64eca3faf02a79831f219d4f3ae05cd278a88b4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/b2d4b0334412390e839d250b848ff0f3466f7a55", - "reference": "b2d4b0334412390e839d250b848ff0f3466f7a55", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/64eca3faf02a79831f219d4f3ae05cd278a88b4b", + "reference": "64eca3faf02a79831f219d4f3ae05cd278a88b4b", "shasum": "" }, "require": { "ext-curl": "*", + "ext-openssl": "*", "php": ">=8.0.0" }, "require-dev": { - "ext-openssl": "*", "laravel/pint": "1.13.*", "phpmailer/phpmailer": "6.8.*", "phpstan/phpstan": "1.10.*", @@ -2314,9 +2314,9 @@ ], "support": { "issues": "https://github.com/utopia-php/messaging/issues", - "source": "https://github.com/utopia-php/messaging/tree/0.7.0" + "source": "https://github.com/utopia-php/messaging/tree/0.8.0" }, - "time": "2023-12-05T13:47:36+00:00" + "time": "2023-12-15T06:44:08+00:00" }, { "name": "utopia-php/migration", From 23b39fee02e17917fca1a2049fed17a973e1d60e Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Sun, 17 Dec 2023 12:41:20 +1300 Subject: [PATCH 07/18] FIx FCM tests --- app/controllers/api/messaging.php | 48 ++++++++--------- app/worker.php | 2 +- tests/e2e/Services/GraphQL/Base.php | 4 +- .../e2e/Services/Messaging/MessagingBase.php | 51 +++++++------------ 4 files changed, 46 insertions(+), 59 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index b01ab4b7a3..fdead6e6fc 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -55,18 +55,18 @@ 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('fromName', '', new Text(128), 'Sender Name.') - ->param('fromEmail', '', new Email(), 'Sender email address.') ->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) + ->param('fromName', '', new Text(128), 'Sender Name.', true) + ->param('fromEmail', '', new Email(), 'Sender email address.', true) ->param('replyToName', '', new Text(128), 'Name set in the reply to field for the mail. Default value is sender name. Reply to name must have reply to email as well.', true) ->param('replyToEmail', '', new Text(128), 'Email set in the reply to field for the mail. Default value is sender email. Reply to email must have reply to name as well.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $fromName, string $fromEmail, string $apiKey, string $domain, ?bool $isEuRegion, ?bool $enabled, string $replyToName, string $replyToEmail, array $cc, array $bcc, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $apiKey, string $domain, ?bool $isEuRegion, ?bool $enabled, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $options = [ @@ -145,16 +145,16 @@ 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('fromName', '', new Text(128), 'Sender Name.') - ->param('fromEmail', '', new Email(), 'Sender email address.') ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) + ->param('fromName', '', new Text(128), 'Sender Name.', true) + ->param('fromEmail', '', new Email(), 'Sender email address.', true) ->param('replyToName', '', new Text(128), 'Name set in the reply to field for the mail. Default value is sender name.', true) ->param('replyToEmail', '', new Text(128), 'Email set in the reply to field for the mail. Default value is sender email.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, string $fromName, string $fromEmail, string $apiKey, ?bool $enabled, string $replyToName, string $replyToEmail, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $apiKey, ?bool $enabled, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $options = [ @@ -608,7 +608,7 @@ 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.', true) + ->param('serviceAccountJSON', '', new Text(0), 'FCM service account JSON.', true) ->param('enabled', null, new Boolean(), 'Set as enabled.', true) ->inject('queueForEvents') ->inject('dbForProject') @@ -903,18 +903,18 @@ App::patch('/v1/messaging/providers/mailgun/:providerId') ->label('sdk.response.model', Response::MODEL_PROVIDER) ->param('providerId', '', new UID(), 'Provider ID.') ->param('name', '', new Text(128), 'Provider name.', true) - ->param('enabled', null, new Boolean(), 'Set as enabled.', 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) ->param('fromName', '', new Text(128), 'Sender Name.', true) ->param('fromEmail', '', new Email(), 'Sender email address.', true) ->param('replyToName', '', new Text(128), 'Name set in the reply to field for the mail. Default value is sender name.', true) ->param('replyToEmail', '', new Text(128), 'Email set in the reply to field for the mail. Default value is sender email.', true) - ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) - ->param('domain', '', new Text(0), 'Mailgun Domain.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, ?bool $isEuRegion, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, string $apiKey, string $domain, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, string $apiKey, string $domain, ?bool $isEuRegion, ?bool $enabled, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -2290,7 +2290,7 @@ App::post('/v1/messaging/messages/email') ->inject('project') ->inject('queueForMessaging') ->inject('response') - ->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, string $description, array $cc, array $bcc, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { + ->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, array $cc, array $bcc, string $description, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Document $project, Messaging $queueForMessaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; @@ -2301,19 +2301,21 @@ App::post('/v1/messaging/messages/email') $mergedTargets = \array_merge($targets, $cc, $bcc); - $foundTargets = $dbForProject->find('targets', [ - Query::equal('$id', $mergedTargets), - Query::equal('providerType', [MESSAGE_TYPE_EMAIL]), - Query::limit(\count($mergedTargets)), - ]); + if (!empty($mergedTargets)) { + $foundTargets = $dbForProject->find('targets', [ + Query::equal('$id', $mergedTargets), + Query::equal('providerType', [MESSAGE_TYPE_EMAIL]), + Query::limit(\count($mergedTargets)), + ]); - if (\count($foundTargets) !== \count($mergedTargets)) { - throw new Exception(Exception::MESSAGE_TARGET_NOT_EMAIL); - } + if (\count($foundTargets) !== \count($mergedTargets)) { + throw new Exception(Exception::MESSAGE_TARGET_NOT_EMAIL); + } - foreach ($foundTargets as $target) { - if ($target->isEmpty()) { - throw new Exception(Exception::USER_TARGET_NOT_FOUND); + foreach ($foundTargets as $target) { + if ($target->isEmpty()) { + throw new Exception(Exception::USER_TARGET_NOT_FOUND); + } } } diff --git a/app/worker.php b/app/worker.php index a8e5607965..c9f1a0df1d 100644 --- a/app/worker.php +++ b/app/worker.php @@ -277,7 +277,7 @@ $worker $worker->workerStart() ->action(function () use ($workerName) { - Console::info("Worker $workerName started"); + Console::info("Worker $workerName started"); }); $worker->start(); diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 2593a58e1a..dc71b4df54 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -1860,8 +1860,8 @@ trait Base } }'; case self::$CREATE_FCM_PROVIDER: - return 'mutation createFcmProvider($providerId: String!, $name: String!, $serverKey: String!) { - messagingCreateFcmProvider(providerId: $providerId, name: $name, serverKey: $serverKey) { + return 'mutation createFcmProvider($providerId: String!, $name: String!, $serviceAccountJSON: String!) { + messagingCreateFcmProvider(providerId: $providerId, name: $name, serviceAccountJSON: $serviceAccountJSON) { _id name provider diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 04fa9f4f22..84b16597cc 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -85,6 +85,7 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]), $providersParams[$key]); + $this->assertEquals(201, $response['headers']['status-code']); $this->assertEquals($providersParams[$key]['name'], $response['body']['name']); \array_push($providers, $response['body']); @@ -555,16 +556,14 @@ trait MessagingBase $to = $emailDSN->getParam('to'); $fromName = $emailDSN->getParam('fromName'); $fromEmail = $emailDSN->getParam('fromEmail'); - $isEuRegion = $emailDSN->getParam('isEuRegion'); $apiKey = $emailDSN->getPassword(); - $domain = $emailDSN->getUser(); - if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) { + if (empty($to) || empty($apiKey)) { $this->markTestSkipped('Email provider not configured'); } // Create provider - $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/mailgun', \array_merge([ + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -572,8 +571,6 @@ trait MessagingBase 'providerId' => ID::unique(), 'name' => 'Mailgun-provider', 'apiKey' => $apiKey, - 'domain' => $domain, - 'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN), 'fromName' => $fromName, 'fromEmail' => $fromEmail ]); @@ -607,27 +604,13 @@ trait MessagingBase $this->assertEquals(201, $user['headers']['status-code']); - // Create Target - $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ], [ - 'targetId' => ID::unique(), - 'providerType' => 'email', - 'providerId' => $provider['body']['$id'], - 'identifier' => $to, - ]); - - $this->assertEquals(201, $target['headers']['status-code']); - // Create Subscriber $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ 'subscriberId' => ID::unique(), - 'targetId' => $target['body']['$id'], + 'targetId' => $user['body']['targets'][0]['$id'], ]); $this->assertEquals(201, $subscriber['headers']['status-code']); @@ -640,13 +623,13 @@ trait MessagingBase ], [ 'messageId' => ID::unique(), 'topics' => [$topic['body']['$id']], - 'subject' => 'Khali beats Undertaker', - 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', + 'subject' => 'New blog post', + 'content' => 'Check out the new blog post at http://localhost', ]); $this->assertEquals(201, $email['headers']['status-code']); - \sleep(5); + \sleep(2); $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'], [ 'origin' => 'http://localhost', @@ -655,6 +638,8 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ]); + \var_dump($message); + $this->assertEquals(200, $message['headers']['status-code']); $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); @@ -665,7 +650,7 @@ trait MessagingBase /** * @depends testSendEmail */ - public function testUpdateEmail(array $email) + public function testUpdateEmail(array $email): void { $message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $email['body']['$id'], [ 'content-type' => 'application/json', @@ -724,8 +709,8 @@ trait MessagingBase $smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN')); $to = $smsDSN->getParam('to'); $from = $smsDSN->getParam('from'); - $authKey = $smsDSN->getPassword(); $senderId = $smsDSN->getUser(); + $authKey = $smsDSN->getPassword(); if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { $this->markTestSkipped('SMS provider not configured'); @@ -738,7 +723,7 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ]), [ 'providerId' => ID::unique(), - 'name' => 'Msg91-1', + 'name' => 'Msg91Sender', 'senderId' => $senderId, 'authKey' => $authKey, 'from' => $from @@ -850,7 +835,7 @@ trait MessagingBase 'messageId' => ID::unique(), 'status' => 'draft', 'topics' => [$sms['body']['topics'][0]], - 'content' => '047487', + 'content' => 'Your OTP code is 123456', ]); $this->assertEquals(201, $sms['headers']['status-code']); @@ -865,7 +850,7 @@ trait MessagingBase $this->assertEquals(200, $sms['headers']['status-code']); - \sleep(5); + \sleep(2); $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $sms['body']['$id'], [ 'origin' => 'http://localhost', @@ -885,9 +870,9 @@ trait MessagingBase $this->markTestSkipped('Push DSN empty'); } - $pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); - $to = $pushDSN->getParam('to'); - $serverKey = $pushDSN->getPassword(); + $dsn = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); + $to = $dsn->getParam('to'); + $serviceAccountJSON = $dsn->getParam('saj'); if (empty($to) || empty($serverKey)) { $this->markTestSkipped('Push provider not configured'); @@ -901,7 +886,7 @@ trait MessagingBase ]), [ 'providerId' => ID::unique(), 'name' => 'FCM-1', - 'serverKey' => $serverKey, + 'serviceAccountJSON' => $serviceAccountJSON, ]); $this->assertEquals(201, $provider['headers']['status-code']); From 1957bc57c268cba249521e3982a7715dba47b859 Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Tue, 19 Dec 2023 18:28:25 +0530 Subject: [PATCH 08/18] makes messaging worker compatible with new messaging lib version --- composer.lock | 36 +++++++++---------- src/Appwrite/Platform/Workers/Messaging.php | 17 +++++---- .../e2e/Services/Messaging/MessagingBase.php | 1 - 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/composer.lock b/composer.lock index 803678ff49..3c195434b3 100644 --- a/composer.lock +++ b/composer.lock @@ -2906,16 +2906,16 @@ }, { "name": "utopia-php/vcs", - "version": "0.6.2", + "version": "0.6.3", "source": { "type": "git", "url": "https://github.com/utopia-php/vcs.git", - "reference": "f135291b87cb45335fc6608722e7f89894bc33ee" + "reference": "86c3f42a2624bcccb7a67b74dcd7bd3a31fc2e4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/vcs/zipball/f135291b87cb45335fc6608722e7f89894bc33ee", - "reference": "f135291b87cb45335fc6608722e7f89894bc33ee", + "url": "https://api.github.com/repos/utopia-php/vcs/zipball/86c3f42a2624bcccb7a67b74dcd7bd3a31fc2e4b", + "reference": "86c3f42a2624bcccb7a67b74dcd7bd3a31fc2e4b", "shasum": "" }, "require": { @@ -2949,9 +2949,9 @@ ], "support": { "issues": "https://github.com/utopia-php/vcs/issues", - "source": "https://github.com/utopia-php/vcs/tree/0.6.2" + "source": "https://github.com/utopia-php/vcs/tree/0.6.3" }, - "time": "2023-11-08T15:36:03+00:00" + "time": "2023-12-14T06:53:39+00:00" }, { "name": "utopia-php/websocket", @@ -3489,16 +3489,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.17.1", + "version": "v4.18.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", "shasum": "" }, "require": { @@ -3539,9 +3539,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" }, - "time": "2023-08-13T19:53:39+00:00" + "time": "2023-12-10T21:03:43+00:00" }, { "name": "phar-io/manifest", @@ -3893,16 +3893,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.24.4", + "version": "1.24.5", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "6bd0c26f3786cd9b7c359675cb789e35a8e07496" + "reference": "fedf211ff14ec8381c9bf5714e33a7a552dd1acc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6bd0c26f3786cd9b7c359675cb789e35a8e07496", - "reference": "6bd0c26f3786cd9b7c359675cb789e35a8e07496", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fedf211ff14ec8381c9bf5714e33a7a552dd1acc", + "reference": "fedf211ff14ec8381c9bf5714e33a7a552dd1acc", "shasum": "" }, "require": { @@ -3934,9 +3934,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.4" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.5" }, - "time": "2023-11-26T18:29:22+00:00" + "time": "2023-12-16T09:33:33+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index e04bace4c1..b075de762b 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -123,7 +123,9 @@ class Messaging extends Action /** * @var Document[] $providers */ - $providers = []; + $providers = [ + $primaryProvider->getId() => $primaryProvider + ]; foreach ($recipients as $recipient) { $providerId = $recipient->getAttribute('providerId'); @@ -144,13 +146,16 @@ class Messaging extends Action */ $results = batch(\array_map(function ($providerId) use ($identifiersByProviderId, $providers, $primaryProvider, $message, $dbForProject) { return function () use ($providerId, $identifiersByProviderId, $providers, $primaryProvider, $message, $dbForProject) { - if ($primaryProvider->getId() === $providerId) { - $provider = $primaryProvider; - } else { + if (\array_key_exists($providerId, $providers)) { + $provider = $providers[$providerId]; + } + else { $provider = $dbForProject->getDocument('providers', $providerId, [Query::equal('enabled', [true])]); if ($provider->isEmpty()) { $provider = $primaryProvider; + } else { + $providers[$providerId] = $provider; } } @@ -183,7 +188,7 @@ class Messaging extends Action try { $response = new Response($provider->getAttribute('type')); - $response->fromArray(\json_decode($adapter->send($data))); + $response->fromArray($adapter->send($data)); $deliveredTotal += $response->getDeliveredTo(); $details[] = $response->getDetails(); @@ -193,7 +198,7 @@ class Messaging extends Action } // Deleting push targets when token has expired. - if ($detail['error'] === 'Expired token.') { + if ($detail['error'] === 'Expired device token.') { $target = $dbForProject->findOne('targets', [Query::equal('identifier', [$detail['recipient']])]); if ($target instanceof Document && !$target->isEmpty()) { $dbForProject->deleteDocument('targets', $target->getId()); diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 84b16597cc..ca472591c7 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -231,7 +231,6 @@ trait MessagingBase ], [ 'topicId' => ID::unique(), 'name' => 'my-app', - 'description' => 'web app' ]); $this->assertEquals(201, $response['headers']['status-code']); $this->assertEquals('my-app', $response['body']['name']); From 5d7eca7c99052cf305b4291294d6f5537f1f3793 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Tue, 19 Dec 2023 23:45:20 +0530 Subject: [PATCH 09/18] lint fix and tests fix --- app/controllers/api/messaging.php | 20 ++++----- composer.lock | 2 +- src/Appwrite/Platform/Workers/Messaging.php | 5 +-- tests/e2e/Services/GraphQL/Base.php | 14 +++---- tests/e2e/Services/GraphQL/MessagingTest.php | 41 ++++++++++++++----- .../e2e/Services/Messaging/MessagingBase.php | 16 ++++++-- 6 files changed, 64 insertions(+), 34 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index fdead6e6fc..53135f2193 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -608,21 +608,21 @@ 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('serviceAccountJSON', '', new Text(0), 'FCM service account JSON.', true) + ->param('serviceAccountJSON', null, new JSON(), 'FCM service account JSON.', 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, ?array $serviceAccountJSON, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) { $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $credentials = []; - if (!empty($serverKey)) { - $credentials['serverKey'] = $serverKey; + if (!\is_null($serviceAccountJSON)) { + $credentials['serviceAccountJSON'] = $serviceAccountJSON; } - if ($enabled === true && \array_key_exists('serverKey', $credentials)) { + if ($enabled === true && \array_key_exists('serviceAccountJSON', $credentials)) { $enabled = true; } else { $enabled = false; @@ -1500,11 +1500,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('serverKey', '', new Text(0), 'FCM Server Key.', true) + ->param('serviceAccountJSON', null, new JSON(), 'FCM service account JSON.', true) ->inject('queueForEvents') ->inject('dbForProject') ->inject('response') - ->action(function (string $providerId, string $name, ?bool $enabled, string $serverKey, Event $queueForEvents, Database $dbForProject, Response $response) { + ->action(function (string $providerId, string $name, ?bool $enabled, ?array $serviceAccountJSON, Event $queueForEvents, Database $dbForProject, Response $response) { $provider = $dbForProject->getDocument('providers', $providerId); if ($provider->isEmpty()) { @@ -1520,12 +1520,12 @@ App::patch('/v1/messaging/providers/fcm/:providerId') $provider->setAttribute('name', $name); } - if (!empty($serverKey)) { - $provider->setAttribute('credentials', ['serverKey' => $serverKey]); + if (!\is_null($serviceAccountJSON)) { + $provider->setAttribute('credentials', ['serviceAccountJSON' => $serviceAccountJSON]); } if ($enabled === true || $enabled === false) { - if ($enabled === true && \array_key_exists('serverKey', $provider->getAttribute('credentials'))) { + if ($enabled === true && \array_key_exists('serviceAccountJSON', $provider->getAttribute('credentials'))) { $enabled = true; } else { $enabled = false; diff --git a/composer.lock b/composer.lock index 3c195434b3..6b7fc0ac4e 100644 --- a/composer.lock +++ b/composer.lock @@ -5849,5 +5849,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index b075de762b..ed72731681 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -148,8 +148,7 @@ class Messaging extends Action return function () use ($providerId, $identifiersByProviderId, $providers, $primaryProvider, $message, $dbForProject) { if (\array_key_exists($providerId, $providers)) { $provider = $providers[$providerId]; - } - else { + } else { $provider = $dbForProject->getDocument('providers', $providerId, [Query::equal('enabled', [true])]); if ($provider->isEmpty()) { @@ -348,7 +347,7 @@ class Messaging extends Action $credentials['bundleId'], $credentials['endpoint'] ), - 'fcm' => new FCM($credentials['serverKey']), + 'fcm' => new FCM($credentials['serviceAccountJSON']), default => null }; } diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index dc71b4df54..2c630e3f75 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -1860,7 +1860,7 @@ trait Base } }'; case self::$CREATE_FCM_PROVIDER: - return 'mutation createFcmProvider($providerId: String!, $name: String!, $serviceAccountJSON: String!) { + return 'mutation createFcmProvider($providerId: String!, $name: String!, $serviceAccountJSON: Json) { messagingCreateFcmProvider(providerId: $providerId, name: $name, serviceAccountJSON: $serviceAccountJSON) { _id name @@ -1904,8 +1904,8 @@ trait Base } }'; case self::$UPDATE_MAILGUN_PROVIDER: - return 'mutation updateMailgunProvider($providerId: String!, $name: String!, $domain: String!, $apiKey: String!, $isEuRegion: Boolean, $enabled: Boolean) { - messagingUpdateMailgunProvider(providerId: $providerId, name: $name, domain: $domain, apiKey: $apiKey, isEuRegion: $isEuRegion, enabled: $enabled) { + return 'mutation updateMailgunProvider($providerId: String!, $name: String!, $domain: String!, $apiKey: String!, $isEuRegion: Boolean, $enabled: Boolean, $fromName: String, $fromEmail: String) { + messagingUpdateMailgunProvider(providerId: $providerId, name: $name, domain: $domain, apiKey: $apiKey, isEuRegion: $isEuRegion, enabled: $enabled, fromName: $fromName, fromEmail: $fromEmail) { _id name provider @@ -1914,8 +1914,8 @@ trait Base } }'; case self::$UPDATE_SENDGRID_PROVIDER: - return 'mutation messagingUpdateSendgridProvider($providerId: String!, $name: String!, $apiKey: String!) { - messagingUpdateSendgridProvider(providerId: $providerId, name: $name, apiKey: $apiKey) { + return 'mutation messagingUpdateSendgridProvider($providerId: String!, $name: String!, $apiKey: String!, $enabled: Boolean, $fromName: String, $fromEmail: String) { + messagingUpdateSendgridProvider(providerId: $providerId, name: $name, apiKey: $apiKey, enabled: $enabled, fromName: $fromName, fromEmail: $fromEmail) { _id name provider @@ -1974,8 +1974,8 @@ trait Base } }'; case self::$UPDATE_FCM_PROVIDER: - return 'mutation updateFcmProvider($providerId: String!, $name: String!, $serverKey: String!) { - messagingUpdateFcmProvider(providerId: $providerId, name: $name, serverKey: $serverKey) { + return 'mutation updateFcmProvider($providerId: String!, $name: String!, $serviceAccountJSON: Json) { + messagingUpdateFcmProvider(providerId: $providerId, name: $name, serviceAccountJSON: $serviceAccountJSON) { _id name provider diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index d1a084cfc1..e778e4e30d 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -23,14 +23,16 @@ class MessagingTest extends Scope 'providerId' => ID::unique(), 'name' => 'Sengrid1', 'apiKey' => 'my-apikey', - 'from' => 'sender-email@my-domain.com', + 'fromName' => 'Sender Name', + 'fromEmail' => 'sender-email@my-domain.com', ], 'Mailgun' => [ 'providerId' => ID::unique(), 'name' => 'Mailgun1', 'apiKey' => 'my-apikey', 'domain' => 'my-domain', - 'from' => 'sender-email@my-domain.com', + 'fromName' => 'Sender Name', + 'fromEmail' => 'sender-email@my-domain.com', 'isEuRegion' => false, ], 'Twilio' => [ @@ -71,7 +73,12 @@ class MessagingTest extends Scope 'Fcm' => [ 'providerId' => ID::unique(), 'name' => 'FCM1', - 'serverKey' => 'my-serverkey', + 'serviceAccountJSON' => [ + 'type' => 'service_account', + "project_id" => "omegle-copy", + "private_key_id" => "ewfwefwefwefwef", + "private_key" => "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkAgEAAoIBAQCeKDbvv4XvGuNAOxZBcxoNnvbINKlq0FtiqgsqLAgDOMt\nGPEANfni+D7lZRrMPhZhcL4YCjAUg+0ZI0D9d2LGofasj9GlBb57SZc/ud2L9FZZ\nk5liXrUk0SUirffBUmj5F/XPTJ+JXc89qPtt15+hqx30h2ID/wxN0AhmViLikR3o\n3YBHAYq0NbmAfQSfdsHX+lvNKvsAxU+LatRPE3tVcvSd3ZnP0zlHYVmp6UCeBWeW\nOTcSPecCcVXmBdMPtHGWdrNG2op1CmHc8JeYJMQ4xgz3obQcOX9+3USsysANjgta\nb07m6xS3AgMBAAECggEAIeSTVVCRZrq36zk8VgJ/r/NE4r95xEk2K/K/Lvb0fx75\no0BO5gsAkYqvgzem/LrVFCEFRkDGMbAhVQ5Fw1pN2U6CyA0hL4jUqgALtMImKJdX\nDa6I5Gibwd5+qt9NOZSgC/Kq14zAxhfQE3U2hyatohyx3Rsz/3lmJo90bX7Jp5md\nGBDOB3pFBqyfUvyHgeqCgvJvidJjxmwArLhUF8szuDRvmSs0lGsfqYprK0sb9phL\nP7Z3qMJk1J4IDL2abSGrTcMP+hk7ju1iqo7WfhIQCvM1TD5dRjYg2IYPIAIzszWz\nxSA67eJpQGSFfOuk82g3UMhfCD2DY2mCE/zkeid9jQKBgQDSB2xA+LpQDX2nuoDR\niZbPYBitxQtkbjieYTR8vwrIzyAvRtOwjnVKsXLyIbUYyHd6RFRDPeBcHb39KuRO\nz7VljQKTVB5RYUmqeGilor0TFaKMnneC7GFH6mWOJyf16DU7bkQw27Pg1e3xbF28\n5ig7QYPqEaDKLg6TMSLsBhdRDQKBgQDAxj9jS9UOTmF3N9T1JFzWfUB2r+AgwE4N\nSITmG/fSz9rlSg+XPh2ijpSrboUbuY/GYq5aCIy1twx09eta07Y/uD/GKLYrk873\no0TxQrnHSKl82fCyd2JPG/W8ocGDnj3u0Dp+tBrLxDiZN2pRurnlkt7P3QUg/gEG\nAovyd3ij0wKBgBbA7x1q1ORvUbmmHuaUfV4iDwpkWoOa3U9rQIBzQfvXVKlKhwyN\nom9hIg7RUAlLToZUeLyAK5pPLpIK34kaP5Cs4iaL6mzumUh6mvu20b0Ljvyk/lWU\nvkVIQ5BO9alSatHxdDnG04n8IzcQgmdAmAMzadMl7cF5k+KmZB4l2sjRAoGAP8JS\nPNlcAntSKUhCG0KHojmTFK5fBvYT2rjdm+4sLYGp+KRiO7fDvXxDF+BaDi11rDv/\nRrAFOiTs7dJYoZXcdX7POQ9GEWu1zJont1RGde9Gf5Dl12E9FsU8pcMqagnwmggt\nELMpGbQwtBxsAdQsoA3PvBhyFdNtKzu0ZeG1+RkCgYBOPhOCR88QPTmQANkwIMH+\n0vt+KhSjE3dhX7rzVkhoNmYF5AaSSpQ3F1JUlYntjblMQVjLesGvWa4gwCOF87xC\nJxHL6LkbNjAyUGZp7to6/F4vTmKoC6Xu/jTRRy2SVjdqiIa0Pm0eLLfRHmSI06pS\n+zLmdpZv/msPfGibbHcXUA==\n-----END PRIVATE KEY-----\n", + ] ], 'Apns' => [ 'providerId' => ID::unique(), @@ -97,6 +104,7 @@ class MessagingTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]), $graphQLPayload); + var_dump($response['body']); \array_push($providers, $response['body']['data']['messagingCreate' . $key . 'Provider']); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($providersParams[$key]['name'], $response['body']['data']['messagingCreate' . $key . 'Provider']['name']); @@ -155,7 +163,12 @@ class MessagingTest extends Scope 'Fcm' => [ 'providerId' => $providers[7]['_id'], 'name' => 'FCM2', - 'serverKey' => 'my-serverkey', + 'serviceAccountJSON' => [ + 'type' => 'service_account', + "project_id" => "omegle-copy", + "private_key_id" => "ewfwefwefwefwef", + "private_key" => "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkAgEAAoIBAQCeKDbvv4XvGuNAOxZBcxoNnvbINKlq0FtiqgsqLAgDOMt\nGPEANfni+D7lZRrMPhZhcL4YCjAUg+0ZI0D9d2LGofasj9GlBb57SZc/ud2L9FZZ\nk5liXrUk0SUirffBUmj5F/XPTJ+JXc89qPtt15+hqx30h2ID/wxN0AhmViLikR3o\n3YBHAYq0NbmAfQSfdsHX+lvNKvsAxU+LatRPE3tVcvSd3ZnP0zlHYVmp6UCeBWeW\nOTcSPecCcVXmBdMPtHGWdrNG2op1CmHc8JeYJMQ4xgz3obQcOX9+3USsysANjgta\nb07m6xS3AgMBAAECggEAIeSTVVCRZrq36zk8VgJ/r/NE4r95xEk2K/K/Lvb0fx75\no0BO5gsAkYqvgzem/LrVFCEFRkDGMbAhVQ5Fw1pN2U6CyA0hL4jUqgALtMImKJdX\nDa6I5Gibwd5+qt9NOZSgC/Kq14zAxhfQE3U2hyatohyx3Rsz/3lmJo90bX7Jp5md\nGBDOB3pFBqyfUvyHgeqCgvJvidJjxmwArLhUF8szuDRvmSs0lGsfqYprK0sb9phL\nP7Z3qMJk1J4IDL2abSGrTcMP+hk7ju1iqo7WfhIQCvM1TD5dRjYg2IYPIAIzszWz\nxSA67eJpQGSFfOuk82g3UMhfCD2DY2mCE/zkeid9jQKBgQDSB2xA+LpQDX2nuoDR\niZbPYBitxQtkbjieYTR8vwrIzyAvRtOwjnVKsXLyIbUYyHd6RFRDPeBcHb39KuRO\nz7VljQKTVB5RYUmqeGilor0TFaKMnneC7GFH6mWOJyf16DU7bkQw27Pg1e3xbF28\n5ig7QYPqEaDKLg6TMSLsBhdRDQKBgQDAxj9jS9UOTmF3N9T1JFzWfUB2r+AgwE4N\nSITmG/fSz9rlSg+XPh2ijpSrboUbuY/GYq5aCIy1twx09eta07Y/uD/GKLYrk873\no0TxQrnHSKl82fCyd2JPG/W8ocGDnj3u0Dp+tBrLxDiZN2pRurnlkt7P3QUg/gEG\nAovyd3ij0wKBgBbA7x1q1ORvUbmmHuaUfV4iDwpkWoOa3U9rQIBzQfvXVKlKhwyN\nom9hIg7RUAlLToZUeLyAK5pPLpIK34kaP5Cs4iaL6mzumUh6mvu20b0Ljvyk/lWU\nvkVIQ5BO9alSatHxdDnG04n8IzcQgmdAmAMzadMl7cF5k+KmZB4l2sjRAoGAP8JS\nPNlcAntSKUhCG0KHojmTFK5fBvYT2rjdm+4sLYGp+KRiO7fDvXxDF+BaDi11rDv/\nRrAFOiTs7dJYoZXcdX7POQ9GEWu1zJont1RGde9Gf5Dl12E9FsU8pcMqagnwmggt\nELMpGbQwtBxsAdQsoA3PvBhyFdNtKzu0ZeG1+RkCgYBOPhOCR88QPTmQANkwIMH+\n0vt+KhSjE3dhX7rzVkhoNmYF5AaSSpQ3F1JUlYntjblMQVjLesGvWa4gwCOF87xC\nJxHL6LkbNjAyUGZp7to6/F4vTmKoC6Xu/jTRRy2SVjdqiIa0Pm0eLLfRHmSI06pS\n+zLmdpZv/msPfGibbHcXUA==\n-----END PRIVATE KEY-----\n", + ] ], 'Apns' => [ 'providerId' => $providers[8]['_id'], @@ -374,7 +387,8 @@ class MessagingTest extends Scope 'providerId' => ID::unique(), 'name' => 'Sengrid1', 'apiKey' => 'my-apikey', - 'from' => 'sender-email@my-domain.com', + 'fromName' => 'Sender', + 'fromEmail' => 'sender-email@my-domain.com', ] ]; $query = $this->getQuery(self::$CREATE_SENDGRID_PROVIDER); @@ -543,7 +557,8 @@ class MessagingTest extends Scope $emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN')); $to = $emailDSN->getParam('to'); - $from = $emailDSN->getParam('from'); + $fromName = $emailDSN->getParam('fromName'); + $fromEmail = $emailDSN->getParam('fromEmail'); $isEuRegion = $emailDSN->getParam('isEuRegion'); $apiKey = $emailDSN->getPassword(); $domain = $emailDSN->getUser(); @@ -560,7 +575,8 @@ class MessagingTest extends Scope 'name' => 'Mailgun1', 'apiKey' => $apiKey, 'domain' => $domain, - 'from' => $from, + 'fromName' => $fromName, + 'fromEmail' => $fromEmail, 'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN), ], ]; @@ -956,9 +972,9 @@ class MessagingTest extends Scope $pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); $to = $pushDSN->getParam('to'); - $serverKey = $pushDSN->getPassword(); + $serviceAccountJSON = $pushDSN->getParam('saj'); - if (empty($to) || empty($serverKey)) { + if (empty($to) || empty($serviceAccountJSON)) { $this->markTestSkipped('Push provider not configured'); } @@ -968,7 +984,12 @@ class MessagingTest extends Scope 'variables' => [ 'providerId' => ID::unique(), 'name' => 'FCM1', - 'serverKey' => $serverKey, + 'serviceAccountJSON' => [ + 'type' => 'service_account', + "project_id" => "token-test", + "private_key_id" => "bitcoin-is-the-future", + "private_key" => "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkAgEAAoIBAQCeKDbvv4XvGuNAOxZBcxoNnvbINKlq0FtiqgsqLAgDOMt\nGPEANfni+D7lZRrMPhZhcL4YCjAUg+0ZI0D9d2LGofasj9GlBb57SZc/ud2L9FZZ\nk5liXrUk0SUirffBUmj5F/XPTJ+JXc89qPtt15+hqx30h2ID/wxN0AhmViLikR3o\n3YBHAYq0NbmAfQSfdsHX+lvNKvsAxU+LatRPE3tVcvSd3ZnP0zlHYVmp6UCeBWeW\nOTcSPecCcVXmBdMPtHGWdrNG2op1CmHc8JeYJMQ4xgz3obQcOX9+3USsysANjgta\nb07m6xS3AgMBAAECggEAIeSTVVCRZrq36zk8VgJ/r/NE4r95xEk2K/K/Lvb0fx75\no0BO5gsAkYqvgzem/LrVFCEFRkDGMbAhVQ5Fw1pN2U6CyA0hL4jUqgALtMImKJdX\nDa6I5Gibwd5+qt9NOZSgC/Kq14zAxhfQE3U2hyatohyx3Rsz/3lmJo90bX7Jp5md\nGBDOB3pFBqyfUvyHgeqCgvJvidJjxmwArLhUF8szuDRvmSs0lGsfqYprK0sb9phL\nP7Z3qMJk1J4IDL2abSGrTcMP+hk7ju1iqo7WfhIQCvM1TD5dRjYg2IYPIAIzszWz\nxSA67eJpQGSFfOuk82g3UMhfCD2DY2mCE/zkeid9jQKBgQDSB2xA+LpQDX2nuoDR\niZbPYBitxQtkbjieYTR8vwrIzyAvRtOwjnVKsXLyIbUYyHd6RFRDPeBcHb39KuRO\nz7VljQKTVB5RYUmqeGilor0TFaKMnneC7GFH6mWOJyf16DU7bkQw27Pg1e3xbF28\n5ig7QYPqEaDKLg6TMSLsBhdRDQKBgQDAxj9jS9UOTmF3N9T1JFzWfUB2r+AgwE4N\nSITmG/fSz9rlSg+XPh2ijpSrboUbuY/GYq5aCIy1twx09eta07Y/uD/GKLYrk873\no0TxQrnHSKl82fCyd2JPG/W8ocGDnj3u0Dp+tBrLxDiZN2pRurnlkt7P3QUg/gEG\nAovyd3ij0wKBgBbA7x1q1ORvUbmmHuaUfV4iDwpkWoOa3U9rQIBzQfvXVKlKhwyN\nom9hIg7RUAlLToZUeLyAK5pPLpIK34kaP5Cs4iaL6mzumUh6mvu20b0Ljvyk/lWU\nvkVIQ5BO9alSatHxdDnG04n8IzcQgmdAmAMzadMl7cF5k+KmZB4l2sjRAoGAP8JS\nPNlcAntSKUhCG0KHojmTFK5fBvYT2rjdm+4sLYGp+KRiO7fDvXxDF+BaDi11rDv/\nRrAFOiTs7dJYoZXcdX7POQ9GEWu1zJont1RGde9Gf5Dl12E9FsU8pcMqagnwmggt\nELMpGbQwtBxsAdQsoA3PvBhyFdNtKzu0ZeG1+RkCgYBOPhOCR88QPTmQANkwIMH+\n0vt+KhSjE3dhX7rzVkhoNmYF5AaSSpQ3F1JUlYntjblMQVjLesGvWa4gwCOF87xC\nJxHL6LkbNjAyUGZp7to6/F4vTmKoC6Xu/jTRRy2SVjdqiIa0Pm0eLLfRHmSI06pS\n+zLmdpZv/msPfGibbHcXUA==\n-----END PRIVATE KEY-----\n", + ] ], ]; $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index ca472591c7..9e1788928d 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -65,7 +65,12 @@ trait MessagingBase 'fcm' => [ 'providerId' => ID::unique(), 'name' => 'FCM1', - 'serverKey' => 'my-serverkey', + 'serviceAccountJSON' => [ + 'type' => 'service_account', + "project_id" => "omegle-copy", + "private_key_id" => "ewfwefwefwefwef", + "private_key" => "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkAgEAAoIBAQCeKDbvv4XvGuNAOxZBcxoNnvbINKlq0FtiqgsqLAgDOMt\nGPEANfni+D7lZRrMPhZhcL4YCjAUg+0ZI0D9d2LGofasj9GlBb57SZc/ud2L9FZZ\nk5liXrUk0SUirffBUmj5F/XPTJ+JXc89qPtt15+hqx30h2ID/wxN0AhmViLikR3o\n3YBHAYq0NbmAfQSfdsHX+lvNKvsAxU+LatRPE3tVcvSd3ZnP0zlHYVmp6UCeBWeW\nOTcSPecCcVXmBdMPtHGWdrNG2op1CmHc8JeYJMQ4xgz3obQcOX9+3USsysANjgta\nb07m6xS3AgMBAAECggEAIeSTVVCRZrq36zk8VgJ/r/NE4r95xEk2K/K/Lvb0fx75\no0BO5gsAkYqvgzem/LrVFCEFRkDGMbAhVQ5Fw1pN2U6CyA0hL4jUqgALtMImKJdX\nDa6I5Gibwd5+qt9NOZSgC/Kq14zAxhfQE3U2hyatohyx3Rsz/3lmJo90bX7Jp5md\nGBDOB3pFBqyfUvyHgeqCgvJvidJjxmwArLhUF8szuDRvmSs0lGsfqYprK0sb9phL\nP7Z3qMJk1J4IDL2abSGrTcMP+hk7ju1iqo7WfhIQCvM1TD5dRjYg2IYPIAIzszWz\nxSA67eJpQGSFfOuk82g3UMhfCD2DY2mCE/zkeid9jQKBgQDSB2xA+LpQDX2nuoDR\niZbPYBitxQtkbjieYTR8vwrIzyAvRtOwjnVKsXLyIbUYyHd6RFRDPeBcHb39KuRO\nz7VljQKTVB5RYUmqeGilor0TFaKMnneC7GFH6mWOJyf16DU7bkQw27Pg1e3xbF28\n5ig7QYPqEaDKLg6TMSLsBhdRDQKBgQDAxj9jS9UOTmF3N9T1JFzWfUB2r+AgwE4N\nSITmG/fSz9rlSg+XPh2ijpSrboUbuY/GYq5aCIy1twx09eta07Y/uD/GKLYrk873\no0TxQrnHSKl82fCyd2JPG/W8ocGDnj3u0Dp+tBrLxDiZN2pRurnlkt7P3QUg/gEG\nAovyd3ij0wKBgBbA7x1q1ORvUbmmHuaUfV4iDwpkWoOa3U9rQIBzQfvXVKlKhwyN\nom9hIg7RUAlLToZUeLyAK5pPLpIK34kaP5Cs4iaL6mzumUh6mvu20b0Ljvyk/lWU\nvkVIQ5BO9alSatHxdDnG04n8IzcQgmdAmAMzadMl7cF5k+KmZB4l2sjRAoGAP8JS\nPNlcAntSKUhCG0KHojmTFK5fBvYT2rjdm+4sLYGp+KRiO7fDvXxDF+BaDi11rDv/\nRrAFOiTs7dJYoZXcdX7POQ9GEWu1zJont1RGde9Gf5Dl12E9FsU8pcMqagnwmggt\nELMpGbQwtBxsAdQsoA3PvBhyFdNtKzu0ZeG1+RkCgYBOPhOCR88QPTmQANkwIMH+\n0vt+KhSjE3dhX7rzVkhoNmYF5AaSSpQ3F1JUlYntjblMQVjLesGvWa4gwCOF87xC\nJxHL6LkbNjAyUGZp7to6/F4vTmKoC6Xu/jTRRy2SVjdqiIa0Pm0eLLfRHmSI06pS\n+zLmdpZv/msPfGibbHcXUA==\n-----END PRIVATE KEY-----\n", + ], ], 'apns' => [ 'providerId' => ID::unique(), @@ -136,7 +141,12 @@ trait MessagingBase ], 'fcm' => [ 'name' => 'FCM2', - 'serverKey' => 'my-serverkey', + 'serviceAccountJSON' => [ + 'type' => 'service_account', + "project_id" => "omegle-copy", + "private_key_id" => "ewfwefwefwefwef", + "private_key" => "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkAgEAAoIBAQCeKDbvv4XvGuNAOxZBcxoNnvbINKlq0FtiqgsqLAgDOMt\nGPEANfni+D7lZRrMPhZhcL4YCjAUg+0ZI0D9d2LGofasj9GlBb57SZc/ud2L9FZZ\nk5liXrUk0SUirffBUmj5F/XPTJ+JXc89qPtt15+hqx30h2ID/wxN0AhmViLikR3o\n3YBHAYq0NbmAfQSfdsHX+lvNKvsAxU+LatRPE3tVcvSd3ZnP0zlHYVmp6UCeBWeW\nOTcSPecCcVXmBdMPtHGWdrNG2op1CmHc8JeYJMQ4xgz3obQcOX9+3USsysANjgta\nb07m6xS3AgMBAAECggEAIeSTVVCRZrq36zk8VgJ/r/NE4r95xEk2K/K/Lvb0fx75\no0BO5gsAkYqvgzem/LrVFCEFRkDGMbAhVQ5Fw1pN2U6CyA0hL4jUqgALtMImKJdX\nDa6I5Gibwd5+qt9NOZSgC/Kq14zAxhfQE3U2hyatohyx3Rsz/3lmJo90bX7Jp5md\nGBDOB3pFBqyfUvyHgeqCgvJvidJjxmwArLhUF8szuDRvmSs0lGsfqYprK0sb9phL\nP7Z3qMJk1J4IDL2abSGrTcMP+hk7ju1iqo7WfhIQCvM1TD5dRjYg2IYPIAIzszWz\nxSA67eJpQGSFfOuk82g3UMhfCD2DY2mCE/zkeid9jQKBgQDSB2xA+LpQDX2nuoDR\niZbPYBitxQtkbjieYTR8vwrIzyAvRtOwjnVKsXLyIbUYyHd6RFRDPeBcHb39KuRO\nz7VljQKTVB5RYUmqeGilor0TFaKMnneC7GFH6mWOJyf16DU7bkQw27Pg1e3xbF28\n5ig7QYPqEaDKLg6TMSLsBhdRDQKBgQDAxj9jS9UOTmF3N9T1JFzWfUB2r+AgwE4N\nSITmG/fSz9rlSg+XPh2ijpSrboUbuY/GYq5aCIy1twx09eta07Y/uD/GKLYrk873\no0TxQrnHSKl82fCyd2JPG/W8ocGDnj3u0Dp+tBrLxDiZN2pRurnlkt7P3QUg/gEG\nAovyd3ij0wKBgBbA7x1q1ORvUbmmHuaUfV4iDwpkWoOa3U9rQIBzQfvXVKlKhwyN\nom9hIg7RUAlLToZUeLyAK5pPLpIK34kaP5Cs4iaL6mzumUh6mvu20b0Ljvyk/lWU\nvkVIQ5BO9alSatHxdDnG04n8IzcQgmdAmAMzadMl7cF5k+KmZB4l2sjRAoGAP8JS\nPNlcAntSKUhCG0KHojmTFK5fBvYT2rjdm+4sLYGp+KRiO7fDvXxDF+BaDi11rDv/\nRrAFOiTs7dJYoZXcdX7POQ9GEWu1zJont1RGde9Gf5Dl12E9FsU8pcMqagnwmggt\nELMpGbQwtBxsAdQsoA3PvBhyFdNtKzu0ZeG1+RkCgYBOPhOCR88QPTmQANkwIMH+\n0vt+KhSjE3dhX7rzVkhoNmYF5AaSSpQ3F1JUlYntjblMQVjLesGvWa4gwCOF87xC\nJxHL6LkbNjAyUGZp7to6/F4vTmKoC6Xu/jTRRy2SVjdqiIa0Pm0eLLfRHmSI06pS\n+zLmdpZv/msPfGibbHcXUA==\n-----END PRIVATE KEY-----\n", + ] ], 'apns' => [ 'name' => 'APNS2', @@ -873,7 +883,7 @@ trait MessagingBase $to = $dsn->getParam('to'); $serviceAccountJSON = $dsn->getParam('saj'); - if (empty($to) || empty($serverKey)) { + if (empty($to) || empty($serviceAccountJSON)) { $this->markTestSkipped('Push provider not configured'); } From f1ba7b08ab40718aa08f0eb0b682676ca0a74ec7 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Wed, 27 Dec 2023 23:35:32 +0000 Subject: [PATCH 10/18] Update the delete identity endpoints to set the params and payload Because no payload was set, the event params (userId and identityId) wasn't picked up automatically. This updates the endpoints so that the payload is set, but also makes sure to set the userId and identityId params since the identityId param's key doesn't match the key in the payload. --- app/controllers/api/account.php | 10 ++++++++-- app/controllers/api/users.php | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index c210b19f4f..9cbe6ce7ef 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -842,7 +842,7 @@ App::get('/v1/account/identities') }); App::delete('/v1/account/identities/:identityId') - ->desc('Delete Identity') + ->desc('Delete identity') ->groups(['api', 'account']) ->label('scope', 'account') ->label('event', 'users.[userId].identities.[identityId].delete') @@ -859,7 +859,8 @@ App::delete('/v1/account/identities/:identityId') ->param('identityId', '', new UID(), 'Identity ID.') ->inject('response') ->inject('dbForProject') - ->action(function (string $identityId, Response $response, Database $dbForProject) { + ->inject('queueForEvents') + ->action(function (string $identityId, Response $response, Database $dbForProject, Event $queueForEvents) { $identity = $dbForProject->getDocument('identities', $identityId); @@ -869,6 +870,11 @@ App::delete('/v1/account/identities/:identityId') $dbForProject->deleteDocument('identities', $identityId); + $queueForEvents + ->setParam('userId', $identity->getAttribute('userId')) + ->setParam('identityId', $identity->getId()) + ->setPayload($response->output($identity, Response::MODEL_IDENTITY)); + return $response->noContent(); }); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 0869453cc9..30f52c614e 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -1211,7 +1211,7 @@ App::delete('/v1/users/:userId') }); App::delete('/v1/users/identities/:identityId') - ->desc('Delete Identity') + ->desc('Delete identity') ->groups(['api', 'users']) ->label('event', 'users.[userId].identities.[identityId].delete') ->label('scope', 'users.write') @@ -1227,7 +1227,8 @@ App::delete('/v1/users/identities/:identityId') ->param('identityId', '', new UID(), 'Identity ID.') ->inject('response') ->inject('dbForProject') - ->action(function (string $identityId, Response $response, Database $dbForProject) { + ->inject('queueForEvents') + ->action(function (string $identityId, Response $response, Database $dbForProject, Event $queueForEvents) { $identity = $dbForProject->getDocument('identities', $identityId); @@ -1237,6 +1238,11 @@ App::delete('/v1/users/identities/:identityId') $dbForProject->deleteDocument('identities', $identityId); + $queueForEvents + ->setParam('userId', $identity->getAttribute('userId')) + ->setParam('identityId', $identity->getId()) + ->setPayload($response->output($identity, Response::MODEL_IDENTITY)); + return $response->noContent(); }); From b6b5570b0b75f7e3c8a1fb6307bbadc589f1cc08 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Wed, 3 Jan 2024 19:48:31 +0000 Subject: [PATCH 11/18] Add General E2E tests to CI pipeline --- .github/workflows/tests.yml | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 842d61ff1c..2fb6840f6e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -75,8 +75,32 @@ jobs: - name: Run Unit Tests run: docker compose exec appwrite test /usr/src/code/tests/unit - e2e_test: - name: E2E Test + e2e_general_test: + name: E2E General Test + runs-on: ubuntu-latest + needs: setup + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: Load Cache + uses: actions/cache@v3 + with: + key: ${{ env.CACHE_KEY }} + path: /tmp/${{ env.IMAGE }}.tar + fail-on-cache-miss: true + + - name: Load and Start Appwrite + run: | + docker load --input /tmp/${{ env.IMAGE }}.tar + docker compose up -d + sleep 10 + + - name: Run General Tests + run: docker compose exec -T appwrite test /usr/src/code/tests/e2e/General --debug + + e2e_service_test: + name: E2E Service Test runs-on: ubuntu-latest needs: setup strategy: @@ -119,4 +143,4 @@ jobs: sleep 10 - name: Run ${{matrix.service}} Tests - run: docker compose exec -T appwrite test /usr/src/code/tests/e2e/Services/${{matrix.service}} --debug \ No newline at end of file + run: docker compose exec -T appwrite test /usr/src/code/tests/e2e/Services/${{matrix.service}} --debug From 4cfd977bd7ddb9344840308e44891e996c51eb1d Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Thu, 4 Jan 2024 00:06:50 +0000 Subject: [PATCH 12/18] Add support for querying topic total --- .../Database/Validator/Queries/Topics.php | 1 + .../e2e/Services/Messaging/MessagingBase.php | 37 ++++++++++++++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Topics.php b/src/Appwrite/Utopia/Database/Validator/Queries/Topics.php index 120b3edc3f..27c818d319 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Topics.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Topics.php @@ -7,6 +7,7 @@ class Topics extends Base public const ALLOWED_ATTRIBUTES = [ 'name', 'description', + 'total' ]; /** diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 690e503e77..1feaf15385 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -5,6 +5,7 @@ namespace Tests\E2E\Services\Messaging; use Tests\E2E\Client; use Utopia\App; use Utopia\Database\Helpers\ID; +use Utopia\Database\Query; use Utopia\DSN\DSN; trait MessagingBase @@ -161,11 +162,11 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'name' => 'Mailgun2', - 'apiKey' => 'my-apikey', - 'domain' => 'my-domain', - 'isEuRegion' => true, - 'enabled' => false, + 'name' => 'Mailgun2', + 'apiKey' => 'my-apikey', + 'domain' => 'my-domain', + 'isEuRegion' => true, + 'enabled' => false, ]); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('Mailgun2', $response['body']['name']); @@ -272,6 +273,32 @@ trait MessagingBase $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, \count($response['body']['topics'])); + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => [ + 'equal("total", [0])' + ], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(1, \count($response['body']['topics'])); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => [ + 'greaterThan("total", 0)' + ], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(0, \count($response['body']['topics'])); + return $topicId; } From fbd277f6aa0ff161838a60e79b950e5a3f58e3f6 Mon Sep 17 00:00:00 2001 From: Ben Humphries Date: Thu, 4 Jan 2024 05:46:08 -0500 Subject: [PATCH 13/18] executor: pass build timeout to runtimes (#7350) open-runtimes executor (v1/runtimes) supports passing a timeout parameter that defaults to 600 seconds. ->param('timeout', 600, new Integer(), 'Commands execution time in seconds.', true) https://github.com/open-runtimes/executor/blob/main/app/http.php#L383 This change passes the _APP_FUNCTIONS_BUILD_TIMEOUT env var. --- src/Executor/Executor.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index c7388069a1..8e73747047 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -72,6 +72,7 @@ class Executor ) { $runtimeId = "$projectId-$deploymentId-build"; $route = "/runtimes"; + $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); $params = [ 'runtimeId' => $runtimeId, 'source' => $source, @@ -84,10 +85,9 @@ class Executor 'cpus' => $this->cpus, 'memory' => $this->memory, 'version' => $version, + 'timeout' => $timeout, ]; - $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); - $response = $this->call(self::METHOD_POST, $route, [ 'x-opr-runtime-id' => $runtimeId ], $params, true, $timeout); $status = $response['headers']['status-code']; @@ -111,7 +111,7 @@ class Executor string $projectId, callable $callback ) { - $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); + $timeout = (int) App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); $runtimeId = "$projectId-$deploymentId-build"; $route = "/runtimes/{$runtimeId}/logs"; From 01df91aee9a87e8dbf4af00c92a0257f367755a4 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Thu, 4 Jan 2024 23:58:48 +0000 Subject: [PATCH 14/18] Replace backticks with double quotes --- src/Appwrite/Platform/Workers/Messaging.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index ed72731681..ebf657ecc5 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -193,7 +193,7 @@ class Messaging extends Action $details[] = $response->getDetails(); foreach ($details as $detail) { if ($detail['status'] === 'failure') { - $deliveryErrors[] = `Failed sending to target {$detail['recipient']} with error: {$detail['error']}`; + $deliveryErrors[] = "Failed sending to target {$detail['recipient']} with error: {$detail['error']}"; } // Deleting push targets when token has expired. From 7e9525f0f9d025ce184e8e4f912e54b8d3e2fc6a Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Fri, 5 Jan 2024 00:10:57 +0000 Subject: [PATCH 15/18] Update validation of topics, users, and targets They should be an array of UID and not just array of Text. --- app/controllers/api/messaging.php | 46 +++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 53135f2193..9a9fdb8b16 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -236,7 +236,7 @@ App::post('/v1/messaging/providers/msg91') $options = []; if (!empty($from)) { - $options ['from'] = $from; + $options['from'] = $from; } $credentials = []; @@ -313,7 +313,7 @@ App::post('/v1/messaging/providers/telesign') $options = []; if (!empty($from)) { - $options ['from'] = $from; + $options['from'] = $from; } $credentials = []; @@ -390,7 +390,7 @@ App::post('/v1/messaging/providers/textmagic') $options = []; if (!empty($from)) { - $options ['from'] = $from; + $options['from'] = $from; } $credentials = []; @@ -467,7 +467,7 @@ App::post('/v1/messaging/providers/twilio') $options = []; if (!empty($from)) { - $options ['from'] = $from; + $options['from'] = $from; } $credentials = []; @@ -544,7 +544,7 @@ App::post('/v1/messaging/providers/vonage') $options = []; if (!empty($from)) { - $options ['from'] = $from; + $options['from'] = $from; } $credentials = []; @@ -2276,9 +2276,9 @@ App::post('/v1/messaging/messages/email') ->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('subject', '', new Text(998), 'Email Subject.') ->param('content', '', new Text(64230), 'Email Content.') - ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs.', true) - ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of User IDs.', true) - ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Targets IDs.', true) + ->param('topics', [], new ArrayList(new UID()), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new UID()), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true) ->param('cc', [], new ArrayList(new UID()), 'Array of target IDs to be added as CC.', true) ->param('bcc', [], new ArrayList(new UID()), 'Array of target IDs to be added as BCC.', true) ->param('description', '', new Text(256), 'Description for message.', true) @@ -2367,9 +2367,9 @@ App::post('/v1/messaging/messages/sms') ->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('content', '', new Text(64230), 'SMS Content.') - ->param('topics', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs.', true) - ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of User IDs.', true) - ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Targets IDs.', true) + ->param('topics', [], new ArrayList(new UID()), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new UID()), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true) ->param('description', '', new Text(256), 'Description for Message.', true) ->param('status', 'processing', new WhiteList(['draft', 'canceled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true) @@ -2448,9 +2448,9 @@ App::post('/v1/messaging/messages/push') ->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('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)), 'List of Topic IDs.', true) - ->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of User IDs.', true) - ->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Targets IDs.', true) + ->param('topics', [], new ArrayList(new UID()), 'List of Topic IDs.', true) + ->param('users', [], new ArrayList(new UID()), 'List of User IDs.', true) + ->param('targets', [], new ArrayList(new UID()), '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) @@ -2694,9 +2694,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('topics', null, new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs.', true) - ->param('users', null, new ArrayList(new Text(Database::LENGTH_KEY)), 'List of User IDs.', true) - ->param('targets', null, new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Targets IDs.', true) + ->param('topics', null, new ArrayList(new UID()), 'List of Topic IDs.', true) + ->param('users', null, new ArrayList(new UID()), 'List of User IDs.', true) + ->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true) ->param('subject', null, new Text(998), 'Email Subject.', true) ->param('description', null, new Text(256), 'Description for Message.', true) ->param('content', null, new Text(64230), 'Email Content.', true) @@ -2822,9 +2822,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('topics', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) - ->param('users', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) - ->param('targets', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) + ->param('topics', null, new ArrayList(new UID()), 'List of Topic IDs.', true) + ->param('users', null, new ArrayList(new UID()), 'List of User IDs.', true) + ->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true) ->param('description', null, new Text(256), 'Description for Message.', true) ->param('content', null, new Text(64230), 'Email Content.', true) ->param('status', null, new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) @@ -2928,9 +2928,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('topics', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Topic IDs.', true) - ->param('users', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true) - ->param('targets', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true) + ->param('topics', null, new ArrayList(new UID()), 'List of Topic IDs.', true) + ->param('users', null, new ArrayList(new UID()), 'List of User IDs.', true) + ->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true) ->param('description', null, new Text(256), 'Description for Message.', true) ->param('title', null, new Text(256), 'Title for push notification.', true) ->param('body', null, new Text(64230), 'Body for push notification.', true) From 2de8c7a68a0a2d4d1092e918d149d3867014f118 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Fri, 5 Jan 2024 00:31:00 +0000 Subject: [PATCH 16/18] Update composer.lock to fix merge conflict --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 6b7fc0ac4e..182da98024 100644 --- a/composer.lock +++ b/composer.lock @@ -2906,16 +2906,16 @@ }, { "name": "utopia-php/vcs", - "version": "0.6.3", + "version": "0.6.4", "source": { "type": "git", "url": "https://github.com/utopia-php/vcs.git", - "reference": "86c3f42a2624bcccb7a67b74dcd7bd3a31fc2e4b" + "reference": "b2595a50a4897a8c88319240810055b7a96efd6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/vcs/zipball/86c3f42a2624bcccb7a67b74dcd7bd3a31fc2e4b", - "reference": "86c3f42a2624bcccb7a67b74dcd7bd3a31fc2e4b", + "url": "https://api.github.com/repos/utopia-php/vcs/zipball/b2595a50a4897a8c88319240810055b7a96efd6d", + "reference": "b2595a50a4897a8c88319240810055b7a96efd6d", "shasum": "" }, "require": { @@ -2949,9 +2949,9 @@ ], "support": { "issues": "https://github.com/utopia-php/vcs/issues", - "source": "https://github.com/utopia-php/vcs/tree/0.6.3" + "source": "https://github.com/utopia-php/vcs/tree/0.6.4" }, - "time": "2023-12-14T06:53:39+00:00" + "time": "2023-12-26T15:38:19+00:00" }, { "name": "utopia-php/websocket", From 864703fb4ee5711af4a05d6927111a9a70b38210 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 8 Jan 2024 20:56:51 +0000 Subject: [PATCH 17/18] Update the install/upgrade arguments to be kebab instead of camel case Kebab case like --http-port is much more common in CLIs than --httpPort. --- src/Appwrite/Platform/Tasks/Install.php | 6 +++--- src/Appwrite/Platform/Tasks/Upgrade.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php index 8591f4bcc3..c6107c6ba8 100644 --- a/src/Appwrite/Platform/Tasks/Install.php +++ b/src/Appwrite/Platform/Tasks/Install.php @@ -25,12 +25,12 @@ class Install extends Action { $this ->desc('Install Appwrite') - ->param('httpPort', '', new Text(4), 'Server HTTP port', true) - ->param('httpsPort', '', new Text(4), 'Server HTTPS port', true) + ->param('http-port', '', new Text(4), 'Server HTTP port', true) + ->param('https-port', '', new Text(4), 'Server HTTPS port', true) ->param('organization', 'appwrite', new Text(0), 'Docker Registry organization', true) ->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true) ->param('interactive', 'Y', new Text(1), 'Run an interactive session', true) - ->param('noStart', false, new Boolean(true), 'Run an interactive session', true) + ->param('no-start', false, new Boolean(true), 'Run an interactive session', true) ->callback(fn ($httpPort, $httpsPort, $organization, $image, $interactive, $noStart) => $this->action($httpPort, $httpsPort, $organization, $image, $interactive, $noStart)); } diff --git a/src/Appwrite/Platform/Tasks/Upgrade.php b/src/Appwrite/Platform/Tasks/Upgrade.php index 1f3e148a82..341ce42fc4 100644 --- a/src/Appwrite/Platform/Tasks/Upgrade.php +++ b/src/Appwrite/Platform/Tasks/Upgrade.php @@ -17,12 +17,12 @@ class Upgrade extends Install { $this ->desc('Upgrade Appwrite') - ->param('httpPort', '', new Text(4), 'Server HTTP port', true) - ->param('httpsPort', '', new Text(4), 'Server HTTPS port', true) + ->param('http-port', '', new Text(4), 'Server HTTP port', true) + ->param('https-port', '', new Text(4), 'Server HTTPS port', true) ->param('organization', 'appwrite', new Text(0), 'Docker Registry organization', true) ->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true) ->param('interactive', 'Y', new Text(1), 'Run an interactive session', true) - ->param('noStart', false, new Boolean(true), 'Run an interactive session', true) + ->param('no-start', false, new Boolean(true), 'Run an interactive session', true) ->callback(fn ($httpPort, $httpsPort, $organization, $image, $interactive, $noStart) => $this->action($httpPort, $httpsPort, $organization, $image, $interactive, $noStart)); } From fc81c032b4ccb43bbf13f618ef660f74008c27ed Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Tue, 9 Jan 2024 13:41:55 +1300 Subject: [PATCH 18/18] Clean up test values --- tests/e2e/Services/GraphQL/MessagingTest.php | 22 +++++++++---------- .../e2e/Services/Messaging/MessagingBase.php | 16 ++++++-------- .../Projects/ProjectsConsoleClientTest.php | 1 - 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index e778e4e30d..1828411483 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -75,9 +75,9 @@ class MessagingTest extends Scope 'name' => 'FCM1', 'serviceAccountJSON' => [ 'type' => 'service_account', - "project_id" => "omegle-copy", - "private_key_id" => "ewfwefwefwefwef", - "private_key" => "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkAgEAAoIBAQCeKDbvv4XvGuNAOxZBcxoNnvbINKlq0FtiqgsqLAgDOMt\nGPEANfni+D7lZRrMPhZhcL4YCjAUg+0ZI0D9d2LGofasj9GlBb57SZc/ud2L9FZZ\nk5liXrUk0SUirffBUmj5F/XPTJ+JXc89qPtt15+hqx30h2ID/wxN0AhmViLikR3o\n3YBHAYq0NbmAfQSfdsHX+lvNKvsAxU+LatRPE3tVcvSd3ZnP0zlHYVmp6UCeBWeW\nOTcSPecCcVXmBdMPtHGWdrNG2op1CmHc8JeYJMQ4xgz3obQcOX9+3USsysANjgta\nb07m6xS3AgMBAAECggEAIeSTVVCRZrq36zk8VgJ/r/NE4r95xEk2K/K/Lvb0fx75\no0BO5gsAkYqvgzem/LrVFCEFRkDGMbAhVQ5Fw1pN2U6CyA0hL4jUqgALtMImKJdX\nDa6I5Gibwd5+qt9NOZSgC/Kq14zAxhfQE3U2hyatohyx3Rsz/3lmJo90bX7Jp5md\nGBDOB3pFBqyfUvyHgeqCgvJvidJjxmwArLhUF8szuDRvmSs0lGsfqYprK0sb9phL\nP7Z3qMJk1J4IDL2abSGrTcMP+hk7ju1iqo7WfhIQCvM1TD5dRjYg2IYPIAIzszWz\nxSA67eJpQGSFfOuk82g3UMhfCD2DY2mCE/zkeid9jQKBgQDSB2xA+LpQDX2nuoDR\niZbPYBitxQtkbjieYTR8vwrIzyAvRtOwjnVKsXLyIbUYyHd6RFRDPeBcHb39KuRO\nz7VljQKTVB5RYUmqeGilor0TFaKMnneC7GFH6mWOJyf16DU7bkQw27Pg1e3xbF28\n5ig7QYPqEaDKLg6TMSLsBhdRDQKBgQDAxj9jS9UOTmF3N9T1JFzWfUB2r+AgwE4N\nSITmG/fSz9rlSg+XPh2ijpSrboUbuY/GYq5aCIy1twx09eta07Y/uD/GKLYrk873\no0TxQrnHSKl82fCyd2JPG/W8ocGDnj3u0Dp+tBrLxDiZN2pRurnlkt7P3QUg/gEG\nAovyd3ij0wKBgBbA7x1q1ORvUbmmHuaUfV4iDwpkWoOa3U9rQIBzQfvXVKlKhwyN\nom9hIg7RUAlLToZUeLyAK5pPLpIK34kaP5Cs4iaL6mzumUh6mvu20b0Ljvyk/lWU\nvkVIQ5BO9alSatHxdDnG04n8IzcQgmdAmAMzadMl7cF5k+KmZB4l2sjRAoGAP8JS\nPNlcAntSKUhCG0KHojmTFK5fBvYT2rjdm+4sLYGp+KRiO7fDvXxDF+BaDi11rDv/\nRrAFOiTs7dJYoZXcdX7POQ9GEWu1zJont1RGde9Gf5Dl12E9FsU8pcMqagnwmggt\nELMpGbQwtBxsAdQsoA3PvBhyFdNtKzu0ZeG1+RkCgYBOPhOCR88QPTmQANkwIMH+\n0vt+KhSjE3dhX7rzVkhoNmYF5AaSSpQ3F1JUlYntjblMQVjLesGvWa4gwCOF87xC\nJxHL6LkbNjAyUGZp7to6/F4vTmKoC6Xu/jTRRy2SVjdqiIa0Pm0eLLfRHmSI06pS\n+zLmdpZv/msPfGibbHcXUA==\n-----END PRIVATE KEY-----\n", + "project_id" => "test-project", + "private_key_id" => "test-private-key-id", + "private_key" => "test-private-key", ] ], 'Apns' => [ @@ -104,7 +104,7 @@ class MessagingTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]), $graphQLPayload); - var_dump($response['body']); + \array_push($providers, $response['body']['data']['messagingCreate' . $key . 'Provider']); $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($providersParams[$key]['name'], $response['body']['data']['messagingCreate' . $key . 'Provider']['name']); @@ -165,9 +165,9 @@ class MessagingTest extends Scope 'name' => 'FCM2', 'serviceAccountJSON' => [ 'type' => 'service_account', - "project_id" => "omegle-copy", - "private_key_id" => "ewfwefwefwefwef", - "private_key" => "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkAgEAAoIBAQCeKDbvv4XvGuNAOxZBcxoNnvbINKlq0FtiqgsqLAgDOMt\nGPEANfni+D7lZRrMPhZhcL4YCjAUg+0ZI0D9d2LGofasj9GlBb57SZc/ud2L9FZZ\nk5liXrUk0SUirffBUmj5F/XPTJ+JXc89qPtt15+hqx30h2ID/wxN0AhmViLikR3o\n3YBHAYq0NbmAfQSfdsHX+lvNKvsAxU+LatRPE3tVcvSd3ZnP0zlHYVmp6UCeBWeW\nOTcSPecCcVXmBdMPtHGWdrNG2op1CmHc8JeYJMQ4xgz3obQcOX9+3USsysANjgta\nb07m6xS3AgMBAAECggEAIeSTVVCRZrq36zk8VgJ/r/NE4r95xEk2K/K/Lvb0fx75\no0BO5gsAkYqvgzem/LrVFCEFRkDGMbAhVQ5Fw1pN2U6CyA0hL4jUqgALtMImKJdX\nDa6I5Gibwd5+qt9NOZSgC/Kq14zAxhfQE3U2hyatohyx3Rsz/3lmJo90bX7Jp5md\nGBDOB3pFBqyfUvyHgeqCgvJvidJjxmwArLhUF8szuDRvmSs0lGsfqYprK0sb9phL\nP7Z3qMJk1J4IDL2abSGrTcMP+hk7ju1iqo7WfhIQCvM1TD5dRjYg2IYPIAIzszWz\nxSA67eJpQGSFfOuk82g3UMhfCD2DY2mCE/zkeid9jQKBgQDSB2xA+LpQDX2nuoDR\niZbPYBitxQtkbjieYTR8vwrIzyAvRtOwjnVKsXLyIbUYyHd6RFRDPeBcHb39KuRO\nz7VljQKTVB5RYUmqeGilor0TFaKMnneC7GFH6mWOJyf16DU7bkQw27Pg1e3xbF28\n5ig7QYPqEaDKLg6TMSLsBhdRDQKBgQDAxj9jS9UOTmF3N9T1JFzWfUB2r+AgwE4N\nSITmG/fSz9rlSg+XPh2ijpSrboUbuY/GYq5aCIy1twx09eta07Y/uD/GKLYrk873\no0TxQrnHSKl82fCyd2JPG/W8ocGDnj3u0Dp+tBrLxDiZN2pRurnlkt7P3QUg/gEG\nAovyd3ij0wKBgBbA7x1q1ORvUbmmHuaUfV4iDwpkWoOa3U9rQIBzQfvXVKlKhwyN\nom9hIg7RUAlLToZUeLyAK5pPLpIK34kaP5Cs4iaL6mzumUh6mvu20b0Ljvyk/lWU\nvkVIQ5BO9alSatHxdDnG04n8IzcQgmdAmAMzadMl7cF5k+KmZB4l2sjRAoGAP8JS\nPNlcAntSKUhCG0KHojmTFK5fBvYT2rjdm+4sLYGp+KRiO7fDvXxDF+BaDi11rDv/\nRrAFOiTs7dJYoZXcdX7POQ9GEWu1zJont1RGde9Gf5Dl12E9FsU8pcMqagnwmggt\nELMpGbQwtBxsAdQsoA3PvBhyFdNtKzu0ZeG1+RkCgYBOPhOCR88QPTmQANkwIMH+\n0vt+KhSjE3dhX7rzVkhoNmYF5AaSSpQ3F1JUlYntjblMQVjLesGvWa4gwCOF87xC\nJxHL6LkbNjAyUGZp7to6/F4vTmKoC6Xu/jTRRy2SVjdqiIa0Pm0eLLfRHmSI06pS\n+zLmdpZv/msPfGibbHcXUA==\n-----END PRIVATE KEY-----\n", + 'project_id' => 'test-project', + 'private_key_id' => 'test-project-id', + 'private_key' => "test-private-key", ] ], 'Apns' => [ @@ -972,7 +972,7 @@ class MessagingTest extends Scope $pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); $to = $pushDSN->getParam('to'); - $serviceAccountJSON = $pushDSN->getParam('saj'); + $serviceAccountJSON = $pushDSN->getParam('serviceAccountJSON'); if (empty($to) || empty($serviceAccountJSON)) { $this->markTestSkipped('Push provider not configured'); @@ -986,9 +986,9 @@ class MessagingTest extends Scope 'name' => 'FCM1', 'serviceAccountJSON' => [ 'type' => 'service_account', - "project_id" => "token-test", - "private_key_id" => "bitcoin-is-the-future", - "private_key" => "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkAgEAAoIBAQCeKDbvv4XvGuNAOxZBcxoNnvbINKlq0FtiqgsqLAgDOMt\nGPEANfni+D7lZRrMPhZhcL4YCjAUg+0ZI0D9d2LGofasj9GlBb57SZc/ud2L9FZZ\nk5liXrUk0SUirffBUmj5F/XPTJ+JXc89qPtt15+hqx30h2ID/wxN0AhmViLikR3o\n3YBHAYq0NbmAfQSfdsHX+lvNKvsAxU+LatRPE3tVcvSd3ZnP0zlHYVmp6UCeBWeW\nOTcSPecCcVXmBdMPtHGWdrNG2op1CmHc8JeYJMQ4xgz3obQcOX9+3USsysANjgta\nb07m6xS3AgMBAAECggEAIeSTVVCRZrq36zk8VgJ/r/NE4r95xEk2K/K/Lvb0fx75\no0BO5gsAkYqvgzem/LrVFCEFRkDGMbAhVQ5Fw1pN2U6CyA0hL4jUqgALtMImKJdX\nDa6I5Gibwd5+qt9NOZSgC/Kq14zAxhfQE3U2hyatohyx3Rsz/3lmJo90bX7Jp5md\nGBDOB3pFBqyfUvyHgeqCgvJvidJjxmwArLhUF8szuDRvmSs0lGsfqYprK0sb9phL\nP7Z3qMJk1J4IDL2abSGrTcMP+hk7ju1iqo7WfhIQCvM1TD5dRjYg2IYPIAIzszWz\nxSA67eJpQGSFfOuk82g3UMhfCD2DY2mCE/zkeid9jQKBgQDSB2xA+LpQDX2nuoDR\niZbPYBitxQtkbjieYTR8vwrIzyAvRtOwjnVKsXLyIbUYyHd6RFRDPeBcHb39KuRO\nz7VljQKTVB5RYUmqeGilor0TFaKMnneC7GFH6mWOJyf16DU7bkQw27Pg1e3xbF28\n5ig7QYPqEaDKLg6TMSLsBhdRDQKBgQDAxj9jS9UOTmF3N9T1JFzWfUB2r+AgwE4N\nSITmG/fSz9rlSg+XPh2ijpSrboUbuY/GYq5aCIy1twx09eta07Y/uD/GKLYrk873\no0TxQrnHSKl82fCyd2JPG/W8ocGDnj3u0Dp+tBrLxDiZN2pRurnlkt7P3QUg/gEG\nAovyd3ij0wKBgBbA7x1q1ORvUbmmHuaUfV4iDwpkWoOa3U9rQIBzQfvXVKlKhwyN\nom9hIg7RUAlLToZUeLyAK5pPLpIK34kaP5Cs4iaL6mzumUh6mvu20b0Ljvyk/lWU\nvkVIQ5BO9alSatHxdDnG04n8IzcQgmdAmAMzadMl7cF5k+KmZB4l2sjRAoGAP8JS\nPNlcAntSKUhCG0KHojmTFK5fBvYT2rjdm+4sLYGp+KRiO7fDvXxDF+BaDi11rDv/\nRrAFOiTs7dJYoZXcdX7POQ9GEWu1zJont1RGde9Gf5Dl12E9FsU8pcMqagnwmggt\nELMpGbQwtBxsAdQsoA3PvBhyFdNtKzu0ZeG1+RkCgYBOPhOCR88QPTmQANkwIMH+\n0vt+KhSjE3dhX7rzVkhoNmYF5AaSSpQ3F1JUlYntjblMQVjLesGvWa4gwCOF87xC\nJxHL6LkbNjAyUGZp7to6/F4vTmKoC6Xu/jTRRy2SVjdqiIa0Pm0eLLfRHmSI06pS\n+zLmdpZv/msPfGibbHcXUA==\n-----END PRIVATE KEY-----\n", + "project_id" => "test-project", + "private_key_id" => "test-private-key-id", + "private_key" => "test-private-key", ] ], ]; diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 9e1788928d..5b76d37565 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -67,9 +67,9 @@ trait MessagingBase 'name' => 'FCM1', 'serviceAccountJSON' => [ 'type' => 'service_account', - "project_id" => "omegle-copy", - "private_key_id" => "ewfwefwefwefwef", - "private_key" => "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkAgEAAoIBAQCeKDbvv4XvGuNAOxZBcxoNnvbINKlq0FtiqgsqLAgDOMt\nGPEANfni+D7lZRrMPhZhcL4YCjAUg+0ZI0D9d2LGofasj9GlBb57SZc/ud2L9FZZ\nk5liXrUk0SUirffBUmj5F/XPTJ+JXc89qPtt15+hqx30h2ID/wxN0AhmViLikR3o\n3YBHAYq0NbmAfQSfdsHX+lvNKvsAxU+LatRPE3tVcvSd3ZnP0zlHYVmp6UCeBWeW\nOTcSPecCcVXmBdMPtHGWdrNG2op1CmHc8JeYJMQ4xgz3obQcOX9+3USsysANjgta\nb07m6xS3AgMBAAECggEAIeSTVVCRZrq36zk8VgJ/r/NE4r95xEk2K/K/Lvb0fx75\no0BO5gsAkYqvgzem/LrVFCEFRkDGMbAhVQ5Fw1pN2U6CyA0hL4jUqgALtMImKJdX\nDa6I5Gibwd5+qt9NOZSgC/Kq14zAxhfQE3U2hyatohyx3Rsz/3lmJo90bX7Jp5md\nGBDOB3pFBqyfUvyHgeqCgvJvidJjxmwArLhUF8szuDRvmSs0lGsfqYprK0sb9phL\nP7Z3qMJk1J4IDL2abSGrTcMP+hk7ju1iqo7WfhIQCvM1TD5dRjYg2IYPIAIzszWz\nxSA67eJpQGSFfOuk82g3UMhfCD2DY2mCE/zkeid9jQKBgQDSB2xA+LpQDX2nuoDR\niZbPYBitxQtkbjieYTR8vwrIzyAvRtOwjnVKsXLyIbUYyHd6RFRDPeBcHb39KuRO\nz7VljQKTVB5RYUmqeGilor0TFaKMnneC7GFH6mWOJyf16DU7bkQw27Pg1e3xbF28\n5ig7QYPqEaDKLg6TMSLsBhdRDQKBgQDAxj9jS9UOTmF3N9T1JFzWfUB2r+AgwE4N\nSITmG/fSz9rlSg+XPh2ijpSrboUbuY/GYq5aCIy1twx09eta07Y/uD/GKLYrk873\no0TxQrnHSKl82fCyd2JPG/W8ocGDnj3u0Dp+tBrLxDiZN2pRurnlkt7P3QUg/gEG\nAovyd3ij0wKBgBbA7x1q1ORvUbmmHuaUfV4iDwpkWoOa3U9rQIBzQfvXVKlKhwyN\nom9hIg7RUAlLToZUeLyAK5pPLpIK34kaP5Cs4iaL6mzumUh6mvu20b0Ljvyk/lWU\nvkVIQ5BO9alSatHxdDnG04n8IzcQgmdAmAMzadMl7cF5k+KmZB4l2sjRAoGAP8JS\nPNlcAntSKUhCG0KHojmTFK5fBvYT2rjdm+4sLYGp+KRiO7fDvXxDF+BaDi11rDv/\nRrAFOiTs7dJYoZXcdX7POQ9GEWu1zJont1RGde9Gf5Dl12E9FsU8pcMqagnwmggt\nELMpGbQwtBxsAdQsoA3PvBhyFdNtKzu0ZeG1+RkCgYBOPhOCR88QPTmQANkwIMH+\n0vt+KhSjE3dhX7rzVkhoNmYF5AaSSpQ3F1JUlYntjblMQVjLesGvWa4gwCOF87xC\nJxHL6LkbNjAyUGZp7to6/F4vTmKoC6Xu/jTRRy2SVjdqiIa0Pm0eLLfRHmSI06pS\n+zLmdpZv/msPfGibbHcXUA==\n-----END PRIVATE KEY-----\n", + "project_id" => "test-project", + "private_key_id" => "test-private-key-id", + "private_key" => "test-private-key", ], ], 'apns' => [ @@ -143,9 +143,9 @@ trait MessagingBase 'name' => 'FCM2', 'serviceAccountJSON' => [ 'type' => 'service_account', - "project_id" => "omegle-copy", - "private_key_id" => "ewfwefwefwefwef", - "private_key" => "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkAgEAAoIBAQCeKDbvv4XvGuNAOxZBcxoNnvbINKlq0FtiqgsqLAgDOMt\nGPEANfni+D7lZRrMPhZhcL4YCjAUg+0ZI0D9d2LGofasj9GlBb57SZc/ud2L9FZZ\nk5liXrUk0SUirffBUmj5F/XPTJ+JXc89qPtt15+hqx30h2ID/wxN0AhmViLikR3o\n3YBHAYq0NbmAfQSfdsHX+lvNKvsAxU+LatRPE3tVcvSd3ZnP0zlHYVmp6UCeBWeW\nOTcSPecCcVXmBdMPtHGWdrNG2op1CmHc8JeYJMQ4xgz3obQcOX9+3USsysANjgta\nb07m6xS3AgMBAAECggEAIeSTVVCRZrq36zk8VgJ/r/NE4r95xEk2K/K/Lvb0fx75\no0BO5gsAkYqvgzem/LrVFCEFRkDGMbAhVQ5Fw1pN2U6CyA0hL4jUqgALtMImKJdX\nDa6I5Gibwd5+qt9NOZSgC/Kq14zAxhfQE3U2hyatohyx3Rsz/3lmJo90bX7Jp5md\nGBDOB3pFBqyfUvyHgeqCgvJvidJjxmwArLhUF8szuDRvmSs0lGsfqYprK0sb9phL\nP7Z3qMJk1J4IDL2abSGrTcMP+hk7ju1iqo7WfhIQCvM1TD5dRjYg2IYPIAIzszWz\nxSA67eJpQGSFfOuk82g3UMhfCD2DY2mCE/zkeid9jQKBgQDSB2xA+LpQDX2nuoDR\niZbPYBitxQtkbjieYTR8vwrIzyAvRtOwjnVKsXLyIbUYyHd6RFRDPeBcHb39KuRO\nz7VljQKTVB5RYUmqeGilor0TFaKMnneC7GFH6mWOJyf16DU7bkQw27Pg1e3xbF28\n5ig7QYPqEaDKLg6TMSLsBhdRDQKBgQDAxj9jS9UOTmF3N9T1JFzWfUB2r+AgwE4N\nSITmG/fSz9rlSg+XPh2ijpSrboUbuY/GYq5aCIy1twx09eta07Y/uD/GKLYrk873\no0TxQrnHSKl82fCyd2JPG/W8ocGDnj3u0Dp+tBrLxDiZN2pRurnlkt7P3QUg/gEG\nAovyd3ij0wKBgBbA7x1q1ORvUbmmHuaUfV4iDwpkWoOa3U9rQIBzQfvXVKlKhwyN\nom9hIg7RUAlLToZUeLyAK5pPLpIK34kaP5Cs4iaL6mzumUh6mvu20b0Ljvyk/lWU\nvkVIQ5BO9alSatHxdDnG04n8IzcQgmdAmAMzadMl7cF5k+KmZB4l2sjRAoGAP8JS\nPNlcAntSKUhCG0KHojmTFK5fBvYT2rjdm+4sLYGp+KRiO7fDvXxDF+BaDi11rDv/\nRrAFOiTs7dJYoZXcdX7POQ9GEWu1zJont1RGde9Gf5Dl12E9FsU8pcMqagnwmggt\nELMpGbQwtBxsAdQsoA3PvBhyFdNtKzu0ZeG1+RkCgYBOPhOCR88QPTmQANkwIMH+\n0vt+KhSjE3dhX7rzVkhoNmYF5AaSSpQ3F1JUlYntjblMQVjLesGvWa4gwCOF87xC\nJxHL6LkbNjAyUGZp7to6/F4vTmKoC6Xu/jTRRy2SVjdqiIa0Pm0eLLfRHmSI06pS\n+zLmdpZv/msPfGibbHcXUA==\n-----END PRIVATE KEY-----\n", + "project_id" => "test-project", + "private_key_id" => "test-private-key-id", + "private_key" => "test-private-key", ] ], 'apns' => [ @@ -647,8 +647,6 @@ trait MessagingBase 'x-appwrite-key' => $this->getProject()['apiKey'], ]); - \var_dump($message); - $this->assertEquals(200, $message['headers']['status-code']); $this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); @@ -881,7 +879,7 @@ trait MessagingBase $dsn = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN')); $to = $dsn->getParam('to'); - $serviceAccountJSON = $dsn->getParam('saj'); + $serviceAccountJSON = $dsn->getParam('serviceAccountJSON'); if (empty($to) || empty($serviceAccountJSON)) { $this->markTestSkipped('Push provider not configured'); diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index 3e63bd8740..4d844c7551 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -1661,7 +1661,6 @@ class ProjectsConsoleClientTest extends Scope foreach ($response['body'] as $key => $value) { if (\preg_match($pattern, $key)) { - \var_dump('Matched key: ' . $key); $matches[$key] = $value; } }