391 Notification refactorings (#441)

* Refactor notifications to allow easier plugins

* Notification refactoring

* Formatting

* Move news to NewsService; cleanup of events

* More refactoring; added send email out for news item and the template

* Formatting

* Formatting
This commit is contained in:
Nabeel S 2019-11-20 10:16:01 -05:00 committed by GitHub
parent 02973a0f22
commit ea3ab21beb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 754 additions and 718 deletions

View File

@ -5,13 +5,11 @@ namespace App\Bootstrap;
use Illuminate\Contracts\Config\Repository as RepositoryContract;
use Illuminate\Contracts\Foundation\Application;
/**
* Class LoadConfiguration
*/
class LoadConfiguration extends \Illuminate\Foundation\Bootstrap\LoadConfiguration
{
/**
* Load the configuration items from all of the files.
* Load the configuration items from all of the files. This reads the config.php from
* that's sitting in the root, and then recursively merges it with the current configs
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @param \Illuminate\Contracts\Config\Repository $repository

View File

@ -6,7 +6,8 @@ use App\Facades\Utils;
use App\Models\Award as AwardModel;
use App\Models\User;
use App\Models\UserAward;
use Log;
use Exception;
use Illuminate\Support\Facades\Log;
/**
* Base class for the Awards, you need to extend this, and implement:
@ -38,12 +39,6 @@ abstract class Award
protected $award;
protected $user;
/**
* AwardInterface constructor.
*
* @param AwardModel $award
* @param User $user
*/
public function __construct(AwardModel $award = null, User $user = null)
{
$this->award = $award;
@ -73,7 +68,7 @@ abstract class Award
*
* @return bool|UserAward
*/
final protected function addAward()
protected function addAward()
{
$w = [
'user_id' => $this->user->id,
@ -90,7 +85,7 @@ abstract class Award
try {
$award->save();
} catch (\Exception $e) {
} catch (Exception $e) {
Log::error(
'Error saving award: '.$e->getMessage(),
$e->getTrace()

View File

@ -2,9 +2,21 @@
namespace App\Contracts;
/**
* Class Listener
*/
use Illuminate\Contracts\Events\Dispatcher;
abstract class Listener
{
public static $callbacks = [];
/**
* Sets up any callbacks that are defined in the child class
*
* @param $events
*/
public function subscribe(Dispatcher $events): void
{
foreach (static::$callbacks as $klass => $cb) {
$events->listen($klass, get_class($this).'@'.$cb);
}
}
}

View File

@ -20,7 +20,7 @@ awards:
name: Pilot 50 flights
description: When a pilot has 50 flights, give this award
image_url:
ref_model: App\Awards\PilotFlightAwards
ref_model: Modules\Awards\Awards\PilotFlightAwards
ref_model_params: 50
created_at: now
updated_at: now

View File

@ -222,3 +222,17 @@
options: ''
type: boolean
description: 'Count transfer hours in calculations, like ranks and the total hours'
- key: notifications.discord_api_key
name: Discord API token
group: notifications
value: ''
options: ''
type: text
description: Discord API token for notifications
- key: 'notifications.discord_public_channel_id'
name: 'Discord Public Channel ID'
group: 'notifications'
value: ''
options: ''
type: 'text'
description: 'Discord public channel ID for broadcasat notifications'

12
app/Events/BaseEvent.php Normal file
View File

@ -0,0 +1,12 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class BaseEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
}

View File

@ -2,20 +2,6 @@
namespace App\Events;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* This event is dispatched when the hourly cron is run
*/
class CronHourly
class CronHourly extends BaseEvent
{
use Dispatchable, SerializesModels;
/**
* CronHourly constructor.
*/
public function __construct()
{
}
}

View File

@ -2,21 +2,10 @@
namespace App\Events;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* This event is dispatched when the monthly cron is run
* It happens after all of the default nightly tasks
*/
class CronMonthly
class CronMonthly extends BaseEvent
{
use Dispatchable, SerializesModels;
/**
* CronMonthly constructor.
*/
public function __construct()
{
}
}

View File

@ -2,21 +2,10 @@
namespace App\Events;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* This event is dispatched when the daily cron is run
* It happens after all of the default nightly tasks
*/
class CronNightly
class CronNightly extends BaseEvent
{
use Dispatchable, SerializesModels;
/**
* CronNightly constructor.
*/
public function __construct()
{
}
}

View File

@ -2,20 +2,12 @@
namespace App\Events;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* This event is dispatched when the weekly cron is run
* It happens after all of the default nightly tasks
*/
class CronWeekly
class CronWeekly extends BaseEvent
{
use Dispatchable, SerializesModels;
/**
* CronWeekly constructor.
*/
public function __construct()
{
}

View File

@ -3,8 +3,6 @@
namespace App\Events;
use App\Models\Pirep;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* This event is dispatched when the expenses for a flight report
@ -27,9 +25,8 @@ use Illuminate\Queue\SerializesModels;
*
* The event will have a copy of the PIREP model, if it's applicable
*/
class Expenses
class Expenses extends BaseEvent
{
use Dispatchable, SerializesModels;
public $pirep;
/**

15
app/Events/NewsAdded.php Normal file
View File

@ -0,0 +1,15 @@
<?php
namespace App\Events;
use App\Models\News;
class NewsAdded extends BaseEvent
{
public $news;
public function __construct(News $news)
{
$this->news = $news;
}
}

View File

@ -3,24 +3,11 @@
namespace App\Events;
use App\Models\Pirep;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* Class PirepAccepted
*/
class PirepAccepted
class PirepAccepted extends BaseEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $pirep;
/**
* PirepAccepted constructor.
*
* @param Pirep $pirep
*/
public function __construct(Pirep $pirep)
{
$this->pirep = $pirep;

View File

@ -3,13 +3,9 @@
namespace App\Events;
use App\Models\Pirep;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class PirepFiled
class PirepFiled extends BaseEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $pirep;
public function __construct(Pirep $pirep)

View File

@ -3,24 +3,11 @@
namespace App\Events;
use App\Models\Pirep;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* Class PirepRejected
*/
class PirepRejected
class PirepRejected extends BaseEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $pirep;
/**
* PirepRejected constructor.
*
* @param Pirep $pirep
*/
public function __construct(Pirep $pirep)
{
$this->pirep = $pirep;

View File

@ -3,24 +3,11 @@
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* Class TestEvent
*/
class TestEvent
class TestEvent extends BaseEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
/**
* Create a new event instance.
*
* @param User $user
*/
public function __construct(User $user)
{
$this->user = $user;

View File

@ -3,24 +3,11 @@
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* Class UserAccepted
*/
class UserAccepted
class UserAccepted extends BaseEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
/**
* UserAccepted constructor.
*
* @param User $user
*/
public function __construct(User $user)
{
$this->user = $user;

View File

@ -3,24 +3,11 @@
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* Class UserRegistered
*/
class UserRegistered
class UserRegistered extends BaseEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
/**
* UserRegistered constructor.
*
* @param User $user
*/
public function __construct(User $user)
{
$this->user = $user;

View File

@ -3,26 +3,15 @@
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* Event triggered when a user's state changes
*/
class UserStateChanged
class UserStateChanged extends BaseEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $old_state;
public $user;
/**
* UserStateChanged constructor.
*
* @param User $user
* @param $old_state
*/
public function __construct(User $user, $old_state)
{
$this->old_state = $old_state;

View File

@ -3,26 +3,18 @@
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* Class UserStatsChanged
*/
class UserStatsChanged
class UserStatsChanged extends BaseEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $stat_name;
public $old_value;
public $user;
/*
* When a user's stats change. Stats changed match the field name:
* airport
* flights
* rank
* airport
* flights
* rank
*/
public function __construct(User $user, $stat_name, $old_value)
{

View File

@ -4,9 +4,9 @@ namespace App\Http\Controllers\Admin;
use App\Contracts\Controller;
use App\Repositories\KvpRepository;
use App\Repositories\NewsRepository;
use App\Repositories\PirepRepository;
use App\Repositories\UserRepository;
use App\Services\NewsService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
@ -15,7 +15,7 @@ use Laracasts\Flash\Flash;
class DashboardController extends Controller
{
private $kvpRepo;
private $newsRepo;
private $newsSvc;
private $pirepRepo;
private $userRepo;
@ -23,20 +23,20 @@ class DashboardController extends Controller
* DashboardController constructor.
*
* @param KvpRepository $kvpRepo
* @param NewsRepository $newsRepo
* @param PirepRepository $pirepRepo
* @param UserRepository $userRepo
* @param $newsSvc
*/
public function __construct(
KvpRepository $kvpRepo,
NewsRepository $newsRepo,
NewsService $newsSvc,
PirepRepository $pirepRepo,
UserRepository $userRepo
) {
$this->kvpRepo = $kvpRepo;
$this->newsRepo = $newsRepo;
$this->pirepRepo = $pirepRepo;
$this->userRepo = $userRepo;
$this->newsSvc = $newsSvc;
}
/**
@ -93,10 +93,10 @@ class DashboardController extends Controller
$attrs = $request->post();
$attrs['user_id'] = Auth::user()->id;
$this->newsRepo->create($attrs);
$this->newsSvc->addNews($attrs);
} elseif ($request->isMethod('delete')) {
$news_id = $request->input('news_id');
$this->newsRepo->delete($news_id);
$id = $request->input('news_id');
$this->newsSvc->deleteNews($id);
}
return view('admin.dashboard.news', [

View File

@ -4,14 +4,19 @@ namespace App\Listeners;
use App\Contracts\Listener;
use App\Events\PirepAccepted;
use App\Events\PirepRejected;
use App\Services\BidService;
use Illuminate\Contracts\Events\Dispatcher;
/**
* Do stuff with bids - like if a PIREP is accepted, then remove the bid
*/
class BidEvents extends Listener
class BidEventHandler extends Listener
{
public static $callbacks = [
PirepAccepted::class => 'onPirepAccept',
PirepRejected::class => 'onPirepReject',
];
private $bidSvc;
public function __construct(BidService $bidSvc)
@ -19,17 +24,6 @@ class BidEvents extends Listener
$this->bidSvc = $bidSvc;
}
/**
* @param $events
*/
public function subscribe(Dispatcher $events): void
{
$events->listen(
PirepAccepted::class,
'App\Listeners\BidEvents@onPirepAccept'
);
}
/**
* When a PIREP is accepted, remove any bids
*
@ -43,4 +37,18 @@ class BidEvents extends Listener
{
$this->bidSvc->removeBidForPirep($event->pirep);
}
/**
* When a PIREP is accepted, remove any bids
*
* @param PirepRejected $event
*
* @throws \UnexpectedValueException
* @throws \InvalidArgumentException
* @throws \Exception
*/
public function onPirepReject(PirepRejected $event): void
{
$this->bidSvc->removeBidForPirep($event->pirep);
}
}

View File

@ -5,9 +5,6 @@ namespace App\Listeners;
use App\Contracts\Listener;
use App\Events\Expenses;
/**
* Class ExpenseListener
*/
class ExpenseListener extends Listener
{
/**

View File

@ -6,41 +6,23 @@ use App\Contracts\Listener;
use App\Events\PirepAccepted;
use App\Events\PirepRejected;
use App\Services\Finance\PirepFinanceService;
use Illuminate\Contracts\Events\Dispatcher;
/**
* Subscribe for events that we do some financial processing for
* This includes when a PIREP is accepted, or rejected
*/
class FinanceEvents extends Listener
class FinanceEventHandler extends Listener
{
private $financeSvc;
/**
* FinanceEvents constructor.
*
* @param PirepFinanceService $financeSvc
*/
public function __construct(
PirepFinanceService $financeSvc
) {
$this->financeSvc = $financeSvc;
}
public static $callbacks = [
PirepAccepted::class => 'onPirepAccept',
PirepRejected::class => 'onPirepReject',
];
/**
* @param $events
*/
public function subscribe(Dispatcher $events): void
public function __construct(PirepFinanceService $financeSvc)
{
$events->listen(
PirepAccepted::class,
'App\Listeners\FinanceEvents@onPirepAccept'
);
$events->listen(
PirepRejected::class,
'App\Listeners\FinanceEvents@onPirepReject'
);
$this->financeSvc = $financeSvc;
}
/**

View File

@ -7,7 +7,7 @@ use App\Events\PirepFiled;
use App\Events\UserStateChanged;
use App\Models\Enums\UserState;
class SetUserActive extends Listener
class UserStateListener extends Listener
{
public function handle(PirepFiled $event): void
{

View File

@ -4,6 +4,10 @@ namespace App\Models;
use App\Contracts\Model;
/**
* @property string subject
* @property string body
*/
class News extends Model
{
public $table = 'news';

View File

@ -1,61 +0,0 @@
<?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,41 @@
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log;
class BaseNotification extends Notification implements ShouldQueue
{
use Queueable;
public $channels = [];
public function __construct()
{
// Look in the notifications.channels config and see where this particular
// notification can go. Map it to $channels
$klass = get_class($this);
$notif_config = config('notifications.channels', []);
if (!array_key_exists($klass, $notif_config)) {
Log::error('Notification type '.$klass.' missing from notifications config');
return;
}
$this->channels = $notif_config[$klass];
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
*
* @return array
*/
public function via($notifiable)
{
return $this->channels;
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Notifications\Channels;
use Illuminate\Notifications\Messages\MailMessage;
trait MailChannel
{
private $mailSubject;
private $mailTemplate;
private $mailTemplateArgs;
/**
* Set the arguments for the toMail() method
*
* @param string $subject Email subject
* @param string $template Markdown template to use
* @param array $args Arguments to pass to the template
*/
public function setMailable($subject, $template, $args)
{
$this->mailSubject = $subject;
$this->mailTemplate = $template;
$this->mailTemplateArgs = $args;
}
/**
* 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($this->mailSubject)
->markdown($this->mailTemplate, $this->mailTemplateArgs);
}
}

View File

@ -1,8 +1,9 @@
<?php
namespace App\Listeners;
namespace App\Notifications;
use App\Contracts\Listener;
use App\Events\NewsAdded;
use App\Events\PirepAccepted;
use App\Events\PirepFiled;
use App\Events\PirepRejected;
@ -10,26 +11,32 @@ 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 App\Notifications\Messages\PirepSubmitted;
use App\Notifications\Messages\UserPending;
use App\Notifications\Messages\UserRejected;
use App\Notifications\Notifiables\Broadcast;
use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
/**
* Handle sending emails on different events
* Listen for different events and map them to different notifications
*/
class NotificationEvents extends Listener
class EventHandler extends Listener
{
/**
* @param Dispatcher $events
*/
public function subscribe(Dispatcher $events): void
private static $broadcastNotifyable;
public static $callbacks = [
PirepAccepted::class => 'onPirepAccepted',
PirepFiled::class => 'onPirepFile',
PirepRejected::class => 'onPirepRejected',
UserRegistered::class => 'onUserRegister',
UserStateChanged::class => 'onUserStateChange',
];
public function __construct()
{
$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');
static::$broadcastNotifyable = app(Broadcast::class);
}
/**
@ -43,7 +50,7 @@ class NotificationEvents extends Listener
try {
Notification::send($admin_users, $notification);
} catch (\Exception $e) {
} catch (Exception $e) {
Log::emergency('Error emailing admins, malformed email='.$e->getMessage());
}
}
@ -56,7 +63,23 @@ class NotificationEvents extends Listener
{
try {
$user->notify($notification);
} catch (\Exception $e) {
} catch (Exception $e) {
Log::emergency('Error emailing admins, malformed email='.$e->getMessage());
}
}
/**
* Send a notification to all users
*
* @param $notification
*/
protected function notifyAllUsers($notification)
{
$users = User::all()->get();
try {
Notification::send($users, $notification);
} catch (Exception $e) {
Log::emergency('Error emailing admins, malformed email='.$e->getMessage());
}
}
@ -70,21 +93,20 @@ class NotificationEvents extends Listener
{
Log::info('NotificationEvents::onUserRegister: '
.$event->user->ident.' is '
.UserState::label($event->user->state)
.', sending active email');
.UserState::label($event->user->state).', sending active email');
/*
* Send all of the admins a notification that a new user registered
*/
$this->notifyAdmins(new \App\Notifications\Admin\UserRegistered($event->user));
$this->notifyAdmins(new Messages\AdminUserRegistered($event->user));
/*
* Send the user a confirmation email
*/
if ($event->user->state === UserState::ACTIVE) {
$this->notifyUser($event->user, new \App\Notifications\UserRegistered($event->user));
$this->notifyUser($event->user, new Messages\UserRegistered($event->user));
} elseif ($event->user->state === UserState::PENDING) {
$this->notifyUser($event->user, new \App\Notifications\UserPending($event->user));
$this->notifyUser($event->user, new UserPending($event->user));
}
}
@ -99,9 +121,9 @@ class NotificationEvents extends Listener
if ($event->old_state === UserState::PENDING) {
if ($event->user->state === UserState::ACTIVE) {
$this->notifyUser($event->user, new \App\Notifications\UserRegistered($event->user));
$this->notifyUser($event->user, new Messages\UserRegistered($event->user));
} elseif ($event->user->state === UserState::REJECTED) {
$this->notifyUser($event->user, new \App\Notifications\UserRejected($event->user));
$this->notifyUser($event->user, new UserRejected($event->user));
}
} elseif ($event->old_state === UserState::ACTIVE) {
Log::info('User state change from active to ??');
@ -127,7 +149,7 @@ class NotificationEvents extends Listener
public function onPirepAccepted(PirepAccepted $event): void
{
Log::info('NotificationEvents::onPirepAccepted: '.$event->pirep->id.' accepted');
$this->notifyUser($event->pirep->user, new \App\Notifications\PirepAccepted($event->pirep));
$this->notifyUser($event->pirep->user, new Messages\PirepAccepted($event->pirep));
}
/**
@ -138,6 +160,17 @@ class NotificationEvents extends Listener
public function onPirepRejected(PirepRejected $event): void
{
Log::info('NotificationEvents::onPirepRejected: '.$event->pirep->id.' rejected');
$this->notifyUser($event->pirep->user, new \App\Notifications\PirepRejected($event->pirep));
$this->notifyUser($event->pirep->user, new Messages\PirepRejected($event->pirep));
}
/**
* Notify all users of a news event
*
* @param \App\Events\NewsAdded $event
*/
public function onNewsAdded(NewsAdded $event): void
{
Log::info('NotificationEvents::onNewsAdded');
$this->notifyAllUsers(new Messages\NewsAdded($event->news));
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace App\Notifications\Messages;
use App\Models\User;
use App\Notifications\BaseNotification;
use App\Notifications\Channels\MailChannel;
class AdminUserRegistered extends BaseNotification
{
use MailChannel;
private $user;
/**
* Create a new notification instance.
*
* @param \App\Models\User $user
*/
public function __construct(User $user)
{
parent::__construct();
$this->user = $user;
$this->setMailable(
'A new user registered',
'notifications.mail.admin.user.registered',
['user' => $user]
);
}
public function toArray($notifiable)
{
return [
'user_id' => $this->user->id,
];
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\Notifications\Messages;
use App\Models\News;
use App\Notifications\BaseNotification;
use App\Notifications\Channels\MailChannel;
class NewsAdded extends BaseNotification
{
use MailChannel;
private $news;
public function __construct(News $news)
{
parent::__construct();
$this->news = $news;
$this->setMailable(
$news->subject,
'notifications.mail.news',
['news' => $news]
);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
*
* @return array
*/
public function toArray($notifiable)
{
return [
'news_id' => $this->news->id,
];
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Notifications\Messages;
use App\Models\Pirep;
use App\Notifications\BaseNotification;
use App\Notifications\Channels\MailChannel;
/**
* Send the PIREP accepted message to a particular user
*/
class PirepAccepted extends BaseNotification
{
use MailChannel;
private $pirep;
/**
* Create a new notification instance.
*
* @param \App\Models\Pirep $pirep
*/
public function __construct(Pirep $pirep)
{
parent::__construct();
$this->pirep = $pirep;
$this->setMailable(
'PIREP Accepted!',
'notifications.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,47 @@
<?php
namespace App\Notifications\Messages;
use App\Models\Pirep;
use App\Notifications\BaseNotification;
use App\Notifications\Channels\MailChannel;
class PirepRejected extends BaseNotification
{
use MailChannel;
private $pirep;
/**
* Create a new notification instance.
*
* @param \App\Models\Pirep $pirep
*/
public function __construct(Pirep $pirep)
{
parent::__construct();
$this->pirep = $pirep;
$this->setMailable(
'PIREP Rejected!',
'notifications.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,47 @@
<?php
namespace App\Notifications\Messages;
use App\Models\Pirep;
use App\Notifications\BaseNotification;
use App\Notifications\Channels\MailChannel;
class PirepSubmitted extends BaseNotification
{
use MailChannel;
private $pirep;
/**
* Create a new notification instance.
*
* @param \App\Models\Pirep $pirep
*/
public function __construct(Pirep $pirep)
{
parent::__construct();
$this->pirep = $pirep;
$this->setMailable(
'New PIREP Submitted',
'notifications.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,42 @@
<?php
namespace App\Notifications\Messages;
use App\Models\User;
use App\Notifications\BaseNotification;
use App\Notifications\Channels\MailChannel;
class UserPending extends BaseNotification
{
use MailChannel;
private $user;
/**
* @param \App\Models\User $user
*/
public function __construct(User $user)
{
$this->user = $user;
$this->setMailable(
'Your registration is pending',
'notifications.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,39 @@
<?php
namespace App\Notifications\Messages;
use App\Models\User;
use App\Notifications\BaseNotification;
use App\Notifications\Channels\MailChannel;
class UserRegistered extends BaseNotification
{
use MailChannel;
private $user;
/**
* Create a new notification instance.
*
* @param \App\Models\User $user
*/
public function __construct(User $user)
{
parent::__construct();
$this->user = $user;
$this->setMailable(
'Welcome to '.config('app.name').'!',
'notifications.mail.user.registered',
['user' => $this->user]
);
}
public function toArray($notifiable)
{
return [
'user_id' => $this->user->id,
];
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace App\Notifications\Messages;
use App\Models\User;
use App\Notifications\BaseNotification;
use App\Notifications\Channels\MailChannel;
class UserRejected extends BaseNotification
{
use MailChannel;
private $user;
/**
* @param \App\Models\User $user
*/
public function __construct(User $user)
{
parent::__construct();
$this->user = $user;
$this->setMailable(
'Your registration has been denied',
'notifications.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,
];
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace App\Notifications;
namespace App\Notifications\Notifiables;
use Illuminate\Notifications\Notifiable;

View File

@ -0,0 +1,25 @@
<?php
namespace App\Notifications\Notifiables;
use Illuminate\Notifications\Notifiable;
/**
* These are notifications that get broadcasted, not to a single person
* (e.g, on Discord, Slack or Telegram or something)
*
* $notifyable = app(Broadcast::class);
* $notifyable->notify($eventclass);
*/
class Broadcast
{
use Notifiable;
/**
* Routing for Discord - the public channel ID that's used
*/
public function routeNotificationForDiscord()
{
return setting('notifications.discord_public_channel_id');
}
}

View File

@ -1,68 +0,0 @@
<?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

@ -1,68 +0,0 @@
<?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

@ -1,68 +0,0 @@
<?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

@ -1,65 +0,0 @@
<?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

@ -1,60 +0,0 @@
<?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

@ -1,65 +0,0 @@
<?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,
];
}
}

View File

@ -6,11 +6,11 @@ use App\Events\Expenses;
use App\Events\PirepFiled;
use App\Events\UserStatsChanged;
use App\Listeners\AwardListener;
use App\Listeners\BidEvents;
use App\Listeners\BidEventHandler;
use App\Listeners\ExpenseListener;
use App\Listeners\FinanceEvents;
use App\Listeners\NotificationEvents;
use App\Listeners\SetUserActive;
use App\Listeners\FinanceEventHandler;
use App\Listeners\UserStateListener;
use App\Notifications\EventHandler;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
@ -23,7 +23,7 @@ class EventServiceProvider extends ServiceProvider
],
PirepFiled::class => [
SetUserActive::class,
UserStateListener::class,
],
Registered::class => [
@ -36,8 +36,8 @@ class EventServiceProvider extends ServiceProvider
];
protected $subscribe = [
BidEvents::class,
FinanceEvents::class,
NotificationEvents::class,
BidEventHandler::class,
FinanceEventHandler::class,
EventHandler::class,
];
}

View File

@ -4,6 +4,7 @@ namespace App\Services;
use App\Contracts\Service;
use App\Support\ClassLoader;
use function get_class;
use Nwidart\Modules\Facades\Module;
class AwardService extends Service
@ -18,9 +19,9 @@ class AwardService extends Service
$awards = [];
$formatted_awards = [];
// Find the awards in the app/Awards directory
$classes = ClassLoader::getClassesInPath(app_path('/Awards'));
$awards = array_merge($awards, $classes);
// Find the awards in the modules/Awards directory
// $classes = ClassLoader::getClassesInPath(module_path('Awards'));
// $awards = array_merge($awards, $classes);
// Look throughout all the other modules, in the module/{MODULE}/Awards directory
foreach (Module::all() as $module) {
@ -33,7 +34,7 @@ class AwardService extends Service
}
foreach ($awards as $award) {
$formatted_awards[\get_class($award)] = $award;
$formatted_awards[get_class($award)] = $award;
}
return $formatted_awards;

View File

@ -0,0 +1,44 @@
<?php
namespace App\Services;
use App\Contracts\Service;
use App\Events\NewsAdded;
use App\Repositories\NewsRepository;
class NewsService extends Service
{
private $newsRepo;
public function __construct(NewsRepository $newsRepo)
{
$this->newsRepo = $newsRepo;
}
/**
* Add a news item
*
* @param array $attrs
*
* @throws \Prettus\Validator\Exceptions\ValidatorException
*
* @return mixed
*/
public function addNews(array $attrs)
{
$news = $this->newsRepo->create($attrs);
event(new NewsAdded($news));
return $news;
}
/**
* Delete something from the news items
*
* @param int $id ID of the news row to delete
*/
public function deleteNews($id)
{
$this->newsRepo->delete($id);
}
}

View File

@ -1,6 +1,6 @@
<?php
use App\Notifications\Backups;
use App\Notifications\Notifiables\Backups;
use Spatie\Backup\Notifications\Notifications\BackupHasFailed;
use Spatie\Backup\Notifications\Notifications\BackupWasSuccessful;
use Spatie\Backup\Notifications\Notifications\CleanupHasFailed;

26
config/notifications.php Normal file
View File

@ -0,0 +1,26 @@
<?php
use App\Notifications\Messages\AdminUserRegistered;
use App\Notifications\Messages\NewsAdded;
use App\Notifications\Messages\PirepAccepted;
use App\Notifications\Messages\PirepRejected;
use App\Notifications\Messages\PirepSubmitted;
use App\Notifications\Messages\UserPending;
use App\Notifications\Messages\UserRegistered;
use App\Notifications\Messages\UserRejected;
return [
/*
* The channels that notifications are sent on
*/
'channels' => [
AdminUserRegistered::class => ['mail'],
NewsAdded::class => ['mail'],
PirepAccepted::class => ['mail'],
PirepRejected::class => ['mail'],
PirepSubmitted::class => ['mail'],
UserPending::class => ['mail'],
UserRegistered::class => ['mail'],
UserRejected::class => ['mail'],
],
];

1
modules/.gitignore vendored
View File

@ -3,6 +3,7 @@
/*
/*/
!.gitignore
!/Awards
!/Installer
!/Sample
!/Vacentral

View File

@ -1,12 +1,14 @@
<?php
namespace App\Awards;
namespace Modules\Awards\Awards;
use App\Contracts\Award;
/**
* Simple example of an awards class, where you can apply an award when a user
* has 100 flights. All award classes need to extend the AwardInterface
* has 100 flights. All award classes need to extend Award and implement the check() method
*
* See: http://docs.phpvms.net/customizing/awards
*/
class PilotFlightAwards extends Award
{

View File

@ -0,0 +1,12 @@
{
"name": "Awards",
"alias": "awards",
"description": "",
"keywords": [],
"active": 1,
"order": 0,
"providers": [],
"aliases": {},
"files": [],
"requires": []
}

View File

@ -0,0 +1,12 @@
@component('mail::message')
# {{ $news->subject }}
$news->body
@component('mail::button', ['url' => route('frontend.pireps.show', [$pirep->id])])
View PIREP
@endcomponent
Thanks,<br>
{{ config('app.name') }}
@endcomponent

View File

@ -34,7 +34,7 @@ class AwardsTest extends TestCase
{
// Create one award that's given out with one flight
$award = factory(App\Models\Award::class)->create([
'ref_model' => App\Awards\PilotFlightAwards::class,
'ref_model' => Modules\Awards\Awards\PilotFlightAwards::class,
'ref_model_params' => 1,
]);

View File

@ -6,11 +6,13 @@ use App\Models\Enums\AcarsType;
use App\Models\Enums\PirepState;
use App\Models\Pirep;
use App\Models\User;
use App\Notifications\Messages\PirepAccepted;
use App\Repositories\SettingRepository;
use App\Services\BidService;
use App\Services\FlightService;
use App\Services\PirepService;
use Carbon\Carbon;
use Illuminate\Support\Facades\Notification;
class PIREPTest extends TestCase
{
@ -81,7 +83,6 @@ class PIREPTest extends TestCase
* Now set the PIREP state to ACCEPTED
*/
$new_pirep_count = $pirep->pilot->flights + 1;
$original_flight_time = $pirep->pilot->flight_time;
$new_flight_time = $pirep->pilot->flight_time + $pirep->flight_time;
$this->pirepSvc->changeState($pirep, PirepState::ACCEPTED);
@ -96,6 +97,9 @@ class PIREPTest extends TestCase
$this->get('/api/fleet/aircraft/'.$pirep->aircraft_id, [], $user)
->assertJson(['data' => ['airport_id' => $pirep->arr_airport_id]]);
// Make sure a notification was sent out to both the user and the admin(s)
Notification::assertSentTo([$user], PirepAccepted::class);
// Try cancelling it
$uri = '/api/pireps/'.$pirep->id.'/cancel';
$response = $this->put($uri, [], [], $user);

View File

@ -8,7 +8,7 @@ use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use Tests\CreatesApplication;
use Tests\TestData;
@ -46,7 +46,7 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
ThrottleRequests::class
);
Mail::fake();
Notification::fake();
Artisan::call('database:create', ['--reset' => true]);
Artisan::call('migrate:refresh', ['--env' => 'testing']);