diff --git a/app/Domains/MailTest/Controllers/MailTestController.php b/app/Domains/MailTest/Controllers/MailTestController.php index 6e5ce5b..ee0f07e 100644 --- a/app/Domains/MailTest/Controllers/MailTestController.php +++ b/app/Domains/MailTest/Controllers/MailTestController.php @@ -4,6 +4,7 @@ namespace App\Domains\MailTest\Controllers; use App\Domains\MailTest\Requests\SendTestMailRequest; use App\Domains\MailTest\Services\MailTestService; +use App\Domains\Tenant\Models\Tenant; use App\Http\Controllers\Controller; use Illuminate\Http\JsonResponse; @@ -13,10 +14,15 @@ class MailTestController extends Controller protected MailTestService $mailTestService, ) {} - public function __invoke(SendTestMailRequest $request): JsonResponse + public function __invoke(SendTestMailRequest $request, string $tenantCode): JsonResponse { + $tenant = Tenant::query() + ->where('codigo', $tenantCode) + ->firstOrFail(); + return response()->json( $this->mailTestService->send( + $tenant, $request->validated('to'), $request->validated('subject'), $request->validated('message'), diff --git a/app/Domains/MailTest/Mailables/TestMail.php b/app/Domains/MailTest/Mailables/TestMail.php index 182f00f..fd0e1fb 100644 --- a/app/Domains/MailTest/Mailables/TestMail.php +++ b/app/Domains/MailTest/Mailables/TestMail.php @@ -2,6 +2,7 @@ namespace App\Domains\MailTest\Mailables; +use App\Domains\Tenant\Models\Tenant; use Illuminate\Bus\Queueable; use Illuminate\Mail\Mailable; use Illuminate\Mail\Mailables\Content; @@ -15,6 +16,7 @@ class TestMail extends Mailable public function __construct( public readonly string $mailSubject, public readonly string $mailMessage, + public readonly Tenant $tenant, ) {} public function envelope(): Envelope @@ -24,14 +26,15 @@ class TestMail extends Mailable public function content(): Content { - $message = nl2br(e($this->mailMessage)); + $this->tenant->loadMissing(['headerLogo', 'footerLogo']); return new Content( - htmlString: <<Prueba de correo de Shopit -

{$message}

-

Si recibiste este mensaje, la configuracion de correo funciona correctamente.

- HTML, + view: 'mail.test', + with: [ + 'tenant' => $this->tenant, + 'headerLogoUrl' => $this->tenant->headerLogo?->getTemporaryUrl(1440), + 'footerLogoUrl' => $this->tenant->footerLogo?->getTemporaryUrl(1440), + ], ); } } diff --git a/app/Domains/MailTest/Services/MailTestService.php b/app/Domains/MailTest/Services/MailTestService.php index e1201f3..e3793b4 100644 --- a/app/Domains/MailTest/Services/MailTestService.php +++ b/app/Domains/MailTest/Services/MailTestService.php @@ -3,6 +3,7 @@ namespace App\Domains\MailTest\Services; use App\Domains\MailTest\Mailables\TestMail; +use App\Domains\Tenant\Models\Tenant; use Illuminate\Support\Facades\Mail; class MailTestService @@ -10,16 +11,17 @@ class MailTestService /** * @return array */ - public function send(string $recipient, ?string $subject = null, ?string $message = null): array + public function send(Tenant $tenant, string $recipient, ?string $subject = null, ?string $message = null): array { $subject ??= 'Prueba de correo de Shopit'; $message ??= 'Este es un correo de prueba enviado desde Shopit.'; - Mail::to($recipient)->send(new TestMail($subject, $message)); + Mail::to($recipient)->send(new TestMail($subject, $message, $tenant)); return [ 'message' => 'Correo de prueba enviado correctamente.', 'recipient' => $recipient, + 'tenant_code' => $tenant->codigo, 'mailer' => (string) config('mail.default'), 'sent_at' => now()->toIso8601String(), ]; diff --git a/app/Domains/MailTest/routes/api.php b/app/Domains/MailTest/routes/api.php index d26b474..a75d512 100644 --- a/app/Domains/MailTest/routes/api.php +++ b/app/Domains/MailTest/routes/api.php @@ -3,4 +3,4 @@ use App\Domains\MailTest\Controllers\MailTestController; use Illuminate\Support\Facades\Route; -Route::post('mail-test/send', MailTestController::class); +Route::post('{tenant_code}/mail-test/send', MailTestController::class); diff --git a/resources/views/components/mail/branded-layout.blade.php b/resources/views/components/mail/branded-layout.blade.php new file mode 100644 index 0000000..c612670 --- /dev/null +++ b/resources/views/components/mail/branded-layout.blade.php @@ -0,0 +1,49 @@ +@props(['tenant', 'headerLogoUrl' => null, 'footerLogoUrl' => null]) + + + + + + + + {{ $tenant->nombre }} + + + + + + + +
+ + + + + + + + + + + +
+ + diff --git a/resources/views/mail/test.blade.php b/resources/views/mail/test.blade.php new file mode 100644 index 0000000..ba5d695 --- /dev/null +++ b/resources/views/mail/test.blade.php @@ -0,0 +1,11 @@ + +

+ Prueba de correo de Shopit +

+ +

{!! nl2br(e($mailMessage)) !!}

+ +

+ Si recibiste este mensaje, la configuración de correo funciona correctamente. +

+
diff --git a/tests/Feature/MailTest/MailTestControllerTest.php b/tests/Feature/MailTest/MailTestControllerTest.php index bfc2bcc..0b67cf2 100644 --- a/tests/Feature/MailTest/MailTestControllerTest.php +++ b/tests/Feature/MailTest/MailTestControllerTest.php @@ -2,17 +2,24 @@ namespace Tests\Feature\MailTest; +use App\Domains\Attachable\Enums\AttachmentType; +use App\Domains\Attachable\Models\Attachment; use App\Domains\MailTest\Mailables\TestMail; +use App\Domains\Tenant\Models\Tenant; +use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\Mail; use Tests\TestCase; class MailTestControllerTest extends TestCase { + use RefreshDatabase; + public function test_it_sends_a_test_email(): void { Mail::fake(); + $tenant = $this->createTenant(); - $response = $this->postJson('/api/mail-test/send', [ + $response = $this->postJson('/api/acme/mail-test/send', [ 'to' => 'recipient@example.com', 'subject' => 'SMTP test', 'message' => 'Test message', @@ -21,21 +28,24 @@ class MailTestControllerTest extends TestCase $response->assertOk() ->assertJsonPath('message', 'Correo de prueba enviado correctamente.') ->assertJsonPath('recipient', 'recipient@example.com') + ->assertJsonPath('tenant_code', 'acme') ->assertJsonPath('mailer', 'array') ->assertJsonStructure(['sent_at']); - Mail::assertSent(TestMail::class, function (TestMail $mail): bool { + Mail::assertSent(TestMail::class, function (TestMail $mail) use ($tenant): bool { return $mail->hasTo('recipient@example.com') && $mail->mailSubject === 'SMTP test' - && $mail->mailMessage === 'Test message'; + && $mail->mailMessage === 'Test message' + && $mail->tenant->is($tenant); }); } public function test_it_uses_default_content_when_optional_fields_are_omitted(): void { Mail::fake(); + $this->createTenant(); - $this->postJson('/api/mail-test/send', [ + $this->postJson('/api/acme/mail-test/send', [ 'to' => 'recipient@example.com', ])->assertOk(); @@ -48,12 +58,110 @@ class MailTestControllerTest extends TestCase public function test_it_validates_the_recipient(): void { Mail::fake(); + $this->createTenant(); - $this->postJson('/api/mail-test/send', [ + $this->postJson('/api/acme/mail-test/send', [ 'to' => 'invalid-email', ])->assertUnprocessable() ->assertJsonValidationErrors(['to']); Mail::assertNothingSent(); } + + public function test_the_mail_template_uses_the_tenant_branding(): void + { + $tenant = new Tenant([ + 'codigo' => 'tenant-store', + 'nombre' => 'Tenant Store', + 'primary_color' => '#778899', + 'header_bg_color' => '#112233', + 'footer_bg_color' => '#445566', + ]); + + $tenant->setRelation('headerLogo', new class extends Attachment + { + public function getTemporaryUrl(int $expiresInMinutes = 10): string + { + return 'https://example.com/header-logo.png'; + } + }); + $tenant->setRelation('footerLogo', new class extends Attachment + { + public function getTemporaryUrl(int $expiresInMinutes = 10): string + { + return 'https://example.com/footer-logo.png'; + } + }); + + $mail = new TestMail( + 'Branded email', + 'Tenant message', + $tenant, + ); + + $html = $mail->render(); + + $this->assertStringContainsString('https://example.com/header-logo.png', $html); + $this->assertStringContainsString('https://example.com/footer-logo.png', $html); + $this->assertStringContainsString('background-color: #112233', $html); + $this->assertStringContainsString('background-color: #445566', $html); + $this->assertStringContainsString('color: #778899', $html); + $this->assertStringContainsString('Tenant Store', $html); + $this->assertStringContainsString('Tenant message', $html); + } + + public function test_it_returns_not_found_for_an_unknown_tenant(): void + { + Mail::fake(); + + $this->postJson('/api/unknown/mail-test/send', [ + 'to' => 'recipient@example.com', + ])->assertNotFound(); + + Mail::assertNothingSent(); + } + + public function test_it_does_not_resolve_the_tenant_by_id(): void + { + Mail::fake(); + $tenant = $this->createTenant(); + + $this->postJson("/api/{$tenant->id}/mail-test/send", [ + 'to' => 'recipient@example.com', + ])->assertNotFound(); + + Mail::assertNothingSent(); + } + + private function createTenant(): Tenant + { + $headerLogo = Attachment::create([ + 'path' => 'tenants/header.png', + 'filename' => 'header.png', + 'type' => AttachmentType::Image, + 'mime_type' => 'image/png', + 'extension' => 'png', + ]); + $footerLogo = Attachment::create([ + 'path' => 'tenants/footer.png', + 'filename' => 'footer.png', + 'type' => AttachmentType::Image, + 'mime_type' => 'image/png', + 'extension' => 'png', + ]); + + return Tenant::create([ + 'codigo' => 'acme', + 'nombre' => 'Acme Store', + 'dominio' => 'acme.example.com', + 'primary_color' => '#778899', + 'secondary_color' => '#64748b', + 'danger_color' => '#dc2626', + 'success_color' => '#16a34a', + 'header_bg_color' => '#112233', + 'footer_bg_color' => '#445566', + 'header_logo_id' => $headerLogo->id, + 'footer_logo_id' => $footerLogo->id, + ]); + } }