Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[10.x] Adds inline attachments support for "notifications" markdown mailables #47643

Merged
merged 19 commits into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 45 additions & 6 deletions src/Illuminate/Notifications/Channels/MailChannel.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Illuminate\Notifications\Channels;

use Illuminate\Config\Repository as ConfigRepository;
use Illuminate\Container\Container;
use Illuminate\Contracts\Mail\Factory as MailFactory;
use Illuminate\Contracts\Mail\Mailable;
use Illuminate\Contracts\Queue\ShouldQueue;
Expand Down Expand Up @@ -95,16 +97,53 @@ protected function buildView($message)
return $message->view;
}

if (property_exists($message, 'theme') && ! is_null($message->theme)) {
$this->markdown->theme($message->theme);
}

return [
'html' => $this->markdown->render($message->markdown, $message->data()),
'text' => $this->markdown->renderText($message->markdown, $message->data()),
'html' => $this->buildMarkdownHtml($message),
'text' => $this->buildMarkdownText($message),
];
}

/**
* Build the HTML view for a Markdown message.
*
* @param \Illuminate\Notifications\Messages\MailMessage $message
* @return \Closure
*/
protected function buildMarkdownHtml($message)
{
return fn ($data) => $this->markdownRenderer($message)->render(
$message->markdown, array_merge($data, $message->data()),
);
}

/**
* Build the text view for a Markdown message.
*
* @param \Illuminate\Notifications\Messages\MailMessage $message
* @return \Closure
*/
protected function buildMarkdownText($message)
{
return fn ($data) => $this->markdownRenderer($message)->renderText(
$message->markdown, array_merge($data, $message->data()),
);
}

/**
* Get the Markdown implementation.
*
* @param \Illuminate\Notifications\Messages\MailMessage $message
* @return \Illuminate\Mail\Markdown
*/
protected function markdownRenderer($message)
{
$config = Container::getInstance()->get(ConfigRepository::class);

$theme = $message->theme ?? $config->get('mail.markdown.theme', 'default');

return $this->markdown->theme($theme);
}

/**
* Get additional meta-data to pass along with the view data.
*
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
body{color: test;}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Embed content: {{ $message->embed(__FILE__) }}
206 changes: 136 additions & 70 deletions tests/Integration/Notifications/SendingMailNotificationsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,42 +74,108 @@ public function testMailIsSent()
'email' => 'taylor@laravel.com',
]);

$this->markdown->shouldReceive('theme')->twice()->with('default')->andReturn($this->markdown);
$this->markdown->shouldReceive('render')->once()->andReturn('htmlContent');
$this->markdown->shouldReceive('renderText')->once()->andReturn('textContent');

$this->mailer->shouldReceive('send')->once()->with(
['html' => 'htmlContent', 'text' => 'textContent'],
array_merge($notification->toMail($user)->toArray(), [
'__laravel_notification_id' => $notification->id,
'__laravel_notification' => get_class($notification),
'__laravel_notification_queued' => false,
]),
m::on(function ($closure) {
$message = m::mock(Message::class);
$this->setMailerSendAssertions($notification, $user, function ($closure) {
$message = m::mock(Message::class);

$message->shouldReceive('to')->once()->with(['taylor@laravel.com']);
$message->shouldReceive('to')->once()->with(['taylor@laravel.com']);

$message->shouldReceive('cc')->once()->with('cc@deepblue.com', 'cc');
$message->shouldReceive('cc')->once()->with('cc@deepblue.com', 'cc');

$message->shouldReceive('bcc')->once()->with('bcc@deepblue.com', 'bcc');
$message->shouldReceive('bcc')->once()->with('bcc@deepblue.com', 'bcc');

$message->shouldReceive('from')->once()->with('jack@deepblue.com', 'Jacques Mayol');
$message->shouldReceive('from')->once()->with('jack@deepblue.com', 'Jacques Mayol');

$message->shouldReceive('replyTo')->once()->with('jack@deepblue.com', 'Jacques Mayol');
$message->shouldReceive('replyTo')->once()->with('jack@deepblue.com', 'Jacques Mayol');

$message->shouldReceive('subject')->once()->with('Test Mail Notification');
$message->shouldReceive('subject')->once()->with('Test Mail Notification');

$message->shouldReceive('priority')->once()->with(1);
$message->shouldReceive('priority')->once()->with(1);

$closure($message);
$closure($message);

return true;
})
);
return true;
});

$user->notify($notification);
}

public function testMailIsSentWithCustomTheme()
{
$notification = new TestMailNotificationWithCustomTheme;
$notification->id = Str::uuid()->toString();

$user = NotifiableUser::forceCreate([
'email' => 'taylor@laravel.com',
]);

$this->markdown->shouldReceive('theme')->twice()->with('my-custom-theme')->andReturn($this->markdown);
$this->markdown->shouldReceive('render')->once()->andReturn('htmlContent');
$this->markdown->shouldReceive('renderText')->once()->andReturn('textContent');

$this->setMailerSendAssertions($notification, $user, function ($closure) {
$message = m::mock(Message::class);

$message->shouldReceive('to')->once()->with(['taylor@laravel.com']);

$message->shouldReceive('cc')->once()->with('cc@deepblue.com', 'cc');

$message->shouldReceive('bcc')->once()->with('bcc@deepblue.com', 'bcc');

$message->shouldReceive('from')->once()->with('jack@deepblue.com', 'Jacques Mayol');

$message->shouldReceive('replyTo')->once()->with('jack@deepblue.com', 'Jacques Mayol');

$message->shouldReceive('subject')->once()->with('Test Mail Notification With Custom Theme');

$message->shouldReceive('priority')->once()->with(1);

$closure($message);

return true;
});

$user->notify($notification);
}

private function setMailerSendAssertions(
Notification $notification,
NotifiableUser $user,
callable $callbackExpectationClosure
) {
$this->mailer->shouldReceive('send')->once()->withArgs(function (...$args) use ($notification, $user, $callbackExpectationClosure) {
$viewArray = $args[0];

if (! m::on(fn ($closure) => $closure([]) === 'htmlContent')->match($viewArray['html'])) {
return false;
}

if (! m::on(fn ($closure) => $closure([]) === 'textContent')->match($viewArray['text'])) {
return false;
}

$data = $args[1];

$expected = array_merge($notification->toMail($user)->toArray(), [
'__laravel_notification_id' => $notification->id,
'__laravel_notification' => get_class($notification),
'__laravel_notification_queued' => false,
]);

if (array_keys($data) !== array_keys($expected)) {
return false;
}
if (array_values($data) !== array_values($expected)) {
return false;
}

return m::on($callbackExpectationClosure)->match($args[2]);
});
}

public function testMailIsSentToNamedAddress()
{
$notification = new TestMailNotification;
Expand All @@ -120,38 +186,31 @@ public function testMailIsSentToNamedAddress()
'name' => 'Taylor Otwell',
]);

$this->markdown->shouldReceive('theme')->twice()->with('default')->andReturn($this->markdown);
$this->markdown->shouldReceive('render')->once()->andReturn('htmlContent');
$this->markdown->shouldReceive('renderText')->once()->andReturn('textContent');

$this->mailer->shouldReceive('send')->once()->with(
['html' => 'htmlContent', 'text' => 'textContent'],
array_merge($notification->toMail($user)->toArray(), [
'__laravel_notification_id' => $notification->id,
'__laravel_notification' => get_class($notification),
'__laravel_notification_queued' => false,
]),
m::on(function ($closure) {
$message = m::mock(Message::class);
$this->setMailerSendAssertions($notification, $user, function ($closure) {
$message = m::mock(Message::class);

$message->shouldReceive('to')->once()->with(['taylor@laravel.com' => 'Taylor Otwell', 'foo_taylor@laravel.com']);
$message->shouldReceive('to')->once()->with(['taylor@laravel.com' => 'Taylor Otwell', 'foo_taylor@laravel.com']);

$message->shouldReceive('cc')->once()->with('cc@deepblue.com', 'cc');
$message->shouldReceive('cc')->once()->with('cc@deepblue.com', 'cc');

$message->shouldReceive('bcc')->once()->with('bcc@deepblue.com', 'bcc');
$message->shouldReceive('bcc')->once()->with('bcc@deepblue.com', 'bcc');

$message->shouldReceive('from')->once()->with('jack@deepblue.com', 'Jacques Mayol');
$message->shouldReceive('from')->once()->with('jack@deepblue.com', 'Jacques Mayol');

$message->shouldReceive('replyTo')->once()->with('jack@deepblue.com', 'Jacques Mayol');
$message->shouldReceive('replyTo')->once()->with('jack@deepblue.com', 'Jacques Mayol');

$message->shouldReceive('subject')->once()->with('Test Mail Notification');
$message->shouldReceive('subject')->once()->with('Test Mail Notification');

$message->shouldReceive('priority')->once()->with(1);
$message->shouldReceive('priority')->once()->with(1);

$closure($message);
$closure($message);

return true;
})
);
return true;
});

$user->notify($notification);
}
Expand All @@ -165,28 +224,21 @@ public function testMailIsSentWithSubject()
'email' => 'taylor@laravel.com',
]);

$this->markdown->shouldReceive('theme')->with('default')->twice()->andReturn($this->markdown);
$this->markdown->shouldReceive('render')->once()->andReturn('htmlContent');
$this->markdown->shouldReceive('renderText')->once()->andReturn('textContent');

$this->mailer->shouldReceive('send')->once()->with(
['html' => 'htmlContent', 'text' => 'textContent'],
array_merge($notification->toMail($user)->toArray(), [
'__laravel_notification_id' => $notification->id,
'__laravel_notification' => get_class($notification),
'__laravel_notification_queued' => false,
]),
m::on(function ($closure) {
$message = m::mock(Message::class);
$this->setMailerSendAssertions($notification, $user, function ($closure) {
$message = m::mock(Message::class);

$message->shouldReceive('to')->once()->with(['taylor@laravel.com']);
$message->shouldReceive('to')->once()->with(['taylor@laravel.com']);

$message->shouldReceive('subject')->once()->with('mail custom subject');
$message->shouldReceive('subject')->once()->with('mail custom subject');

$closure($message);
$closure($message);

return true;
})
);
return true;
});

$user->notify($notification);
}
Expand All @@ -200,28 +252,21 @@ public function testMailIsSentToMultipleAddresses()
'email' => 'taylor@laravel.com',
]);

$this->markdown->shouldReceive('theme')->with('default')->twice()->andReturn($this->markdown);
$this->markdown->shouldReceive('render')->once()->andReturn('htmlContent');
$this->markdown->shouldReceive('renderText')->once()->andReturn('textContent');

$this->mailer->shouldReceive('send')->once()->with(
['html' => 'htmlContent', 'text' => 'textContent'],
array_merge($notification->toMail($user)->toArray(), [
'__laravel_notification_id' => $notification->id,
'__laravel_notification' => get_class($notification),
'__laravel_notification_queued' => false,
]),
m::on(function ($closure) {
$message = m::mock(Message::class);
$this->setMailerSendAssertions($notification, $user, function ($closure) {
$message = m::mock(Message::class);

$message->shouldReceive('to')->once()->with(['foo_taylor@laravel.com', 'bar_taylor@laravel.com']);
$message->shouldReceive('to')->once()->with(['foo_taylor@laravel.com', 'bar_taylor@laravel.com']);

$message->shouldReceive('subject')->once()->with('mail custom subject');
$message->shouldReceive('subject')->once()->with('mail custom subject');

$closure($message);
$closure($message);

return true;
})
);
return true;
});

$user->notify($notification);
}
Expand Down Expand Up @@ -457,3 +502,24 @@ public function toMail($notifiable)
->view([null, 'plain']);
}
}

class TestMailNotificationWithCustomTheme extends Notification
{
public function via($notifiable)
{
return [MailChannel::class];
}

public function toMail($notifiable)
{
return (new MailMessage)
->priority(1)
->cc('cc@deepblue.com', 'cc')
->bcc('bcc@deepblue.com', 'bcc')
->from('jack@deepblue.com', 'Jacques Mayol')
->replyTo('jack@deepblue.com', 'Jacques Mayol')
->line('The introduction to the notification.')
->theme('my-custom-theme')
->mailer('foo');
}
}
Loading