Discord notifications for PIREP and News events #433 (#1215)

* Discord notifications for events #433

* Style fixes

* Check for blank webhook urls and disable

* Cleanup items after review

* Changes and fixes

* Style fixes

* Don't load env for testing

* Fix status text

* Refactor saving fields/fares so events get the latest data

* Cleanup

* Style fixes
This commit is contained in:
Nabeel S
2021-06-04 10:51:59 -04:00
committed by GitHub
parent 17447c6903
commit 9b2e466b7e
46 changed files with 1249 additions and 456 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ FROM php:7.4-fpm-alpine
WORKDIR /var/www/ WORKDIR /var/www/
RUN apk add gmp-dev icu-dev RUN apk add gmp-dev icu-dev zlib-dev libpng-dev
RUN curl --silent --show-error https://getcomposer.org/installer | php RUN curl --silent --show-error https://getcomposer.org/installer | php
# Copy any config files in # Copy any config files in
+2 -2
View File
@@ -17,8 +17,8 @@ class EmailTest extends Command
*/ */
public function handle() public function handle()
{ {
/** @var App\Notifications\EventHandler $eventHandler */ /** @var App\Notifications\NotificationEventsHandler $eventHandler */
$eventHandler = app(App\Notifications\EventHandler::class); $eventHandler = app(App\Notifications\NotificationEventsHandler::class);
$news = new App\Models\News(); $news = new App\Models\News();
$news->user_id = 1; $news->user_id = 1;
+12 -4
View File
@@ -2,9 +2,9 @@
namespace App\Contracts; namespace App\Contracts;
use App\Notifications\Channels\Discord\DiscordMessage;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Log;
class Notification extends \Illuminate\Notifications\Notification implements ShouldQueue class Notification extends \Illuminate\Notifications\Notification implements ShouldQueue
{ {
@@ -17,14 +17,14 @@ class Notification extends \Illuminate\Notifications\Notification implements Sho
{ {
// Look in the notifications.channels config and see where this particular // Look in the notifications.channels config and see where this particular
// notification can go. Map it to $channels // notification can go. Map it to $channels
$klass = static::class; /*$klass = static::class;
$notif_config = config('notifications.channels', []); $notif_config = config('notifications.channels', []);
if (!array_key_exists($klass, $notif_config)) { if (!array_key_exists($klass, $notif_config)) {
Log::error('Notification type '.$klass.' missing from notifications config, defaulting to mail'); Log::error('Notification type '.$klass.' missing from notifications config, defaulting to mail');
return; return;
} }
$this->channels = $notif_config[$klass]; $this->channels = $notif_config[$klass];*/
} }
/** /**
@@ -34,8 +34,16 @@ class Notification extends \Illuminate\Notifications\Notification implements Sho
* *
* @return array * @return array
*/ */
public function via($notifiable) /*public function via($notifiable)
{ {
return $this->channels; return $this->channels;
}*/
/**
* @return DiscordMessage|null
*/
public function toDiscordChannel($notifiable): ?DiscordMessage
{
return null;
} }
} }
+12 -11
View File
@@ -2,11 +2,14 @@
namespace App\Contracts; namespace App\Contracts;
use Exception;
use Illuminate\Validation\Validator; use Illuminate\Validation\Validator;
use function is_array;
use Prettus\Repository\Eloquent\BaseRepository; use Prettus\Repository\Eloquent\BaseRepository;
use Prettus\Repository\Exceptions\RepositoryException;
/** /**
* @mixin \Prettus\Repository\Eloquent\BaseRepository * @mixin BaseRepository
*/ */
abstract class Repository extends BaseRepository abstract class Repository extends BaseRepository
{ {
@@ -20,8 +23,8 @@ abstract class Repository extends BaseRepository
{ {
try { try {
return $this->find($id, $columns); return $this->find($id, $columns);
} catch (\Exception $e) { } catch (Exception $e) {
return; return null;
} }
} }
@@ -32,11 +35,7 @@ abstract class Repository extends BaseRepository
*/ */
public function validate($values) public function validate($values)
{ {
$validator = Validator::make( $validator = Validator::make($values, $this->model()->rules);
$values,
$this->model()->rules
);
if ($validator->fails()) { if ($validator->fails()) {
return $validator->messages(); return $validator->messages();
} }
@@ -50,6 +49,8 @@ abstract class Repository extends BaseRepository
* @param int $count * @param int $count
* @param string $sort_by created_at (default) or updated_at * @param string $sort_by created_at (default) or updated_at
* *
* @throws RepositoryException
*
* @return mixed * @return mixed
*/ */
public function recent($count = null, $sort_by = 'created_at') public function recent($count = null, $sort_by = 'created_at')
@@ -71,7 +72,7 @@ abstract class Repository extends BaseRepository
return $this->scopeQuery(function ($query) use ($where, $sort_by, $order_by) { return $this->scopeQuery(function ($query) use ($where, $sort_by, $order_by) {
$q = $query->where($where); $q = $query->where($where);
// See if there are multi-column sorts // See if there are multi-column sorts
if (\is_array($sort_by)) { if (is_array($sort_by)) {
foreach ($sort_by as $key => $sort) { foreach ($sort_by as $key => $sort) {
$q = $q->orderBy($key, $sort); $q = $q->orderBy($key, $sort);
} }
@@ -98,7 +99,7 @@ abstract class Repository extends BaseRepository
return $this->scopeQuery(function ($query) use ($col, $values, $sort_by, $order_by) { return $this->scopeQuery(function ($query) use ($col, $values, $sort_by, $order_by) {
$q = $query->whereNotIn($col, $values); $q = $query->whereNotIn($col, $values);
// See if there are multi-column sorts // See if there are multi-column sorts
if (\is_array($sort_by)) { if (is_array($sort_by)) {
foreach ($sort_by as $key => $sort) { foreach ($sort_by as $key => $sort) {
$q = $q->orderBy($key, $sort); $q = $q->orderBy($key, $sort);
} }
@@ -118,7 +119,7 @@ abstract class Repository extends BaseRepository
* @param array $columns * @param array $columns
* @param string $method * @param string $method
* *
* @throws \Prettus\Repository\Exceptions\RepositoryException * @throws RepositoryException
* *
* @return mixed * @return mixed
*/ */
@@ -0,0 +1,32 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class DiscordFields extends Migration
{
public function up()
{
// Delete the old Discord fields and then a webhook will get added
DB::table('settings')
->where(['key' => 'notifications.discord_api_key'])
->delete();
DB::table('settings')
->where(['key' => 'notifications.discord_public_channel_id'])
->delete();
DB::table('settings')
->where(['key' => 'notifications.discord_public_channel_id'])
->delete();
// Add a field to the user to enter their own Discord ID
Schema::table('users', function (Blueprint $table) {
$table->string('discord_id')
->default('')
->after('rank_id');
});
}
}
+8 -8
View File
@@ -368,20 +368,20 @@
options: '' options: ''
type: boolean type: boolean
description: 'Count transfer hours in calculations, like ranks and the total hours' description: 'Count transfer hours in calculations, like ranks and the total hours'
- key: notifications.discord_api_key - key: notifications.discord_public_webhook_url
name: Discord API token name: Discord Public Webhook URL
group: notifications group: notifications
value: '' value: ''
options: '' options: ''
type: text type: text
description: Discord API token for notifications description: The Discord Webhook URL for public notifications
- key: 'notifications.discord_public_channel_id' - key: notifications.discord_private_webhook_url
name: 'Discord Public Channel ID' name: Discord Private Webhook URL
group: 'notifications' group: notifications
value: '' value: ''
options: '' options: ''
type: 'text' type: text
description: 'Discord public channel ID for broadcasat notifications' description: The Discord Webhook URL for private notifications
- key: 'cron.random_id' - key: 'cron.random_id'
name: 'Cron Randomized ID' name: 'Cron Randomized ID'
group: 'cron' group: 'cron'
+16
View File
@@ -0,0 +1,16 @@
<?php
namespace App\Events;
use App\Contracts\Event;
use App\Models\Pirep;
class PirepStateChange extends Event
{
public $pirep;
public function __construct(Pirep $pirep)
{
$this->pirep = $pirep;
}
}
+19
View File
@@ -0,0 +1,19 @@
<?php
namespace App\Events;
use App\Contracts\Event;
use App\Models\Pirep;
/**
* Status change like Boarding, Taxi, etc
*/
class PirepStatusChange extends Event
{
public $pirep;
public function __construct(Pirep $pirep)
{
$this->pirep = $pirep;
}
}
+28 -34
View File
@@ -23,10 +23,10 @@ use App\Models\Enums\PirepFieldSource;
use App\Models\Enums\PirepSource; use App\Models\Enums\PirepSource;
use App\Models\Pirep; use App\Models\Pirep;
use App\Models\PirepComment; use App\Models\PirepComment;
use App\Repositories\AcarsRepository; use App\Models\PirepFare;
use App\Models\PirepFieldValue;
use App\Repositories\JournalRepository; use App\Repositories\JournalRepository;
use App\Repositories\PirepRepository; use App\Repositories\PirepRepository;
use App\Services\FareService;
use App\Services\Finance\PirepFinanceService; use App\Services\Finance\PirepFinanceService;
use App\Services\PirepService; use App\Services\PirepService;
use App\Services\UserService; use App\Services\UserService;
@@ -37,8 +37,6 @@ use Illuminate\Support\Facades\Log;
class PirepController extends Controller class PirepController extends Controller
{ {
private $acarsRepo;
private $fareSvc;
private $financeSvc; private $financeSvc;
private $journalRepo; private $journalRepo;
private $pirepRepo; private $pirepRepo;
@@ -46,8 +44,6 @@ class PirepController extends Controller
private $userSvc; private $userSvc;
/** /**
* @param AcarsRepository $acarsRepo
* @param FareService $fareSvc
* @param PirepFinanceService $financeSvc * @param PirepFinanceService $financeSvc
* @param JournalRepository $journalRepo * @param JournalRepository $journalRepo
* @param PirepRepository $pirepRepo * @param PirepRepository $pirepRepo
@@ -55,16 +51,12 @@ class PirepController extends Controller
* @param UserService $userSvc * @param UserService $userSvc
*/ */
public function __construct( public function __construct(
AcarsRepository $acarsRepo,
FareService $fareSvc,
PirepFinanceService $financeSvc, PirepFinanceService $financeSvc,
JournalRepository $journalRepo, JournalRepository $journalRepo,
PirepRepository $pirepRepo, PirepRepository $pirepRepo,
PirepService $pirepSvc, PirepService $pirepSvc,
UserService $userSvc UserService $userSvc
) { ) {
$this->acarsRepo = $acarsRepo;
$this->fareSvc = $fareSvc;
$this->financeSvc = $financeSvc; $this->financeSvc = $financeSvc;
$this->journalRepo = $journalRepo; $this->journalRepo = $journalRepo;
$this->pirepRepo = $pirepRepo; $this->pirepRepo = $pirepRepo;
@@ -101,7 +93,7 @@ class PirepController extends Controller
/** /**
* Check if a PIREP is cancelled * Check if a PIREP is cancelled
* *
* @param $pirep * @param Pirep $pirep
* *
* @throws \App\Exceptions\PirepCancelled * @throws \App\Exceptions\PirepCancelled
*/ */
@@ -113,50 +105,52 @@ class PirepController extends Controller
} }
/** /**
* @param $pirep
* @param Request $request * @param Request $request
*
* @return PirepFieldValue[]
*/ */
protected function updateFields($pirep, Request $request) protected function getFields(Request $request): ?array
{ {
if (!$request->filled('fields')) { if (!$request->filled('fields')) {
return; return [];
} }
$pirep_fields = []; $pirep_fields = [];
foreach ($request->input('fields') as $field_name => $field_value) { foreach ($request->input('fields') as $field_name => $field_value) {
$pirep_fields[] = [ $pirep_fields[] = new PirepFieldValue([
'name' => $field_name, 'name' => $field_name,
'value' => $field_value, 'value' => $field_value,
'source' => PirepFieldSource::ACARS, 'source' => PirepFieldSource::ACARS,
]; ]);
} }
$this->pirepSvc->updateCustomFields($pirep->id, $pirep_fields); return $pirep_fields;
} }
/** /**
* Save the fares * Save the fares
* *
* @param $pirep
* @param Request $request * @param Request $request
* *
* @throws \Exception * @throws \Exception
*
* @return PirepFare[]
*/ */
protected function updateFares($pirep, Request $request) protected function getFares(Request $request): ?array
{ {
if (!$request->filled('fares')) { if (!$request->filled('fares')) {
return; return [];
} }
$fares = []; $fares = [];
foreach ($request->post('fares') as $fare) { foreach ($request->post('fares') as $fare) {
$fares[] = [ $fares[] = new PirepFare([
'fare_id' => $fare['id'], 'fare_id' => $fare['id'],
'count' => $fare['count'], 'count' => $fare['count'],
]; ]);
} }
$this->fareSvc->saveForPirep($pirep, $fares); return $fares;
} }
/** /**
@@ -210,14 +204,13 @@ class PirepController extends Controller
$attrs = $this->parsePirep($request); $attrs = $this->parsePirep($request);
$attrs['source'] = PirepSource::ACARS; $attrs['source'] = PirepSource::ACARS;
$pirep = $this->pirepSvc->prefile($user, $attrs); $fields = $this->getFields($request);
$fares = $this->getFares($request);
$pirep = $this->pirepSvc->prefile($user, $attrs, $fields, $fares);
Log::info('PIREP PREFILED'); Log::info('PIREP PREFILED');
Log::info($pirep->id); Log::info($pirep->id);
$this->updateFields($pirep, $request);
$this->updateFares($pirep, $request);
return $this->get($pirep->id); return $this->get($pirep->id);
} }
@@ -258,9 +251,9 @@ class PirepController extends Controller
} }
} }
$pirep = $this->pirepRepo->update($attrs, $pirep_id); $fields = $this->getFields($request);
$this->updateFields($pirep, $request); $fares = $this->getFares($request);
$this->updateFares($pirep, $request); $pirep = $this->pirepSvc->update($pirep_id, $attrs, $fields, $fares);
event(new PirepUpdated($pirep)); event(new PirepUpdated($pirep));
@@ -303,9 +296,9 @@ class PirepController extends Controller
} }
try { try {
$pirep = $this->pirepSvc->file($pirep, $attrs); $fields = $this->getFields($request);
$this->updateFields($pirep, $request); $fares = $this->getFares($request);
$this->updateFares($pirep, $request); $pirep = $this->pirepSvc->file($pirep, $attrs, $fields, $fares);
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error($e); Log::error($e);
@@ -411,7 +404,8 @@ class PirepController extends Controller
$pirep = Pirep::find($pirep_id); $pirep = Pirep::find($pirep_id);
$this->checkCancelled($pirep); $this->checkCancelled($pirep);
$this->updateFields($pirep, $request); $fields = $this->getFields($request);
$this->pirepSvc->updateCustomFields($pirep_id, $fields);
return new PirepFieldCollection($pirep->fields); return new PirepFieldCollection($pirep->fields);
} }
+1 -4
View File
@@ -6,10 +6,7 @@ use App\Contracts\Listener;
use App\Events\PirepPrefiled; use App\Events\PirepPrefiled;
/** /**
* Look for and run any of the award classes. Don't modify this. * Handler for PIREP events
* See the documentation on creating awards:
*
* @url http://docs.phpvms.net/customizing/awards
*/ */
class PirepEventsHandler extends Listener class PirepEventsHandler extends Listener
{ {
+9
View File
@@ -12,6 +12,7 @@ use Carbon\Carbon;
* @property int id * @property int id
* @property mixed subfleet_id * @property mixed subfleet_id
* @property string airport_id The apt where the aircraft is * @property string airport_id The apt where the aircraft is
* @property string ident
* @property string name * @property string name
* @property string icao * @property string icao
* @property string registration * @property string registration
@@ -71,6 +72,14 @@ class Aircraft extends Model
'zfw' => 'nullable|numeric', 'zfw' => 'nullable|numeric',
]; ];
/**
* @return string
*/
public function getIdentAttribute(): string
{
return $this->registration.' ('.$this->icao.')';
}
/** /**
* See if this aircraft is active * See if this aircraft is active
* *
+2 -2
View File
@@ -33,7 +33,7 @@ class PirepStatus extends Enum
public const LANDED = 'LAN'; public const LANDED = 'LAN';
public const ARRIVED = 'ONB'; // On block public const ARRIVED = 'ONB'; // On block
public const CANCELLED = 'DX'; public const CANCELLED = 'DX';
public const EMERG_DECENT = 'EMG'; public const EMERG_DESCENT = 'EMG';
protected static $labels = [ protected static $labels = [
self::INITIATED => 'pireps.status.initialized', self::INITIATED => 'pireps.status.initialized',
@@ -58,6 +58,6 @@ class PirepStatus extends Enum
self::LANDED => 'pireps.status.landed', self::LANDED => 'pireps.status.landed',
self::ARRIVED => 'pireps.status.arrived', self::ARRIVED => 'pireps.status.arrived',
self::CANCELLED => 'pireps.status.cancelled', self::CANCELLED => 'pireps.status.cancelled',
self::EMERG_DECENT => 'pireps.status.emerg_decent', self::EMERG_DESCENT => 'pireps.status.emerg_decent',
]; ];
} }
+3
View File
@@ -3,6 +3,7 @@
namespace App\Models; namespace App\Models;
use App\Contracts\Model; use App\Contracts\Model;
use Illuminate\Notifications\Notifiable;
/** /**
* @property int id * @property int id
@@ -13,6 +14,8 @@ use App\Contracts\Model;
*/ */
class News extends Model class News extends Model
{ {
use Notifiable;
public $table = 'news'; public $table = 'news';
protected $fillable = [ protected $fillable = [
+16 -2
View File
@@ -3,6 +3,8 @@
namespace App\Models; namespace App\Models;
use App\Contracts\Model; use App\Contracts\Model;
use App\Events\PirepStateChange;
use App\Events\PirepStatusChange;
use App\Models\Enums\AcarsType; use App\Models\Enums\AcarsType;
use App\Models\Enums\PirepFieldSource; use App\Models\Enums\PirepFieldSource;
use App\Models\Enums\PirepState; use App\Models\Enums\PirepState;
@@ -10,7 +12,9 @@ use App\Models\Traits\HashIdTrait;
use App\Support\Units\Distance; use App\Support\Units\Distance;
use App\Support\Units\Fuel; use App\Support\Units\Fuel;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Kleemans\AttributeEvents;
/** /**
* @property string id * @property string id
@@ -44,8 +48,8 @@ use Illuminate\Support\Collection;
* @property Flight|null flight * @property Flight|null flight
* @property Collection fields * @property Collection fields
* @property string status * @property string status
* @property PirepState state * @property int state
* @property int source * @property int source
* @property string source_name * @property string source_name
* @property Carbon submitted_at * @property Carbon submitted_at
* @property Carbon created_at * @property Carbon created_at
@@ -57,7 +61,9 @@ use Illuminate\Support\Collection;
*/ */
class Pirep extends Model class Pirep extends Model
{ {
use AttributeEvents;
use HashIdTrait; use HashIdTrait;
use Notifiable;
public $table = 'pireps'; public $table = 'pireps';
@@ -137,6 +143,14 @@ class Pirep extends Model
'route' => 'nullable', 'route' => 'nullable',
]; ];
/**
* Auto-dispatch events for lifecycle state changes
*/
protected $dispatchesEvents = [
'status:*' => PirepStatusChange::class,
'state:*' => PirepStateChange::class,
];
/* /*
* If a PIREP is in these states, then it can't be changed. * If a PIREP is in these states, then it can't be changed.
*/ */
+1
View File
@@ -11,6 +11,7 @@ use App\Models\Enums\PirepFieldSource;
* @property string slug * @property string slug
* @property string value * @property string value
* @property string source * @property string source
* @property Pirep pirep
* *
* @method static updateOrCreate(array $array, array $array1) * @method static updateOrCreate(array $array, array $array1)
*/ */
+3
View File
@@ -32,6 +32,7 @@ use Laratrust\Traits\LaratrustUserTrait;
* @property Rank rank * @property Rank rank
* @property Journal journal * @property Journal journal
* @property int rank_id * @property int rank_id
* @property string discord_id
* @property int state * @property int state
* @property bool opt_in * @property bool opt_in
* @property Pirep[] pireps * @property Pirep[] pireps
@@ -66,6 +67,7 @@ class User extends Authenticatable
'pilot_id', 'pilot_id',
'airline_id', 'airline_id',
'rank_id', 'rank_id',
'discord_id',
'api_key', 'api_key',
'country', 'country',
'home_airport_id', 'home_airport_id',
@@ -89,6 +91,7 @@ class User extends Authenticatable
*/ */
protected $hidden = [ protected $hidden = [
'api_key', 'api_key',
'discord_id',
'password', 'password',
'remember_token', 'remember_token',
]; ];
@@ -0,0 +1,36 @@
<?php
namespace App\Notifications\Channels\Discord;
use App\Contracts\Notification;
use App\Support\HttpClient;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7;
use Illuminate\Support\Facades\Log;
class Discord
{
private $httpClient;
public function __construct(HttpClient $httpClient)
{
$this->httpClient = $httpClient;
}
public function send($notifiable, Notification $notification)
{
$message = $notification->toDiscordChannel($notifiable);
if ($message === null || empty($message->webhook_url)) {
Log::debug('Discord notifications not configured, skipping');
return;
}
try {
$data = $message->toArray();
$this->httpClient->post($message->webhook_url, $data);
} catch (RequestException $e) {
$response = Psr7\Message::toString($e->getResponse());
Log::error('Error sending Discord notification: '.$e->getMessage().', '.$response);
}
}
}
@@ -0,0 +1,140 @@
<?php
namespace App\Notifications\Channels\Discord;
use Carbon\Carbon;
/**
* Original is from https://gist.github.com/freekmurze/e4415090f650e070d3de8b905875cf78
*
* Markdown guide: https://birdie0.github.io/discord-webhooks-guide/other/discord_markdown.html
*/
class DiscordMessage
{
const COLOR_SUCCESS = '#0B6623';
const COLOR_WARNING = '#FD6A02';
const COLOR_ERROR = '#ED2939';
public $webhook_url;
protected $title;
protected $url;
protected $description;
protected $timestamp;
protected $footer;
protected $color;
protected $author = [];
protected $fields = [];
/**
* Supply the webhook URL that this should be going to
*/
public function webhook(string $url): self
{
$this->webhook_url = $url;
return $this;
}
/**
* Title of the notification
*/
public function title(string $title): self
{
$this->title = $title;
return $this;
}
public function url(string $url): self
{
$this->url = $url;
return $this;
}
/**
* @param array|string $descriptionLines
*/
public function description($descriptionLines): self
{
if (!is_array($descriptionLines)) {
$descriptionLines = [$descriptionLines];
}
$this->description = implode(PHP_EOL, $descriptionLines);
return $this;
}
/**
* Set the author information:
* [
* 'name' => '',
* 'url' => '',
* 'icon_url' => '',
*/
public function author(array $author): self
{
$this->author = $author;
return $this;
}
/**
* Set the fields
*/
public function fields(array $fields): self
{
$this->fields = [];
foreach ($fields as $name => $value) {
$this->fields[] = [
'name' => '**'.$name.'**', // bold
'value' => $value,
'inline' => true,
];
}
return $this;
}
public function footer(string $footer): self
{
$this->footer = $footer;
return $this;
}
public function success(): self
{
$this->color = static::COLOR_SUCCESS;
return $this;
}
public function warning(): self
{
$this->color = static::COLOR_WARNING;
return $this;
}
public function error(): self
{
$this->color = static::COLOR_ERROR;
return $this;
}
public function toArray(): array
{
return [
'embeds' => [
[
'title' => $this->title,
'url' => $this->url,
'type' => 'rich',
'description' => $this->description,
// 'color' => hexdec($this->color),
'author' => $this->author,
'fields' => $this->fields,
'footer' => [
'text' => $this->footer ?? '',
],
'timestamp' => Carbon::now('UTC'),
],
],
];
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ trait MailChannel
* @param string $template Markdown template to use * @param string $template Markdown template to use
* @param array $args Arguments to pass to the template * @param array $args Arguments to pass to the template
*/ */
public function setMailable($subject, $template, $args) public function setMailable(string $subject, string $template, array $args)
{ {
$this->mailSubject = $subject; $this->mailSubject = $subject;
$this->mailTemplate = $template; $this->mailTemplate = $template;
@@ -4,17 +4,15 @@ namespace App\Notifications\Messages;
use App\Contracts\Notification; use App\Contracts\Notification;
use App\Models\User; use App\Models\User;
use App\Notifications\Channels\Discord\Discord;
use App\Notifications\Channels\Discord\DiscordMessage;
use App\Notifications\Channels\MailChannel; use App\Notifications\Channels\MailChannel;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
class AdminUserRegistered extends Notification implements ShouldQueue class AdminUserRegistered extends Notification implements ShouldQueue
{ {
use Queueable;
use MailChannel; use MailChannel;
public $channels = ['mail'];
private $user; private $user;
/** /**
@@ -34,6 +32,32 @@ class AdminUserRegistered extends Notification implements ShouldQueue
); );
} }
public function via($notifiable)
{
return ['mail', Discord::class];
}
/**
* Send a Discord notification
*
* @param User $pirep
* @param mixed $user
*
* @return DiscordMessage|null
*/
public function toDiscordChannel($user): ?DiscordMessage
{
if (empty(setting('notifications.discord_private_webhook_url'))) {
return null;
}
$dm = new DiscordMessage();
return $dm->webhook(setting('notifications.discord_private_webhook_url'))
->success()
->title('New User Registered: '.$user->ident)
->fields([]);
}
public function toArray($notifiable) public function toArray($notifiable)
{ {
return [ return [
+30 -3
View File
@@ -4,16 +4,15 @@ namespace App\Notifications\Messages;
use App\Contracts\Notification; use App\Contracts\Notification;
use App\Models\News; use App\Models\News;
use App\Notifications\Channels\Discord\Discord;
use App\Notifications\Channels\Discord\DiscordMessage;
use App\Notifications\Channels\MailChannel; use App\Notifications\Channels\MailChannel;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
class NewsAdded extends Notification implements ShouldQueue class NewsAdded extends Notification implements ShouldQueue
{ {
use Queueable;
use MailChannel; use MailChannel;
public $channels = ['mail'];
public $requires_opt_in = true; public $requires_opt_in = true;
private $news; private $news;
@@ -30,6 +29,34 @@ class NewsAdded extends Notification implements ShouldQueue
); );
} }
public function via($notifiable)
{
return ['mail', Discord::class];
}
/**
* @param News $news
*
* @return DiscordMessage|null
*/
public function toDiscordChannel($news): ?DiscordMessage
{
if (empty(setting('notifications.discord_public_webhook_url'))) {
return null;
}
$dm = new DiscordMessage();
return $dm->webhook(setting('notifications.discord_public_webhook_url'))
->success()
->title('News: '.$news->subject)
->author([
'name' => $news->user->ident.' - '.$news->user->name_private,
'url' => '',
'icon_url' => $news->user->resolveAvatarUrl(),
])
->description($news->body);
}
/** /**
* Get the array representation of the notification. * Get the array representation of the notification.
* *
+6 -5
View File
@@ -5,19 +5,15 @@ namespace App\Notifications\Messages;
use App\Contracts\Notification; use App\Contracts\Notification;
use App\Models\Pirep; use App\Models\Pirep;
use App\Notifications\Channels\MailChannel; use App\Notifications\Channels\MailChannel;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
/** /**
* Send the PIREP accepted message to a particular user * Send the PIREP accepted message to a particular user, can also be sent to Discord
*/ */
class PirepAccepted extends Notification implements ShouldQueue class PirepAccepted extends Notification implements ShouldQueue
{ {
use Queueable;
use MailChannel; use MailChannel;
public $channels = ['mail'];
private $pirep; private $pirep;
/** /**
@@ -38,6 +34,11 @@ class PirepAccepted extends Notification implements ShouldQueue
); );
} }
public function via($notifiable)
{
return ['mail'];
}
/** /**
* Get the array representation of the notification. * Get the array representation of the notification.
* *
@@ -0,0 +1,102 @@
<?php
namespace App\Notifications\Messages;
use App\Contracts\Notification;
use App\Models\Pirep;
use App\Notifications\Channels\Discord\Discord;
use App\Notifications\Channels\Discord\DiscordMessage;
use App\Support\Units\Distance;
use App\Support\Units\Time;
use Illuminate\Contracts\Queue\ShouldQueue;
use PhpUnitsOfMeasure\Exception\NonNumericValue;
use PhpUnitsOfMeasure\Exception\NonStringUnitName;
/**
* Send the PIREP accepted message to a particular user, can also be sent to Discord
*/
class PirepPrefiled extends Notification implements ShouldQueue
{
private $pirep;
/**
* Create a new notification instance.
*
* @param Pirep $pirep
*/
public function __construct(Pirep $pirep)
{
parent::__construct();
$this->pirep = $pirep;
}
public function via($notifiable)
{
return [Discord::class];
}
/**
* Send a Discord notification
*
* @param Pirep $pirep
*
* @return DiscordMessage|null
*/
public function toDiscordChannel($pirep): ?DiscordMessage
{
if (empty(setting('notifications.discord_public_webhook_url'))) {
return null;
}
$title = 'Flight '.$pirep->airline->code.$pirep->ident.' Prefiled';
$fields = [
'Flight' => $pirep->airline->code.$pirep->ident,
'Departure Airport' => $pirep->dpt_airport_id,
'Arrival Airport' => $pirep->arr_airport_id,
'Equipment' => $pirep->aircraft->ident,
'Flight Time (Planned)' => Time::minutesToTimeString($pirep->planned_flight_time),
];
if ($pirep->planned_distance) {
try {
$planned_distance = new Distance(
$pirep->planned_distance,
config('phpvms.internal_units.distance')
);
$pd = $planned_distance[$planned_distance->unit].' '.$planned_distance->unit;
$fields['Distance (Planned)'] = $pd;
} catch (NonNumericValue $e) {
} catch (NonStringUnitName $e) {
}
}
$dm = new DiscordMessage();
return $dm->webhook(setting('notifications.discord_public_webhook_url'))
->success()
->title($title)
->description($pirep->user->discord_id ? 'Flight by <@'.$pirep->user->discord_id.'>' : '')
->url(route('frontend.pireps.show', [$pirep->id]))
->author([
'name' => $pirep->user->ident.' - '.$pirep->user->name_private,
'url' => route('frontend.pireps.show', [$pirep->id]),
'icon_url' => $pirep->user->resolveAvatarUrl(),
])
->fields($fields);
}
/**
* 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,
];
}
}
+6 -5
View File
@@ -5,22 +5,18 @@ namespace App\Notifications\Messages;
use App\Contracts\Notification; use App\Contracts\Notification;
use App\Models\Pirep; use App\Models\Pirep;
use App\Notifications\Channels\MailChannel; use App\Notifications\Channels\MailChannel;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
class PirepRejected extends Notification implements ShouldQueue class PirepRejected extends Notification implements ShouldQueue
{ {
use Queueable;
use MailChannel; use MailChannel;
public $channels = ['mail'];
private $pirep; private $pirep;
/** /**
* Create a new notification instance. * Create a new notification instance.
* *
* @param \App\Models\Pirep $pirep * @param Pirep $pirep
*/ */
public function __construct(Pirep $pirep) public function __construct(Pirep $pirep)
{ {
@@ -35,6 +31,11 @@ class PirepRejected extends Notification implements ShouldQueue
); );
} }
public function via($notifiable)
{
return ['mail'];
}
/** /**
* Get the array representation of the notification. * Get the array representation of the notification.
* *
@@ -0,0 +1,141 @@
<?php
namespace App\Notifications\Messages;
use App\Contracts\Notification;
use App\Models\Enums\PirepStatus;
use App\Models\Pirep;
use App\Notifications\Channels\Discord\Discord;
use App\Notifications\Channels\Discord\DiscordMessage;
use App\Support\Units\Distance;
use App\Support\Units\Time;
use Illuminate\Contracts\Queue\ShouldQueue;
use PhpUnitsOfMeasure\Exception\NonNumericValue;
use PhpUnitsOfMeasure\Exception\NonStringUnitName;
/**
* Send the PIREP accepted message to a particular user, can also be sent to Discord
*/
class PirepStatusChanged extends Notification implements ShouldQueue
{
private $pirep;
// TODO: Int'l languages for these
protected static $verbs = [
PirepStatus::INITIATED => 'is initialized',
PirepStatus::SCHEDULED => 'is scheduled',
PirepStatus::BOARDING => 'is boarding',
PirepStatus::RDY_START => 'is ready for start',
PirepStatus::PUSHBACK_TOW => 'is pushing back',
PirepStatus::DEPARTED => 'has departed',
PirepStatus::RDY_DEICE => 'is ready for de-icing',
PirepStatus::STRT_DEICE => 'is de-icing',
PirepStatus::GRND_RTRN => 'on ground return',
PirepStatus::TAXI => 'is taxiing',
PirepStatus::TAKEOFF => 'has taken off',
PirepStatus::INIT_CLIM => 'in initial climb',
PirepStatus::AIRBORNE => 'is enroute',
PirepStatus::ENROUTE => 'is enroute',
PirepStatus::DIVERTED => 'has diverted',
PirepStatus::APPROACH => 'on approach',
PirepStatus::APPROACH_ICAO => 'on approach',
PirepStatus::ON_FINAL => 'on final approach',
PirepStatus::LANDING => 'is landing',
PirepStatus::LANDED => 'has landed',
PirepStatus::ARRIVED => 'has arrived',
PirepStatus::CANCELLED => 'has cancelled',
PirepStatus::EMERG_DESCENT => 'in emergency descent',
];
/**
* Create a new notification instance.
*
* @param Pirep $pirep
*/
public function __construct(Pirep $pirep)
{
parent::__construct();
$this->pirep = $pirep;
}
public function via($notifiable)
{
return [Discord::class];
}
/**
* Send a Discord notification
*
* @param Pirep $pirep
*
* @return DiscordMessage|null
*/
public function toDiscordChannel($pirep): ?DiscordMessage
{
if (empty(setting('notifications.discord_public_webhook_url'))) {
return null;
}
$title = 'Flight '.$pirep->airline->code.$pirep->ident.' '.self::$verbs[$pirep->status];
$fields = [
'Flight' => $pirep->airline->code.$pirep->ident,
'Departure Airport' => $pirep->dpt_airport_id,
'Arrival Airport' => $pirep->arr_airport_id,
'Equipment' => $pirep->aircraft->ident,
'Flight Time' => Time::minutesToTimeString($pirep->flight_time),
];
// Show the distance, but include the planned distance if it's been set
if ($pirep->distance) {
$unit = config('phpvms.internal_units.distance');
try {
$planned_distance = new Distance($pirep->distance, $unit);
$pd = $planned_distance[$planned_distance->unit];
$fields['Distance'] = $pd;
// Add the planned distance in
if ($pirep->planned_distance) {
try {
$planned_distance = new Distance($pirep->planned_distance, $unit);
$pd = $planned_distance[$planned_distance->unit];
$fields['Distance'] .= '/'.$pd;
} catch (NonNumericValue | NonStringUnitName $e) {
}
}
$fields['Distance'] .= ' '.$planned_distance->unit;
} catch (NonNumericValue | NonStringUnitName $e) {
}
}
$dm = new DiscordMessage();
return $dm->webhook(setting('notifications.discord_public_webhook_url'))
->success()
->title($title)
->description($pirep->user->discord_id ? 'Flight by <@'.$pirep->user->discord_id.'>' : '')
->url(route('frontend.pireps.show', [$pirep->id]))
->author([
'name' => $pirep->user->ident.' - '.$pirep->user->name_private,
'url' => route('frontend.pireps.show', [$pirep->id]),
'icon_url' => $pirep->user->resolveAvatarUrl(),
])
->fields($fields);
}
/**
* 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,
];
}
}
+60 -4
View File
@@ -4,17 +4,19 @@ namespace App\Notifications\Messages;
use App\Contracts\Notification; use App\Contracts\Notification;
use App\Models\Pirep; use App\Models\Pirep;
use App\Notifications\Channels\Discord\Discord;
use App\Notifications\Channels\Discord\DiscordMessage;
use App\Notifications\Channels\MailChannel; use App\Notifications\Channels\MailChannel;
use Illuminate\Bus\Queueable; use App\Support\Units\Distance;
use App\Support\Units\Time;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use PhpUnitsOfMeasure\Exception\NonNumericValue;
use PhpUnitsOfMeasure\Exception\NonStringUnitName;
class PirepSubmitted extends Notification implements ShouldQueue class PirepSubmitted extends Notification implements ShouldQueue
{ {
use Queueable;
use MailChannel; use MailChannel;
public $channels = ['mail'];
private $pirep; private $pirep;
/** /**
@@ -35,6 +37,60 @@ class PirepSubmitted extends Notification implements ShouldQueue
); );
} }
public function via($notifiable)
{
return ['mail', Discord::class];
}
/**
* Send a Discord notification
*
* @param Pirep $pirep
*
* @return DiscordMessage|null
*/
public function toDiscordChannel($pirep): ?DiscordMessage
{
if (empty(setting('notifications.discord_public_webhook_url'))) {
return null;
}
$title = 'Flight '.$pirep->airline->code.$pirep->ident.' Filed';
$fields = [
'Flight' => $pirep->airline->code.$pirep->ident,
'Departure Airport' => $pirep->dpt_airport_id,
'Arrival Airport' => $pirep->arr_airport_id,
'Equipment' => $pirep->aircraft->ident,
'Flight Time (Planned)' => Time::minutesToTimeString($pirep->planned_flight_time),
];
if ($pirep->planned_distance) {
try {
$planned_distance = new Distance(
$pirep->planned_distance,
config('phpvms.internal_units.distance')
);
$pd = $planned_distance[$planned_distance->unit].' '.$planned_distance->unit;
$fields['Distance (Planned)'] = $pd;
} catch (NonNumericValue | NonStringUnitName $e) {
}
}
$dm = new DiscordMessage();
return $dm->webhook(setting('notifications.discord_public_webhook_url'))
->success()
->title($title)
->description($pirep->user->discord_id ? 'Flight by <@'.$pirep->user->discord_id.'>' : '')
->url(route('frontend.pireps.show', [$pirep->id]))
->author([
'name' => $pirep->user->ident.' - '.$pirep->user->name_private,
'url' => route('frontend.pireps.show', [$pirep->id]),
'icon_url' => $pirep->user->resolveAvatarUrl(),
])
->fields($fields);
}
/** /**
* Get the array representation of the notification. * Get the array representation of the notification.
* *
+6 -5
View File
@@ -5,20 +5,16 @@ namespace App\Notifications\Messages;
use App\Contracts\Notification; use App\Contracts\Notification;
use App\Models\User; use App\Models\User;
use App\Notifications\Channels\MailChannel; use App\Notifications\Channels\MailChannel;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
class UserPending extends Notification implements ShouldQueue class UserPending extends Notification implements ShouldQueue
{ {
use Queueable;
use MailChannel; use MailChannel;
public $channels = ['mail'];
private $user; private $user;
/** /**
* @param \App\Models\User $user * @param User $user
*/ */
public function __construct(User $user) public function __construct(User $user)
{ {
@@ -33,6 +29,11 @@ class UserPending extends Notification implements ShouldQueue
); );
} }
public function via($notifiable)
{
return ['mail'];
}
/** /**
* Get the array representation of the notification. * Get the array representation of the notification.
* *
@@ -5,22 +5,18 @@ namespace App\Notifications\Messages;
use App\Contracts\Notification; use App\Contracts\Notification;
use App\Models\User; use App\Models\User;
use App\Notifications\Channels\MailChannel; use App\Notifications\Channels\MailChannel;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
class UserRegistered extends Notification implements ShouldQueue class UserRegistered extends Notification implements ShouldQueue
{ {
use Queueable;
use MailChannel; use MailChannel;
public $channels = ['mail'];
private $user; private $user;
/** /**
* Create a new notification instance. * Create a new notification instance.
* *
* @param \App\Models\User $user * @param User $user
*/ */
public function __construct(User $user) public function __construct(User $user)
{ {
@@ -35,6 +31,11 @@ class UserRegistered extends Notification implements ShouldQueue
); );
} }
public function via($notifiable)
{
return ['mail'];
}
public function toArray($notifiable) public function toArray($notifiable)
{ {
return [ return [
+5 -2
View File
@@ -13,8 +13,6 @@ class UserRejected extends Notification implements ShouldQueue
use Queueable; use Queueable;
use MailChannel; use MailChannel;
public $channels = ['mail'];
private $user; private $user;
/** /**
@@ -33,6 +31,11 @@ class UserRejected extends Notification implements ShouldQueue
); );
} }
public function via($notifiable)
{
return ['mail'];
}
/** /**
* Get the array representation of the notification. * Get the array representation of the notification.
* *
@@ -6,13 +6,13 @@ use App\Contracts\Listener;
use App\Events\NewsAdded; use App\Events\NewsAdded;
use App\Events\PirepAccepted; use App\Events\PirepAccepted;
use App\Events\PirepFiled; use App\Events\PirepFiled;
use App\Events\PirepPrefiled;
use App\Events\PirepRejected; use App\Events\PirepRejected;
use App\Events\PirepStatusChange;
use App\Events\UserRegistered; use App\Events\UserRegistered;
use App\Events\UserStateChanged; use App\Events\UserStateChanged;
use App\Models\Enums\UserState; use App\Models\Enums\UserState;
use App\Models\User; use App\Models\User;
use App\Notifications\Messages\PirepSubmitted;
use App\Notifications\Messages\UserPending;
use App\Notifications\Messages\UserRejected; use App\Notifications\Messages\UserRejected;
use App\Notifications\Notifiables\Broadcast; use App\Notifications\Notifiables\Broadcast;
use Exception; use Exception;
@@ -23,17 +23,19 @@ use Illuminate\Support\Facades\Notification;
/** /**
* Listen for different events and map them to different notifications * Listen for different events and map them to different notifications
*/ */
class EventHandler extends Listener class NotificationEventsHandler extends Listener
{ {
private static $broadcastNotifyable; private static $broadcastNotifyable;
public static $callbacks = [ public static $callbacks = [
NewsAdded::class => 'onNewsAdded', NewsAdded::class => 'onNewsAdded',
PirepAccepted::class => 'onPirepAccepted', PirepPrefiled::class => 'onPirepPrefile',
PirepFiled::class => 'onPirepFile', PirepStatusChange::class => 'onPirepStatusChange',
PirepRejected::class => 'onPirepRejected', PirepAccepted::class => 'onPirepAccepted',
UserRegistered::class => 'onUserRegister', PirepFiled::class => 'onPirepFile',
UserStateChanged::class => 'onUserStateChange', PirepRejected::class => 'onPirepRejected',
UserRegistered::class => 'onUserRegister',
UserStateChanged::class => 'onUserStateChange',
]; ];
public function __construct() public function __construct()
@@ -56,7 +58,8 @@ class EventHandler extends Listener
} }
try { try {
Notification::send([$user], $notification); $this->notifyUser($user, $notification);
// Notification::send([$user], $notification);
} catch (Exception $e) { } catch (Exception $e) {
Log::emergency('Error emailing admin ('.$user->email.'). Error='.$e->getMessage()); Log::emergency('Error emailing admin ('.$user->email.'). Error='.$e->getMessage());
} }
@@ -117,19 +120,24 @@ class EventHandler extends Listener
.$event->user->ident.' is ' .$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 Messages\AdminUserRegistered($event->user));
/* /*
* Send the user a confirmation email * Send the user a confirmation email
*/ */
if ($event->user->state === UserState::ACTIVE) { if ($event->user->state === UserState::ACTIVE) {
$this->notifyUser($event->user, new Messages\UserRegistered($event->user)); $this->notifyUser($event->user, new Messages\UserRegistered($event->user));
} elseif ($event->user->state === UserState::PENDING) { } elseif ($event->user->state === UserState::PENDING) {
$this->notifyUser($event->user, new UserPending($event->user)); $this->notifyUser($event->user, new Messages\UserPending($event->user));
} }
/*
* Send all of the admins a notification that a new user registered
*/
$this->notifyAdmins(new Messages\AdminUserRegistered($event->user));
/**
* Discord and other notifications
*/
Notification::send([$event->user], new Messages\AdminUserRegistered($event->user));
} }
/** /**
@@ -152,15 +160,34 @@ class EventHandler extends Listener
} }
} }
/**
* Prefile notification
*/
public function onPirepPrefile(PirepPrefiled $event): void
{
Log::info('NotificationEvents::onPirepPrefile: '.$event->pirep->id.' prefiled');
Notification::send([$event->pirep], new Messages\PirepPrefiled($event->pirep));
}
/**
* Status Change notification
*/
public function onPirepStatusChange(PirepStatusChange $event): void
{
Log::info('NotificationEvents::onPirepStatusChange: '.$event->pirep->id.' prefiled');
Notification::send([$event->pirep], new Messages\PirepStatusChanged($event->pirep));
}
/** /**
* Notify the admins that a new PIREP has been filed * Notify the admins that a new PIREP has been filed
* *
* @param \App\Events\PirepFiled $event * @param PirepFiled $event
*/ */
public function onPirepFile(PirepFiled $event): void public function onPirepFile(PirepFiled $event): void
{ {
Log::info('NotificationEvents::onPirepFile: '.$event->pirep->id.' filed '); Log::info('NotificationEvents::onPirepFile: '.$event->pirep->id.' filed');
$this->notifyAdmins(new PirepSubmitted($event->pirep)); $this->notifyAdmins(new Messages\PirepSubmitted($event->pirep));
Notification::send([$event->pirep], new Messages\PirepSubmitted($event->pirep));
} }
/** /**
@@ -194,5 +221,6 @@ class EventHandler extends Listener
{ {
Log::info('NotificationEvents::onNewsAdded'); Log::info('NotificationEvents::onNewsAdded');
$this->notifyAllUsers(new Messages\NewsAdded($event->news)); $this->notifyAllUsers(new Messages\NewsAdded($event->news));
Notification::send([$event->news], new Messages\NewsAdded($event->news));
} }
} }
+2 -2
View File
@@ -11,7 +11,7 @@ use App\Listeners\ExpenseListener;
use App\Listeners\FinanceEventHandler; use App\Listeners\FinanceEventHandler;
use App\Listeners\PirepEventsHandler; use App\Listeners\PirepEventsHandler;
use App\Listeners\UserStateListener; use App\Listeners\UserStateListener;
use App\Notifications\EventHandler; use App\Notifications\NotificationEventsHandler;
use Codedge\Updater\Events\UpdateAvailable; use Codedge\Updater\Events\UpdateAvailable;
use Codedge\Updater\Events\UpdateSucceeded; use Codedge\Updater\Events\UpdateSucceeded;
use Illuminate\Auth\Events\Registered; use Illuminate\Auth\Events\Registered;
@@ -49,7 +49,7 @@ class EventServiceProvider extends ServiceProvider
protected $subscribe = [ protected $subscribe = [
BidEventHandler::class, BidEventHandler::class,
FinanceEventHandler::class, FinanceEventHandler::class,
EventHandler::class, NotificationEventsHandler::class,
AwardHandler::class, AwardHandler::class,
PirepEventsHandler::class, PirepEventsHandler::class,
]; ];
+5 -9
View File
@@ -292,14 +292,14 @@ class FareService extends Service
/** /**
* Save the list of fares * Save the list of fares
* *
* @param Pirep $pirep * @param Pirep $pirep
* @param array $fares ['fare_id', 'count'] * @param PirepFare[] $fares
* *
* @throws \Exception * @throws \Exception
*/ */
public function saveForPirep(Pirep $pirep, array $fares) public function saveForPirep(Pirep $pirep, array $fares)
{ {
if (!$fares) { if (!$fares || empty($fares)) {
return; return;
} }
@@ -308,13 +308,9 @@ class FareService extends Service
// Add them in // Add them in
foreach ($fares as $fare) { foreach ($fares as $fare) {
$fare['pirep_id'] = $pirep->id; $fare->pirep_id = $pirep->id;
// other fields: ['fare_id', 'count']
Log::info('Saving fare pirep='.$pirep->id.', fare='.$fare['count']); Log::info('Saving fare pirep='.$pirep->id.', fare='.$fare['count']);
$fare->save();
$field = new PirepFare($fare);
$field->save();
} }
} }
} }
+65 -31
View File
@@ -36,7 +36,6 @@ use App\Repositories\AircraftRepository;
use App\Repositories\AirportRepository; use App\Repositories\AirportRepository;
use App\Repositories\PirepRepository; use App\Repositories\PirepRepository;
use Carbon\Carbon; use Carbon\Carbon;
use function count;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -45,16 +44,18 @@ class PirepService extends Service
private $aircraftRepo; private $aircraftRepo;
private $airportRepo; private $airportRepo;
private $airportSvc; private $airportSvc;
private $fareSvc;
private $geoSvc; private $geoSvc;
private $pirepRepo; private $pirepRepo;
private $simBriefSvc; private $simBriefSvc;
private $userSvc; private $userSvc;
/** /**
* @param AircraftRepository $aircraftRepo
* @param GeoService $geoSvc
* @param AirportRepository $airportRepo * @param AirportRepository $airportRepo
* @param AirportService $airportSvc * @param AirportService $airportSvc
* @param AircraftRepository $aircraftRepo
* @param FareService $fareSvc
* @param GeoService $geoSvc
* @param PirepRepository $pirepRepo * @param PirepRepository $pirepRepo
* @param SimBriefService $simBriefSvc * @param SimBriefService $simBriefSvc
* @param UserService $userSvc * @param UserService $userSvc
@@ -63,6 +64,7 @@ class PirepService extends Service
AirportRepository $airportRepo, AirportRepository $airportRepo,
AirportService $airportSvc, AirportService $airportSvc,
AircraftRepository $aircraftRepo, AircraftRepository $aircraftRepo,
FareService $fareSvc,
GeoService $geoSvc, GeoService $geoSvc,
PirepRepository $pirepRepo, PirepRepository $pirepRepo,
SimBriefService $simBriefSvc, SimBriefService $simBriefSvc,
@@ -71,6 +73,7 @@ class PirepService extends Service
$this->airportRepo = $airportRepo; $this->airportRepo = $airportRepo;
$this->airportSvc = $airportSvc; $this->airportSvc = $airportSvc;
$this->aircraftRepo = $aircraftRepo; $this->aircraftRepo = $aircraftRepo;
$this->fareSvc = $fareSvc;
$this->geoSvc = $geoSvc; $this->geoSvc = $geoSvc;
$this->pirepRepo = $pirepRepo; $this->pirepRepo = $pirepRepo;
$this->simBriefSvc = $simBriefSvc; $this->simBriefSvc = $simBriefSvc;
@@ -80,15 +83,17 @@ class PirepService extends Service
/** /**
* Create a prefiled PIREP * Create a prefiled PIREP
* *
* @param \App\Models\User $user * @param User $user
* @param array $attrs * @param array $attrs
* @param PirepFieldValue[] $fields
* @param PirepFare[] $fares
* *
* @throws AirportNotFound If one of the departure or arrival airports isn't found locally * @throws AirportNotFound If one of the departure or arrival airports isn't found locally
* @throws \Exception * @throws \Exception
* *
* @return \App\Models\Pirep * @return \App\Models\Pirep
*/ */
public function prefile(User $user, array $attrs): Pirep public function prefile(User $user, array $attrs, array $fields = [], array $fares = []): Pirep
{ {
$attrs['user_id'] = $user->id; $attrs['user_id'] = $user->id;
$attrs['state'] = PirepState::IN_PROGRESS; $attrs['state'] = PirepState::IN_PROGRESS;
@@ -176,6 +181,7 @@ class PirepService extends Service
} }
} }
$pirep->status = PirepStatus::INITIATED;
$pirep->save(); $pirep->save();
$pirep->refresh(); $pirep->refresh();
@@ -189,6 +195,9 @@ class PirepService extends Service
} }
} }
$this->updateCustomFields($pirep->id, $fields);
$this->fareSvc->saveForPirep($pirep, $fares);
event(new PirepPrefiled($pirep)); event(new PirepPrefiled($pirep));
return $pirep; return $pirep;
@@ -202,10 +211,10 @@ class PirepService extends Service
* *
* @return Pirep * @return Pirep
*/ */
public function create(Pirep $pirep, array $field_values = []): Pirep public function create(Pirep $pirep, array $fields = []): Pirep
{ {
if (empty($field_values)) { if (empty($fields)) {
$field_values = []; $fields = [];
} }
// Check the block times. If a block on (arrival) time isn't // Check the block times. If a block on (arrival) time isn't
@@ -241,9 +250,23 @@ class PirepService extends Service
$pirep->save(); $pirep->save();
$pirep->refresh(); $pirep->refresh();
if (count($field_values) > 0) { $this->updateCustomFields($pirep->id, $fields);
$this->updateCustomFields($pirep->id, $field_values);
} return $pirep;
}
/**
* @param PirepFieldValue[] $fields
* @param PirepFare[] $fares
*
* @throws \Prettus\Validator\Exceptions\ValidatorException
* @throws \Exception
*/
public function update(string $pirep_id, array $attrs, array $fields = [], array $fares = []): Pirep
{
$pirep = $this->pirepRepo->update($attrs, $pirep_id);
$this->updateCustomFields($pirep_id, $fields);
$this->fareSvc->saveForPirep($pirep, $fares);
return $pirep; return $pirep;
} }
@@ -251,18 +274,19 @@ class PirepService extends Service
/** /**
* Finalize a PIREP (meaning it's been filed) * Finalize a PIREP (meaning it's been filed)
* *
* @param Pirep $pirep * @param Pirep $pirep
* @param array $attrs * @param array $attrs
* @param array PirepFieldValue[] $field_values * @param PirepFieldValue[] $fields
* @param PirepFare[] $fares
* *
* @throws \Exception * @throws \Exception
* *
* @return Pirep * @return Pirep
*/ */
public function file(Pirep $pirep, array $attrs = [], array $field_values = []): Pirep public function file(Pirep $pirep, array $attrs = [], array $fields = [], array $fares = []): Pirep
{ {
if (empty($field_values)) { if (empty($fields)) {
$field_values = []; $fields = [];
} }
// Check if the PIREP has already been submitted // Check if the PIREP has already been submitted
@@ -319,9 +343,8 @@ class PirepService extends Service
$pirep->save(); $pirep->save();
$pirep->refresh(); $pirep->refresh();
if (count($field_values) > 0) { $this->updateCustomFields($pirep->id, $fields);
$this->updateCustomFields($pirep->id, $field_values); $this->fareSvc->saveForPirep($pirep, $fares);
}
return $pirep; return $pirep;
} }
@@ -518,30 +541,41 @@ class PirepService extends Service
*/ */
public function delete(Pirep $pirep): void public function delete(Pirep $pirep): void
{ {
$user_id = $pirep->user_id;
$w = ['pirep_id' => $pirep->id]; $w = ['pirep_id' => $pirep->id];
PirepComment::where($w)->forceDelete(); PirepComment::where($w)->forceDelete();
PirepFare::where($w)->forceDelete(); PirepFare::where($w)->forceDelete();
PirepFieldValue::where($w)->forceDelete(); PirepFieldValue::where($w)->forceDelete();
SimBrief::where($w)->forceDelete(); SimBrief::where($w)->forceDelete();
$pirep->forceDelete(); $pirep->forceDelete();
// Update the user's last PIREP
$last_pirep = Pirep::where(['user_id' => $user_id, 'state' => PirepState::ACCEPTED])
->latest('submitted_at')
->first();
$user = User::find($user_id);
$user->last_pirep_id = !empty($last_pirep) ? $last_pirep->id : null;
$user->save();
} }
/** /**
* Update any custom PIREP fields * Update any custom PIREP fields
* *
* @param $pirep_id * @param string $pirep_id
* @param array $field_values * @param PirepFieldValue[] $field_values
*/ */
public function updateCustomFields($pirep_id, array $field_values) public function updateCustomFields(string $pirep_id, array $field_values): void
{ {
if (!$field_values || empty($field_values)) {
return;
}
foreach ($field_values as $fv) { foreach ($field_values as $fv) {
PirepFieldValue::updateOrCreate( PirepFieldValue::updateOrCreate(
['pirep_id' => $pirep_id, ['pirep_id' => $pirep_id, 'name' => $fv->name],
'name' => $fv['name'], ['value' => $fv->value, 'source' => $fv->source]
],
['value' => $fv['value'],
'source' => $fv['source'],
]
); );
} }
} }
@@ -554,7 +588,7 @@ class PirepService extends Service
* *
* @return Pirep * @return Pirep
*/ */
public function changeState(Pirep $pirep, int $new_state) public function changeState(Pirep $pirep, int $new_state): Pirep
{ {
Log::info('PIREP '.$pirep->id.' state change from '.$pirep->state.' to '.$new_state); Log::info('PIREP '.$pirep->id.' state change from '.$pirep->state.' to '.$new_state);
+26 -3
View File
@@ -3,6 +3,7 @@
namespace App\Support; namespace App\Support;
use GuzzleHttp\Client as GuzzleClient; use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\RequestOptions;
/** /**
* Helper for HTTP stuff * Helper for HTTP stuff
@@ -11,9 +12,8 @@ class HttpClient
{ {
private $httpClient; private $httpClient;
public function __construct( public function __construct(GuzzleClient $httpClient)
GuzzleClient $httpClient {
) {
$this->httpClient = $httpClient; $this->httpClient = $httpClient;
} }
@@ -45,6 +45,29 @@ class HttpClient
return $body; return $body;
} }
/**
* @param $uri
* @param $body
* @param array $opts
*
* @return mixed
*/
public function post($uri, $body, array $opts = [])
{
$opts = array_merge([
'connect_timeout' => 2,
RequestOptions::JSON => $body,
], $opts);
$response = $this->httpClient->post($uri, $opts);
$content_type = $response->getHeaderLine('content-type');
if (strpos($content_type, 'application/json') !== false) {
$body = \GuzzleHttp\json_decode($body, true);
}
return $body;
}
/** /**
* Download a file to a given path * Download a file to a given path
* *
+2 -1
View File
@@ -67,7 +67,8 @@
"laravel/legacy-factories": "^1.1", "laravel/legacy-factories": "^1.1",
"fakerphp/faker": "^v1.14", "fakerphp/faker": "^v1.14",
"wildbit/swiftmailer-postmark": "^3.3", "wildbit/swiftmailer-postmark": "^3.3",
"queueworker/sansdaemon": "^1.2" "queueworker/sansdaemon": "^1.2",
"jpkleemans/attribute-events": "^1.1"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "^3.5", "barryvdh/laravel-debugbar": "^3.5",
Generated
+316 -257
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -26,6 +26,7 @@ services:
- ./composer-lock.json:/var/www/composer-lock.json - ./composer-lock.json:/var/www/composer-lock.json
- ./env.php:/var/www/env.php - ./env.php:/var/www/env.php
- ./resources/docker/php/www.conf:/usr/local/etc/php-fpm.d/www.conf - ./resources/docker/php/www.conf:/usr/local/etc/php-fpm.d/www.conf
- ./vendor/var/www/vendor
depends_on: depends_on:
- mysql - mysql
- redis - redis
+1 -1
View File
@@ -46,7 +46,7 @@ class FlightRouteAwards extends Award
*/ */
public function check($dptarr = null): bool public function check($dptarr = null): bool
{ {
if ($this->user->last_pirep_id === null) { if ($this->user->last_pirep_id === null || empty($this->user->last_pirep)) {
return false; return false;
} }
+1 -1
View File
@@ -3,7 +3,7 @@
namespace Modules\Awards\Awards; namespace Modules\Awards\Awards;
use App\Contracts\Award; use App\Contracts\Award;
use Log; use Illuminate\Support\Facades\Log;
/** /**
* All award classes need to extend Award and implement the check() method * All award classes need to extend Award and implement the check() method
@@ -2,7 +2,7 @@
<div class="col-md-12"> <div class="col-md-12">
<table class="table"> <table class="table">
<tr> <tr>
<td>@lang('common.name')</td> <td>{{ __('common.name') }}</td>
<td> <td>
<div class="input-group form-group-no-border{{ $errors->has('name') ? ' has-danger' : '' }}"> <div class="input-group form-group-no-border{{ $errors->has('name') ? ' has-danger' : '' }}">
{{ Form::text('name', null, ['class' => 'form-control']) }} {{ Form::text('name', null, ['class' => 'form-control']) }}
@@ -14,7 +14,7 @@
</tr> </tr>
<tr> <tr>
<td>@lang('common.email')</td> <td>{{ __('common.email') }}</td>
<td> <td>
<div class="input-group form-group-no-border{{ $errors->has('email') ? ' has-danger' : '' }}"> <div class="input-group form-group-no-border{{ $errors->has('email') ? ' has-danger' : '' }}">
{{ Form::text('email', null, ['class' => 'form-control']) }} {{ Form::text('email', null, ['class' => 'form-control']) }}
@@ -26,7 +26,22 @@
</tr> </tr>
<tr> <tr>
<td>@lang('common.airline')</td> <td>Discord ID <span class="small">
<a href="https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-" target="_blank">
How to find your ID</a></span>
</td>
<td>
<div class="input-group form-group-no-border{{ $errors->has('discord_id') ? ' has-danger' : '' }}">
{{ Form::text('discord_id', null, ['class' => 'form-control']) }}
</div>
@if ($errors->has('discord_id'))
<p class="text-danger">{{ $errors->first('discord_id') }}</p>
@endif
</td>
</tr>
<tr>
<td>{{ __('common.airline') }}</td>
<td> <td>
<div class="input-group form-group-no-border{{ $errors->has('airline') ? ' has-danger' : '' }}"> <div class="input-group form-group-no-border{{ $errors->has('airline') ? ' has-danger' : '' }}">
{{ Form::select('airline_id', $airlines, null , ['class' => 'form-control select2']) }} {{ Form::select('airline_id', $airlines, null , ['class' => 'form-control select2']) }}
@@ -38,7 +53,7 @@
</tr> </tr>
<tr> <tr>
<td>@lang('airports.home')</td> <td>{{ __('airports.home') }}</td>
<td> <td>
<div class="input-group form-group-no-border{{ $errors->has('home_airport_id') ? ' has-danger' : '' }}"> <div class="input-group form-group-no-border{{ $errors->has('home_airport_id') ? ' has-danger' : '' }}">
{{ Form::select('home_airport_id', $airports, null , ['class' => 'form-control select2']) }} {{ Form::select('home_airport_id', $airports, null , ['class' => 'form-control select2']) }}
@@ -50,7 +65,7 @@
</tr> </tr>
<tr> <tr>
<td>@lang('common.country')</td> <td>{{ __('common.country') }}</td>
<td> <td>
<div class="input-group form-group-no-border{{ $errors->has('country') ? ' has-danger' : '' }}"> <div class="input-group form-group-no-border{{ $errors->has('country') ? ' has-danger' : '' }}">
{{ Form::select('country', $countries, null, ['class' => 'form-control select2' ]) }} {{ Form::select('country', $countries, null, ['class' => 'form-control select2' ]) }}
@@ -62,7 +77,7 @@
</tr> </tr>
<tr> <tr>
<td>@lang('common.timezone')</td> <td>{{ __('common.timezone') }}</td>
<td> <td>
<div class="input-group form-group-no-border{{ $errors->has('timezone') ? ' has-danger' : '' }}"> <div class="input-group form-group-no-border{{ $errors->has('timezone') ? ' has-danger' : '' }}">
{{ Form::select('timezone', $timezones, null, ['class' => 'form-control select2' ]) }} {{ Form::select('timezone', $timezones, null, ['class' => 'form-control select2' ]) }}
@@ -74,9 +89,9 @@
</tr> </tr>
<tr> <tr>
<td>@lang('profile.changepassword')</td> <td>{{ __('profile.changepassword') }}</td>
<td> <td>
<p>@lang('profile.newpassword'):</p> <p>{{ __('profile.newpassword') }}:</p>
<div class="input-group form-group-no-border{{ $errors->has('password') ? ' has-danger' : '' }}"> <div class="input-group form-group-no-border{{ $errors->has('password') ? ' has-danger' : '' }}">
{{ Form::password('password', ['class' => 'form-control']) }} {{ Form::password('password', ['class' => 'form-control']) }}
</div> </div>
@@ -84,7 +99,7 @@
<p class="text-danger">{{ $errors->first('password') }}</p> <p class="text-danger">{{ $errors->first('password') }}</p>
@endif @endif
<p>@lang('passwords.confirm'):</p> <p>{{ __('passwords.confirm') }}:</p>
<div class="input-group form-group-no-border{{ $errors->has('password_confirmation') ? ' has-danger' : '' }}"> <div class="input-group form-group-no-border{{ $errors->has('password_confirmation') ? ' has-danger' : '' }}">
{{ Form::password('password_confirmation', ['class' => 'form-control']) }} {{ Form::password('password_confirmation', ['class' => 'form-control']) }}
</div> </div>
@@ -94,14 +109,14 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<td>@lang('profile.avatar')</td> <td>{{ __('profile.avatar') }}</td>
<td> <td>
<div class="input-group form-group-no-border{{ $errors->has('avatar') ? ' has-danger' : '' }}"> <div class="input-group form-group-no-border{{ $errors->has('avatar') ? ' has-danger' : '' }}">
{{ Form::file('avatar', null) }} {{ Form::file('avatar', null) }}
</div> </div>
<p class="small">@lang('profile.avatarresize', [ <p class="small">{{ __('profile.avatarresize', [
'width' => config('phpvms.avatar.width'), 'width' => config('phpvms.avatar.width'),
'height' => config('phpvms.avatar.height')]) 'height' => config('phpvms.avatar.height')]) }}
</p> </p>
@if ($errors->has('avatar')) @if ($errors->has('avatar'))
<p class="text-danger">{{ $errors->first('avatar') }}</p> <p class="text-danger">{{ $errors->first('avatar') }}</p>
@@ -130,13 +145,13 @@
@endforeach @endforeach
<tr> <tr>
<td>@lang('profile.opt-in')</td> <td>{{ __('profile.opt-in') }}</td>
<td> <td>
<div class="input-group form-group-no-border"> <div class="input-group form-group-no-border">
{{ Form::hidden('opt_in', 0, false) }} {{ Form::hidden('opt_in', 0, false) }}
{{ Form::checkbox('opt_in', 1, null) }} {{ Form::checkbox('opt_in', 1, null) }}
</div> </div>
<p class="small">@lang('profile.opt-in-descrip') <p class="small">{{ __('profile.opt-in-descrip') }}
</p> </p>
</td> </td>
</tr> </tr>
@@ -153,6 +153,10 @@
<td>@lang('profile.apikey')&nbsp;&nbsp;<span class="description">(@lang('profile.dontshare'))</span></td> <td>@lang('profile.apikey')&nbsp;&nbsp;<span class="description">(@lang('profile.dontshare'))</span></td>
<td><span id="apiKey_show" style="display: none">{{ $user->api_key }} <i class="fas fa-eye-slash" onclick="apiKeyHide()"></i></span><span id="apiKey_hide">@lang('profile.apikey-show') <i class="fas fa-eye" onclick="apiKeyShow()"></i></span></td> <td><span id="apiKey_show" style="display: none">{{ $user->api_key }} <i class="fas fa-eye-slash" onclick="apiKeyHide()"></i></span><span id="apiKey_hide">@lang('profile.apikey-show') <i class="fas fa-eye" onclick="apiKeyShow()"></i></span></td>
</tr> </tr>
<tr>
<td>Discord ID</td>
<td>{{ $user->discord_id ?? '-' }}</td>
</tr>
<tr> <tr>
<td>@lang('common.timezone')</td> <td>@lang('common.timezone')</td>
<td>{{ $user->timezone }}</td> <td>{{ $user->timezone }}</td>
@@ -174,7 +178,7 @@
@if(!$field->private) @if(!$field->private)
<tr> <tr>
<td>{{ $field->name }}</td> <td>{{ $field->name }}</td>
<td>{{ $field->value }}</td> <td>{{ $field->value ?? '-'}}</td>
</tr> </tr>
@endif @endif
@endforeach @endforeach
+3
View File
@@ -450,6 +450,7 @@ class AcarsTest extends TestCase
'level' => 38000, 'level' => 38000,
'planned_distance' => 400, 'planned_distance' => 400,
'planned_flight_time' => 120, 'planned_flight_time' => 120,
'status' => PirepStatus::BOARDING,
'route' => 'POINTA POINTB', 'route' => 'POINTA POINTB',
'source_name' => 'AcarsTest::testAcarsUpdates', 'source_name' => 'AcarsTest::testAcarsUpdates',
'fields' => [ 'fields' => [
@@ -487,6 +488,8 @@ class AcarsTest extends TestCase
$uri = '/api/pireps/'.$pirep_id.'/update'; $uri = '/api/pireps/'.$pirep_id.'/update';
$this->post($uri, [ $this->post($uri, [
'flight_time' => 60, 'flight_time' => 60,
'distance' => 20,
'status' => PirepStatus::AIRBORNE,
'fields' => [ 'fields' => [
'custom_field' => 'custom_value_changed', 'custom_field' => 'custom_value_changed',
], ],
+1
View File
@@ -14,6 +14,7 @@ trait CreatesApplication
public function createApplication() public function createApplication()
{ {
$app = require __DIR__.'/../bootstrap/app.php'; $app = require __DIR__.'/../bootstrap/app.php';
$app->loadEnvironmentFrom('');
$app->make(Kernel::class)->bootstrap(); $app->make(Kernel::class)->bootstrap();
return $app; return $app;
+10 -12
View File
@@ -13,6 +13,7 @@ use App\Models\Flight;
use App\Models\Journal; use App\Models\Journal;
use App\Models\JournalTransaction; use App\Models\JournalTransaction;
use App\Models\Pirep; use App\Models\Pirep;
use App\Models\PirepFare;
use App\Models\Subfleet; use App\Models\Subfleet;
use App\Models\User; use App\Models\User;
use App\Repositories\ExpenseRepository; use App\Repositories\ExpenseRepository;
@@ -763,11 +764,10 @@ class FinanceTest extends TestCase
// Override the fares // Override the fares
$fare_counts = []; $fare_counts = [];
foreach ($fares as $fare) { foreach ($fares as $fare) {
$fare_counts[] = [ $fare_counts[] = new PirepFare([
'fare_id' => $fare->id, 'fare_id' => $fare->id,
'price' => $fare->price,
'count' => round($fare->capacity / 2), 'count' => round($fare->capacity / 2),
]; ]);
} }
$this->fareSvc->saveForPirep($pirep, $fare_counts); $this->fareSvc->saveForPirep($pirep, $fare_counts);
@@ -777,7 +777,7 @@ class FinanceTest extends TestCase
foreach ($all_fares as $fare) { foreach ($all_fares as $fare) {
$set_fare = $fare_counts->where('fare_id', $fare->id)->first(); $set_fare = $fare_counts->where('fare_id', $fare->id)->first();
$this->assertEquals($set_fare['count'], $fare->count); $this->assertEquals($set_fare['count'], $fare->count);
$this->assertEquals($set_fare['price'], $fare->price); $this->assertNotEmpty($fare->price);
} }
} }
@@ -892,11 +892,10 @@ class FinanceTest extends TestCase
// Override the fares // Override the fares
$fare_counts = []; $fare_counts = [];
foreach ($fares as $fare) { foreach ($fares as $fare) {
$fare_counts[] = [ $fare_counts[] = new PirepFare([
'fare_id' => $fare->id, 'fare_id' => $fare->id,
'price' => $fare->price,
'count' => 100, 'count' => 100,
]; ]);
} }
$this->fareSvc->saveForPirep($pirep, $fare_counts); $this->fareSvc->saveForPirep($pirep, $fare_counts);
@@ -948,11 +947,10 @@ class FinanceTest extends TestCase
// Override the fares // Override the fares
$fare_counts = []; $fare_counts = [];
foreach ($fares as $fare) { foreach ($fares as $fare) {
$fare_counts[] = [ $fare_counts[] = new PirepFare([
'fare_id' => $fare->id, 'fare_id' => $fare->id,
'price' => $fare->price,
'count' => 100, 'count' => 100,
]; ]);
} }
$this->fareSvc->saveForPirep($pirep, $fare_counts); $this->fareSvc->saveForPirep($pirep, $fare_counts);
@@ -1074,11 +1072,11 @@ class FinanceTest extends TestCase
// Override the fares // Override the fares
$fare_counts = []; $fare_counts = [];
foreach ($fares as $fare) { foreach ($fares as $fare) {
$fare_counts[] = [ $fare_counts[] = new PirepFare([
'fare_id' => $fare->id, 'fare_id' => $fare->id,
'price' => $fare->price, 'price' => $fare->price,
'count' => 100, 'count' => 100,
]; ]);
} }
$this->fareSvc->saveForPirep($pirep, $fare_counts); $this->fareSvc->saveForPirep($pirep, $fare_counts);
+2 -1
View File
@@ -4,6 +4,7 @@ namespace Tests;
use App\Events\UserRegistered; use App\Events\UserRegistered;
use App\Models\Enums\UserState; use App\Models\Enums\UserState;
use App\Models\User;
use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Notification; use Illuminate\Support\Facades\Notification;
@@ -26,7 +27,7 @@ class RegistrationTest extends TestCase
setting('pilots.auto_accept', true); setting('pilots.auto_accept', true);
$attrs = factory(\App\Models\User::class)->make()->toArray(); $attrs = factory(User::class)->make()->toArray();
$attrs['password'] = Hash::make('secret'); $attrs['password'] = Hash::make('secret');
$user = $userSvc->createUser($attrs); $user = $userSvc->createUser($attrs);
+1 -2
View File
@@ -57,11 +57,10 @@ abstract class TestCase extends \Illuminate\Foundation\Testing\TestCase
ThrottleRequests::class ThrottleRequests::class
); );
Notification::fake();
Artisan::call('database:create', ['--reset' => true]); Artisan::call('database:create', ['--reset' => true]);
Artisan::call('migrate:refresh', ['--env' => 'testing', '--force' => true]); Artisan::call('migrate:refresh', ['--env' => 'testing', '--force' => true]);
Notification::fake();
// $this->disableExceptionHandling(); // $this->disableExceptionHandling();
} }