diff --git a/database/migrations/1_create_users_table.php b/database/migrations/2024_01_01_00000_create_users_table.php similarity index 100% rename from database/migrations/1_create_users_table.php rename to database/migrations/2024_01_01_00000_create_users_table.php diff --git a/database/migrations/2_create_layouts_table.php b/database/migrations/2024_01_01_00001_create_layouts_table.php similarity index 100% rename from database/migrations/2_create_layouts_table.php rename to database/migrations/2024_01_01_00001_create_layouts_table.php diff --git a/database/migrations/3_create_templates_table.php b/database/migrations/2024_01_01_00002_create_templates_table.php similarity index 100% rename from database/migrations/3_create_templates_table.php rename to database/migrations/2024_01_01_00002_create_templates_table.php diff --git a/database/migrations/4_create_logs_table.php b/database/migrations/2024_01_01_00003_create_logs_table.php similarity index 100% rename from database/migrations/4_create_logs_table.php rename to database/migrations/2024_01_01_00003_create_logs_table.php diff --git a/database/migrations/5_create_attachments_table.php b/database/migrations/2024_01_01_00004_create_attachments_table.php similarity index 100% rename from database/migrations/5_create_attachments_table.php rename to database/migrations/2024_01_01_00004_create_attachments_table.php diff --git a/database/migrations/6_transform_logs_cc_bcc_array.php b/database/migrations/2024_01_01_00005_transform_logs_cc_bcc_array.php similarity index 100% rename from database/migrations/6_transform_logs_cc_bcc_array.php rename to database/migrations/2024_01_01_00005_transform_logs_cc_bcc_array.php diff --git a/database/migrations/7_add_tries_to_logs_table.php b/database/migrations/2024_01_01_00006_add_tries_to_logs_table.php similarity index 100% rename from database/migrations/7_add_tries_to_logs_table.php rename to database/migrations/2024_01_01_00006_add_tries_to_logs_table.php diff --git a/database/migrations/8_add_tags_metadata_to_logs_table.php b/database/migrations/2024_01_01_00007_add_tags_metadata_to_logs_table.php similarity index 100% rename from database/migrations/8_add_tags_metadata_to_logs_table.php rename to database/migrations/2024_01_01_00007_add_tags_metadata_to_logs_table.php diff --git a/database/migrations/9_add_tags_to_templates_table.php b/database/migrations/2024_01_01_00008_add_tags_to_templates_table.php similarity index 100% rename from database/migrations/9_add_tags_to_templates_table.php rename to database/migrations/2024_01_01_00008_add_tags_to_templates_table.php diff --git a/database/migrations/2024_08_27_074130_add_replyto_to_logs_table.php b/database/migrations/2024_08_27_074130_add_replyto_to_logs_table.php new file mode 100644 index 0000000..6894dc0 --- /dev/null +++ b/database/migrations/2024_08_27_074130_add_replyto_to_logs_table.php @@ -0,0 +1,21 @@ +json('replyTo')->nullable(); + }); + } + + public function down(): void + { + Schema::table('logs', function (Blueprint $table) { + $table->dropColumn('replyTo'); + }); + } +}; diff --git a/src/Actions/Logs/CreateFromGenericMail.php b/src/Actions/Logs/CreateFromGenericMail.php index fd63fd6..548ce65 100644 --- a/src/Actions/Logs/CreateFromGenericMail.php +++ b/src/Actions/Logs/CreateFromGenericMail.php @@ -32,6 +32,7 @@ public function run(GenericMailDto $genericMailDto): Log email: Config::get('mail.from.address') ), 'recipient' => $genericMailDto->recipient, + 'replyTo' => $genericMailDto->replyTo, 'cc' => $genericMailDto->cc, 'bcc' => $genericMailDto->bcc, 'error' => $genericMailDto->error, diff --git a/src/Actions/SendMail.php b/src/Actions/SendMail.php index 50b4c57..93e0f7b 100644 --- a/src/Actions/SendMail.php +++ b/src/Actions/SendMail.php @@ -120,6 +120,7 @@ protected function send(RecipientDto $recipient): void trigger: $this->params->trigger, sender: $this->params->sender, recipient: $recipient->email, + replyTo: $this->params->replyTo, cc: $recipient->cc, bcc: $recipient->bcc, subject: $this->params->subject, diff --git a/src/Dto/GenericMailDto.php b/src/Dto/GenericMailDto.php index e5883e3..47abc1a 100644 --- a/src/Dto/GenericMailDto.php +++ b/src/Dto/GenericMailDto.php @@ -21,6 +21,8 @@ class GenericMailDto extends DataTransferObject public ?ContactDto $sender; + public ?ContactDto $replyTo; + /** @var \MailCarrier\Dto\ContactDto[]|null */ public ?array $cc; diff --git a/src/Dto/SendMailDto.php b/src/Dto/SendMailDto.php index 495d337..201e1bd 100644 --- a/src/Dto/SendMailDto.php +++ b/src/Dto/SendMailDto.php @@ -19,6 +19,9 @@ class SendMailDto extends DataTransferObject #[CastWith(ContactStringCaster::class)] public ?ContactDto $sender; + #[CastWith(ContactStringCaster::class)] + public ?ContactDto $replyTo; + public ?string $recipient; /** @var \MailCarrier\Dto\ContactDto[]|null */ diff --git a/src/Http/Requests/SendMailRequest.php b/src/Http/Requests/SendMailRequest.php index 1ba75b0..5407513 100644 --- a/src/Http/Requests/SendMailRequest.php +++ b/src/Http/Requests/SendMailRequest.php @@ -26,6 +26,7 @@ public function rules(): array 'trigger' => 'sometimes|string|max:255', 'subject' => 'required|string|max:255', 'sender' => ['sometimes', new ContactRule], + 'replyTo' => ['sometimes', new ContactRule], 'cc' => 'sometimes|array', 'bcc' => 'sometimes|array', 'cc.*' => [new ContactRule], diff --git a/src/Mail/GenericMail.php b/src/Mail/GenericMail.php index 57859ef..4eef1d0 100644 --- a/src/Mail/GenericMail.php +++ b/src/Mail/GenericMail.php @@ -63,6 +63,10 @@ public function build(): self $this->params->subject, fn (GenericMail $mail) => $mail->subject($this->params->subject) ) + ->when( + $this->params->replyTo, + fn (GenericMail $mail) => $mail->replyTo($this->params->replyTo->email, $this->params->replyTo->name) + ) ->when( $this->params->cc, fn (GenericMail $mail) => $mail->cc($this->params->cc) diff --git a/src/MailCarrierServiceProvider.php b/src/MailCarrierServiceProvider.php index 1d6bb9c..86eee02 100644 --- a/src/MailCarrierServiceProvider.php +++ b/src/MailCarrierServiceProvider.php @@ -47,15 +47,16 @@ public function configurePackage(Package $package): void RetryCommand::class, ]) ->hasMigrations([ - '1_create_users_table', - '2_create_layouts_table', - '3_create_templates_table', - '4_create_logs_table', - '5_create_attachments_table', - '6_transform_logs_cc_bcc_array', - '7_add_tries_to_logs_table', - '8_add_tags_metadata_to_logs_table', - '9_add_tags_to_templates_table', + '2024_01_01_00000_create_users_table', + '2024_01_01_00001_create_layouts_table', + '2024_01_01_00002_create_templates_table', + '2024_01_01_00003_create_logs_table', + '2024_01_01_00004_create_attachments_table', + '2024_01_01_00005_transform_logs_cc_bcc_array', + '2024_01_01_00006_add_tries_to_logs_table', + '2024_01_01_00007_add_tags_metadata_to_logs_table', + '2024_01_01_00008_add_tags_to_templates_table', + '2024_08_27_074130_add_replyto_to_logs_table', ]) ->runsMigrations(); } diff --git a/src/Models/Log.php b/src/Models/Log.php index 5d342f0..4f8603a 100644 --- a/src/Models/Log.php +++ b/src/Models/Log.php @@ -22,6 +22,7 @@ * @property string|null $trigger * @property string|null $subject * @property \MailCarrier\Dto\ContactDto $sender + * @property \MailCarrier\Dto\ContactDto|null $replyTo * @property \Illuminate\Support\Collection|null $cc * @property \Illuminate\Support\Collection|null $bcc * @property string $recipient @@ -67,6 +68,7 @@ class Log extends Model 'bcc', 'sender', 'recipient', + 'replyTo', 'template_frozen', 'variables', 'error', @@ -89,6 +91,7 @@ class Log extends Model protected $casts = [ 'status' => LogStatus::class, 'sender' => ContactDto::class, + 'replyTo' => ContactDto::class, 'cc' => CollectionOfContacts::class, 'bcc' => CollectionOfContacts::class, 'template_frozen' => LogTemplateDto::class, diff --git a/tests/Feature/Logs/GetTriggersTest.php b/tests/Feature/Logs/GetTriggersTest.php index ea26c57..7533368 100644 --- a/tests/Feature/Logs/GetTriggersTest.php +++ b/tests/Feature/Logs/GetTriggersTest.php @@ -20,5 +20,8 @@ 'trigger' => 'bar', ]); - expect(GetTriggers::resolve()->run())->toEqualCanonicalizing(['foo', 'bar']); + expect(GetTriggers::resolve()->run())->toEqualCanonicalizing([ + 'foo' => 'foo', + 'bar' => 'bar', + ]); }); diff --git a/tests/Feature/SendMailTest.php b/tests/Feature/SendMailTest.php index 2e30737..f6b0d3a 100644 --- a/tests/Feature/SendMailTest.php +++ b/tests/Feature/SendMailTest.php @@ -1324,3 +1324,52 @@ && $mail->hasMetadata('meta2', 'value2'); }); }); + +it('accepts a replyTo as string', function () { + Template::factory()->create([ + 'slug' => 'welcome', + ]); + + postJson(route('mailcarrier.send'), [ + 'enqueue' => false, + 'template' => 'welcome', + 'subject' => 'Welcome!', + 'recipient' => 'recipient@example.org', + 'replyTo' => 'reply@example.org', + ])->assertOk(); + + Mail::assertSent(GenericMail::class, 1); + Mail::assertSent(GenericMail::class, function (GenericMail $mail) { + $mail->build(); + + return $mail->hasTo('recipient@example.org') + && $mail->hasSubject('Welcome!') + && $mail->hasReplyTo('reply@example.org'); + }); +}); + +it('accepts a replyTo as object', function () { + Template::factory()->create([ + 'slug' => 'welcome', + ]); + + postJson(route('mailcarrier.send'), [ + 'enqueue' => false, + 'template' => 'welcome', + 'subject' => 'Welcome!', + 'recipient' => 'recipient@example.org', + 'replyTo' => [ + 'email' => 'reply@example.org', + 'name' => 'Reply', + ], + ])->assertOk(); + + Mail::assertSent(GenericMail::class, 1); + Mail::assertSent(GenericMail::class, function (GenericMail $mail) { + $mail->build(); + + return $mail->hasTo('recipient@example.org') + && $mail->hasSubject('Welcome!') + && $mail->hasReplyTo('reply@example.org', 'Reply'); + }); +});