From 7b99fab51215826c210c7079e4caea8a6369a857 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Fri, 15 Dec 2023 03:19:24 +1300 Subject: [PATCH] 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