diff --git a/app/Database/seeds/settings.yml b/app/Database/seeds/settings.yml index 24a87b32..cd8807da 100644 --- a/app/Database/seeds/settings.yml +++ b/app/Database/seeds/settings.yml @@ -410,6 +410,41 @@ options: '' type: text description: The Discord Webhook URL for private notifications +- key: notifications.discord_pirep_status + name: Discord Pirep Messages (Public) + group: notifications + value: true + options: '' + type: boolean + description: Pirep status messages (Only key events are being sent) +- key: notifications.mail_pirep_admin + name: Pirep Filed (Admin) + group: notifications + value: true + options: '' + type: boolean + description: Pirep filed mails sent to admins +- key: notifications.mail_pirep_user_ack + name: Pirep Accepted (Pilot) + group: notifications + value: true + options: '' + type: boolean + description: Pirep Accepted mails sent to pilots +- key: notifications.mail_pirep_user_rej + name: Pirep Rejected (Pilot) + group: notifications + value: true + options: '' + type: boolean + description: Pirep Rejected mails sent to pilots +- key: notifications.mail_news + name: News Mails + group: notifications + value: true + options: '' + type: boolean + description: News mails sent to all members - key: 'cron.random_id' name: 'Cron Randomized ID' group: 'cron' diff --git a/app/Http/Controllers/Admin/AirlinesController.php b/app/Http/Controllers/Admin/AirlinesController.php index afbc6104..774420c1 100644 --- a/app/Http/Controllers/Admin/AirlinesController.php +++ b/app/Http/Controllers/Admin/AirlinesController.php @@ -38,7 +38,7 @@ class AirlinesController extends Controller public function index(Request $request) { $this->airlineRepo->pushCriteria(new RequestCriteria($request)); - $airlines = $this->airlineRepo->all(); + $airlines = $this->airlineRepo->orderby('name', 'asc')->get(); return view('admin.airlines.index', [ 'airlines' => $airlines, diff --git a/app/Http/Controllers/Admin/FlightController.php b/app/Http/Controllers/Admin/FlightController.php index 783cc827..5e984b82 100644 --- a/app/Http/Controllers/Admin/FlightController.php +++ b/app/Http/Controllers/Admin/FlightController.php @@ -308,7 +308,7 @@ class FlightController extends Controller $where['airline_id'] = $airline_id; $file_name = 'flights-'.$airline_id.'.csv'; } - $flights = $this->flightRepo->where($where)->get(); + $flights = $this->flightRepo->where($where)->orderBy('airline_id')->orderBy('flight_number')->orderBy('route_code')->orderBy('route_leg')->get(); $path = $exporter->exportFlights($flights); return response()->download($path, $file_name, ['content-type' => 'text/csv'])->deleteFileAfterSend(true); diff --git a/app/Http/Controllers/Admin/SubfleetController.php b/app/Http/Controllers/Admin/SubfleetController.php index 3410ca03..7e7a64ba 100644 --- a/app/Http/Controllers/Admin/SubfleetController.php +++ b/app/Http/Controllers/Admin/SubfleetController.php @@ -83,7 +83,7 @@ class SubfleetController extends Controller public function index(Request $request) { $this->subfleetRepo->with(['airline'])->pushCriteria(new RequestCriteria($request)); - $subfleets = $this->subfleetRepo->all(); + $subfleets = $this->subfleetRepo->orderby('name', 'asc')->get(); return view('admin.subfleets.index', [ 'subfleets' => $subfleets, diff --git a/app/Http/Controllers/Admin/TypeRatingController.php b/app/Http/Controllers/Admin/TypeRatingController.php index dbe4f630..5a3727f3 100644 --- a/app/Http/Controllers/Admin/TypeRatingController.php +++ b/app/Http/Controllers/Admin/TypeRatingController.php @@ -32,7 +32,7 @@ class TypeRatingController extends Controller public function index(Request $request) { $this->typeratingRepo->pushCriteria(new RequestCriteria($request)); - $typeratings = $this->typeratingRepo->all(); + $typeratings = $this->typeratingRepo->orderby('type', 'asc')->get(); return view('admin.typeratings.index', [ 'typeratings' => $typeratings, @@ -50,7 +50,6 @@ class TypeRatingController extends Controller $model = $this->typeratingRepo->create($input); Flash::success('Type Rating saved successfully.'); - // Cache::forget(config('cache.keys.RANKS_PILOT_LIST.key')); return redirect(route('admin.typeratings.edit', [$model->id])); } diff --git a/app/Notifications/Channels/Discord/DiscordMessage.php b/app/Notifications/Channels/Discord/DiscordMessage.php index 3875e9db..18c24440 100644 --- a/app/Notifications/Channels/Discord/DiscordMessage.php +++ b/app/Notifications/Channels/Discord/DiscordMessage.php @@ -11,14 +11,16 @@ use Carbon\Carbon; */ class DiscordMessage { - const COLOR_SUCCESS = '#0B6623'; - const COLOR_WARNING = '#FD6A02'; - const COLOR_ERROR = '#ED2939'; + const COLOR_SUCCESS = '0B6623'; + const COLOR_WARNING = 'FD6A02'; + const COLOR_ERROR = 'ED2939'; public $webhook_url; protected $title; protected $url; + protected $thumbnail = []; + protected $image = []; protected $description; protected $timestamp; protected $footer; @@ -26,30 +28,43 @@ class DiscordMessage protected $author = []; protected $fields = []; - /** - * Supply the webhook URL that this should be going to - */ + // 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 - */ + // Title of the embed public function title(string $title): self { $this->title = $title; return $this; } + // URL of the Title public function url(string $url): self { $this->url = $url; return $this; } + // Thumbnail image (placed right side of embed) + // ['url' => ''] + public function thumbnail(array $thumbnail): self + { + $this->thumbnail = $thumbnail; + return $this; + } + + // Main image (placed bottom of embed) + // ['url' => ''] + public function image(array $image): self + { + $this->image = $image; + return $this; + } + /** * @param array|string $descriptionLines */ @@ -63,22 +78,15 @@ class DiscordMessage return $this; } - /** - * Set the author information: - * [ - * 'name' => '', - * 'url' => '', - * 'icon_url' => '', - */ + // Author details + // ['name' => '', 'url' => '', 'icon_url' => ''] public function author(array $author): self { $this->author = $author; return $this; } - /** - * Set the fields - */ + // Fields public function fields(array $fields): self { $this->fields = []; @@ -99,32 +107,45 @@ class DiscordMessage return $this; } + // Fixed Success Color public function success(): self { - $this->color = static::COLOR_SUCCESS; + $this->color = hexdec('0B6623'); // static::COLOR_SUCCESS; return $this; } + // Fixed Warning public function warning(): self { - $this->color = static::COLOR_WARNING; + $this->color = hexdec('FD6A02'); // static::COLOR_WARNING; return $this; } + // Fixed Error public function error(): self { - $this->color = static::COLOR_ERROR; + $this->color = hexdec('ED2939'); // static::COLOR_ERROR; + return $this; + } + + // Custom Color + public function color(string $embed_color): self + { + $this->color = hexdec($embed_color); return $this; } public function toArray(): array { $embeds = [ + 'type' => 'rich', + 'color' => $this->color, 'title' => $this->title, 'url' => $this->url, - 'type' => 'rich', + 'thumbnail' => $this->thumbnail, 'description' => $this->description, 'author' => $this->author, + 'image' => $this->image, 'timestamp' => Carbon::now('UTC'), ]; diff --git a/app/Notifications/Messages/Broadcast/NewsAdded.php b/app/Notifications/Messages/Broadcast/NewsAdded.php index fd57310f..1f96bfe2 100644 --- a/app/Notifications/Messages/Broadcast/NewsAdded.php +++ b/app/Notifications/Messages/Broadcast/NewsAdded.php @@ -31,7 +31,7 @@ class NewsAdded extends Notification implements ShouldQueue public function toDiscordChannel($news): ?DiscordMessage { $dm = new DiscordMessage(); - return $dm->url(setting('notifications.discord_public_webhook_url')) + return $dm->webhook(setting('notifications.discord_public_webhook_url')) ->success() ->title('News: '.$news->subject) ->author([ diff --git a/app/Notifications/Messages/Broadcast/PirepFiled.php b/app/Notifications/Messages/Broadcast/PirepFiled.php index ef23123c..0c7fb170 100644 --- a/app/Notifications/Messages/Broadcast/PirepFiled.php +++ b/app/Notifications/Messages/Broadcast/PirepFiled.php @@ -43,11 +43,10 @@ class PirepFiled extends Notification implements ShouldQueue { $title = 'Flight '.$pirep->ident.' Filed'; $fields = [ - 'Flight' => $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), + 'Dep.Airport' => $pirep->dpt_airport_id, + 'Arr.Airport' => $pirep->arr_airport_id, + 'Equipment' => $pirep->aircraft->ident, + 'Flight Time' => Time::minutesToTimeString($pirep->flight_time), ]; if ($pirep->distance) { @@ -63,16 +62,19 @@ class PirepFiled extends Notification implements ShouldQueue } } + // User avatar, somehow $pirep->user->resolveAvatarUrl() is not being accepted by Discord as thumbnail + $user_avatar = !empty($pirep->user->avatar) ? $pirep->user->avatar->url : $pirep->user->gravatar(256); + $dm = new DiscordMessage(); - return $dm->url(setting('notifications.discord_public_webhook_url')) + 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])) + ->thumbnail(['url' => $user_avatar]) + ->image(['url' => $pirep->airline->logo]) ->author([ - 'name' => $pirep->user->ident.' - '.$pirep->user->name_private, - 'url' => route('frontend.profile.show', [$pirep->user_id]), - 'icon_url' => $pirep->user->resolveAvatarUrl(), + 'name' => $pirep->user->ident.' - '.$pirep->user->name_private, + 'url' => route('frontend.profile.show', [$pirep->user_id]), ]) ->fields($fields); } diff --git a/app/Notifications/Messages/Broadcast/PirepStatusChanged.php b/app/Notifications/Messages/Broadcast/PirepStatusChanged.php index ef923002..d83f60f8 100644 --- a/app/Notifications/Messages/Broadcast/PirepStatusChanged.php +++ b/app/Notifications/Messages/Broadcast/PirepStatusChanged.php @@ -9,11 +9,9 @@ use App\Notifications\Channels\Discord\DiscordMessage; use App\Notifications\Channels\Discord\DiscordWebhook; use App\Support\Units\Distance; use App\Support\Units\Time; -use function config; use Illuminate\Contracts\Queue\ShouldQueue; use PhpUnitsOfMeasure\Exception\NonNumericValue; use PhpUnitsOfMeasure\Exception\NonStringUnitName; -use function route; /** * Send the PIREP accepted message to a particular user, can also be sent to Discord @@ -75,14 +73,16 @@ class PirepStatusChanged extends Notification implements ShouldQueue */ public function toDiscordChannel($pirep): ?DiscordMessage { - $title = 'Flight '.$pirep->ident.' '.self::$verbs[$pirep->status]; + if (empty(setting('notifications.discord_public_webhook_url'))) { + return null; + } + $title = 'Flight '.$pirep->ident.' '.self::$verbs[$pirep->status]; $fields = [ - 'Flight' => $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), + 'Dep.Airport' => $pirep->dpt_airport_id, + 'Arr.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 @@ -109,16 +109,29 @@ class PirepStatusChanged extends Notification implements ShouldQueue } } + // User avatar, somehow $pirep->user->resolveAvatarUrl() is not being accepted by Discord as thumbnail + $user_avatar = !empty($pirep->user->avatar) ? $pirep->user->avatar->url : $pirep->user->gravatar(256); + + // Proper coloring for the messages + // Pirep Filed > success, normals > warning, non-normals > error + $danger_types = [ + PirepStatus::GRND_RTRN, + PirepStatus::DIVERTED, + PirepStatus::CANCELLED, + PirepStatus::PAUSED, + PirepStatus::EMERG_DESCENT, + ]; + $color = in_array($pirep->status, $danger_types, true) ? 'ED2939' : 'FD6A02'; + $dm = new DiscordMessage(); - return $dm->url(setting('notifications.discord_public_webhook_url')) - ->success() + return $dm->webhook(setting('notifications.discord_public_webhook_url')) + ->color($color) ->title($title) ->description($pirep->user->discord_id ? 'Flight by <@'.$pirep->user->discord_id.'>' : '') - ->url(route('frontend.pireps.show', [$pirep->id])) + ->thumbnail(['url' => $user_avatar]) ->author([ - 'name' => $pirep->user->ident.' - '.$pirep->user->name_private, - 'url' => route('frontend.profile.show', [$pirep->user_id]), - 'icon_url' => $pirep->user->resolveAvatarUrl(), + 'name' => $pirep->user->ident.' - '.$pirep->user->name_private, + 'url' => route('frontend.profile.show', [$pirep->user_id]), ]) ->fields($fields); } diff --git a/app/Notifications/Messages/Broadcast/UserRegistered.php b/app/Notifications/Messages/Broadcast/UserRegistered.php index 840c4e6a..8eea22c5 100644 --- a/app/Notifications/Messages/Broadcast/UserRegistered.php +++ b/app/Notifications/Messages/Broadcast/UserRegistered.php @@ -49,7 +49,7 @@ class UserRegistered extends Notification implements ShouldQueue public function toDiscordChannel($notifiable): ?DiscordMessage { $dm = new DiscordMessage(); - return $dm->url(setting('notifications.discord_private_webhook_url')) + return $dm->webhook(setting('notifications.discord_private_webhook_url')) ->success() ->title('New User Registered: '.$this->user->ident) ->author([ diff --git a/app/Notifications/NotificationEventsHandler.php b/app/Notifications/NotificationEventsHandler.php index bd0199e9..f31ad1fa 100644 --- a/app/Notifications/NotificationEventsHandler.php +++ b/app/Notifications/NotificationEventsHandler.php @@ -11,6 +11,7 @@ use App\Events\PirepRejected; use App\Events\PirepStatusChange; use App\Events\UserRegistered; use App\Events\UserStateChanged; +use App\Models\Enums\PirepStatus; use App\Models\Enums\UserState; use App\Models\User; use App\Notifications\Messages\UserRejected; @@ -161,7 +162,7 @@ class NotificationEventsHandler extends Listener } /** - * Prefile notification + * Prefile notification. Disabled intentionally, No need to send it to Discord */ public function onPirepPrefile(PirepPrefiled $event): void { @@ -170,16 +171,33 @@ class NotificationEventsHandler extends Listener /* * Broadcast notifications */ - Notification::send([$event->pirep], new Messages\Broadcast\PirepPrefiled($event->pirep)); + // Notification::send([$event->pirep], new Messages\Broadcast\PirepPrefiled($event->pirep)); } /** - * Status Change notification. Disabled for now, too noisy + * Status Change notification. + * Reduced the messages (Boarding, Pushback, TakeOff, Landing and non-normals only) + * If needed array can be tied to a setting at admin side for further customization */ public function onPirepStatusChange(PirepStatusChange $event): void { - // Log::info('NotificationEvents::onPirepStatusChange: '.$event->pirep->id.' prefiled'); - // Notification::send([$event->pirep], new Messages\Discord\PirepStatusChanged($event->pirep)); + Log::info('NotificationEvents::onPirepStatusChange: '.$event->pirep->id.' status changed'); + + $message_types = [ + PirepStatus::BOARDING, + PirepStatus::PUSHBACK_TOW, + PirepStatus::GRND_RTRN, + PirepStatus::TAKEOFF, + PirepStatus::LANDED, + PirepStatus::DIVERTED, + PirepStatus::CANCELLED, + PirepStatus::PAUSED, + PirepStatus::EMERG_DESCENT, + ]; + + if (setting('notifications.discord_pirep_status', true) && in_array($event->pirep->status, $message_types, true)) { + Notification::send([$event->pirep], new Messages\Broadcast\PirepStatusChanged($event->pirep)); + } } /** @@ -190,7 +208,9 @@ class NotificationEventsHandler extends Listener public function onPirepFile(PirepFiled $event): void { Log::info('NotificationEvents::onPirepFile: '.$event->pirep->id.' filed'); - $this->notifyAdmins(new Messages\PirepFiled($event->pirep)); + if (setting('notifications.mail_pirep_admin', true)) { + $this->notifyAdmins(new Messages\PirepFiled($event->pirep)); + } /* * Broadcast notifications @@ -205,8 +225,10 @@ class NotificationEventsHandler extends Listener */ public function onPirepAccepted(PirepAccepted $event): void { - Log::info('NotificationEvents::onPirepAccepted: '.$event->pirep->id.' accepted'); - $this->notifyUser($event->pirep->user, new Messages\PirepAccepted($event->pirep)); + if (setting('notifications.mail_pirep_user_ack', true)) { + Log::info('NotificationEvents::onPirepAccepted: '.$event->pirep->id.' accepted'); + $this->notifyUser($event->pirep->user, new Messages\PirepAccepted($event->pirep)); + } } /** @@ -216,8 +238,10 @@ class NotificationEventsHandler extends Listener */ public function onPirepRejected(PirepRejected $event): void { - Log::info('NotificationEvents::onPirepRejected: '.$event->pirep->id.' rejected'); - $this->notifyUser($event->pirep->user, new Messages\PirepRejected($event->pirep)); + if (setting('notifications.mail_pirep_user_rej', true)) { + Log::info('NotificationEvents::onPirepRejected: '.$event->pirep->id.' rejected'); + $this->notifyUser($event->pirep->user, new Messages\PirepRejected($event->pirep)); + } } /** @@ -228,7 +252,9 @@ class NotificationEventsHandler extends Listener public function onNewsAdded(NewsAdded $event): void { Log::info('NotificationEvents::onNewsAdded'); - $this->notifyAllUsers(new Messages\NewsAdded($event->news)); + if (setting('notifications.mail_news', true)) { + $this->notifyAllUsers(new Messages\NewsAdded($event->news)); + } /* * Broadcast notifications diff --git a/resources/views/admin/flights/fields.blade.php b/resources/views/admin/flights/fields.blade.php index e1adabfa..f011eecf 100644 --- a/resources/views/admin/flights/fields.blade.php +++ b/resources/views/admin/flights/fields.blade.php @@ -174,7 +174,6 @@ -
@@ -260,8 +259,9 @@
{{ Form::textarea('notes', null, [ - 'class' => 'form-control input-text', - 'style' => 'padding: 10px', + 'id' => 'editor', + 'class' => 'editor', + 'style' => 'padding: 5px', ]) }}

{{ $errors->first('notes') }}

@@ -288,3 +288,10 @@
+@section('scripts') + @parent + + +@endsection \ No newline at end of file