diff --git a/.gitignore b/.gitignore index 43915ef..7a911c6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ build composer.lock coverage docs -phpunit.xml phpstan.neon testbench.yaml vendor diff --git a/composer.json b/composer.json index 4a818ff..23c0c3e 100644 --- a/composer.json +++ b/composer.json @@ -3,17 +3,27 @@ "description": "Multi-channel Laravel notification sender", "type": "library", "license": "MIT", + "keywords": [ + "laravel", + "sendgrid", + "notifications", + "sendgrid-api", + "laravel-package" + ], "authors": [ { "name": "Chijioke Ibekwe", "email": "ibekwe.chijioke18@gmail.com" } ], + "homepage": "https://github.com/chijioke-ibekwe/raven", "require": { - "sendgrid/sendgrid": "~7" + "sendgrid/sendgrid": "~7", + "aws/aws-sdk-php": "^3.300", + "phpmailer/phpmailer": "^6.9" }, "require-dev": { - "orchestra/testbench": "7.0", + "orchestra/testbench": "^6.0", "phpunit/phpunit": "^9.6" }, "autoload": { diff --git a/config/raven.php b/config/raven.php index e265cbc..923e91a 100644 --- a/config/raven.php +++ b/config/raven.php @@ -2,20 +2,31 @@ return [ - 'notification-service' => [ + 'default' => [ 'email' => env('EMAIL_NOTIFICATION_PROVIDER', 'sendgrid'), 'sms' => env('SMS_NOTIFICATION_PROVIDER', 'nexmo') ], - 'api-key' => [ - 'sendgrid' => env('SENDGRID_API_KEY') + 'providers' => [ + 'sendgrid' => [ + 'key' => env('SENDGRID_API_KEY') + ], + 'ses' => [ + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'template_source' => env('AWS_SES_TEMPLATE_SOURCE', 'sendgrid'), + 'template_directory' => env('AWS_SES_TEMPLATE_DIRECTORY', 'resources/views/emails') + ] ], - 'mail' => [ - 'from' => [ - 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), - 'name' => env('MAIL_FROM_NAME', 'Example'), - ] + 'customizations' => [ + 'mail' => [ + 'from' => [ + 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), + 'name' => env('MAIL_FROM_NAME', 'Example'), + ] + ], ], 'api' => [ diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..05d8858 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,32 @@ + + + + + ./tests/Unit + + + + ./tests/Feature + + + + + + + + + + + + src/ + + + \ No newline at end of file diff --git a/src/Channels/AmazonSesChannel.php b/src/Channels/AmazonSesChannel.php new file mode 100644 index 0000000..8b88b2c --- /dev/null +++ b/src/Channels/AmazonSesChannel.php @@ -0,0 +1,111 @@ +sesClient = app(SesClient::class); + $this->sendGrid = app(SendGrid::class); + } + + /** + * Send the given notification. + * + * @param mixed $notifiable + * @param EmailNotificationSender $emailNotification + * @return void + * @throws Exception + */ + public function send(mixed $notifiable, EmailNotificationSender $emailNotification): void + { + $email = $emailNotification->toAmazonSes($notifiable); + + $sender = config('raven.customizations.mail.from'); + $email->setFrom($sender['address'], $sender['name']); + + $template_source = config('raven.providers.ses.template_source'); + if($template_source !== 'sendgrid') { + Log::error("Template source $template_source not currently supported"); + throw new Exception("Template source $template_source not currently supported"); + } + + $template_response = $this->getSendGridTemplateContent($emailNotification); + + $params = $emailNotification->notificationData->getParams(); + $clean_html = $this->cleanTemplate($template_response['html_content'], $params); + $clean_plain = $this->cleanTemplate($template_response['plain_content'], $params); + + $email->Subject = $template_response['subject']; + $email->Body = $clean_html; + $email->AltBody = $clean_plain; + + if (!$email->preSend()) { + Log::error("Failed sending mail: " . $email->ErrorInfo); + throw new Exception($email->ErrorInfo); + } else { + $message = $email->getSentMIMEMessage(); + } + + try { + $result = $this->sesClient->sendRawEmail([ + 'RawMessage' => [ + 'Data' => $message + ] + ]); + Log::info($result); + } catch (SesException $error) { + Log::error("Failed sending mail: " . $error->getAwsErrorMessage()); + } + } + + /** + * @throws Exception + */ + private function getSendGridTemplateContent(EmailNotificationSender $emailNotification): array + { + try { + $template_id = $emailNotification->notificationContext->email_template_id; + $response = $this->sendGrid->client->templates()->_($template_id)->get(); + + if(!($response->statusCode() >= '200' && $response->statusCode() < 300)) { + throw new Exception("SendGrid server returned error response"); + } + + $body_json = $response->body(); + $body_arr = json_decode($body_json, true); + $subject = $body_arr['versions'][0]['subject']; + $html_content = $body_arr['versions'][0]['html_content']; + $plain_content = $body_arr['versions'][0]['plain_content']; + + return [ + 'subject' => $subject, + 'html_content' => $html_content, + 'plain_content' => $plain_content + ]; + + } catch (Exception $e) { + Log::error("Failed sending mail: " . $e->getMessage()); + throw new Exception($e); + } + } + + private function cleanTemplate($template, $data) + { + foreach ($data as $key => $value) { + $template = str_replace('{{' . $key . '}}', $value, $template); + } + return $template; + } +} \ No newline at end of file diff --git a/src/Channels/SendGridChannel.php b/src/Channels/SendGridChannel.php index d66bebb..2039fb2 100644 --- a/src/Channels/SendGridChannel.php +++ b/src/Channels/SendGridChannel.php @@ -9,31 +9,37 @@ class SendGridChannel { + private SendGrid $sendGrid; + + public function __construct() + { + $this->sendGrid = app(SendGrid::class); + } + /** * Send the given notification. * * @param mixed $notifiable - * @param EmailNotificationSender $sender - * @param SendGrid $sendGrid + * @param EmailNotificationSender $emailNotification * @return void */ - public function send(mixed $notifiable, EmailNotificationSender $sender, SendGrid $sendGrid): void + public function send(mixed $notifiable, EmailNotificationSender $emailNotification): void { - try { - $email = $sender->toSendgrid($notifiable); + $email = $emailNotification->toSendgrid($notifiable); $email->setClickTracking(true, true); $email->setOpenTracking(true, "--sub--"); - $email->setFrom(config('raven.mail.from.address'), config('raven.mail.from.name')); + $sender = config('raven.customizations.mail.from'); + $email->setFrom($sender['address'], $sender['name']); - $response = $sendGrid->send($email); + $response = $this->sendGrid->send($email); - if ($response->statusCode() != '202') { + if($response->statusCode() >= '200' && $response->statusCode() < 300) { Log::info("Mail success response: " . $response->body()); } } catch (Exception $e) { - Log::error("Failed sending mail to $email: " . $e->getMessage()); + Log::error("Failed sending mail: " . $e->getMessage()); } } } \ No newline at end of file diff --git a/src/Data/NotificationData.php b/src/Data/Scroll.php similarity index 98% rename from src/Data/NotificationData.php rename to src/Data/Scroll.php index 61e7b0a..ba9b4ce 100644 --- a/src/Data/NotificationData.php +++ b/src/Data/Scroll.php @@ -5,7 +5,7 @@ use Illuminate\Notifications\Notifiable; use ChijiokeIbekwe\Raven\Exceptions\RavenInvalidDataException; -class NotificationData +class Scroll { /** @@ -151,7 +151,7 @@ public function setParams(array $params): void } /** - * @param mixed $attachments + * @param mixed $attachmentUrls * @return void */ public function setAttachmentUrls(mixed $attachmentUrls): void diff --git a/src/Events/Raven.php b/src/Events/Raven.php index 00333e9..da74b1b 100644 --- a/src/Events/Raven.php +++ b/src/Events/Raven.php @@ -4,7 +4,7 @@ use Illuminate\Queue\SerializesModels; use Illuminate\Foundation\Events\Dispatchable; -use ChijiokeIbekwe\Raven\Data\NotificationData; +use ChijiokeIbekwe\Raven\Data\Scroll; class Raven { @@ -13,7 +13,7 @@ class Raven /** * Create a new event instance. */ - public function __construct(public NotificationData $notificationData) + public function __construct(public Scroll $scroll) { // } diff --git a/src/Listeners/RavenListener.php b/src/Listeners/RavenListener.php index 8cb7dd3..de8273e 100644 --- a/src/Listeners/RavenListener.php +++ b/src/Listeners/RavenListener.php @@ -2,7 +2,7 @@ namespace ChijiokeIbekwe\Raven\Listeners; -use ChijiokeIbekwe\Raven\Data\NotificationData; +use ChijiokeIbekwe\Raven\Data\Scroll; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Notification; use ChijiokeIbekwe\Raven\Events\Raven; @@ -20,6 +20,7 @@ class RavenListener { const EMAIL_PATTERN = '#^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$#'; const PHONE_PATTERN = '#^\+?[0-9\s-()]+$#'; + /** * Create the event listener. */ @@ -34,7 +35,7 @@ public function __construct() */ public function handle(Raven $event): void { - $data = $event->notificationData; + $data = $event->scroll; $context_name = $data->getContextName(); $context = NotificationContext::where('name', $context_name)->first(); @@ -44,9 +45,12 @@ public function handle(Raven $event): void $this->sendNotifications($data, $context); } - private function sendNotifications(NotificationData $data, NotificationContext $context) + /** + * @throws \Throwable + */ + private function sendNotifications(Scroll $scroll, NotificationContext $context): void { - $factory = new ChannelSenderFactory($data, $context); + $factory = new ChannelSenderFactory($scroll, $context); $channels = $context->notification_channels; foreach($channels as $channel){ @@ -56,7 +60,7 @@ private function sendNotifications(NotificationData $data, NotificationContext $ $channel_sender = $factory->getSender($channel_type); - $recipients = $data->getRecipients(); + $recipients = $scroll->getRecipients(); if(!$channel_sender) { Log::error("Notification channel $channel_type->name is not currently supported"); @@ -65,7 +69,7 @@ private function sendNotifications(NotificationData $data, NotificationContext $ Log::info("Sending notification for context $context->name through channel $channel_type->name"); - if(!$data->getHasOnDemand()) { + if(!$scroll->getHasOnDemand()) { Notification::send($recipients, $channel_sender); continue; } @@ -81,19 +85,19 @@ private function sendNotifications(NotificationData $data, NotificationContext $ } } - private function resolveRouteWithChannelSender($recipient, $channel_sender) + private function resolveRouteWithChannelSender($recipient, $channel_sender): void { $sender_class = get_class($channel_sender); switch($sender_class) { case EmailNotificationSender::class: if(preg_match(self::EMAIL_PATTERN, $recipient)) { - Notification::route(config('raven.notification-service.email'), $recipient)->notify($channel_sender); + Notification::route(config('raven.default.email'), $recipient)->notify($channel_sender); }; return; case SmsNotificationSender::class: if(preg_match(self::PHONE_PATTERN, $recipient)) { - Notification::route(config('raven.notification-service.sms'), $recipient)->notify($channel_sender); + Notification::route(config('raven.default.sms'), $recipient)->notify($channel_sender); }; return; case DatabaseNotificationSender::class: diff --git a/src/Notifications/DatabaseNotificationSender.php b/src/Notifications/DatabaseNotificationSender.php index 03411ad..6c17f62 100644 --- a/src/Notifications/DatabaseNotificationSender.php +++ b/src/Notifications/DatabaseNotificationSender.php @@ -5,7 +5,7 @@ use Illuminate\Notifications\Notification; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Bus\Queueable; -use ChijiokeIbekwe\Raven\Data\NotificationData; +use ChijiokeIbekwe\Raven\Data\Scroll; use ChijiokeIbekwe\Raven\Exceptions\RavenInvalidDataException; use ChijiokeIbekwe\Raven\Models\NotificationContext; @@ -13,7 +13,7 @@ class DatabaseNotificationSender extends Notification implements ShouldQueue, IN { use Queueable; - public function __construct(public readonly NotificationData $notificationData, + public function __construct(public readonly Scroll $scroll, public readonly NotificationContext $notificationContext) { // @@ -42,14 +42,14 @@ public function databaseType(object $notifiable): string */ public function toDatabase(object $notifiable): array { - $param_keys = array_keys($this->notificationData->getParams()); + $param_keys = array_keys($this->scroll->getParams()); for ($i = 0; $i < count($param_keys); $i++) { $old_key = $param_keys[$i]; $param_keys[$i] = '{' . $old_key . '}'; } - $param_values = array_values($this->notificationData->getParams()); + $param_values = array_values($this->scroll->getParams()); $body = str_replace($param_keys, $param_values, $this->notificationContext->body); diff --git a/src/Notifications/EmailNotificationSender.php b/src/Notifications/EmailNotificationSender.php index c0373a4..361d44b 100644 --- a/src/Notifications/EmailNotificationSender.php +++ b/src/Notifications/EmailNotificationSender.php @@ -5,9 +5,11 @@ use Illuminate\Notifications\Notification; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Bus\Queueable; -use ChijiokeIbekwe\Raven\Data\NotificationData; +use ChijiokeIbekwe\Raven\Data\Scroll; use ChijiokeIbekwe\Raven\Exceptions\RavenInvalidDataException; use ChijiokeIbekwe\Raven\Models\NotificationContext; +use PHPMailer\PHPMailer\Exception; +use PHPMailer\PHPMailer\PHPMailer; use SendGrid\Mail\Attachment; use SendGrid\Mail\Mail; use SendGrid\Mail\TypeException; @@ -16,7 +18,7 @@ class EmailNotificationSender extends Notification implements ShouldQueue, INoti { use Queueable; - public function __construct(public readonly NotificationData $notificationData, + public function __construct(public readonly Scroll $scroll, public readonly NotificationContext $notificationContext) { // @@ -24,7 +26,7 @@ public function __construct(public readonly NotificationData $notificationDat public function via(mixed $notifiable): array { - return [config('raven.notification-service.email')]; + return [config('raven.default.email')]; } /** @@ -36,28 +38,26 @@ public function via(mixed $notifiable): array */ public function toSendgrid(mixed $notifiable): ?Mail { - $provider = config('raven.notification-service.email'); - $route = $notifiable->routeNotificationFor('mail'); if (!$route) { - throw new RavenInvalidDataException("Missing route for $provider"); + throw new RavenInvalidDataException("Missing route for mail"); } $email = new Mail(); $email->setTemplateId($this->notificationContext->email_template_id); $email->addTo($route); - if(!empty($this->notificationData->getCcs())){ - $email->addCcs($this->notificationData->getCcs()); + if(!empty($this->scroll->getCcs())){ + $email->addCcs($this->scroll->getCcs()); } - $substitutions = $this->notificationData->getParams(); + $substitutions = $this->scroll->getParams(); $email->addDynamicTemplateDatas($substitutions); - if(!empty($this->notificationData->getAttachmentUrls())) { + if(!empty($this->scroll->getAttachmentUrls())) { $attachments = []; - foreach ($this->notificationData->getAttachmentUrls() as $url){ + foreach ($this->scroll->getAttachmentUrls() as $url){ $attachment = new Attachment(); $filename = basename($url); $file_encoded = base64_encode(file_get_contents($url)); @@ -74,6 +74,39 @@ public function toSendgrid(mixed $notifiable): ?Mail { return $email; } + /** + * Get the PHPMailer object for Amazon SES channel. + * + * @param mixed $notifiable + * @return PHPMailer|null + * @throws RavenInvalidDataException|TypeException|Exception + */ + public function toAmazonSes(mixed $notifiable): ?PHPMailer { + + $route = $notifiable->routeNotificationFor('mail'); + + if (!$route) { + throw new RavenInvalidDataException("Missing route for mail"); + } + + $email = new PHPMailer(true); + $email->addAddress($route); + + if(!empty($this->scroll->getCcs())){ + foreach ($this->scroll->getCcs() as $email){ + $email->addCc($email); + } + } + + if(!empty($this->scroll->getAttachmentUrls())) { + foreach ($this->scroll->getAttachmentUrls() as $url){ + $email->addAttachment($url); + } + } + + return $email; + } + /** * @throws \Throwable */ diff --git a/src/Notifications/SmsNotificationSender.php b/src/Notifications/SmsNotificationSender.php index b4fae53..a198729 100644 --- a/src/Notifications/SmsNotificationSender.php +++ b/src/Notifications/SmsNotificationSender.php @@ -5,21 +5,21 @@ use Illuminate\Notifications\Notification; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Bus\Queueable; -use ChijiokeIbekwe\Raven\Data\NotificationData; +use ChijiokeIbekwe\Raven\Data\Scroll; use ChijiokeIbekwe\Raven\Models\NotificationContext; class SmsNotificationSender extends Notification implements ShouldQueue, INotificationSender { use Queueable; - public function __construct(public readonly NotificationData $notificationDTO, + public function __construct(public readonly Scroll $scroll, public readonly NotificationContext $notificationContext) { // } public function via($notifiable): array { - return ['raven.notification-service.sms']; + return ['raven.default.sms']; } public function validateNotification() diff --git a/src/RavenServiceProvider.php b/src/RavenServiceProvider.php index 0b6bd3b..a4b7f83 100644 --- a/src/RavenServiceProvider.php +++ b/src/RavenServiceProvider.php @@ -2,6 +2,9 @@ namespace ChijiokeIbekwe\Raven; +use Aws\Ses\SesClient; +use ChijiokeIbekwe\Raven\Channels\AmazonSesChannel; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\Notification; use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; @@ -48,12 +51,24 @@ public function boot(): void $this->registerRoutes(); $this->app->singleton(SendGrid::class, function ($app) { - return new SendGrid(config('raven.api-key.sendgrid')); + return new SendGrid(config('raven.providers.sendgrid.key')); + }); + + $this->app->singleton(SesClient::class, function ($app) { + return new SesClient([ + 'credentials' => Arr::only(config('raven.providers.ses'), ['key', 'secret']), + 'version' => 'latest', + 'region' => config('raven.providers.ses.region') + ]); }); Notification::extend('sendgrid', function ($app) { return new SendGridChannel(); }); + + Notification::extend('ses', function ($app) { + return new AmazonSesChannel(); + }); } protected function registerRoutes(): void diff --git a/src/Services/ChannelSenderFactory.php b/src/Services/ChannelSenderFactory.php index d56bae3..4f88e84 100644 --- a/src/Services/ChannelSenderFactory.php +++ b/src/Services/ChannelSenderFactory.php @@ -5,7 +5,7 @@ use ChijiokeIbekwe\Raven\Enums\ChannelType; use ChijiokeIbekwe\Raven\Notifications\DatabaseNotificationSender; use ChijiokeIbekwe\Raven\Notifications\EmailNotificationSender; -use ChijiokeIbekwe\Raven\Data\NotificationData; +use ChijiokeIbekwe\Raven\Data\Scroll; use ChijiokeIbekwe\Raven\Models\NotificationContext; use ChijiokeIbekwe\Raven\Notifications\SmsNotificationSender; @@ -19,16 +19,16 @@ class ChannelSenderFactory /** - * @param NotificationData $notificationData + * @param Scroll $scroll * @param NotificationContext $notificationContext */ - public function __construct(private readonly NotificationData $notificationData, + public function __construct(private readonly Scroll $scroll, private readonly NotificationContext $notificationContext) { - $email_sender = new EmailNotificationSender($this->notificationData, $this->notificationContext); - $sms_sender = new SmsNotificationSender($this->notificationData, $this->notificationContext); - $database_sender = new DatabaseNotificationSender($this->notificationData, $this->notificationContext); + $email_sender = new EmailNotificationSender($this->scroll, $this->notificationContext); + $sms_sender = new SmsNotificationSender($this->scroll, $this->notificationContext); + $database_sender = new DatabaseNotificationSender($this->scroll, $this->notificationContext); $this->sender_store = [ diff --git a/tests/Feature/NotificationTest.php b/tests/Feature/SendGridNotificationTest.php similarity index 73% rename from tests/Feature/NotificationTest.php rename to tests/Feature/SendGridNotificationTest.php index 088c0fc..a533336 100644 --- a/tests/Feature/NotificationTest.php +++ b/tests/Feature/SendGridNotificationTest.php @@ -4,7 +4,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\Notification; -use ChijiokeIbekwe\Raven\Data\NotificationData; +use ChijiokeIbekwe\Raven\Data\Scroll; use ChijiokeIbekwe\Raven\Events\Raven; use ChijiokeIbekwe\Raven\Exceptions\RavenEntityNotFoundException; use ChijiokeIbekwe\Raven\Exceptions\RavenInvalidDataException; @@ -16,14 +16,13 @@ use ChijiokeIbekwe\Raven\Tests\TestCase; use ChijiokeIbekwe\Raven\Tests\Utilities\User; -class NotificationTest extends TestCase +class SendGridNotificationTest extends TestCase { use RefreshDatabase; public function getEnvironmentSetUp($app): void { - $app['config']->set('raven.notification-service.email', 'sendgrid'); - $app['config']->set('raven.notification-service.database', 'database'); + $app['config']->set('raven.default.email', 'sendgrid'); // run the up() method (perform the migration) (new \CreateNotificationContextsTable)->up(); @@ -38,42 +37,40 @@ public function test_that_email_notifications_are_sent_when_the_raven_listener_r Notification::fake(); - $user = User::factory(1)->make([ + $user = User::factory()->make([ 'name' => 'John Doe', 'email' => 'john.doe@raven.com' - ])->get(0); + ]); - $context = NotificationContext::factory(1)->create([ + $context = NotificationContext::factory()->create([ 'email_template_id' => 'sendgrid-template', 'name' => 'user-created' - ])->get(0); + ]); $channel = NotificationChannel::where('type', 'EMAIL')->first(); $context->notification_channels()->attach($channel->id); - $data = new NotificationData(); - $data->setContextName('user-created'); - $data->setRecipients($user); - $data->setCcs(["email@raven.com" => "Jane Doe"]); - $data->setParams([ + $scroll = new Scroll(); + $scroll->setContextName('user-created'); + $scroll->setRecipients($user); + $scroll->setCcs(["email@raven.com" => "Jane Doe"]); + $scroll->setParams([ 'booking_id' => 'JET12345' ]); (new RavenListener())->handle( - new Raven($data) + new Raven($scroll) ); - Notification::assertCount(1); - Notification::assertSentTo( $user, EmailNotificationSender::class, - function (EmailNotificationSender $notification) use ($user, $data, $context) { + function (EmailNotificationSender $notification) use ($user, $scroll, $context) { $mail = $notification->toSendgrid($user); $via = $notification->via($user); - return $notification->notificationData === $data && + return $notification->scroll === $scroll && $notification->notificationContext->name === $context->name && $mail->getTemplateId()->getTemplateId() === 'sendgrid-template' && $mail->getDynamicTemplateDatas() === [ @@ -93,42 +90,40 @@ public function test_that_email_notifications_are_sent_when_the_an_email_address Notification::fake(); - $user = User::factory(1)->make([ + $user = User::factory()->make([ 'name' => 'John Doe', 'email' => 'john.doe@raven.com' - ])->get(0); + ]); - $context = NotificationContext::factory(1)->create([ + $context = NotificationContext::factory()->create([ 'email_template_id' => 'sendgrid-template', 'name' => 'user-created' - ])->get(0); + ]); $channel = NotificationChannel::where('type', 'EMAIL')->first(); $context->notification_channels()->attach($channel->id); - $data = new NotificationData(); - $data->setContextName('user-created'); - $data->setRecipients([$user, 'jane.doe@raven.com']); - $data->setCcs(["email@raven.com" => "Jane Doe"]); - $data->setParams([ + $scroll = new Scroll(); + $scroll->setContextName('user-created'); + $scroll->setRecipients([$user, 'jane.doe@raven.com']); + $scroll->setCcs(["email@raven.com" => "Jane Doe"]); + $scroll->setParams([ 'booking_id' => 'JET12345' ]); (new RavenListener())->handle( - new Raven($data) + new Raven($scroll) ); - Notification::assertCount(2); - Notification::assertSentTo( $user, EmailNotificationSender::class, - function (EmailNotificationSender $notification) use ($user, $data, $context) { + function (EmailNotificationSender $notification) use ($user, $scroll, $context) { $mail = $notification->toSendgrid($user); $via = $notification->via($user); - return $notification->notificationData === $data && + return $notification->scroll === $scroll && $notification->notificationContext->name === $context->name && $mail->getTemplateId()->getTemplateId() === 'sendgrid-template' && $mail->getDynamicTemplateDatas() === [ @@ -148,44 +143,42 @@ public function test_that_database_notifications_are_sent_when_the_raven_listene Notification::fake(); - $user = User::factory(1)->make([ + $user = User::factory()->make([ 'name' => 'John Doe', 'email' => 'john.doe@raven.com' - ])->get(0); + ]); - $context = NotificationContext::factory(1)->create([ + $context = NotificationContext::factory()->create([ 'name' => 'user-verified', 'title' => 'Verification', 'body' => 'User with id {user_id} has been verified on the platform on {date_time}', 'type' => 'user' - ])->get(0); + ]); $channel = NotificationChannel::where('type', 'DATABASE')->first(); $context->notification_channels()->attach($channel->id); - $data = new NotificationData(); - $data->setContextName('user-verified'); - $data->setRecipients($user); - $data->setParams([ + $scroll = new Scroll(); + $scroll->setContextName('user-verified'); + $scroll->setRecipients($user); + $scroll->setParams([ 'user_id' => '345', 'date_time' => '11-12-2023 10:51' ]); (new RavenListener())->handle( - new Raven($data) + new Raven($scroll) ); - Notification::assertCount(1); - Notification::assertSentTo( $user, DatabaseNotificationSender::class, - function (DatabaseNotificationSender $notification) use ($user, $data, $context) { + function (DatabaseNotificationSender $notification) use ($user, $scroll, $context) { $content = $notification->toDatabase($user); $via = $notification->via($user); - return $notification->notificationData === $data && + return $notification->scroll === $scroll && $notification->notificationContext->name === $context->name && data_get($content, 'title') === 'Verification' && data_get($content, 'body') === 'User with id 345 has been verified on the platform on 11-12-2023 10:51' && @@ -205,20 +198,20 @@ public function test_that_exception_is_thrown_when_notification_context_name_is_ Notification::fake(); - $user = User::factory(1)->make([ + $user = User::factory()->make([ 'name' => 'John Doe', 'email' => 'john.doe@raven.com' - ])->get(0); + ]); - $data = new NotificationData(); - $data->setRecipients($user); - $data->setParams([ + $scroll = new Scroll(); + $scroll->setRecipients($user); + $scroll->setParams([ 'user_id' => '345', 'date_time' => '11-12-2023 10:51' ]); (new RavenListener())->handle( - new Raven($data) + new Raven($scroll) ); } @@ -230,21 +223,21 @@ public function test_that_exception_is_thrown_when_notification_context_name_doe Notification::fake(); - $user = User::factory(1)->make([ + $user = User::factory()->make([ 'name' => 'John Doe', 'email' => 'john.doe@raven.com' - ])->get(0); + ]); - $data = new NotificationData(); - $data->setContextName('user-verified'); - $data->setRecipients($user); - $data->setParams([ + $scroll = new Scroll(); + $scroll->setContextName('user-verified'); + $scroll->setRecipients($user); + $scroll->setParams([ 'user_id' => '345', 'date_time' => '11-12-2023 10:51' ]); (new RavenListener())->handle( - new Raven($data) + new Raven($scroll) ); } @@ -256,29 +249,29 @@ public function test_that_exception_is_thrown_when_email_notification_context_ha Notification::fake(); - $user = User::factory(1)->make([ + $user = User::factory()->make([ 'name' => 'John Doe', 'email' => 'john.doe@raven.com' - ])->get(0); + ]); - $context = NotificationContext::factory(1)->create([ + $context = NotificationContext::factory()->create([ 'name' => 'user-updated' - ])->get(0); + ]); $channel = NotificationChannel::where('type', 'EMAIL')->first(); $context->notification_channels()->attach($channel->id); - $data = new NotificationData(); - $data->setContextName('user-updated'); - $data->setRecipients($user); - $data->setParams([ + $scroll = new Scroll(); + $scroll->setContextName('user-updated'); + $scroll->setRecipients($user); + $scroll->setParams([ 'user_id' => '345', 'date_time' => '11-12-2023 10:51' ]); (new RavenListener())->handle( - new Raven($data) + new Raven($scroll) ); } @@ -290,30 +283,30 @@ public function test_that_exception_is_thrown_when_database_notification_context Notification::fake(); - $user = User::factory(1)->make([ + $user = User::factory()->make([ 'name' => 'John Doe', 'email' => 'john.doe@raven.com' - ])->get(0); + ]); - $context = NotificationContext::factory(1)->create([ + $context = NotificationContext::factory()->create([ 'name' => 'user-updated', 'body' => 'User with id {user_id} has been updated on {date_time}' - ])->get(0); + ]); $channel = NotificationChannel::where('type', 'DATABASE')->first(); $context->notification_channels()->attach($channel->id); - $data = new NotificationData(); - $data->setContextName('user-updated'); - $data->setRecipients($user); - $data->setParams([ + $scroll = new Scroll(); + $scroll->setContextName('user-updated'); + $scroll->setRecipients($user); + $scroll->setParams([ 'user_id' => '345', 'date_time' => '11-12-2023 10:51' ]); (new RavenListener())->handle( - new Raven($data) + new Raven($scroll) ); } @@ -325,30 +318,30 @@ public function test_that_exception_is_thrown_when_database_notification_context Notification::fake(); - $user = User::factory(1)->make([ + $user = User::factory()->make([ 'name' => 'John Doe', 'email' => 'john.doe@raven.com' - ])->get(0); + ]); - $context = NotificationContext::factory(1)->create([ + $context = NotificationContext::factory()->create([ 'name' => 'user-updated', 'title' => 'User Updated' - ])->get(0); + ]); $channel = NotificationChannel::where('type', 'DATABASE')->first(); $context->notification_channels()->attach($channel->id); - $data = new NotificationData(); - $data->setContextName('user-updated'); - $data->setRecipients($user); - $data->setParams([ + $scroll = new Scroll(); + $scroll->setContextName('user-updated'); + $scroll->setRecipients($user); + $scroll->setParams([ 'user_id' => '345', 'date_time' => '11-12-2023 10:51' ]); (new RavenListener())->handle( - new Raven($data) + new Raven($scroll) ); } @@ -360,29 +353,29 @@ public function test_that_exception_is_thrown_when_recipients_are_not_provided_i Notification::fake(); - $user = User::factory(1)->make([ + $user = User::factory()->make([ 'name' => 'John Doe', 'email' => 'john.doe@raven.com' - ])->get(0); + ]); - $context = NotificationContext::factory(1)->create([ + $context = NotificationContext::factory()->create([ 'email_template_id' => 'sendgrid-template', 'name' => 'user-created' - ])->get(0); + ]); $channel = NotificationChannel::where('type', 'EMAIL')->first(); $context->notification_channels()->attach($channel->id); - $data = new NotificationData(); - $data->setContextName('user-created'); - $data->setParams([ + $scroll = new Scroll(); + $scroll->setContextName('user-created'); + $scroll->setParams([ 'user_id' => '345', 'date_time' => '11-12-2023 10:51' ]); (new RavenListener())->handle( - new Raven($data) + new Raven($scroll) ); } @@ -397,25 +390,25 @@ public function test_that_exception_is_thrown_when_a_non_notifiable_recipient_is Notification::fake(); - $context = NotificationContext::factory(1)->create([ + $context = NotificationContext::factory()->create([ 'email_template_id' => 'sendgrid-template', 'name' => 'user-created' - ])->get(0); + ]); $channel = NotificationChannel::where('type', 'EMAIL')->first(); $context->notification_channels()->attach($channel->id); - $data = new NotificationData(); - $data->setContextName('user-created'); - $data->setRecipients($channel); - $data->setParams([ + $scroll = new Scroll(); + $scroll->setContextName('user-created'); + $scroll->setRecipients($channel); + $scroll->setParams([ 'user_id' => '345', 'date_time' => '11-12-2023 10:51' ]); (new RavenListener())->handle( - new Raven($data) + new Raven($scroll) ); } } diff --git a/tests/Utilities/UserFactory.php b/tests/Utilities/UserFactory.php index f046b85..b5bb8bd 100644 --- a/tests/Utilities/UserFactory.php +++ b/tests/Utilities/UserFactory.php @@ -18,8 +18,8 @@ class UserFactory extends Factory public function definition(): array { return [ - 'name' => fake()->name(), - 'email' => fake()->unique()->safeEmail(), + 'name' => $this->faker->name(), + 'email' => $this->faker->email, 'email_verified_at' => now(), 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 'remember_token' => Str::random(10),