Added email notification on new private messages
This commit is contained in:
parent
a464682b47
commit
fb8c05edad
|
@ -69,6 +69,9 @@ return [
|
|||
// callable like [$instance, 'method'] or 'function'
|
||||
// or $function
|
||||
// ]
|
||||
|
||||
'message.created' => \Engelsystem\Events\Listener\Messages::class . '@created',
|
||||
|
||||
'news.created' => \Engelsystem\Events\Listener\News::class . '@created',
|
||||
|
||||
'oauth2.login' => \Engelsystem\Events\Listener\OAuth2::class . '@login',
|
||||
|
|
|
@ -18,6 +18,7 @@ class SettingsFactory extends Factory
|
|||
'language' => $this->faker->locale(),
|
||||
'theme' => $this->faker->numberBetween(1, 20),
|
||||
'email_human' => $this->faker->boolean(),
|
||||
'email_messages' => $this->faker->boolean(),
|
||||
'email_goody' => $this->faker->boolean(),
|
||||
'email_shiftinfo' => $this->faker->boolean(),
|
||||
'email_news' => $this->faker->boolean(),
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class AddEmailMessagesToUsersSettings extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->schema->table('users_settings', function (Blueprint $table): void {
|
||||
$table->boolean('email_messages')->default(false)->after('email_human');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->schema->table('users_settings', function (Blueprint $table): void {
|
||||
$table->dropColumn('email_messages');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -57,6 +57,7 @@ function guest_register()
|
|||
$pronoun = '';
|
||||
$email_shiftinfo = false;
|
||||
$email_by_human_allowed = false;
|
||||
$email_messages = false;
|
||||
$email_news = false;
|
||||
$email_goody = false;
|
||||
$tshirt_size = '';
|
||||
|
@ -155,6 +156,10 @@ function guest_register()
|
|||
$email_by_human_allowed = true;
|
||||
}
|
||||
|
||||
if ($request->has('email_messages')) {
|
||||
$email_messages = true;
|
||||
}
|
||||
|
||||
if ($request->has('email_news')) {
|
||||
$email_news = true;
|
||||
}
|
||||
|
@ -263,6 +268,7 @@ function guest_register()
|
|||
'language' => $session->get('locale'),
|
||||
'theme' => config('theme'),
|
||||
'email_human' => $email_by_human_allowed,
|
||||
'email_messages' => $email_messages,
|
||||
'email_goody' => $email_goody,
|
||||
'email_shiftinfo' => $email_shiftinfo,
|
||||
'email_news' => $email_news,
|
||||
|
@ -434,6 +440,11 @@ function guest_register()
|
|||
__('Notify me of new news'),
|
||||
$email_news
|
||||
),
|
||||
form_checkbox(
|
||||
'email_messages',
|
||||
__('settings.profile.email_messages'),
|
||||
$email_messages
|
||||
),
|
||||
form_checkbox(
|
||||
'email_by_human_allowed',
|
||||
__('Allow heaven angels to contact you by e-mail.'),
|
||||
|
|
|
@ -166,6 +166,12 @@ msgstr "Es gibt eine neue News: %1$s"
|
|||
msgid "notification.news.new.text"
|
||||
msgstr "Du kannst sie dir unter %3$s anschauen."
|
||||
|
||||
msgid "notification.messages.new"
|
||||
msgstr "Neue private Nachricht von %s"
|
||||
|
||||
msgid "notification.messages.new.text"
|
||||
msgstr "Du hast eine neue private Nachricht von %s bekommen. Du kannst sie dir unter %s anschauen."
|
||||
|
||||
msgid "notification.angeltype.confirmed"
|
||||
msgstr "Du wurdest als %s bestätigt"
|
||||
|
||||
|
|
|
@ -2999,6 +2999,9 @@ msgstr "Das %s darf mir E-Mails senden (z.B. wenn sich meine Schichten ändern).
|
|||
msgid "settings.profile.email_news"
|
||||
msgstr "Benachrichtige mich bei neuen News."
|
||||
|
||||
msgid "settings.profile.email_messages"
|
||||
msgstr "Benachrichtige mich bei neuen privaten Nachrichten."
|
||||
|
||||
msgid "settings.profile.email_by_human_allowed"
|
||||
msgstr "Erlaube Himmel-Engeln dich per Mail zu kontaktieren."
|
||||
|
||||
|
|
|
@ -165,6 +165,12 @@ msgstr "A new news is available: %1$s"
|
|||
msgid "notification.news.new.text"
|
||||
msgstr "You can watch it at %3$s"
|
||||
|
||||
msgid "notification.messages.new"
|
||||
msgstr "New private message from %s"
|
||||
|
||||
msgid "notification.messages.new.text"
|
||||
msgstr "you've got a new private message from %s. You can view it under %s"
|
||||
|
||||
msgid "notification.angeltype.confirmed"
|
||||
msgstr "You have been confirmed as an %s"
|
||||
|
||||
|
|
|
@ -268,6 +268,9 @@ msgstr "The %s is allowed to send me an e-mail (e.g. when my shifts change)."
|
|||
msgid "settings.profile.email_news"
|
||||
msgstr "Notify me of new news."
|
||||
|
||||
msgid "settings.profile.email_messages"
|
||||
msgstr "Notify me on new private messages."
|
||||
|
||||
msgid "settings.profile.email_by_human_allowed"
|
||||
msgstr "Allow heaven angels to contact you by e-mail."
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{% extends "emails/mail.twig" %}
|
||||
|
||||
{% block introduction %}
|
||||
{% endblock %}
|
||||
|
||||
{% block message %}
|
||||
{{ __('notification.messages.new.text', [sender, url('/messages/' ~ send_message.sender.id)]) }}
|
||||
{% endblock %}
|
|
@ -117,6 +117,11 @@
|
|||
__('settings.profile.email_news'),
|
||||
user.settings.email_news
|
||||
) }}
|
||||
{{ f.checkbox(
|
||||
'email_messages',
|
||||
__('settings.profile.email_messages'),
|
||||
user.settings.email_messages
|
||||
) }}
|
||||
{{ f.checkbox(
|
||||
'email_human',
|
||||
__('settings.profile.email_by_human_allowed'),
|
||||
|
|
|
@ -149,6 +149,8 @@ class MessagesController extends BaseController
|
|||
$newMessage->read = $otherUser->id == $currentUser->id; // if its to myself, I obviously read it.
|
||||
$newMessage->save();
|
||||
|
||||
event('message.created', ['message' => $newMessage]);
|
||||
|
||||
return $this->redirect->to('/messages/' . $otherUser->id . '#newest');
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ class SettingsController extends BaseController
|
|||
$user->settings->email_shiftinfo = $data['email_shiftinfo'] ?: false;
|
||||
$user->settings->email_news = $data['email_news'] ?: false;
|
||||
$user->settings->email_human = $data['email_human'] ?: false;
|
||||
$user->settings->email_messages = $data['email_messages'] ?: false;
|
||||
|
||||
if (config('enable_goody')) {
|
||||
$user->settings->email_goody = $data['email_goody'] ?: false;
|
||||
|
@ -275,6 +276,7 @@ class SettingsController extends BaseController
|
|||
'email_shiftinfo' => 'optional|checked',
|
||||
'email_news' => 'optional|checked',
|
||||
'email_human' => 'optional|checked',
|
||||
'email_messages' => 'optional|checked',
|
||||
'email_goody' => 'optional|checked',
|
||||
];
|
||||
if (config('enable_planned_arrival')) {
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Events\Listener;
|
||||
|
||||
use Engelsystem\Mail\EngelsystemMailer;
|
||||
use Engelsystem\Models\Message;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Mailer\Exception\TransportException;
|
||||
|
||||
class Messages
|
||||
{
|
||||
public function __construct(
|
||||
protected LoggerInterface $log,
|
||||
protected EngelsystemMailer $mailer
|
||||
) {
|
||||
}
|
||||
|
||||
public function created(Message $message): void
|
||||
{
|
||||
if (!$message->receiver->settings->email_messages) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sendMail($message, $message->receiver, 'notification.messages.new', 'emails/messages-new');
|
||||
}
|
||||
|
||||
private function sendMail(Message $message, User $user, string $subject, string $template): void
|
||||
{
|
||||
try {
|
||||
$this->mailer->sendViewTranslated(
|
||||
$user,
|
||||
$subject,
|
||||
$template,
|
||||
['sender' => $message->sender->name, 'send_message' => $message, 'username' => $user->name]
|
||||
);
|
||||
} catch (TransportException $e) {
|
||||
$this->log->error(
|
||||
'Unable to send email "{title}" to user {user} with {exception}',
|
||||
['title' => $subject, 'user' => $user->name, 'exception' => $e]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
|
|||
* @property string $language
|
||||
* @property int $theme
|
||||
* @property bool $email_human
|
||||
* @property bool $email_messages
|
||||
* @property bool $email_goody
|
||||
* @property bool $email_shiftinfo
|
||||
* @property bool $email_news
|
||||
|
@ -19,6 +20,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
|
|||
* @method static QueryBuilder|Settings[] whereLanguage($value)
|
||||
* @method static QueryBuilder|Settings[] whereTheme($value)
|
||||
* @method static QueryBuilder|Settings[] whereEmailHuman($value)
|
||||
* @method static QueryBuilder|Settings[] whereEmailMessages($value)
|
||||
* @method static QueryBuilder|Settings[] whereEmailGoody($value)
|
||||
* @method static QueryBuilder|Settings[] whereEmailShiftinfo($value)
|
||||
* @method static QueryBuilder|Settings[] whereEmailNews($value)
|
||||
|
@ -34,6 +36,7 @@ class Settings extends HasUserModel
|
|||
/** @var array<string, bool> Default attributes */
|
||||
protected $attributes = [ // phpcs:ignore
|
||||
'email_human' => false,
|
||||
'email_messages' => false,
|
||||
'email_goody' => false,
|
||||
'email_shiftinfo' => false,
|
||||
'email_news' => false,
|
||||
|
@ -50,6 +53,7 @@ class Settings extends HasUserModel
|
|||
'language',
|
||||
'theme',
|
||||
'email_human',
|
||||
'email_messages',
|
||||
'email_goody',
|
||||
'email_shiftinfo',
|
||||
'email_news',
|
||||
|
@ -61,6 +65,7 @@ class Settings extends HasUserModel
|
|||
'user_id' => 'integer',
|
||||
'theme' => 'integer',
|
||||
'email_human' => 'boolean',
|
||||
'email_messages' => 'boolean',
|
||||
'email_goody' => 'boolean',
|
||||
'email_shiftinfo' => 'boolean',
|
||||
'email_news' => 'boolean',
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Engelsystem\Test\Unit\Controllers;
|
|||
|
||||
use Carbon\Carbon;
|
||||
use Engelsystem\Controllers\MessagesController;
|
||||
use Engelsystem\Events\EventDispatcher;
|
||||
use Engelsystem\Helpers\Authenticator;
|
||||
use Engelsystem\Http\Exceptions\HttpForbidden;
|
||||
use Engelsystem\Http\Exceptions\ValidationException;
|
||||
|
@ -34,6 +35,8 @@ class MessagesControllerTest extends ControllerTest
|
|||
protected Carbon $oneMinuteAgo;
|
||||
protected Carbon $twoMinutesAgo;
|
||||
|
||||
protected EventDispatcher $events;
|
||||
|
||||
/**
|
||||
* @testdox index: underNormalConditions -> returnsCorrectViewAndData
|
||||
* @covers \Engelsystem\Controllers\MessagesController::__construct
|
||||
|
@ -229,7 +232,7 @@ class MessagesControllerTest extends ControllerTest
|
|||
*/
|
||||
public function testRedirectToConversationWithUserIdGivenRedirect(): void
|
||||
{
|
||||
$this->request = $this->request->withParsedBody(['user_id' => '1']);
|
||||
$this->request = $this->request->withParsedBody(['user_id' => '1']);
|
||||
$this->response->expects($this->once())
|
||||
->method('redirectTo')
|
||||
->with('http://localhost/messages/1#newest')
|
||||
|
@ -441,6 +444,8 @@ class MessagesControllerTest extends ControllerTest
|
|||
->with('http://localhost/messages/' . $this->userB->id . '#newest')
|
||||
->willReturn($this->response);
|
||||
|
||||
$this->setExpects($this->events, 'dispatch', ['message.created'], []);
|
||||
|
||||
$this->controller->send($this->request);
|
||||
|
||||
$msg = Message::whereText('a')->first();
|
||||
|
@ -463,6 +468,8 @@ class MessagesControllerTest extends ControllerTest
|
|||
->with('http://localhost/messages/' . $this->userA->id . '#newest')
|
||||
->willReturn($this->response);
|
||||
|
||||
$this->setExpects($this->events, 'dispatch', ['message.created'], []);
|
||||
|
||||
$this->controller->send($this->request);
|
||||
|
||||
$msg = Message::whereText('a')->first();
|
||||
|
@ -536,6 +543,9 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
$this->controller = $this->app->get(MessagesController::class);
|
||||
$this->controller->setValidator(new Validator());
|
||||
|
||||
$this->events = $this->createMock(EventDispatcher::class);
|
||||
$this->app->instance('events.dispatcher', $this->events);
|
||||
}
|
||||
|
||||
protected function assertArrayOrCollection(mixed $obj): void
|
||||
|
@ -547,11 +557,11 @@ class MessagesControllerTest extends ControllerTest
|
|||
{
|
||||
Message::unguard(); // unguard temporarily to save custom creation dates.
|
||||
$msg = new Message([
|
||||
'user_id' => $from->id,
|
||||
'user_id' => $from->id,
|
||||
'receiver_id' => $to->id,
|
||||
'text' => $text,
|
||||
'created_at' => $at,
|
||||
'updated_at' => $at,
|
||||
'text' => $text,
|
||||
'created_at' => $at,
|
||||
'updated_at' => $at,
|
||||
]);
|
||||
$msg->save();
|
||||
Message::reguard();
|
||||
|
|
|
@ -45,6 +45,7 @@ class SettingsControllerTest extends ControllerTest
|
|||
'email_shiftinfo' => true,
|
||||
'email_news' => true,
|
||||
'email_human' => true,
|
||||
'email_messages' => true,
|
||||
'email_goody' => true,
|
||||
'shirt_size' => 'S',
|
||||
];
|
||||
|
@ -122,6 +123,7 @@ class SettingsControllerTest extends ControllerTest
|
|||
$this->assertEquals($body['email_shiftinfo'], $this->user->settings->email_shiftinfo);
|
||||
$this->assertEquals($body['email_news'], $this->user->settings->email_news);
|
||||
$this->assertEquals($body['email_human'], $this->user->settings->email_human);
|
||||
$this->assertEquals($body['email_messages'], $this->user->settings->email_messages);
|
||||
$this->assertEquals($body['email_goody'], $this->user->settings->email_goody);
|
||||
$this->assertEquals($body['shirt_size'], $this->user->personalData->shirt_size);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Test\Unit\Events\Listener;
|
||||
|
||||
use Engelsystem\Events\Listener\Messages;
|
||||
use Engelsystem\Mail\EngelsystemMailer;
|
||||
use Engelsystem\Models\Message;
|
||||
use Engelsystem\Models\User\Settings;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Test\Unit\HasDatabase;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Psr\Log\Test\TestLogger;
|
||||
use Symfony\Component\Mailer\Exception\TransportException;
|
||||
|
||||
class MessagesTest extends TestCase
|
||||
{
|
||||
use HasDatabase;
|
||||
|
||||
protected TestLogger $log;
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Events\Listener\Messages::created
|
||||
* @covers \Engelsystem\Events\Listener\Messages::__construct
|
||||
* @covers \Engelsystem\Events\Listener\Messages::sendMail
|
||||
*/
|
||||
public function testCreated(): void
|
||||
{
|
||||
/** @var EngelsystemMailer|MockObject $mailer */
|
||||
$mailer = $this->createMock(EngelsystemMailer::class);
|
||||
/** @var User $user */
|
||||
$user = User::factory()
|
||||
->has(Settings::factory([
|
||||
'email_messages' => true,
|
||||
]))
|
||||
->create();
|
||||
$message = Message::factory()->create(['receiver_id' => $user->id]);
|
||||
|
||||
$mailer->expects($this->once())
|
||||
->method('sendViewTranslated')
|
||||
->willReturnCallback(function (
|
||||
User $receiver,
|
||||
string $subject,
|
||||
string $template,
|
||||
array $data
|
||||
) use ($user): void {
|
||||
$this->assertEquals($user->id, $receiver->id);
|
||||
$this->assertEquals('notification.messages.new', $subject);
|
||||
$this->assertEquals('emails/messages-new', $template);
|
||||
$this->assertArrayHasKey('username', $data);
|
||||
$this->assertArrayHasKey('sender', $data);
|
||||
$this->assertArrayHasKey('send_message', $data);
|
||||
});
|
||||
|
||||
$handler = new Messages($this->log, $mailer);
|
||||
$handler->created($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Events\Listener\Messages::created
|
||||
*/
|
||||
public function testCreatedNoEmail(): void
|
||||
{
|
||||
/** @var EngelsystemMailer|MockObject $mailer */
|
||||
$mailer = $this->createMock(EngelsystemMailer::class);
|
||||
/** @var User $user */
|
||||
$user = User::factory()
|
||||
->has(Settings::factory([
|
||||
'email_messages' => false,
|
||||
]))
|
||||
->create();
|
||||
$message = Message::factory()->create(['receiver_id' => $user->id]);
|
||||
$mailer->expects($this->never())->method('sendViewTranslated');
|
||||
|
||||
$handler = new Messages($this->log, $mailer);
|
||||
$handler->created($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Events\Listener\Messages::sendMail
|
||||
*/
|
||||
public function testSendMailExceptionHandling(): void
|
||||
{
|
||||
/** @var EngelsystemMailer|MockObject $mailer */
|
||||
$mailer = $this->createMock(EngelsystemMailer::class);
|
||||
/** @var User $user */
|
||||
$user = User::factory()
|
||||
->has(Settings::factory([
|
||||
'email_messages' => true,
|
||||
]))
|
||||
->create();
|
||||
$message = Message::factory()->create(['receiver_id' => $user->id]);
|
||||
$mailer->expects($this->once())
|
||||
->method('sendViewTranslated')
|
||||
->willReturnCallback(function (): void {
|
||||
throw new TransportException();
|
||||
});
|
||||
|
||||
$handler = new Messages($this->log, $mailer);
|
||||
|
||||
$handler->created($message);
|
||||
$this->assertTrue($this->log->hasErrorThatContains('Unable to send email'));
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->log = new TestLogger();
|
||||
|
||||
parent::setUp();
|
||||
$this->initDatabase();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue