Use Notification/Notifiable (#379)

* Add migrations for notifiables

* Configure spatie-backup to run as part of cron

* Convert Mailer to Notification; add pirep notifications

* Styling
This commit is contained in:
Nabeel S
2019-08-30 15:59:17 -04:00
committed by GitHub
parent b213f2bb4c
commit 7ace8bccd6
50 changed files with 1703 additions and 214 deletions

View File

@@ -27,6 +27,10 @@ class Kernel extends ConsoleKernel
$schedule->command(Weekly::class)->weeklyOn(0);
$schedule->command(Monthly::class)->monthlyOn(1);
$schedule->command(Hourly::class)->hourly();
// When spatie-backups runs
$schedule->command('backup:clean')->daily()->at('01:00');
$schedule->command('backup:run')->daily()->at('02:00');
}
/**

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateNotificationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('notifications', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('type');
$table->morphs('notifiable');
$table->text('data');
$table->timestamp('read_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('notifications');
}
}

View File

@@ -11,7 +11,7 @@
value: ''
options: ''
type: text
description: 'Email where notices, etc are sent'
description: 'Email where system notices, etc are sent'
- key: general.check_prerelease_version
name: 'Pre-release versions in version check'
group: general

View File

@@ -3,12 +3,17 @@
namespace App\Listeners;
use App\Contracts\Listener;
use App\Events\PirepAccepted;
use App\Events\PirepFiled;
use App\Events\PirepRejected;
use App\Events\UserRegistered;
use App\Events\UserStateChanged;
use App\Models\Enums\UserState;
use App\Models\User;
use App\Notifications\PirepSubmitted;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Facades\Mail;
use Log;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
/**
* Handle sending emails on different events
@@ -20,44 +25,22 @@ class NotificationEvents extends Listener
*/
public function subscribe(Dispatcher $events): void
{
$events->listen(
\App\Events\UserRegistered::class,
'App\Listeners\NotificationEvents@onUserRegister'
);
$events->listen(
\App\Events\UserStateChanged::class,
'App\Listeners\NotificationEvents@onUserStateChange'
);
$events->listen(UserRegistered::class, 'App\Listeners\NotificationEvents@onUserRegister');
$events->listen(UserStateChanged::class, 'App\Listeners\NotificationEvents@onUserStateChange');
$events->listen(PirepFiled::class, 'App\Listeners\NotificationEvents@onPirepFile');
$events->listen(PirepAccepted::class, 'App\Listeners\NotificationEvents@onPirepAccepted');
$events->listen(PirepRejected::class, 'App\Listeners\NotificationEvents@onPirepRejected');
}
/**
* @return bool
*/
protected function mailerActive(): bool
{
if (empty(config('mail.host'))) {
Log::info('No mail host specified!');
return false;
}
return true;
}
/**
* @param $to
* @param $email
* Send a notification to all of the admins
*
* @return mixed
* @param \Illuminate\Notifications\Notification $notification
*/
protected function sendEmail($to, $email)
protected function notifyAdmins($notification)
{
try {
return Mail::to($to)->send($email);
} catch (\Exception $e) {
Log::error('Error sending email!');
Log::error($e);
}
$admin_users = User::whereRoleIs('admin')->get();
Notification::send($admin_users, $notification);
}
/**
@@ -67,32 +50,24 @@ class NotificationEvents extends Listener
*/
public function onUserRegister(UserRegistered $event): void
{
Log::info('onUserRegister: '
Log::info('NotificationEvents::onUserRegister: '
.$event->user->ident.' is '
.UserState::label($event->user->state)
.', sending active email');
if (!$this->mailerActive()) {
return;
}
/*
* Send all of the admins a notification that a new user registered
*/
$this->notifyAdmins(new \App\Notifications\Admin\UserRegistered($event->user));
// First send the admin a notification
$admin_email = setting('general.admin_email');
Log::info('Sending admin notification email to "'.$admin_email.'"');
if (!empty($admin_email)) {
$email = new \App\Mail\Admin\UserRegistered($event->user);
$this->sendEmail($admin_email, $email);
}
// Then notify the user
/*
* Send the user a confirmation email
*/
if ($event->user->state === UserState::ACTIVE) {
$email = new \App\Mail\UserRegistered($event->user);
$event->user->notify(new \App\Notifications\UserRegistered($event->user));
} elseif ($event->user->state === UserState::PENDING) {
$email = new \App\Mail\UserPending($event->user);
$event->user->notify(new \App\Notifications\UserPending($event->user));
}
$this->sendEmail($event->user->email, $email);
}
/**
@@ -102,23 +77,49 @@ class NotificationEvents extends Listener
*/
public function onUserStateChange(UserStateChanged $event): void
{
if (!$this->mailerActive()) {
return;
}
Log::info('NotificationEvents::onUserStateChange: New user state='.$event->user->state);
if ($event->old_state === UserState::PENDING) {
if ($event->user->state === UserState::ACTIVE) {
$email = new \App\Mail\UserRegistered(
$event->user,
'Your registration has been accepted!'
);
$event->user->notify(new \App\Notifications\UserRegistered($event->user));
} elseif ($event->user->state === UserState::REJECTED) {
$email = new \App\Mail\UserRejected($event->user);
$event->user->notify(new \App\Notifications\UserRejected($event->user));
}
$this->sendEmail($event->user->email, $email);
} // TODO: Other state transitions
elseif ($event->old_state === UserState::ACTIVE) {
} elseif ($event->old_state === UserState::ACTIVE) {
Log::info('User state change from active to ??');
}
}
/**
* Notify the admins that a new PIREP has been filed
*
* @param \App\Events\PirepFiled $event
*/
public function onPirepFile(PirepFiled $event): void
{
Log::info('NotificationEvents::onPirepFile: '.$event->pirep->id.' filed ');
$this->notifyAdmins(new PirepSubmitted($event->pirep));
}
/**
* Notify the user that their PIREP has been accepted
*
* @param \App\Events\PirepAccepted $event
*/
public function onPirepAccepted(PirepAccepted $event): void
{
Log::info('NotificationEvents::onPirepAccepted: '.$event->pirep->id.' accepted');
$event->pirep->user->notify(new \App\Notifications\PirepAccepted($event->pirep));
}
/**
* Notify the user that their PIREP has been accepted
*
* @param \App\Events\PirepRejected $event
*/
public function onPirepRejected(PirepRejected $event): void
{
Log::info('NotificationEvents::onPirepRejected: '.$event->pirep->id.' rejected');
$event->pirep->user->notify(new \App\Notifications\PirepRejected($event->pirep));
}
}

View File

@@ -1,29 +0,0 @@
<?php
namespace App\Mail\Admin;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class UserRegistered extends Mailable
{
use Queueable, SerializesModels;
public $subject;
public $user;
public function __construct(User $user, $subject = null)
{
$this->subject = $subject ?: 'A new user registered';
$this->user = $user;
}
public function build()
{
return $this
->markdown('emails.admin.registered')
->subject($this->subject)
->with(['user' => $this->user]);
}
}

View File

@@ -1,30 +0,0 @@
<?php
namespace App\Mail;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class NewLoginDetails extends Mailable
{
use Queueable, SerializesModels;
public $subject;
public $user;
public $newpw;
public function __construct(User $user, $newpw = null, $subject = null)
{
$this->subject = $subject ?: 'New Login Details';
$this->newpw = $newpw ?: 'N/A';
$this->user = $user;
}
public function build()
{
return $this->markdown('emails.user.new_login_details')
->subject($this->subject)
->with(['user' => $this->user, 'newpw' => $this->newpw]);
}
}

View File

@@ -1,28 +0,0 @@
<?php
namespace App\Mail;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class UserPending extends Mailable
{
use Queueable, SerializesModels;
public $subject;
public $user;
public function __construct(User $user, $subject = null)
{
$this->subject = $subject ?: 'Your registration is pending!';
$this->user = $user;
}
public function build()
{
return $this->markdown('emails.user.pending')
->subject($this->subject)
->with(['user' => $this->user]);
}
}

View File

@@ -1,29 +0,0 @@
<?php
namespace App\Mail;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class UserRegistered extends Mailable
{
use Queueable, SerializesModels;
public $subject;
public $user;
public function __construct(User $user, $subject = null)
{
$this->subject = $subject ?: 'Welcome to '.config('app.name').'!';
$this->user = $user;
}
public function build()
{
return $this
->markdown('emails.user.registered')
->subject($this->subject)
->with(['user' => $this->user]);
}
}

View File

@@ -1,29 +0,0 @@
<?php
namespace App\Mail;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class UserRejected extends Mailable
{
use Queueable, SerializesModels;
public $subject;
public $user;
public function __construct(User $user, $subject = null)
{
$this->subject = $subject ?: 'Your registration has been denied';
$this->user = $user;
}
public function build()
{
return $this
->markdown('emails.user.rejected')
->subject($this->subject)
->with(['user' => $this->user]);
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace App\Notifications\Admin;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class UserRegistered extends Notification implements ShouldQueue
{
use Queueable;
private $user;
/**
* Create a new notification instance.
*
* @param \App\Models\User $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
*
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
*
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage())
->from(config('mail.from.address'))
->markdown('mail.admin.user.registered')
->subject('A new user registered')
->with(['user' => $this->user]);
}
public function toArray($notifiable)
{
return [
'user_id' => $this->user->id,
];
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Notifications;
use Illuminate\Notifications\Notifiable;
class Backups
{
use Notifiable;
public function routeNotificationForMail()
{
return setting('general.admin_email');
}
public function routeNotificationForSlack()
{
return config('backup.notifications.slack.webhook_url');
}
public function getKey()
{
return 1;
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Notifications;
use App\Models\Pirep;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class PirepAccepted extends Notification implements ShouldQueue
{
use Queueable;
private $pirep;
/**
* Create a new notification instance.
*
* @param \App\Models\Pirep $pirep
*/
public function __construct(Pirep $pirep)
{
$this->pirep = $pirep;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
*
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
*
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage())
->from(config('mail.from.address', 'no-reply@phpvms.net'))
->subject('PIREP Accepted!')
->markdown('mail.pirep.accepted', ['pirep' => $this->pirep]);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
*
* @return array
*/
public function toArray($notifiable)
{
return [
'pirep_id' => $this->pirep->id,
'user_id' => $this->pirep->user_id,
];
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Notifications;
use App\Models\Pirep;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class PirepRejected extends Notification implements ShouldQueue
{
use Queueable;
private $pirep;
/**
* Create a new notification instance.
*
* @param \App\Models\Pirep $pirep
*/
public function __construct(Pirep $pirep)
{
$this->pirep = $pirep;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
*
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
*
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage())
->from(config('mail.from.address', 'no-reply@phpvms.net'))
->subject('PIREP Rejected!')
->markdown('mail.pirep.rejected', ['pirep' => $this->pirep]);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
*
* @return array
*/
public function toArray($notifiable)
{
return [
'pirep_id' => $this->pirep->id,
'user_id' => $this->pirep->user_id,
];
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Notifications;
use App\Models\Pirep;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class PirepSubmitted extends Notification implements ShouldQueue
{
use Queueable;
private $pirep;
/**
* Create a new notification instance.
*
* @param \App\Models\Pirep $pirep
*/
public function __construct(Pirep $pirep)
{
$this->pirep = $pirep;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
*
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
*
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage())
->from(config('mail.from.address', 'no-reply@phpvms.net'))
->subject('New PIREP Submitted')
->markdown('mail.admin.pirep.submitted', ['pirep' => $this->pirep]);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
*
* @return array
*/
public function toArray($notifiable)
{
return [
'pirep_id' => $this->pirep->id,
'user_id' => $this->pirep->user_id,
];
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Notifications;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class UserPending extends Notification implements ShouldQueue
{
use Queueable;
private $user;
/**
* @param \App\Models\User $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
*
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
*
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage())
->from(config('mail.from.address', 'no-reply@phpvms.net'))
->subject('Your registration is pending')
->markdown('mail.user.pending', ['user' => $this->user]);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
*
* @return array
*/
public function toArray($notifiable)
{
return [
'user_id' => $this->user->id,
];
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace App\Notifications;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class UserRegistered extends Notification implements ShouldQueue
{
use Queueable;
private $user;
/**
* Create a new notification instance.
*
* @param \App\Models\User $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
*
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
*
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage())
->from(config('mail.from.address', 'no-reply@phpvms.net'))
->subject('Welcome to '.config('app.name').'!')
->markdown('mail.user.registered', ['user' => $this->user]);
}
public function toArray($notifiable)
{
return [
'user_id' => $this->user->id,
];
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Notifications;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class UserRejected extends Notification implements ShouldQueue
{
use Queueable;
private $user;
/**
* @param \App\Models\User $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
*
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
*
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage())
->from(config('mail.from.address', 'no-reply@phpvms.net'))
->subject('Your registration has been denied')
->markdown('mail.user.rejected', ['user' => $this->user]);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
*
* @return array
*/
public function toArray($notifiable)
{
return [
'user_id' => $this->user->id,
];
}
}