Compare commits

..

5 Commits

Author SHA1 Message Date
nabeelio
db34d0e3e7 Add test for METAR string 2021-03-15 09:14:39 -04:00
Nabeel S
fffbab7201 Merge branch 'dev' into patch-2 2021-03-15 08:30:29 -04:00
B.Fatih KOZ
76a2a16fa6 Merge branch 'dev' into patch-2 2021-03-14 03:54:53 +03:00
B.Fatih KOZ
cfbd1c901a Merge branch 'dev' into patch-2 2021-03-10 04:53:25 +03:00
B.Fatih KOZ
617813bdbf Fix Metar Decoding / Wind check for Wind Chill
PR aims to fix the bug #1071 by checking both the wind speed and it's value for starting Wind Chill calculation.
2021-03-09 16:06:39 +03:00
374 changed files with 55577 additions and 34029 deletions

View File

@@ -30,7 +30,6 @@ declare -a remove_files=(
intellij_style.xml intellij_style.xml
config.php config.php
docker-compose.yml docker-compose.yml
docker-compose.local.yml
Makefile Makefile
phpcs.xml phpcs.xml
phpunit.xml phpunit.xml
@@ -74,12 +73,8 @@ ls -al $BASE_DIR/../
tar -czf $TAR_NAME -C $BASE_DIR . tar -czf $TAR_NAME -C $BASE_DIR .
sha256sum $TAR_NAME >"$TAR_NAME.sha256" sha256sum $TAR_NAME >"$TAR_NAME.sha256"
tar2zip $TAR_NAME
cd $BASE_DIR;
zip -r $ZIP_NAME .* *
sha256sum $ZIP_NAME >"$ZIP_NAME.sha256" sha256sum $ZIP_NAME >"$ZIP_NAME.sha256"
mv $ZIP_NAME /tmp
mv "$ZIP_NAME.sha256" /tmp
ls -al /tmp ls -al /tmp

View File

@@ -8,7 +8,7 @@ APP_LOCALE="en"
PHPVMS_INSTALLED="true" PHPVMS_INSTALLED="true"
APP_LOG="daily" APP_LOG="daily"
LOG_LEVEL="debug" APP_LOG_LEVEL="debug"
APP_LOG_MAX_FILES="3" APP_LOG_MAX_FILES="3"
DB_CONNECTION="mysql" DB_CONNECTION="mysql"

View File

@@ -7,7 +7,7 @@ jobs:
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
php-versions: ['7.3', '7.4', '8.0'] php-versions: ['7.3', '7.4']
name: PHP ${{ matrix.php-versions }} name: PHP ${{ matrix.php-versions }}
env: env:
extensions: intl, pcov, mbstring extensions: intl, pcov, mbstring
@@ -41,6 +41,7 @@ jobs:
with: with:
path: ${{ steps.composer-cache.outputs.dir }} path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
# Configure PHP # Configure PHP
- name: Setup PHP - name: Setup PHP

1
.gitignore vendored
View File

@@ -74,5 +74,4 @@ error_log
.sass-cache .sass-cache
.DS_Store .DS_Store
/config.php /config.php
/config.bak.php
/VERSION /VERSION

View File

@@ -28,8 +28,6 @@ RedirectMatch 403 ^/composer.phar
RedirectMatch 403 ^/env.php.*?$ RedirectMatch 403 ^/env.php.*?$
RedirectMatch 403 ^/env.php RedirectMatch 403 ^/env.php
RedirectMatch 403 ^/env.php$ RedirectMatch 403 ^/env.php$
RedirectMatch 403 ^/config.php$
RedirectMatch 403 ^/config.bak.php$
RedirectMatch 403 ^/Makefile RedirectMatch 403 ^/Makefile
RedirectMatch 403 ^/package.json RedirectMatch 403 ^/package.json
RedirectMatch 403 ^/package-lock.json RedirectMatch 403 ^/package-lock.json

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 zlib-dev libpng-dev RUN apk add gmp-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
@@ -12,9 +12,7 @@ RUN ln -sf /dev/stderr /var/log/fpm-error.log
RUN docker-php-ext-install \ RUN docker-php-ext-install \
calendar \ calendar \
intl \
pdo_mysql \ pdo_mysql \
gd \
gmp \ gmp \
opcache && \ opcache && \
docker-php-ext-enable pdo_mysql opcache docker-php-ext-enable pdo_mysql opcache
@@ -27,6 +25,4 @@ RUN php composer.phar install \
--no-scripts \ --no-scripts \
--prefer-dist --prefer-dist
RUN chown -R www-data:www-data /var/www
EXPOSE 9000 EXPOSE 9000

View File

@@ -1,3 +1,5 @@
BSD 3-Clause License
Copyright (c) 2017, phpvms - http://www.phpvms.net Copyright (c) 2017, phpvms - http://www.phpvms.net
All rights reserved. All rights reserved.
@@ -15,9 +17,6 @@ modification, are permitted provided that the following conditions are met:
contributors may be used to endorse or promote products derived from contributors may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.
* A "powered by phpvms" is required in page footers, unless the license has
purchased to omit it.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

View File

@@ -82,6 +82,10 @@ test:
phpcs: phpcs:
@vendor/bin/php-cs-fixer fix --config=.php_cs -v --diff --diff-format=udiff --dry-run @vendor/bin/php-cs-fixer fix --config=.php_cs -v --diff --diff-format=udiff --dry-run
#.PHONY: phpstan
#phpstan:
# vendor/bin/phpstan analyse -c phpstan.neon -v --level 2 app
.PHONY: replay-acars .PHONY: replay-acars
replay-acars: replay-acars:
#@php artisan phpvms:replay AAL10,AAL3113,BAW172,DAL988,FIN6,MSR986 --manual #@php artisan phpvms:replay AAL10,AAL3113,BAW172,DAL988,FIN6,MSR986 --manual
@@ -91,6 +95,11 @@ replay-acars:
sass-watch: sass-watch:
sass --watch public/assets/admin/sass/paper-dashboard.scss:public/assets/admin/css/paper-dashboard.css sass --watch public/assets/admin/sass/paper-dashboard.scss:public/assets/admin/css/paper-dashboard.css
.PHONY: schema
schema:
#php artisan infyom:scaffold Aircraft --fieldsFile=database/schema/aircraft.json
echo ""
.PHONY: deploy-package .PHONY: deploy-package
deploy-package: deploy-package:
./.travis/deploy_script.sh ./.travis/deploy_script.sh
@@ -100,9 +109,17 @@ reset-installer:
@php artisan database:create --reset @php artisan database:create --reset
@php artisan migrate:refresh --seed @php artisan migrate:refresh --seed
.PHONY: docker-test .PHONY: docker
docker-test: docker:
@docker-compose -f docker-compose.yml -f docker-compose.local.yml up @mkdir -p $(CURR_PATH)/tmp/mysql
-docker rm -f phpvms
docker build -t phpvms .
docker run --name=phpvms \
-v $(CURR_PATH):/var/www/ \
-v $(CURR_PATH)/tmp/mysql:/var/lib/mysql \
-p 8080:80 \
phpvms
.PHONY: docker-clean .PHONY: docker-clean
docker-clean: docker-clean:

View File

@@ -30,16 +30,15 @@ A full distribution, with all of the composer dependencies, is available at this
[View installation details](https://docs.phpvms.net/installation/installation) [View installation details](https://docs.phpvms.net/installation/installation)
## Development Environment with Docker ## Development Environment
A full development environment can be brought up using Docker, without having to install composer/npm locally A full development environment can be brought up using Docker:
```bash ```bash
make docker-test composer install
npm install
# **OR** with docker-compose directly docker-compose build
docker-compose up
docker-compose -f docker-compose.yml -f docker-compose.local.yml up
``` ```
Then go to `http://localhost`. If you're using dnsmasq, the `app` container is listening on `phpvms.test`, or you can add to your `/etc/hosts` file: Then go to `http://localhost`. If you're using dnsmasq, the `app` container is listening on `phpvms.test`, or you can add to your `/etc/hosts` file:
@@ -48,8 +47,6 @@ Then go to `http://localhost`. If you're using dnsmasq, the `app` container is l
127.0.0.1 phpvms.test 127.0.0.1 phpvms.test
``` ```
The `docker-compose.local.yml` overrides the `app` section in `docker-compose.yml`. The standard `docker-compose.yml` can be used if you want to deploy from the image, or as a template for your own Dockerized deployments.
### Building JS/CSS assets ### Building JS/CSS assets
Yarn is required, run: Yarn is required, run:

View File

@@ -4,9 +4,9 @@ namespace App\Console\Commands;
use App; use App;
use App\Contracts\Command; use App\Contracts\Command;
use App\Services\Installer\ConfigService;
use App\Services\Installer\SeederService; use App\Services\Installer\SeederService;
use DatabaseSeeder; use DatabaseSeeder;
use Modules\Installer\Services\ConfigService;
/** /**
* Create the config files * Create the config files
@@ -81,13 +81,13 @@ class CreateConfigs extends Command
$this->info('Regenerating the config files'); $this->info('Regenerating the config files');
$cfgSvc->createConfigFiles([ $cfgSvc->createConfigFiles([
'APP_ENV' => 'dev', 'APP_ENV' => 'dev',
'SITE_NAME' => $this->argument('name'), 'SITE_NAME' => $this->argument('name'),
'DB_CONNECTION' => 'mysql', 'DB_CONN' => 'mysql',
'DB_HOST' => $this->argument('db_host'), 'DB_HOST' => $this->argument('db_host'),
'DB_DATABASE' => $this->argument('db_name'), 'DB_NAME' => $this->argument('db_name'),
'DB_USERNAME' => $this->argument('db_user'), 'DB_USER' => $this->argument('db_user'),
'DB_PASSWORD' => $this->argument('db_pass'), 'DB_PASS' => $this->argument('db_pass'),
]); ]);
$this->info('Config files generated!'); $this->info('Config files generated!');

View File

@@ -79,9 +79,9 @@ class DevInstall extends Command
$this->info('Regenerating the config files'); $this->info('Regenerating the config files');
$cfgSvc->createConfigFiles([ $cfgSvc->createConfigFiles([
'APP_ENV' => 'dev', 'APP_ENV' => 'dev',
'SITE_NAME' => 'phpvms test', 'SITE_NAME' => 'phpvms test',
'DB_CONNECTION' => 'sqlite', 'DB_CONN' => 'sqlite',
]); ]);
$this->info('Config files generated!'); $this->info('Config files generated!');

View File

@@ -1,32 +0,0 @@
<?php
namespace App\Console\Commands;
use App;
use App\Contracts\Command;
class EmailTest extends Command
{
protected $signature = 'phpvms:email-test';
protected $description = 'Send a test notification to admins';
/**
* Run dev related commands
*
* @throws \Symfony\Component\HttpFoundation\File\Exception\FileException
*/
public function handle()
{
/** @var App\Notifications\NotificationEventsHandler $eventHandler */
$eventHandler = app(App\Notifications\NotificationEventsHandler::class);
$news = new App\Models\News();
$news->user_id = 1;
$news->subject = 'Test News';
$news->body = 'Test Body';
$news->save();
$newsEvent = new App\Events\NewsAdded($news);
$eventHandler->onNewsAdded($newsEvent);
}
}

View File

@@ -1,38 +0,0 @@
<?php
namespace App\Console\Commands;
use App;
use App\Contracts\Command;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log;
class ProcessQueue extends Command
{
protected $signature = 'queue:cron';
protected $description = 'Process the queue from a cron job';
/**
* Run the queue tasks
*/
public function handle()
{
Artisan::call('queue:work', [
'--sansdaemon' => null,
'--stop-when-empty' => null,
]);
Log::info(Artisan::output());
///** @var App\Support\WorkCommand $queueWorker */
//$queueWorker = new App\Support\WorkCommand(app('queue.worker'), app('cache.store'));
//$queueWorker->setInput($queueWorker->createInputFromArguments([]));
//$queueWorker->handle();
/*$output = $this->call('queue:work', [
'--stop-when-empty' => null,
]);
Log::info($output);*/
}
}

View File

@@ -1,25 +0,0 @@
<?php
namespace App\Console\Commands;
use App\Contracts\Command;
use App\Services\Installer\ConfigService;
/**
* Command to rewrite the config files
*/
class RewriteConfigs extends Command
{
protected $signature = 'phpvms:rewrite-configs';
protected $description = 'Rewrite the config files';
/**
* Run dev related commands
*/
public function handle()
{
/** @var ConfigService $configSvc */
$configSvc = app(ConfigService::class);
$configSvc->rewriteConfigFiles();
}
}

View File

@@ -1,25 +0,0 @@
<?php
namespace App\Console\Cron;
use App\Contracts\Command;
use Illuminate\Support\Facades\Artisan;
/**
* This just calls the CronHourly event, so all of the
* listeners, etc can just be called to run those tasks
*/
class JobQueue extends Command
{
protected $signature = 'cron:queue';
protected $description = 'Run the cron queue tasks';
protected $schedule;
public function handle(): void
{
$this->redirectLoggingToFile('cron');
Artisan::call('queue:cron');
$this->info(Artisan::output());
}
}

View File

@@ -3,7 +3,6 @@
namespace App\Console; namespace App\Console;
use App\Console\Cron\Hourly; use App\Console\Cron\Hourly;
use App\Console\Cron\JobQueue;
use App\Console\Cron\Monthly; use App\Console\Cron\Monthly;
use App\Console\Cron\Nightly; use App\Console\Cron\Nightly;
use App\Console\Cron\Weekly; use App\Console\Cron\Weekly;
@@ -26,13 +25,6 @@ class Kernel extends ConsoleKernel
*/ */
protected function schedule(Schedule $schedule): void protected function schedule(Schedule $schedule): void
{ {
// If not using the queue worker then run those via cron
if (!config('queue.worker', false)) {
$schedule->command(JobQueue::class)
->everyMinute()
->withoutOverlapping();
}
$schedule->command(Nightly::class)->dailyAt('01:00'); $schedule->command(Nightly::class)->dailyAt('01:00');
$schedule->command(Weekly::class)->weeklyOn(0); $schedule->command(Weekly::class)->weeklyOn(0);
$schedule->command(Monthly::class)->monthlyOn(1); $schedule->command(Monthly::class)->monthlyOn(1);

View File

@@ -24,9 +24,9 @@ abstract class Command extends \Illuminate\Console\Command
parent::__construct(); parent::__construct();
// Running in the console but not in the tests // Running in the console but not in the tests
/*if (app()->runningInConsole() && env('APP_ENV') !== 'testing') { if (app()->runningInConsole() && env('APP_ENV') !== 'testing') {
$this->redirectLoggingToFile('stdout'); $this->redirectLoggingToFile('stdout');
}*/ }
} }
/** /**

View File

@@ -170,11 +170,6 @@ class ImportExport
} }
foreach ($split_values as $value) { foreach ($split_values as $value) {
$value = trim($value);
if ($value === '') {
continue;
}
// This isn't in the query string format, so it's // This isn't in the query string format, so it's
// just a straight key-value pair set // just a straight key-value pair set
if (strpos($value, '?') === false) { if (strpos($value, '?') === false) {

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,16 +34,8 @@ 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;
} }
} }

View File

@@ -2,14 +2,11 @@
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 BaseRepository * @mixin \Prettus\Repository\Eloquent\BaseRepository
*/ */
abstract class Repository extends BaseRepository abstract class Repository extends BaseRepository
{ {
@@ -23,8 +20,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 null; return;
} }
} }
@@ -35,7 +32,11 @@ abstract class Repository extends BaseRepository
*/ */
public function validate($values) public function validate($values)
{ {
$validator = Validator::make($values, $this->model()->rules); $validator = Validator::make(
$values,
$this->model()->rules
);
if ($validator->fails()) { if ($validator->fails()) {
return $validator->messages(); return $validator->messages();
} }
@@ -49,8 +50,6 @@ 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')
@@ -72,7 +71,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);
} }
@@ -99,7 +98,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);
} }
@@ -119,7 +118,7 @@ abstract class Repository extends BaseRepository
* @param array $columns * @param array $columns
* @param string $method * @param string $method
* *
* @throws RepositoryException * @throws \Prettus\Repository\Exceptions\RepositoryException
* *
* @return mixed * @return mixed
*/ */

View File

@@ -2,10 +2,7 @@
namespace App\Contracts; namespace App\Contracts;
use App\Support\Resources\CustomAnonymousResourceCollection;
use App\Support\Resources\CustomPaginatedResourceResponse;
use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Pagination\AbstractPaginator;
/** /**
* Base class for a resource/response * Base class for a resource/response
@@ -29,28 +26,4 @@ class Resource extends JsonResource
} }
} }
} }
/**
* Customize the response to exclude all the extra data that isn't used. Based on:
* https://gist.github.com/derekphilipau/4be52164a69ce487dcd0673656d280da
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function toResponse($request)
{
return $this->resource instanceof AbstractPaginator
? (new CustomPaginatedResourceResponse($this))->toResponse($request)
: parent::toResponse($request);
}
public static function collection($resource)
{
return tap(new CustomAnonymousResourceCollection($resource, static::class), function ($collection) {
if (property_exists(static::class, 'preserveKeys')) {
$collection->preserveKeys = (new static([]))->preserveKeys === true;
}
});
}
} }

View File

@@ -5,7 +5,6 @@ namespace App\Cron\Hourly;
use App\Contracts\Listener; use App\Contracts\Listener;
use App\Events\CronHourly; use App\Events\CronHourly;
use App\Models\Enums\PirepState; use App\Models\Enums\PirepState;
use App\Models\Enums\PirepStatus;
use App\Models\Pirep; use App\Models\Pirep;
use App\Services\PirepService; use App\Services\PirepService;
use Carbon\Carbon; use Carbon\Carbon;
@@ -18,7 +17,7 @@ use Illuminate\Support\Facades\Log;
class DeletePireps extends Listener class DeletePireps extends Listener
{ {
/** /**
* Delete old rejected PIREPs * Remove expired bids
* *
* @param CronHourly $event * @param CronHourly $event
* *
@@ -38,11 +37,8 @@ class DeletePireps extends Listener
*/ */
protected function deletePireps(int $expire_time_hours, int $state) protected function deletePireps(int $expire_time_hours, int $state)
{ {
$dt = Carbon::now('UTC')->subHours($expire_time_hours); $dt = Carbon::now()->subHours($expire_time_hours);
$pireps = Pirep::where('created_at', '<', $dt) $pireps = Pirep::whereDate('created_at', '<', $dt)->where(['state' => $state])->get();
->where(['state' => $state])
->where('status', '<>', PirepStatus::PAUSED)
->get();
/** @var PirepService $pirepSvc */ /** @var PirepService $pirepSvc */
$pirepSvc = app(PirepService::class); $pirepSvc = app(PirepService::class);

View File

@@ -25,7 +25,7 @@ class RemoveExpiredBids extends Listener
return; return;
} }
$date = Carbon::now('UTC')->subHours(setting('bids.expire_time')); $date = Carbon::now()->subHours(setting('bids.expire_time'));
Bid::where('created_at', '<', $date)->delete(); Bid::whereDate('created_at', '<', $date)->delete();
} }
} }

View File

@@ -4,11 +4,9 @@ namespace App\Cron\Hourly;
use App\Contracts\Listener; use App\Contracts\Listener;
use App\Events\CronHourly; use App\Events\CronHourly;
use App\Events\PirepCancelled;
use App\Models\Enums\PirepState; use App\Models\Enums\PirepState;
use App\Models\Pirep; use App\Models\Pirep;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
/** /**
* Remove expired live flights * Remove expired live flights
@@ -28,15 +26,9 @@ class RemoveExpiredLiveFlights extends Listener
return; return;
} }
$date = Carbon::now('UTC')->subHours(setting('acars.live_time')); $date = Carbon::now()->subHours(setting('acars.live_time'));
$pireps = Pirep::where('updated_at', '<', $date) Pirep::whereDate('updated_at', '<', $date)
->where('state', PirepState::IN_PROGRESS) ->where('state', PirepState::IN_PROGRESS)
->get(); ->delete();
foreach ($pireps as $pirep) {
event(new PirepCancelled($pirep));
Log::info('Cron: Deleting Expired Live PIREP id='.$pirep->id.', state='.PirepState::label($pirep->state));
$pirep->delete();
}
} }
} }

View File

@@ -1,9 +1,9 @@
<?php <?php
namespace App\Cron\Hourly; namespace App\Cron\Nightly;
use App\Contracts\Listener; use App\Contracts\Listener;
use App\Events\CronHourly; use App\Events\CronNightly;
use App\Services\SimBriefService; use App\Services\SimBriefService;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -22,9 +22,9 @@ class ClearExpiredSimbrief extends Listener
/** /**
* @param \App\Events\CronNightly $event * @param \App\Events\CronNightly $event
*/ */
public function handle(CronHourly $event): void public function handle(CronNightly $event): void
{ {
Log::info('Hourly: Removing expired Simbrief entries'); Log::info('Nightly: Removing expired Simbrief entries');
$this->simbriefSvc->removeExpiredEntries(); $this->simbriefSvc->removeExpiredEntries();
} }
} }

View File

@@ -7,6 +7,9 @@ use App\Events\CronNightly;
use App\Services\VersionService; use App\Services\VersionService;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
/**
* Determine if any pilots should be set to ON LEAVE status
*/
class NewVersionCheck extends Listener class NewVersionCheck extends Listener
{ {
private $versionSvc; private $versionSvc;

View File

@@ -11,7 +11,7 @@ if (!function_exists('createFactoryICAO')) {
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$max = strlen($characters) - 1; $max = strlen($characters) - 1;
$string = ''; $string = '';
for ($i = 0; $i < 5; $i++) { for ($i = 0; $i < 4; $i++) {
try { try {
$string .= $characters[random_int(0, $max)]; $string .= $characters[random_int(0, $max)];
} catch (Exception $e) { } catch (Exception $e) {

View File

@@ -1,20 +1,17 @@
<?php <?php
use App\Models\Journal;
use Carbon\Carbon;
use Faker\Generator as Faker; use Faker\Generator as Faker;
use Ramsey\Uuid\Uuid;
$factory->define(App\Models\JournalTransaction::class, function (Faker $faker) { $factory->define(App\Models\JournalTransactions::class, function (Faker $faker) {
return [ return [
'transaction_group' => Uuid::uuid4()->toString(), 'transaction_group' => \Ramsey\Uuid\Uuid::uuid4()->toString(),
'journal_id' => function () { 'journal_id' => function () {
return factory(Journal::class)->create()->id; return factory(\App\Models\Journal::class)->create()->id;
}, },
'credit' => $faker->numberBetween(100, 10000), 'credit' => $faker->numberBetween(100, 10000),
'debit' => $faker->numberBetween(100, 10000), 'debit' => $faker->numberBetween(100, 10000),
'currency' => 'USD', 'currency' => 'USD',
'memo' => $faker->sentence(6), 'memo' => $faker->sentence(6),
'post_date' => Carbon::now('UTC'), 'post_date' => \Carbon\Carbon::now(),
]; ];
}); });

View File

@@ -1,13 +0,0 @@
<?php
use Faker\Generator as Faker;
$factory->define(App\Models\Role::class, function (Faker $faker) {
return [
'id' => null,
'name' => $faker->name,
'display_name' => $faker->name,
'read_only' => false,
'disable_activity_checks' => $faker->boolean(),
];
});

View File

@@ -1,34 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddDisableactivitychecksToRoles extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('roles', function (Blueprint $table) {
$table->boolean('disable_activity_checks')
->default(false)
->after('read_only');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('roles', function (Blueprint $table) {
$table->dropColumn('disable_activity_checks');
});
}
}

View File

@@ -1,19 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
class RemoveSettingRemoveBidOnAccept extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
DB::table('settings')
->where(['key' => 'pireps.remove_bid_on_accept'])
->delete();
}
}

View File

@@ -1,30 +0,0 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Add a `anumeric_callsign` column for Alphanumeric Callsign to be assigned for a flight
* Exp DLH78BF, THY8EA, OGE1978
* According to FAA and EASA, callsigns must be maximum 7 chars in which first 3 chars is
* airline ICAO code remaining rest can be used freely according to airline's choices
*/
class FlightsAddAlphanumericCallsign extends Migration
{
public function up()
{
Schema::table('flights', function (Blueprint $table) {
$table->string('callsign', 4)
->nullable()
->after('flight_number');
});
}
public function down()
{
Schema::table('flights', function (Blueprint $table) {
$table->dropColumn('callsign');
});
}
}

View File

@@ -1,21 +0,0 @@
<?php
use App\Contracts\Migration;
use App\Services\Installer\ConfigService;
/**
* Migrate the configuration files
*/
class MigrateConfigs extends Migration
{
public function up()
{
/** @var ConfigService $configSvc */
$configSvc = app(ConfigService::class);
$configSvc->rewriteConfigFiles();
}
public function down()
{
}
}

View File

@@ -1,26 +0,0 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Increase Airport ICAO size to 5 chars
* https://github.com/nabeelio/phpvms/issues/1052
*/
class IncreaseIcaoSizes extends Migration
{
public function up()
{
Schema::table('airports', function (Blueprint $table) {
$table->string('iata', 5)->change();
$table->string('icao', 5)->change();
});
Schema::table('pireps', function (Blueprint $table) {
$table->string('dpt_airport_id', 5)->change();
$table->string('arr_airport_id', 5)->change();
$table->string('alt_airport_id', 5)->change();
});
}
}

View File

@@ -1,19 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
class RemoveSettingSimbriefExpireDays extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
DB::table('settings')
->where(['key' => 'simbrief.expire_days'])
->delete();
}
}

View File

@@ -1,32 +0,0 @@
<?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');
});
}
}

View File

@@ -1,18 +0,0 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class DiscordPrivateChannelId extends Migration
{
public function up()
{
// Add a field to the user to enter their own Discord ID
Schema::table('users', function (Blueprint $table) {
$table->string('discord_private_channel_id')
->default('')
->after('discord_id');
});
}
}

View File

@@ -1,5 +1,519 @@
acars: acars:
- pirep_id: b68R5gwVzpVe - id: aM8QpMPEB15e
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.934117958358'
lon: '-76.77856721815'
heading: '124'
altitude: '8.1663703232199'
vs: '0'
gs: '0.0064996252497234'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: eZ6VJ3xj8vge
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.934117498661'
lon: '-76.778566516289'
heading: '124'
altitude: '8.1664622222087'
vs: '0'
gs: '0'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: bo2QqDLl2lLa
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.933884143334'
lon: '-76.778210172233'
heading: '124'
altitude: '8.1707802663933'
vs: '0'
gs: '14.419195209695'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: aM8QpM4qV2Be
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.933705349611'
lon: '-76.777936938059'
heading: '124'
altitude: '8.170089899507'
vs: '0'
gs: '15.392330039049'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: dR6oxR9qjoOd
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.933130691906'
lon: '-76.777152737985'
heading: '158'
altitude: '8.1683570286331'
vs: '0'
gs: '10.450467475023'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: erkRwJODRvEa
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.932580370289'
lon: '-76.777450200122'
heading: '221'
altitude: '8.1695896791822'
vs: '0'
gs: '12.932334300694'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: b2kv53VMy7Ad
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.932012550651'
lon: '-76.778009113329'
heading: '296'
altitude: '8.1683852467213'
vs: '0'
gs: '10.502719192825'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: eXDoE14JxAve
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.932052237309'
lon: '-76.778111495187'
heading: '290'
altitude: '8.1719753739837'
vs: '0'
gs: '12.643743277153'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: b68R5gZ5YyOe
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.932664026837'
lon: '-76.779705339967'
heading: '293'
altitude: '8.2203963962548'
vs: '0'
gs: '64.870244840054'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: bqxYvGNN5N0a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.934300220408'
lon: '-76.783954914814'
heading: '293'
altitude: '8.3302468103811'
vs: '0'
gs: '122.78529244208'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: en5rpBKw514d
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.935736496556'
lon: '-76.78765616448'
heading: '293'
altitude: '49.554739665916'
vs: '21'
gs: '146.79677958636'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: erkRwJA29l2a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.976972983585'
lon: '-76.896548114872'
heading: '297'
altitude: '6228.684012199'
vs: '62'
gs: '281.03976876098'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: dR6oxR3r5nwd
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.061360208405'
lon: '-77.056156629983'
heading: '301'
altitude: '12522.331716891'
vs: '25'
gs: '371.70833265547'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: e1wr82J877Zb
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.17373613295'
lon: '-77.260347185993'
heading: '301'
altitude: '16802.15636323'
vs: '43'
gs: '421.37353688139'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: bqxYvGyExN2a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.193907285814'
lon: '-77.29810465405'
heading: '297'
altitude: '17395.953175647'
vs: '40'
gs: '425.98105291451'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: aQW0wQDQk5Md
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.648921231143'
lon: '-78.014696613517'
heading: '323'
altitude: '37108.124381987'
vs: '22'
gs: '438.52028383384'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: e9rQ5lk3p63a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.796585259338'
lon: '-78.194734005052'
heading: '260'
altitude: '39718.178225504'
vs: '19'
gs: '432.41969107334'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: aQW0wQP8vZqd
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.660552760063'
lon: '-78.407597067994'
heading: '242'
altitude: '40998.775690971'
vs: '-25'
gs: '449.51695639627'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: bqxYvGKgp32a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.592775999582'
lon: '-78.638711340118'
heading: '298'
altitude: '41060.297106821'
vs: '0'
gs: '427.14806185954'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: bqxYvGg2r02a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.718367591656'
lon: '-78.840980459275'
heading: '284'
altitude: '41065.55293844'
vs: '1'
gs: '424.89060056552'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: e0RV61wPj53b
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.77448809677'
lon: '-79.082727467209'
heading: '283'
altitude: '41069.809333539'
vs: '0'
gs: '425.02780492483'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: dwpmBOo3wWwe
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.813031600863'
lon: '-79.249543355636'
heading: '283'
altitude: '41072.545805172'
vs: '0'
gs: '425.04687332464'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: ejRqlxXoZPle
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.840653974635'
lon: '-79.370042672541'
heading: '283'
altitude: '40396.200981621'
vs: '-16'
gs: '428.08364925851'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: eVOPBYw4q9Xa
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.868358744495'
lon: '-79.491434926253'
heading: '283'
altitude: '39399.093383161'
vs: '-16'
gs: '427.57826037174'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: aOYyrOmVPzEd
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.896191929474'
lon: '-79.613169477385'
heading: '284'
altitude: '36491.730092364'
vs: '-55'
gs: '429.74732238829'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: dL98oLQgyzje
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.9242378342'
lon: '-79.736368411294'
heading: '284'
altitude: '32998.644142986'
vs: '-61'
gs: '434.90864533098'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: e9rQ5lqD2o8a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.952608029755'
lon: '-79.861339775352'
heading: '284'
altitude: '29069.168636089'
vs: '-68'
gs: '441.90475491564'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: av2oANWY1vma
pirep_id: b68R5gwVzpVe
type: '0' type: '0'
nav_type: null nav_type: null
order: '0' order: '0'
@@ -36,7 +550,8 @@ acars:
sim_time: now sim_time: now
created_at: 'now' created_at: 'now'
updated_at: 'now' updated_at: 'now'
- pirep_id: b68R5gwVzpVe - id: e1wr82gp8zGb
pirep_id: b68R5gwVzpVe
type: '0' type: '0'
nav_type: null nav_type: null
order: '0' order: '0'
@@ -54,7 +569,8 @@ acars:
sim_time: now sim_time: now
created_at: 'now' created_at: 'now'
updated_at: 'now' updated_at: 'now'
- pirep_id: b68R5gwVzpVe - id: dG65jDL2gK0b
pirep_id: b68R5gwVzpVe
type: '0' type: '0'
nav_type: null nav_type: null
order: '0' order: '0'
@@ -72,7 +588,8 @@ acars:
sim_time: now sim_time: now
created_at: 'now' created_at: 'now'
updated_at: 'now' updated_at: 'now'
- pirep_id: b68R5gwVzpVe - id: epYQ0ENmyvXa
pirep_id: b68R5gwVzpVe
type: '0' type: '0'
nav_type: null nav_type: null
order: '0' order: '0'
@@ -90,7 +607,8 @@ acars:
sim_time: now sim_time: now
created_at: 'now' created_at: 'now'
updated_at: 'now' updated_at: 'now'
- pirep_id: b68R5gwVzpVe - id: erkRwJPrVoEa
pirep_id: b68R5gwVzpVe
type: '0' type: '0'
nav_type: null nav_type: null
order: '0' order: '0'
@@ -108,7 +626,8 @@ acars:
sim_time: now sim_time: now
created_at: 'now' created_at: 'now'
updated_at: 'now' updated_at: 'now'
- pirep_id: b68R5gwVzpVe - id: e1wr82gZXqZb
pirep_id: b68R5gwVzpVe
type: '0' type: '0'
nav_type: null nav_type: null
order: '0' order: '0'
@@ -126,7 +645,8 @@ acars:
sim_time: now sim_time: now
created_at: 'now' created_at: 'now'
updated_at: 'now' updated_at: 'now'
- pirep_id: b68R5gwVzpVe - id: eER95AJ4XLga
pirep_id: b68R5gwVzpVe
type: '0' type: '0'
nav_type: null nav_type: null
order: '0' order: '0'
@@ -144,7 +664,8 @@ acars:
sim_time: now sim_time: now
created_at: 'now' created_at: 'now'
updated_at: 'now' updated_at: 'now'
- pirep_id: b68R5gwVzpVe - id: dPNZvP0O0Gza
pirep_id: b68R5gwVzpVe
type: '0' type: '0'
nav_type: null nav_type: null
order: '0' order: '0'
@@ -162,7 +683,8 @@ acars:
sim_time: now sim_time: now
created_at: 'now' created_at: 'now'
updated_at: 'now' updated_at: 'now'
- pirep_id: b68R5gwVzpVe - id: aQW0wQYVm2Yd
pirep_id: b68R5gwVzpVe
type: '0' type: '0'
nav_type: null nav_type: null
order: '0' order: '0'
@@ -180,7 +702,8 @@ acars:
sim_time: now sim_time: now
created_at: 'now' created_at: 'now'
updated_at: 'now' updated_at: 'now'
- pirep_id: b68R5gwVzpVe - id: eXDoE11x32We
pirep_id: b68R5gwVzpVe
type: '0' type: '0'
nav_type: null nav_type: null
order: '0' order: '0'

File diff suppressed because one or more lines are too long

View File

@@ -54,13 +54,6 @@
options: '' options: ''
type: text type: text
description: 'Enter your Google Analytics Tracking ID' description: 'Enter your Google Analytics Tracking ID'
- key: general.record_user_ip
name: 'Record user IP address'
group: general
value: true
options: ''
type: boolean
description: Record the user's IP address on register/login
- key: units.currency - key: units.currency
name: 'Currency' name: 'Currency'
group: units group: units
@@ -151,20 +144,6 @@
options: options:
type: text type: text
description: If an airport's Jet A Fuel Cost isn't added, set this value by default description: If an airport's Jet A Fuel Cost isn't added, set this value by default
- key: airports.default_100ll_fuel_cost
name: 'Default 100LL Fuel Cost'
group: airports
value: 0.9
options:
type: text
description: If an airport's 100LL Fuel Cost isn't added, set this value by default
- key: airports.default_mogas_fuel_cost
name: 'Default MOGAS Fuel Cost'
group: airports
value: 0.8
options:
type: text
description: If an airport's MOGAS Fuel Cost isn't added, set this value by default
- key: bids.disable_flight_on_bid - key: bids.disable_flight_on_bid
name: 'Disable flight on bid' name: 'Disable flight on bid'
group: bids group: bids
@@ -214,13 +193,13 @@
options: '' options: ''
type: boolean type: boolean
description: 'Only allow briefs to be created for bidded flights' description: 'Only allow briefs to be created for bidded flights'
- key: simbrief.expire_hours - key: simbrief.expire_days
name: 'Simbrief Expire Time' name: 'Simbrief Expire Time'
group: simbrief group: simbrief
value: 6 value: 5
options: '' options: ''
type: number type: number
description: 'Hours after how long to remove unused briefs' description: 'Days after how long to remove unused briefs'
- key: simbrief.noncharter_pax_weight - key: simbrief.noncharter_pax_weight
name: 'Non-Charter Passenger Weight' name: 'Non-Charter Passenger Weight'
group: simbrief group: simbrief
@@ -256,20 +235,6 @@
options: '' options: ''
type: boolean type: boolean
description: 'Use pilot ident as Simbrief ATC Callsign' description: 'Use pilot ident as Simbrief ATC Callsign'
- key: simbrief.name_private
name: 'Use Privatized Name at OFPs'
group: simbrief
value: false
options: ''
type: boolean
description: 'Use privatized user name as SimBrief OFP captain name'
- key: simbrief.block_aircraft
name: 'Restrict Aircraft'
group: simbrief
value: false
options: ''
type: boolean
description: 'When enabled, an aircraft can only be used for one active SimBrief OFP and Flight/Pirep'
- key: pireps.duplicate_check_time - key: pireps.duplicate_check_time
name: 'PIREP duplicate time check' name: 'PIREP duplicate time check'
group: pireps group: pireps
@@ -291,6 +256,13 @@
options: '' options: ''
type: boolean type: boolean
description: 'Only allow aircraft that are at the departure airport' description: 'Only allow aircraft that are at the departure airport'
- key: pireps.remove_bid_on_accept
name: 'Remove bid on accept'
group: pireps
value: false
options: ''
type: boolean
description: 'When a PIREP is accepted, remove the bid, if it exists'
- key: pireps.advanced_fuel - key: pireps.advanced_fuel
name: 'Advanced Fuel Calculations' name: 'Advanced Fuel Calculations'
group: pireps group: pireps
@@ -375,20 +347,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_public_webhook_url - key: notifications.discord_api_key
name: Discord Public Webhook URL name: Discord API token
group: notifications group: notifications
value: '' value: ''
options: '' options: ''
type: text type: text
description: The Discord Webhook URL for public notifications description: Discord API token for notifications
- key: notifications.discord_private_webhook_url - key: 'notifications.discord_public_channel_id'
name: Discord Private Webhook URL name: 'Discord Public Channel ID'
group: notifications group: 'notifications'
value: '' value: ''
options: '' options: ''
type: text type: 'text'
description: The Discord Webhook URL for private notifications description: 'Discord public channel ID for broadcasat notifications'
- key: 'cron.random_id' - key: 'cron.random_id'
name: 'Cron Randomized ID' name: 'Cron Randomized ID'
group: 'cron' group: 'cron'

View File

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

View File

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

View File

@@ -1,38 +0,0 @@
<?php
namespace App\Exceptions;
use App\Models\Aircraft;
class AircraftNotAvailable extends AbstractHttpException
{
public const MESSAGE = 'The aircraft is not available for flight';
private $aircraft;
public function __construct(Aircraft $aircraft)
{
$this->aircraft = $aircraft;
parent::__construct(
400,
static::MESSAGE
);
}
public function getErrorType(): string
{
return 'aircraft-not-available';
}
public function getErrorDetails(): string
{
return $this->getMessage();
}
public function getErrorMetadata(): array
{
return [
'aircraft_id' => $this->aircraft->id,
];
}
}

View File

@@ -1,44 +0,0 @@
<?php
namespace App\Exceptions;
use App\Models\Pirep;
class PirepError extends AbstractHttpException
{
private $pirep;
private $error;
public function __construct(Pirep $pirep, string $error)
{
$this->error = $error;
$this->pirep = $pirep;
parent::__construct(400, $error);
}
/**
* Return the RFC 7807 error type (without the URL root)
*/
public function getErrorType(): string
{
return 'pirep-error';
}
/**
* Get the detailed error string
*/
public function getErrorDetails(): string
{
return $this->getMessage();
}
/**
* Return an array with the error details, merged with the RFC7807 response
*/
public function getErrorMetadata(): array
{
return [
'pirep_id' => $this->pirep->id,
];
}
}

View File

@@ -1,44 +0,0 @@
<?php
namespace App\Exceptions;
/**
* Prefile Error
*
* If listening to the prefile event message, use `throw new PrefileError("message message");`
* to abort the prefile process and send the message up to ACARS
*/
class PrefileError extends AbstractHttpException
{
private $error;
public function __construct(string $error)
{
$this->error = $error;
parent::__construct(400, $error);
}
/**
* Return the RFC 7807 error type (without the URL root)
*/
public function getErrorType(): string
{
return 'prefile-error';
}
/**
* Get the detailed error string
*/
public function getErrorDetails(): string
{
return $this->getMessage();
}
/**
* Return an array with the error details, merged with the RFC7807 response
*/
public function getErrorMetadata(): array
{
return [];
}
}

View File

@@ -1,38 +0,0 @@
<?php
namespace App\Exceptions;
class UserNotFound extends AbstractHttpException
{
public function __construct()
{
parent::__construct(
404,
'User not found'
);
}
/**
* Return the RFC 7807 error type (without the URL root)
*/
public function getErrorType(): string
{
return 'user-not-found';
}
/**
* Get the detailed error string
*/
public function getErrorDetails(): string
{
return $this->getMessage();
}
/**
* Return an array with the error details, merged with the RFC7807 response
*/
public function getErrorMetadata(): array
{
return [];
}
}

View File

@@ -115,7 +115,7 @@ class FlightController extends Controller
$avail_fleets = $all_aircraft->except($flight->subfleets->modelKeys()); $avail_fleets = $all_aircraft->except($flight->subfleets->modelKeys());
foreach ($avail_fleets as $ac) { foreach ($avail_fleets as $ac) {
$retval[$ac->id] = '['.$ac->airline->icao.']&nbsp;'.$ac->type.' - '.$ac->name; $retval[$ac->id] = $ac->type.' - '.$ac->name;
} }
return $retval; return $retval;
@@ -152,7 +152,7 @@ class FlightController extends Controller
{ {
return view('admin.flights.create', [ return view('admin.flights.create', [
'flight' => null, 'flight' => null,
'days' => 0, 'days' => [],
'flight_fields' => $this->flightFieldRepo->all(), 'flight_fields' => $this->flightFieldRepo->all(),
'airlines' => $this->airlineRepo->selectBoxList(), 'airlines' => $this->airlineRepo->selectBoxList(),
'airports' => $this->airportRepo->selectBoxList(true, false), 'airports' => $this->airportRepo->selectBoxList(true, false),

View File

@@ -7,24 +7,29 @@ use App\Repositories\KvpRepository;
use App\Services\CronService; use App\Services\CronService;
use App\Services\VersionService; use App\Services\VersionService;
use App\Support\Utils; use App\Support\Utils;
use Codedge\Updater\UpdaterManager;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Laracasts\Flash\Flash; use Laracasts\Flash\Flash;
use Nwidart\Modules\Facades\Module;
class MaintenanceController extends Controller class MaintenanceController extends Controller
{ {
private $cronSvc; private $cronSvc;
private $kvpRepo; private $kvpRepo;
private $updateManager;
private $versionSvc; private $versionSvc;
public function __construct( public function __construct(
CronService $cronSvc, CronService $cronSvc,
KvpRepository $kvpRepo, KvpRepository $kvpRepo,
UpdaterManager $updateManager,
VersionService $versionSvc VersionService $versionSvc
) { ) {
$this->cronSvc = $cronSvc; $this->cronSvc = $cronSvc;
$this->kvpRepo = $kvpRepo; $this->kvpRepo = $kvpRepo;
$this->updateManager = $updateManager;
$this->versionSvc = $versionSvc; $this->versionSvc = $versionSvc;
} }
@@ -101,6 +106,24 @@ class MaintenanceController extends Controller
return redirect(route('admin.maintenance.index')); return redirect(route('admin.maintenance.index'));
} }
/**
* Update the phpVMS install
*
* @param \Illuminate\Http\Request $request
*
* @return mixed
*/
public function update(Request $request)
{
$new_version_tag = $this->kvpRepo->get('latest_version_tag');
Log::info('Attempting to update to '.$new_version_tag);
$module = Module::find('updater');
$module->enable();
return redirect('/update/downloader');
}
/** /**
* Enable the cron, or if it's enabled, change the ID that is used * Enable the cron, or if it's enabled, change the ID that is used
* *

View File

@@ -100,7 +100,7 @@ class PirepController extends Controller
$tmp[$ac->id] = $ac['name'].' - '.$ac['registration']; $tmp[$ac->id] = $ac['name'].' - '.$ac['registration'];
} }
$aircraft[$subfleet->type] = $tmp; $aircraft[$subfleet->name] = $tmp;
} }
return $aircraft; return $aircraft;

View File

@@ -6,12 +6,12 @@ use App\Contracts\Controller;
use App\Http\Requests\CreateUserRequest; use App\Http\Requests\CreateUserRequest;
use App\Http\Requests\UpdateUserRequest; use App\Http\Requests\UpdateUserRequest;
use App\Models\Rank; use App\Models\Rank;
use App\Models\Role;
use App\Models\User; use App\Models\User;
use App\Models\UserAward; use App\Models\UserAward;
use App\Repositories\AirlineRepository; use App\Repositories\AirlineRepository;
use App\Repositories\AirportRepository; use App\Repositories\AirportRepository;
use App\Repositories\PirepRepository; use App\Repositories\PirepRepository;
use App\Repositories\RoleRepository;
use App\Repositories\UserRepository; use App\Repositories\UserRepository;
use App\Services\UserService; use App\Services\UserService;
use App\Support\Timezonelist; use App\Support\Timezonelist;
@@ -29,7 +29,6 @@ class UserController extends Controller
private $airlineRepo; private $airlineRepo;
private $airportRepo; private $airportRepo;
private $pirepRepo; private $pirepRepo;
private $roleRepo;
private $userRepo; private $userRepo;
private $userSvc; private $userSvc;
@@ -39,7 +38,6 @@ class UserController extends Controller
* @param AirlineRepository $airlineRepo * @param AirlineRepository $airlineRepo
* @param AirportRepository $airportRepo * @param AirportRepository $airportRepo
* @param PirepRepository $pirepRepo * @param PirepRepository $pirepRepo
* @param RoleRepository $roleRepo
* @param UserRepository $userRepo * @param UserRepository $userRepo
* @param UserService $userSvc * @param UserService $userSvc
*/ */
@@ -47,14 +45,12 @@ class UserController extends Controller
AirlineRepository $airlineRepo, AirlineRepository $airlineRepo,
AirportRepository $airportRepo, AirportRepository $airportRepo,
PirepRepository $pirepRepo, PirepRepository $pirepRepo,
RoleRepository $roleRepo,
UserRepository $userRepo, UserRepository $userRepo,
UserService $userSvc UserService $userSvc
) { ) {
$this->airlineRepo = $airlineRepo; $this->airlineRepo = $airlineRepo;
$this->airportRepo = $airportRepo; $this->airportRepo = $airportRepo;
$this->pirepRepo = $pirepRepo; $this->pirepRepo = $pirepRepo;
$this->roleRepo = $roleRepo;
$this->userSvc = $userSvc; $this->userSvc = $userSvc;
$this->userRepo = $userRepo; $this->userRepo = $userRepo;
} }
@@ -92,7 +88,6 @@ class UserController extends Controller
->mapWithKeys(function ($item, $key) { ->mapWithKeys(function ($item, $key) {
return [strtolower($item['alpha2']) => $item['name']]; return [strtolower($item['alpha2']) => $item['name']];
}); });
$roles = $this->roleRepo->selectBoxList(false, true);
return view('admin.users.create', [ return view('admin.users.create', [
'user' => null, 'user' => null,
@@ -103,7 +98,7 @@ class UserController extends Controller
'countries' => $countries, 'countries' => $countries,
'airports' => $airports, 'airports' => $airports,
'ranks' => Rank::all()->pluck('name', 'id'), 'ranks' => Rank::all()->pluck('name', 'id'),
'roles' => $roles, 'roles' => Role::all()->pluck('name', 'id'),
]); ]);
} }
@@ -168,7 +163,6 @@ class UserController extends Controller
$airlines = $this->airlineRepo->selectBoxList(); $airlines = $this->airlineRepo->selectBoxList();
$airports = $this->airportRepo->selectBoxList(false); $airports = $this->airportRepo->selectBoxList(false);
$roles = $this->roleRepo->selectBoxList(false, true);
return view('admin.users.edit', [ return view('admin.users.edit', [
'user' => $user, 'user' => $user,
@@ -179,7 +173,7 @@ class UserController extends Controller
'airports' => $airports, 'airports' => $airports,
'airlines' => $airlines, 'airlines' => $airlines,
'ranks' => Rank::all()->pluck('name', 'id'), 'ranks' => Rank::all()->pluck('name', 'id'),
'roles' => $roles, 'roles' => Role::all()->pluck('name', 'id'),
]); ]);
} }
@@ -258,12 +252,15 @@ class UserController extends Controller
public function destroy($id) public function destroy($id)
{ {
$user = $this->userRepo->findWithoutFail($id); $user = $this->userRepo->findWithoutFail($id);
if (empty($user)) { if (empty($user)) {
Flash::error('User not found'); Flash::error('User not found');
return redirect(route('admin.users.index')); return redirect(route('admin.users.index'));
} }
$this->userSvc->removeUser($user); $this->userRepo->delete($id);
Flash::success('User deleted successfully.'); Flash::success('User deleted successfully.');
return redirect(route('admin.users.index')); return redirect(route('admin.users.index'));

View File

@@ -193,9 +193,9 @@ class AcarsController extends Controller
} }
// Change the PIREP status if it's as SCHEDULED before // Change the PIREP status if it's as SCHEDULED before
/*if ($pirep->status === PirepStatus::INITIATED) { if ($pirep->status === PirepStatus::INITIATED) {
$pirep->status = PirepStatus::AIRBORNE; $pirep->status = PirepStatus::AIRBORNE;
}*/ }
$pirep->save(); $pirep->save();

View File

@@ -16,8 +16,9 @@ class AirlineController extends Controller
* *
* @param AirlineRepository $airlineRepo * @param AirlineRepository $airlineRepo
*/ */
public function __construct(AirlineRepository $airlineRepo) public function __construct(
{ AirlineRepository $airlineRepo
) {
$this->airlineRepo = $airlineRepo; $this->airlineRepo = $airlineRepo;
} }
@@ -30,9 +31,11 @@ class AirlineController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$airlines = $this->airlineRepo->whereOrder(['active' => true], 'name')->paginate(); $airports = $this->airlineRepo
->whereOrder(['active' => true], 'name', 'asc')
->paginate();
return AirlineResource::collection($airlines); return AirlineResource::collection($airports);
} }
/** /**

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Contracts\Controller; use App\Contracts\Controller;
use App\Events\PirepPrefiled;
use App\Events\PirepUpdated; use App\Events\PirepUpdated;
use App\Exceptions\AircraftPermissionDenied; use App\Exceptions\AircraftPermissionDenied;
use App\Exceptions\PirepCancelled; use App\Exceptions\PirepCancelled;
@@ -23,10 +24,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\Models\PirepFare; use App\Repositories\AcarsRepository;
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,6 +38,8 @@ 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;
@@ -44,6 +47,8 @@ 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
@@ -51,12 +56,16 @@ 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;
@@ -93,7 +102,7 @@ class PirepController extends Controller
/** /**
* Check if a PIREP is cancelled * Check if a PIREP is cancelled
* *
* @param Pirep $pirep * @param $pirep
* *
* @throws \App\Exceptions\PirepCancelled * @throws \App\Exceptions\PirepCancelled
*/ */
@@ -105,52 +114,50 @@ class PirepController extends Controller
} }
/** /**
* @param $pirep
* @param Request $request * @param Request $request
*
* @return PirepFieldValue[]
*/ */
protected function getFields(Request $request): ?array protected function updateFields($pirep, Request $request)
{ {
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[] = new PirepFieldValue([ $pirep_fields[] = [
'name' => $field_name, 'name' => $field_name,
'value' => $field_value, 'value' => $field_value,
'source' => PirepFieldSource::ACARS, 'source' => PirepFieldSource::ACARS,
]); ];
} }
return $pirep_fields; $this->pirepSvc->updateCustomFields($pirep->id, $pirep_fields);
} }
/** /**
* Save the fares * Save the fares
* *
* @param $pirep
* @param Request $request * @param Request $request
* *
* @throws \Exception * @throws \Exception
*
* @return PirepFare[]
*/ */
protected function getFares(Request $request): ?array protected function updateFares($pirep, Request $request)
{ {
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[] = new PirepFare([ $fares[] = [
'fare_id' => $fare['id'], 'fare_id' => $fare['id'],
'count' => $fare['count'], 'count' => $fare['count'],
]); ];
} }
return $fares; $this->fareSvc->saveForPirep($pirep, $fares);
} }
/** /**
@@ -167,7 +174,6 @@ class PirepController extends Controller
'comments', 'comments',
'flight', 'flight',
'simbrief', 'simbrief',
'position',
'user', 'user',
]; ];
@@ -205,13 +211,16 @@ class PirepController extends Controller
$attrs = $this->parsePirep($request); $attrs = $this->parsePirep($request);
$attrs['source'] = PirepSource::ACARS; $attrs['source'] = PirepSource::ACARS;
$fields = $this->getFields($request); $pirep = $this->pirepSvc->prefile($user, $attrs);
$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);
event(new PirepPrefiled($pirep));
return $this->get($pirep->id); return $this->get($pirep->id);
} }
@@ -252,9 +261,9 @@ class PirepController extends Controller
} }
} }
$fields = $this->getFields($request); $pirep = $this->pirepRepo->update($attrs, $pirep_id);
$fares = $this->getFares($request); $this->updateFields($pirep, $request);
$pirep = $this->pirepSvc->update($pirep_id, $attrs, $fields, $fares); $this->updateFares($pirep, $request);
event(new PirepUpdated($pirep)); event(new PirepUpdated($pirep));
@@ -297,13 +306,11 @@ class PirepController extends Controller
} }
try { try {
$fields = $this->getFields($request); $pirep = $this->pirepSvc->file($pirep, $attrs);
$fares = $this->getFares($request); $this->updateFields($pirep, $request);
$pirep = $this->pirepSvc->file($pirep, $attrs, $fields, $fares); $this->updateFares($pirep, $request);
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error($e); Log::error($e);
throw $e;
} }
// See if there there is any route data posted // See if there there is any route data posted
@@ -405,8 +412,7 @@ class PirepController extends Controller
$pirep = Pirep::find($pirep_id); $pirep = Pirep::find($pirep_id);
$this->checkCancelled($pirep); $this->checkCancelled($pirep);
$fields = $this->getFields($request); $this->updateFields($pirep, $request);
$this->pirepSvc->updateCustomFields($pirep_id, $fields);
return new PirepFieldCollection($pirep->fields); return new PirepFieldCollection($pirep->fields);
} }

View File

@@ -3,8 +3,6 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Contracts\Controller; use App\Contracts\Controller;
use App\Exceptions\Unauthorized;
use App\Exceptions\UserNotFound;
use App\Http\Resources\Bid as BidResource; use App\Http\Resources\Bid as BidResource;
use App\Http\Resources\Pirep as PirepResource; use App\Http\Resources\Pirep as PirepResource;
use App\Http\Resources\Subfleet as SubfleetResource; use App\Http\Resources\Subfleet as SubfleetResource;
@@ -93,10 +91,6 @@ class UserController extends Controller
public function get($id) public function get($id)
{ {
$user = $this->userSvc->getUser($id); $user = $this->userSvc->getUser($id);
if ($user === null) {
throw new UserNotFound();
}
return new UserResource($user); return new UserResource($user);
} }
@@ -114,9 +108,6 @@ class UserController extends Controller
{ {
$user_id = $this->getUserId($request); $user_id = $this->getUserId($request);
$user = $this->userSvc->getUser($user_id); $user = $this->userSvc->getUser($user_id);
if ($user === null) {
throw new UserNotFound();
}
// Add a bid // Add a bid
if ($request->isMethod('PUT') || $request->isMethod('POST')) { if ($request->isMethod('PUT') || $request->isMethod('POST')) {
@@ -145,28 +136,6 @@ class UserController extends Controller
return BidResource::collection($bids); return BidResource::collection($bids);
} }
/**
* Get a particular bid for a user
*
* @param $bid_id
* @param \Illuminate\Http\Request $request
*
* @return \App\Http\Resources\Bid
*/
public function get_bid($bid_id, Request $request)
{
/** @var \App\Models\User $user */
$user = Auth::user();
// Return the current bid
$bid = $this->bidSvc->getBid($user, $bid_id);
if ($bid->user_id !== $user->id) {
throw new Unauthorized(new \Exception('Bid not not belong to authenticated user'));
}
return new BidResource($bid);
}
/** /**
* Return the fleet that this user is allowed to * Return the fleet that this user is allowed to
* *
@@ -177,10 +146,6 @@ class UserController extends Controller
public function fleet(Request $request) public function fleet(Request $request)
{ {
$user = $this->userRepo->find($this->getUserId($request)); $user = $this->userRepo->find($this->getUserId($request));
if ($user === null) {
throw new UserNotFound();
}
$subfleets = $this->userSvc->getAllowableSubfleets($user); $subfleets = $this->userSvc->getAllowableSubfleets($user);
return SubfleetResource::collection($subfleets); return SubfleetResource::collection($subfleets);

View File

@@ -5,7 +5,6 @@ namespace App\Http\Controllers\Auth;
use App\Contracts\Controller; use App\Contracts\Controller;
use App\Exceptions\PilotIdNotFound; use App\Exceptions\PilotIdNotFound;
use App\Models\Enums\UserState; use App\Models\Enums\UserState;
use App\Models\User;
use App\Services\UserService; use App\Services\UserService;
use Illuminate\Foundation\Auth\AuthenticatesUsers; use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@@ -105,16 +104,14 @@ class LoginController extends Controller
*/ */
protected function sendLoginResponse(Request $request) protected function sendLoginResponse(Request $request)
{ {
/** @var User $user */
$user = Auth::user(); $user = Auth::user();
if (setting('general.record_user_ip', true)) { $user->last_ip = $request->ip();
$user->last_ip = $request->ip(); $user->save();
$user->save();
}
if ($user->state !== UserState::ACTIVE && $user->state !== UserState::ON_LEAVE) { if ($user->state !== UserState::ACTIVE && $user->state !== UserState::ON_LEAVE) {
Log::info('Trying to login '.$user->ident.', state '.UserState::label($user->state)); Log::info('Trying to login '.$user->ident.', state '
.UserState::label($user->state));
// Log them out // Log them out
$this->guard()->logout(); $this->guard()->logout();

View File

@@ -119,16 +119,11 @@ class RegisterController extends Controller
* *
* @return User * @return User
*/ */
protected function create(Request $request): User protected function create(array $opts)
{ {
// Default options // Default options
$opts = $request->all();
$opts['password'] = Hash::make($opts['password']); $opts['password'] = Hash::make($opts['password']);
if (setting('general.record_user_ip', true)) {
$opts['last_ip'] = $request->ip();
}
// Convert transfer hours into minutes // Convert transfer hours into minutes
if (isset($opts['transfer_time'])) { if (isset($opts['transfer_time'])) {
$opts['transfer_time'] *= 60; $opts['transfer_time'] *= 60;
@@ -163,7 +158,7 @@ class RegisterController extends Controller
{ {
$this->validator($request->all())->validate(); $this->validator($request->all())->validate();
$user = $this->create($request); $user = $this->create($request->all());
if ($user->state === UserState::PENDING) { if ($user->state === UserState::PENDING) {
return view('auth.pending'); return view('auth.pending');
} }

View File

@@ -36,8 +36,8 @@ class AirportController extends Controller
{ {
$id = strtoupper($id); $id = strtoupper($id);
$airport = $this->airportRepo->where('id', $id)->first(); $airport = $this->airportRepo->find($id);
if (!$airport) { if (empty($airport)) {
Flash::error('Airport not found!'); Flash::error('Airport not found!');
return redirect(route('frontend.dashboard.index')); return redirect(route('frontend.dashboard.index'));
} }
@@ -46,14 +46,12 @@ class AirportController extends Controller
->with(['dpt_airport', 'arr_airport', 'airline']) ->with(['dpt_airport', 'arr_airport', 'airline'])
->findWhere([ ->findWhere([
'arr_airport_id' => $id, 'arr_airport_id' => $id,
'active' => 1,
])->all(); ])->all();
$outbound_flights = $this->flightRepo $outbound_flights = $this->flightRepo
->with(['dpt_airport', 'arr_airport', 'airline']) ->with(['dpt_airport', 'arr_airport', 'airline'])
->findWhere([ ->findWhere([
'dpt_airport_id' => $id, 'dpt_airport_id' => $id,
'active' => 1,
])->all(); ])->all();
return view('airports.show', [ return view('airports.show', [

View File

@@ -3,7 +3,6 @@
namespace App\Http\Controllers\Frontend; namespace App\Http\Controllers\Frontend;
use App\Contracts\Controller; use App\Contracts\Controller;
use App\Models\Airline;
use App\Models\File; use App\Models\File;
use Auth; use Auth;
use Flash; use Flash;
@@ -19,7 +18,6 @@ class DownloadController extends Controller
*/ */
public function index() public function index()
{ {
$airlines = Airline::where('active', 1)->count();
$files = File::orderBy('ref_model', 'asc')->get(); $files = File::orderBy('ref_model', 'asc')->get();
/** /**
@@ -41,28 +39,19 @@ class DownloadController extends Controller
$klass = new $class(); $klass = new $class();
$obj = $klass->find($id); $obj = $klass->find($id);
// Check if the object is there first $category = explode('\\', $class);
if (isset($obj)) { $category = end($category);
$category = explode('\\', $class);
$category = end($category);
if ($category == 'Aircraft' && $airlines > 1) { if ($category == 'Aircraft') {
$group_name = $category.' > '.$obj->subfleet->airline->name.' '.$obj->icao.' '.$obj->registration; $group_name = $category.' > '.$obj->icao.' '.$obj->registration;
} elseif ($category == 'Aircraft') { } elseif ($category == 'Airport') {
$group_name = $category.' > '.$obj->icao.' '.$obj->registration; $group_name = $category.' > '.$obj->icao.' : '.$obj->name.' ('.$obj->country.')';
} elseif ($category == 'Airport') { } else {
$group_name = $category.' > '.$obj->icao.' : '.$obj->name.' ('.$obj->country.')'; $group_name = $category.' > '.$obj->name;
} elseif ($category == 'Subfleet' && $airlines > 1) {
$group_name = $category.' > '.$obj->airline->name.' '.$obj->name;
} else {
$group_name = $category.' > '.$obj->name;
}
$regrouped_files[$group_name] = $files;
} }
}
ksort($regrouped_files, SORT_STRING); $regrouped_files[$group_name] = $files;
}
return view('downloads.index', [ return view('downloads.index', [
'grouped_files' => $regrouped_files, 'grouped_files' => $regrouped_files,
@@ -70,7 +59,7 @@ class DownloadController extends Controller
} }
/** /**
* Show the application dashboard * Show the application dashboard.
* *
* @param string $id * @param string $id
* *

View File

@@ -5,7 +5,6 @@ namespace App\Http\Controllers\Frontend;
use App\Contracts\Controller; use App\Contracts\Controller;
use App\Models\Bid; use App\Models\Bid;
use App\Models\Enums\FlightType; use App\Models\Enums\FlightType;
use App\Models\Flight;
use App\Repositories\AirlineRepository; use App\Repositories\AirlineRepository;
use App\Repositories\AirportRepository; use App\Repositories\AirportRepository;
use App\Repositories\Criteria\WhereCriteria; use App\Repositories\Criteria\WhereCriteria;
@@ -106,15 +105,6 @@ class FlightController extends Controller
Log::emergency($e); Log::emergency($e);
} }
// Get only used Flight Types for the search form
// And filter according to settings
$usedtypes = Flight::select('flight_type')->where($where)->groupby('flight_type')->orderby('flight_type', 'asc')->get();
// Build collection with type codes and labels
$flight_types = collect('', '');
foreach ($usedtypes as $ftype) {
$flight_types->put($ftype->flight_type, FlightType::label($ftype->flight_type));
}
$flights = $this->flightRepo->searchCriteria($request) $flights = $this->flightRepo->searchCriteria($request)
->with([ ->with([
'dpt_airport', 'dpt_airport',
@@ -138,7 +128,7 @@ class FlightController extends Controller
'saved' => $saved_flights, 'saved' => $saved_flights,
'subfleets' => $this->subfleetRepo->selectBoxList(true), 'subfleets' => $this->subfleetRepo->selectBoxList(true),
'flight_number' => $request->input('flight_number'), 'flight_number' => $request->input('flight_number'),
'flight_types' => $flight_types, 'flight_types' => FlightType::select(true),
'flight_type' => $request->input('flight_type'), 'flight_type' => $request->input('flight_type'),
'arr_icao' => $request->input('arr_icao'), 'arr_icao' => $request->input('arr_icao'),
'dep_icao' => $request->input('dep_icao'), 'dep_icao' => $request->input('dep_icao'),

View File

@@ -3,7 +3,6 @@
namespace App\Http\Controllers\Frontend; namespace App\Http\Controllers\Frontend;
use App\Contracts\Controller; use App\Contracts\Controller;
use App\Models\Enums\UserState;
use App\Models\User; use App\Models\User;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -16,7 +15,7 @@ class HomeController extends Controller
public function index() public function index()
{ {
try { try {
$users = User::where('state', '!=', UserState::DELETED)->orderBy('created_at', 'desc')->take(4)->get(); $users = User::orderBy('created_at', 'desc')->take(4)->get();
} catch (\PDOException $e) { } catch (\PDOException $e) {
Log::emergency($e); Log::emergency($e);
return view('system/errors/database_error', [ return view('system/errors/database_error', [

View File

@@ -9,7 +9,6 @@ use App\Models\Enums\PirepSource;
use App\Models\Enums\PirepState; use App\Models\Enums\PirepState;
use App\Models\Fare; use App\Models\Fare;
use App\Models\Pirep; use App\Models\Pirep;
use App\Models\PirepFare;
use App\Models\SimBrief; use App\Models\SimBrief;
use App\Models\User; use App\Models\User;
use App\Repositories\AircraftRepository; use App\Repositories\AircraftRepository;
@@ -104,7 +103,7 @@ class PirepController extends Controller
$tmp[$ac->id] = $ac['name'].' - '.$ac['registration']; $tmp[$ac->id] = $ac['name'].' - '.$ac['registration'];
} }
$aircraft[$subfleet->type] = $tmp; $aircraft[$subfleet->name] = $tmp;
} }
return $aircraft; return $aircraft;
@@ -113,18 +112,19 @@ class PirepController extends Controller
/** /**
* Save any custom fields found * Save any custom fields found
* *
* @param Pirep $pirep
* @param Request $request * @param Request $request
*/ */
protected function saveCustomFields(Request $request): array protected function saveCustomFields(Pirep $pirep, Request $request)
{ {
$fields = []; $custom_fields = [];
$pirep_fields = $this->pirepFieldRepo->all(); $pirep_fields = $this->pirepFieldRepo->all();
foreach ($pirep_fields as $field) { foreach ($pirep_fields as $field) {
if (!$request->filled($field->slug)) { if (!$request->filled($field->slug)) {
continue; continue;
} }
$fields[] = [ $custom_fields[] = [
'name' => $field->name, 'name' => $field->name,
'slug' => $field->slug, 'slug' => $field->slug,
'value' => $request->input($field->slug), 'value' => $request->input($field->slug),
@@ -132,9 +132,8 @@ class PirepController extends Controller
]; ];
} }
Log::info('PIREP Custom Fields', $fields); Log::info('PIREP Custom Fields', $custom_fields);
$this->pirepSvc->updateCustomFields($pirep->id, $custom_fields);
return $fields;
} }
/** /**
@@ -160,10 +159,10 @@ class PirepController extends Controller
$count = $request->input($field_name); $count = $request->input($field_name);
} }
$fares[] = new PirepFare([ $fares[] = [
'fare_id' => $fare->id, 'fare_id' => $fare->id,
'count' => $count, 'count' => $count,
]); ];
} }
$this->fareSvc->saveForPirep($pirep, $fares); $this->fareSvc->saveForPirep($pirep, $fares);
@@ -212,7 +211,6 @@ class PirepController extends Controller
return view('pireps.show', [ return view('pireps.show', [
'pirep' => $pirep, 'pirep' => $pirep,
'map_features' => $map_features, 'map_features' => $map_features,
'user' => Auth::user(),
]); ]);
} }
@@ -390,8 +388,8 @@ class PirepController extends Controller
$attrs['submitted_at'] = Carbon::now('UTC'); $attrs['submitted_at'] = Carbon::now('UTC');
$pirep->submitted_at = Carbon::now('UTC'); $pirep->submitted_at = Carbon::now('UTC');
$fields = $this->saveCustomFields($request); $pirep = $this->pirepSvc->create($pirep);
$pirep = $this->pirepSvc->create($pirep, $fields); $this->saveCustomFields($pirep, $request);
$this->saveFares($pirep, $request); $this->saveFares($pirep, $request);
$this->pirepSvc->saveRoute($pirep); $this->pirepSvc->saveRoute($pirep);
@@ -400,13 +398,7 @@ class PirepController extends Controller
if ($brief !== null) { if ($brief !== null) {
/** @var SimBriefService $sbSvc */ /** @var SimBriefService $sbSvc */
$sbSvc = app(SimBriefService::class); $sbSvc = app(SimBriefService::class);
// Keep the flight_id with SimBrief depending on the button selected $sbSvc->attachSimbriefToPirep($pirep, $brief);
// Save = Keep the flight_id , Submit = Remove the flight_id
if ($attrs['submit'] === 'save') {
$sbSvc->attachSimbriefToPirep($pirep, $brief, true);
} elseif ($attrs['submit'] === 'submit') {
$sbSvc->attachSimbriefToPirep($pirep, $brief);
}
} }
} }
@@ -436,18 +428,12 @@ class PirepController extends Controller
*/ */
public function edit($id) public function edit($id)
{ {
/** @var Pirep $pirep */
$pirep = $this->pirepRepo->findWithoutFail($id); $pirep = $this->pirepRepo->findWithoutFail($id);
if (empty($pirep)) { if (empty($pirep)) {
Flash::error('Pirep not found'); Flash::error('Pirep not found');
return redirect(route('frontend.pireps.index')); return redirect(route('frontend.pireps.index'));
} }
if ($pirep->user_id !== Auth::id()) {
Flash::error('Cannot edit someone else\'s PIREP!');
return redirect(route('admin.pireps.index'));
}
// Eager load the subfleet and fares under it // Eager load the subfleet and fares under it
if ($pirep->aircraft) { if ($pirep->aircraft) {
$pirep->aircraft->load('subfleet.fares'); $pirep->aircraft->load('subfleet.fares');
@@ -500,21 +486,12 @@ class PirepController extends Controller
*/ */
public function update($id, UpdatePirepRequest $request) public function update($id, UpdatePirepRequest $request)
{ {
/** @var User $user */
$user = Auth::user();
/** @var Pirep $pirep */
$pirep = $this->pirepRepo->findWithoutFail($id); $pirep = $this->pirepRepo->findWithoutFail($id);
if (empty($pirep)) { if (empty($pirep)) {
Flash::error('Pirep not found'); Flash::error('Pirep not found');
return redirect(route('admin.pireps.index')); return redirect(route('admin.pireps.index'));
} }
if ($user->id !== $pirep->user_id) {
Flash::error('Cannot edit someone else\'s PIREP!');
return redirect(route('admin.pireps.index'));
}
$orig_route = $pirep->route; $orig_route = $pirep->route;
$attrs = $request->all(); $attrs = $request->all();
$attrs['submit'] = strtolower($attrs['submit']); $attrs['submit'] = strtolower($attrs['submit']);
@@ -532,8 +509,7 @@ class PirepController extends Controller
$this->pirepSvc->saveRoute($pirep); $this->pirepSvc->saveRoute($pirep);
} }
$fields = $this->saveCustomFields($request); $this->saveCustomFields($pirep, $request);
$this->pirepSvc->updateCustomFields($pirep->id, $fields);
$this->saveFares($pirep, $request); $this->saveFares($pirep, $request);
if ($attrs['submit'] === 'save') { if ($attrs['submit'] === 'save') {
@@ -568,11 +544,6 @@ class PirepController extends Controller
return redirect(route('admin.pireps.index')); return redirect(route('admin.pireps.index'));
} }
if ($pirep->user_id !== Auth::id()) {
Flash::error('Cannot edit someone else\'s PIREP!');
return redirect(route('admin.pireps.index'));
}
$this->pirepSvc->submit($pirep); $this->pirepSvc->submit($pirep);
return redirect(route('frontend.pireps.show', [$pirep->id])); return redirect(route('frontend.pireps.show', [$pirep->id]));
} }

View File

@@ -10,7 +10,6 @@ use App\Repositories\AirlineRepository;
use App\Repositories\AirportRepository; use App\Repositories\AirportRepository;
use App\Repositories\UserRepository; use App\Repositories\UserRepository;
use App\Support\Countries; use App\Support\Countries;
use App\Support\Discord;
use App\Support\Timezonelist; use App\Support\Timezonelist;
use App\Support\Utils; use App\Support\Utils;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@@ -182,16 +181,6 @@ class ProfileController extends Controller
Storage::delete($user->avatar); Storage::delete($user->avatar);
} }
// Find out the user's private channel id
/*
// TODO: Uncomment when Discord API functionality is enabled
if ($request->filled('discord_id')) {
$discord_id = $request->post('discord_id');
if ($discord_id !== $user->discord_id) {
$req_data['discord_private_channel_id'] = Discord::getPrivateChannelId($discord_id);
}
}*/
if ($request->hasFile('avatar')) { if ($request->hasFile('avatar')) {
$avatar = $request->file('avatar'); $avatar = $request->file('avatar');
$file_name = $user->ident.'.'.$avatar->getClientOriginalExtension(); $file_name = $user->ident.'.'.$avatar->getClientOriginalExtension();

View File

@@ -4,8 +4,6 @@ namespace App\Http\Controllers\Frontend;
use App\Exceptions\AssetNotFound; use App\Exceptions\AssetNotFound;
use App\Models\Aircraft; use App\Models\Aircraft;
use App\Models\Enums\AircraftState;
use App\Models\Enums\AircraftStatus;
use App\Models\Enums\FareType; use App\Models\Enums\FareType;
use App\Models\Enums\FlightType; use App\Models\Enums\FlightType;
use App\Models\Fare; use App\Models\Fare;
@@ -70,9 +68,6 @@ class SimBriefController
return redirect(route('frontend.flights.index')); return redirect(route('frontend.flights.index'));
} }
// Generate SimBrief Static ID
$static_id = $user->ident.'_'.$flight->id;
// No aircraft selected, show selection form // No aircraft selected, show selection form
if (!$aircraft_id) { if (!$aircraft_id) {
// If no subfleets defined for flight get them from user // If no subfleets defined for flight get them from user
@@ -82,37 +77,8 @@ class SimBriefController
$subfleets = $this->userSvc->getAllowableSubfleets($user); $subfleets = $this->userSvc->getAllowableSubfleets($user);
} }
// Build an array of subfleet id's from the subfleets collection
$sf_ids = $subfleets->map(function ($subfleets) {
return collect($subfleets->toArray())
->only(['id'])
->all();
});
// Now we can build a proper aircrafts collection
// Contents will be either members of flight->subfleets
// or members of user's allowable subfleets
$aircrafts = Aircraft::whereIn('subfleet_id', $sf_ids)
->where('state', AircraftState::PARKED)
->where('status', AircraftStatus::ACTIVE)
->orderby('icao')
->orderby('registration')
->get();
if (setting('pireps.only_aircraft_at_dpt_airport')) {
$aircrafts = $aircrafts->where('airport_id', $flight->dpt_airport_id);
}
if (setting('simbrief.block_aircraft')) {
// Build a list of aircraft_id's being used for active sb packs
$sb_aircraft = SimBrief::whereNotNull('flight_id')->pluck('aircraft_id');
// Filter aircraft list to non used/blocked ones
$aircrafts = $aircrafts->whereNotIn('id', $sb_aircraft);
}
return view('flights.simbrief_aircraft', [ return view('flights.simbrief_aircraft', [
'flight' => $flight, 'flight' => $flight,
'aircrafts' => $aircrafts,
'subfleets' => $subfleets, 'subfleets' => $subfleets,
]); ]);
} }
@@ -240,7 +206,6 @@ class SimBriefController
'tpayload' => $tpayload, 'tpayload' => $tpayload,
'tcargoload' => $tcargoload, 'tcargoload' => $tcargoload,
'loaddist' => implode(' ', $loaddist), 'loaddist' => implode(' ', $loaddist),
'static_id' => $static_id,
]); ]);
} }
@@ -371,31 +336,6 @@ class SimBriefController
]); ]);
} }
/**
* Get the latest generated OFP. Pass in two additional items, the Simbrief userid and static_id
* This will get the latest edited/regenerated of from Simbrief and update our records
* We do not need to send the fares again, so used an empty array
*/
public function update_ofp(Request $request)
{
/** @var User $user */
$user = Auth::user();
$ofp_id = $request->input('ofp_id');
$flight_id = $request->input('flight_id');
$aircraft_id = $request->input('aircraft_id');
$sb_userid = $request->input('sb_userid');
$sb_static_id = $request->input('sb_static_id');
$fares = [];
$simbrief = $this->simBriefSvc->downloadOfp($user->id, $ofp_id, $flight_id, $aircraft_id, $fares, $sb_userid, $sb_static_id);
if ($simbrief === null) {
$error = new AssetNotFound(new Exception('Simbrief OFP not found'));
return $error->getResponse();
}
return redirect(route('frontend.simbrief.briefing', [$ofp_id]));
}
/** /**
* Generate the API code * Generate the API code
* *

View File

@@ -25,6 +25,7 @@ use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Illuminate\View\View; use Illuminate\View\View;
use function in_array; use function in_array;
use Laracasts\Flash\Flash;
use RuntimeException; use RuntimeException;
class InstallerController extends Controller class InstallerController extends Controller
@@ -202,21 +203,21 @@ class InstallerController extends Controller
Log::error('Testing db before writing configs failed'); Log::error('Testing db before writing configs failed');
Log::error($e->getMessage()); Log::error($e->getMessage());
flash()->error($e->getMessage()); Flash::error($e->getMessage());
return redirect(route('installer.step2'))->withInput(); return redirect(route('installer.step2'))->withInput();
} }
// Now write out the env file // Now write out the env file
$attrs = [ $attrs = [
'SITE_NAME' => $request->post('site_name'), 'SITE_NAME' => $request->post('site_name'),
'APP_URL' => $request->post('app_url'), 'SITE_URL' => $request->post('site_url'),
'DB_CONNECTION' => $request->post('db_conn'), 'DB_CONN' => $request->post('db_conn'),
'DB_HOST' => $request->post('db_host'), 'DB_HOST' => $request->post('db_host'),
'DB_PORT' => $request->post('db_port'), 'DB_PORT' => $request->post('db_port'),
'DB_DATABASE' => $request->post('db_name'), 'DB_NAME' => $request->post('db_name'),
'DB_USERNAME' => $request->post('db_user'), 'DB_USER' => $request->post('db_user'),
'DB_PASSWORD' => $request->post('db_pass'), 'DB_PASS' => $request->post('db_pass'),
'DB_PREFIX' => $request->post('db_prefix'), 'DB_PREFIX' => $request->post('db_prefix'),
]; ];
/* /*
@@ -230,7 +231,7 @@ class InstallerController extends Controller
Log::error('Config files failed to write'); Log::error('Config files failed to write');
Log::error($e->getMessage()); Log::error($e->getMessage());
flash()->error($e->getMessage()); Flash::error($e->getMessage());
return redirect(route('installer.step2'))->withInput(); return redirect(route('installer.step2'))->withInput();
} }
@@ -256,7 +257,7 @@ class InstallerController extends Controller
Log::error('Error on db setup: '.$e->getMessage()); Log::error('Error on db setup: '.$e->getMessage());
//dd($e); //dd($e);
$this->envSvc->removeConfigFiles(); $this->envSvc->removeConfigFiles();
flash()->error($e->getMessage()); Flash::error($e->getMessage());
return redirect(route('installer.step2'))->withInput(); return redirect(route('installer.step2'))->withInput();
} }

View File

@@ -3,32 +3,49 @@
namespace App\Http\Controllers\System; namespace App\Http\Controllers\System;
use App\Contracts\Controller; use App\Contracts\Controller;
use App\Repositories\KvpRepository;
use App\Services\AnalyticsService;
use App\Services\Installer\InstallerService; use App\Services\Installer\InstallerService;
use App\Services\Installer\MigrationService; use App\Services\Installer\MigrationService;
use App\Services\Installer\SeederService; use App\Services\Installer\SeederService;
use Codedge\Updater\UpdaterManager;
use function count; use function count;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
class UpdateController extends Controller class UpdateController extends Controller
{ {
private $analyticsSvc;
private $installerSvc; private $installerSvc;
private $kvpRepo;
private $migrationSvc; private $migrationSvc;
private $seederSvc; private $seederSvc;
private $updateManager;
/** /**
* @param AnalyticsService $analyticsSvc
* @param InstallerService $installerSvc * @param InstallerService $installerSvc
* @param KvpRepository $kvpRepo
* @param MigrationService $migrationSvc * @param MigrationService $migrationSvc
* @param SeederService $seederSvc * @param SeederService $seederSvc
* @param UpdaterManager $updateManager
*/ */
public function __construct( public function __construct(
AnalyticsService $analyticsSvc,
InstallerService $installerSvc, InstallerService $installerSvc,
KvpRepository $kvpRepo,
MigrationService $migrationSvc, MigrationService $migrationSvc,
SeederService $seederSvc SeederService $seederSvc,
UpdaterManager $updateManager
) { ) {
$this->analyticsSvc = $analyticsSvc;
$this->migrationSvc = $migrationSvc; $this->migrationSvc = $migrationSvc;
$this->seederSvc = $seederSvc; $this->seederSvc = $seederSvc;
$this->installerSvc = $installerSvc; $this->installerSvc = $installerSvc;
$this->kvpRepo = $kvpRepo;
$this->updateManager = $updateManager;
} }
/** /**
@@ -90,4 +107,38 @@ class UpdateController extends Controller
{ {
return redirect('/admin'); return redirect('/admin');
} }
/**
* Show the update page with the latest version
*
* @return Factory|View
*/
public function updater()
{
$version = $this->kvpRepo->get('latest_version_tag');
return view('system.updater.downloader/downloader', [
'version' => $version,
]);
}
/**
* Download the actual update and then forward the user to the updater page
*
* @return mixed
*/
public function update_download()
{
$version = $this->kvpRepo->get('latest_version_tag');
if (empty($version)) {
return view('system.updater.steps.step1-no-update');
}
$release = $this->updateManager->source('github')->fetch($version);
$this->updateManager->source('github')->update($release);
$this->analyticsSvc->sendUpdate();
Log::info('Update completed to '.$version.', redirecting');
return redirect('/update');
}
} }

View File

@@ -50,9 +50,6 @@ class ApiAuth implements Middleware
return $user; return $user;
}); });
// Force english locale for API
app()->setLocale('en');
return $next($request); return $next($request);
} }

View File

@@ -15,7 +15,6 @@ class JsonResponse implements Middleware
{ {
$response = $next($request); $response = $next($request);
$response->headers->set('Content-Type', 'application/json'); $response->headers->set('Content-Type', 'application/json');
$response->headers->set('charset', 'utf-8');
return $response; return $response;
} }

View File

@@ -52,7 +52,7 @@ class SetActiveTheme implements Middleware
} }
try { try {
$theme = setting('general.theme', 'default'); $theme = setting('general.theme');
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error($e->getMessage()); Log::error($e->getMessage());
$theme = 'default'; $theme = 'default';

View File

@@ -19,7 +19,7 @@ class FileRequest extends FormRequest
return [ return [
'distance' => 'required|numeric', 'distance' => 'required|numeric',
'flight_time' => 'required|integer', 'flight_time' => 'required|integer',
'fuel_used' => 'sometimes|numeric', 'fuel_used' => 'required|numeric',
'block_time' => 'sometimes|integer', 'block_time' => 'sometimes|integer',
'airline_id' => 'sometimes|exists:airlines,id', 'airline_id' => 'sometimes|exists:airlines,id',
'aircraft_id' => 'sometimes|exists:aircraft,id', 'aircraft_id' => 'sometimes|exists:aircraft,id',

View File

@@ -9,7 +9,7 @@ class Bid extends Resource
public function toArray($request) public function toArray($request)
{ {
$res = parent::toArray($request); $res = parent::toArray($request);
$res['flight'] = new BidFlight($this->flight); $res['flight'] = new Flight($this->flight);
return $res; return $res;
} }

View File

@@ -1,36 +0,0 @@
<?php
namespace App\Http\Resources;
use App\Http\Resources\SimBrief as SimbriefResource;
/**
* @mixin \App\Models\Flight
*/
class BidFlight extends Flight
{
/**
* @param \Illuminate\Http\Request $request
*
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
*
* @return array
*/
public function toArray($request)
{
$res = parent::toArray($request);
if ($this->whenLoaded('simbrief')) {
unset($res['subfleets']);
$res['simbrief'] = new SimbriefResource($this->simbrief);
} else {
unset($res['simbrief']);
$res['subfleets'] = Subfleet::collection($this->whenLoaded('subfleets'));
}
$res['fields'] = $this->setFields();
return $res;
}
}

View File

@@ -1,41 +0,0 @@
<?php
namespace App\Http\Resources;
class BidSubfleet extends Subfleet
{
protected $aircraft;
protected $fares;
public function __construct($resource, $aircraft, $fares)
{
parent::__construct($resource);
$this->aircraft = $aircraft;
$this->fares = $fares;
}
public function toArray($request)
{
$res = [];
$res['airline_id'] = $this->airline_id;
$res['hub_id'] = $this->hub_id;
$res['type'] = $this->type;
$res['simbrief_type'] = $this->simbrief_type;
$res['name'] = $this->name;
$res['fuel_type'] = $this->fuel_type;
$res['cost_block_hour'] = $this->cost_block_hour;
$res['cost_delay_minute'] = $this->cost_delay_minute;
$res['ground_handling_multiplier'] = $this->ground_handling_multiplier;
$res['cargo_capacity'] = $this->cargo_capacity;
$res['fuel_capacity'] = $this->fuel_capacity;
$res['gross_weight'] = $this->gross_weight;
$res['fares'] = Fare::collection($this->fares);
// There should only be one aircraft tied to a bid subfleet, wrap in a collection
$res['aircraft'] = Aircraft::collection([$this->aircraft]);
return $res;
}
}

View File

@@ -15,7 +15,7 @@ class Flight extends Resource
/** /**
* Set the fields on the flight object * Set the fields on the flight object
*/ */
protected function setFields() private function setFields()
{ {
/** @var \Illuminate\Support\Collection $field_values */ /** @var \Illuminate\Support\Collection $field_values */
$return_values = new stdClass(); $return_values = new stdClass();

View File

@@ -18,7 +18,7 @@ class News extends Resource
$res = parent::toArray($request); $res = parent::toArray($request);
$res['user'] = [ $res['user'] = [
'id' => $this->user->id, 'id' => $this->user->id,
'name' => $this->user->name_private, 'name' => $this->user->name,
]; ];
return $res; return $res;

View File

@@ -12,27 +12,25 @@ class SimBrief extends Resource
public function toArray($request) public function toArray($request)
{ {
$data = [ $data = [
'id' => $this->id, 'id' => $this->id,
'aircraft_id' => $this->aircraft_id, 'url' => url(route('api.flights.briefing', ['id' => $this->id])),
'url' => url(route('api.flights.briefing', ['id' => $this->id])),
]; ];
$fares = [];
try { try {
if (!empty($this->fare_data)) { if (!empty($this->fare_data)) {
$fares = [];
$fare_data = json_decode($this->fare_data, true); $fare_data = json_decode($this->fare_data, true);
foreach ($fare_data as $fare) { foreach ($fare_data as $fare) {
$fares[] = new \App\Models\Fare($fare); $fares[] = new \App\Models\Fare($fare);
} }
$fares = collect($fares); $this->aircraft->subfleet->fares = collect($fares);
} }
} catch (\Exception $e) { } catch (\Exception $e) {
// Invalid fare data // Invalid fare data
} }
$data['subfleet'] = new BidSubfleet($this->aircraft->subfleet, $this->aircraft, $fares); $data['subfleet'] = new Subfleet($this->aircraft->subfleet);
return $data; return $data;
} }

View File

@@ -3,7 +3,8 @@
namespace App\Listeners; namespace App\Listeners;
use App\Contracts\Listener; use App\Contracts\Listener;
use App\Events\PirepFiled; use App\Events\PirepAccepted;
use App\Events\PirepRejected;
use App\Services\BidService; use App\Services\BidService;
/** /**
@@ -12,7 +13,8 @@ use App\Services\BidService;
class BidEventHandler extends Listener class BidEventHandler extends Listener
{ {
public static $callbacks = [ public static $callbacks = [
PirepFiled::class => 'onPirepFiled', PirepAccepted::class => 'onPirepAccept',
PirepRejected::class => 'onPirepReject',
]; ];
private $bidSvc; private $bidSvc;
@@ -23,15 +25,29 @@ class BidEventHandler extends Listener
} }
/** /**
* When a PIREP is filed, remove any bids * When a PIREP is accepted, remove any bids
* *
* @param PirepFiled $event * @param PirepAccepted $event
* *
* @throws \UnexpectedValueException * @throws \UnexpectedValueException
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
* @throws \Exception * @throws \Exception
*/ */
public function onPirepFiled(PirepFiled $event): void public function onPirepAccept(PirepAccepted $event): void
{
$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); $this->bidSvc->removeBidForPirep($event->pirep);
} }

View File

@@ -1,22 +0,0 @@
<?php
namespace App\Listeners;
use Illuminate\Log\Events\MessageLogged;
use Symfony\Component\Console\Output\ConsoleOutput;
/**
* Show logs in the console
*
* https://stackoverflow.com/questions/48264479/log-laravel-with-artisan-output
*/
class MessageLoggedListener
{
public function handle(MessageLogged $event)
{
if (app()->runningInConsole() && app()->environment() !== 'testing') {
$output = new ConsoleOutput();
$output->writeln("<$event->level>$event->message</$event->level>");
}
}
}

View File

@@ -1,26 +0,0 @@
<?php
namespace App\Listeners;
use App\Contracts\Listener;
use App\Events\PirepPrefiled;
/**
* Handler for PIREP events
*/
class PirepEventsHandler extends Listener
{
/** The events and the callback */
public static $callbacks = [
PirepPrefiled::class => 'onPirepPrefile',
];
/**
* Called when a PIREP is prefiled
*
* @param PirepPrefiled $event
*/
public function onPirepPrefile(PirepPrefiled $event)
{
}
}

View File

@@ -12,7 +12,6 @@ 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
@@ -25,7 +24,6 @@ use Carbon\Carbon;
* @property int status * @property int status
* @property int state * @property int state
* @property Carbon landing_time * @property Carbon landing_time
* @property float fuel_onboard
*/ */
class Aircraft extends Model class Aircraft extends Model
{ {
@@ -72,14 +70,6 @@ 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
* *

View File

@@ -6,7 +6,6 @@ use App\Contracts\Model;
use App\Models\Enums\JournalType; use App\Models\Enums\JournalType;
use App\Models\Traits\FilesTrait; use App\Models\Traits\FilesTrait;
use App\Models\Traits\JournalTrait; use App\Models\Traits\JournalTrait;
use Illuminate\Support\Str;
/** /**
* Class Airline * Class Airline
@@ -85,7 +84,7 @@ class Airline extends Model
*/ */
public function setIataAttribute($iata) public function setIataAttribute($iata)
{ {
$this->attributes['iata'] = Str::upper($iata); $this->attributes['iata'] = strtoupper($iata);
} }
/** /**
@@ -95,7 +94,7 @@ class Airline extends Model
*/ */
public function setIcaoAttribute($icao): void public function setIcaoAttribute($icao): void
{ {
$this->attributes['icao'] = Str::upper($icao); $this->attributes['icao'] = strtoupper($icao);
} }
public function subfleets() public function subfleets()

View File

@@ -46,7 +46,6 @@ class Airport extends Model
'lon', 'lon',
'hub', 'hub',
'timezone', 'timezone',
'tz',
'ground_handling_cost', 'ground_handling_cost',
'fuel_100ll_cost', 'fuel_100ll_cost',
'fuel_jeta_cost', 'fuel_jeta_cost',

View File

@@ -6,7 +6,7 @@ use App\Contracts\Model;
use Carbon\Carbon; use Carbon\Carbon;
/** /**
* @property int user_id * @property string user_id
* @property string flight_id * @property string flight_id
* @property Carbon created_at * @property Carbon created_at
* @property Carbon updated_at * @property Carbon updated_at

View File

@@ -77,7 +77,7 @@ class Days extends Enum
*/ */
public static function in($mask, $day): bool public static function in($mask, $day): bool
{ {
return in_mask($mask, $day); return ($mask & $day) === $day;
} }
/** /**

View File

@@ -4,6 +4,9 @@ namespace App\Models\Enums;
use App\Contracts\Enum; use App\Contracts\Enum;
/**
* Class PirepState
*/
class PirepState extends Enum class PirepState extends Enum
{ {
public const IN_PROGRESS = 0; // flight is ongoing public const IN_PROGRESS = 0; // flight is ongoing
@@ -13,7 +16,6 @@ class PirepState extends Enum
public const DELETED = 4; public const DELETED = 4;
public const DRAFT = 5; public const DRAFT = 5;
public const REJECTED = 6; public const REJECTED = 6;
public const PAUSED = 7;
protected static $labels = [ protected static $labels = [
self::IN_PROGRESS => 'pireps.state.in_progress', self::IN_PROGRESS => 'pireps.state.in_progress',
@@ -23,6 +25,5 @@ class PirepState extends Enum
self::DELETED => 'pireps.state.deleted', self::DELETED => 'pireps.state.deleted',
self::DRAFT => 'pireps.state.draft', self::DRAFT => 'pireps.state.draft',
self::REJECTED => 'pireps.state.rejected', self::REJECTED => 'pireps.state.rejected',
self::PAUSED => 'pireps.state.paused',
]; ];
} }

View File

@@ -33,8 +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_DESCENT = 'EMG'; public const EMERG_DECENT = 'EMG';
public const PAUSED = 'PSD';
protected static $labels = [ protected static $labels = [
self::INITIATED => 'pireps.status.initialized', self::INITIATED => 'pireps.status.initialized',
@@ -59,7 +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_DESCENT => 'pireps.status.emerg_decent', self::EMERG_DECENT => 'pireps.status.emerg_decent',
self::PAUSED => 'pireps.status.paused',
]; ];
} }

View File

@@ -11,7 +11,6 @@ class UserState extends Enum
public const REJECTED = 2; public const REJECTED = 2;
public const ON_LEAVE = 3; public const ON_LEAVE = 3;
public const SUSPENDED = 4; public const SUSPENDED = 4;
public const DELETED = 5;
protected static $labels = [ protected static $labels = [
self::PENDING => 'user.state.pending', self::PENDING => 'user.state.pending',
@@ -19,6 +18,5 @@ class UserState extends Enum
self::REJECTED => 'user.state.rejected', self::REJECTED => 'user.state.rejected',
self::ON_LEAVE => 'user.state.on_leave', self::ON_LEAVE => 'user.state.on_leave',
self::SUSPENDED => 'user.state.suspended', self::SUSPENDED => 'user.state.suspended',
self::DELETED => 'user.state.deleted',
]; ];
} }

View File

@@ -13,7 +13,6 @@ use App\Models\Traits\ReferenceTrait;
* @property string flight_type * @property string flight_type
* @property string ref_model * @property string ref_model
* @property string ref_model_id * @property string ref_model_id
* @property bool charge_to_user
* *
* @mixin \Illuminate\Database\Eloquent\Builder * @mixin \Illuminate\Database\Eloquent\Builder
*/ */
@@ -37,7 +36,7 @@ class Expense extends Model
]; ];
public static $rules = [ public static $rules = [
'active' => 'bool', 'active' => 'boolean',
'airline_id' => 'integer', 'airline_id' => 'integer',
'amount' => 'float', 'amount' => 'float',
'multiplier' => 'bool', 'multiplier' => 'bool',

View File

@@ -15,7 +15,6 @@ use Illuminate\Support\Collection;
* @property Airline airline * @property Airline airline
* @property int airline_id * @property int airline_id
* @property mixed flight_number * @property mixed flight_number
* @property mixed callsign
* @property mixed route_code * @property mixed route_code
* @property int route_leg * @property int route_leg
* @property bool has_bid * @property bool has_bid
@@ -61,7 +60,6 @@ class Flight extends Model
'id', 'id',
'airline_id', 'airline_id',
'flight_number', 'flight_number',
'callsign',
'route_code', 'route_code',
'route_leg', 'route_leg',
'dpt_airport_id', 'dpt_airport_id',
@@ -106,7 +104,6 @@ class Flight extends Model
public static $rules = [ public static $rules = [
'airline_id' => 'required|exists:airlines,id', 'airline_id' => 'required|exists:airlines,id',
'flight_number' => 'required', 'flight_number' => 'required',
'callsign' => 'string|max:4|nullable',
'route_code' => 'nullable', 'route_code' => 'nullable',
'route_leg' => 'nullable', 'route_leg' => 'nullable',
'dpt_airport_id' => 'required|exists:airports,id', 'dpt_airport_id' => 'required|exists:airports,id',

View File

@@ -186,7 +186,7 @@ class Journal extends Model
*/ */
public function getCurrentBalance() public function getCurrentBalance()
{ {
return $this->getBalanceOn(Carbon::now('UTC')); return $this->getBalanceOn(Carbon::now());
} }
/** /**

View File

@@ -3,19 +3,13 @@
namespace App\Models; namespace App\Models;
use App\Contracts\Model; use App\Contracts\Model;
use Illuminate\Notifications\Notifiable;
/** /**
* @property int id * @property string subject
* @property int|mixed user_id * @property string body
* @property string subject
* @property string body
* @property User user
*/ */
class News extends Model class News extends Model
{ {
use Notifiable;
public $table = 'news'; public $table = 'news';
protected $fillable = [ protected $fillable = [

View File

@@ -3,8 +3,6 @@
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;
@@ -12,9 +10,7 @@ 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
@@ -48,9 +44,8 @@ use Kleemans\AttributeEvents;
* @property Flight|null flight * @property Flight|null flight
* @property Collection fields * @property Collection fields
* @property string status * @property string status
* @property int state * @property bool state
* @property int source * @property string source
* @property string source_name
* @property Carbon submitted_at * @property Carbon submitted_at
* @property Carbon created_at * @property Carbon created_at
* @property Carbon updated_at * @property Carbon updated_at
@@ -61,9 +56,7 @@ use Kleemans\AttributeEvents;
*/ */
class Pirep extends Model class Pirep extends Model
{ {
use AttributeEvents;
use HashIdTrait; use HashIdTrait;
use Notifiable;
public $table = 'pireps'; public $table = 'pireps';
@@ -143,14 +136,6 @@ 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.
*/ */

View File

@@ -11,7 +11,6 @@ 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)
*/ */

View File

@@ -5,12 +5,6 @@ namespace App\Models;
use Laratrust\Models\LaratrustRole; use Laratrust\Models\LaratrustRole;
/** /**
* @property int id
* @property string name
* @property string display_name
* @property bool read_only
* @property bool disable_activity_checks
*
* @mixin \Illuminate\Database\Eloquent\Builder * @mixin \Illuminate\Database\Eloquent\Builder
*/ */
class Role extends LaratrustRole class Role extends LaratrustRole
@@ -20,12 +14,10 @@ class Role extends LaratrustRole
'name', 'name',
'display_name', 'display_name',
'read_only', 'read_only',
'disable_activity_checks',
]; ];
protected $casts = [ protected $casts = [
'read_only' => 'boolean', 'read_only' => 'boolean',
'disable_activity_checks' => 'boolean',
]; ];
/** /**

View File

@@ -49,7 +49,7 @@ class SimBrief extends Model
* *
* @return \App\Models\SimBriefXML|null * @return \App\Models\SimBriefXML|null
*/ */
public function getXmlAttribute(): ?SimBriefXML public function getXmlAttribute(): SimBriefXML
{ {
if (empty($this->attributes['ofp_xml'])) { if (empty($this->attributes['ofp_xml'])) {
return null; return null;

View File

@@ -20,7 +20,6 @@ use App\Models\Traits\FilesTrait;
* @property float cost_delay_minute * @property float cost_delay_minute
* @property Airline airline * @property Airline airline
* @property Airport hub * @property Airport hub
* @property int fuel_type
*/ */
class Subfleet extends Model class Subfleet extends Model
{ {

View File

@@ -3,6 +3,7 @@
namespace App\Models; namespace App\Models;
use App\Models\Enums\JournalType; use App\Models\Enums\JournalType;
use App\Models\Enums\PirepState;
use App\Models\Traits\JournalTrait; use App\Models\Traits\JournalTrait;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
@@ -32,16 +33,11 @@ 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 string last_ip
* @property bool opt_in * @property bool opt_in
* @property Pirep[] pireps
* @property string last_pirep_id * @property string last_pirep_id
* @property Pirep last_pirep * @property Pirep last_pirep
* @property UserFieldValue[] fields * @property UserFieldValue[] fields
* @property Role[] roles
* @property Subfleet[] subfleets
* *
* @mixin \Illuminate\Database\Eloquent\Builder * @mixin \Illuminate\Database\Eloquent\Builder
* @mixin \Illuminate\Notifications\Notifiable * @mixin \Illuminate\Notifications\Notifiable
@@ -68,8 +64,6 @@ class User extends Authenticatable
'pilot_id', 'pilot_id',
'airline_id', 'airline_id',
'rank_id', 'rank_id',
'discord_id',
'discord_private_channel_id',
'api_key', 'api_key',
'country', 'country',
'home_airport_id', 'home_airport_id',
@@ -84,7 +78,6 @@ class User extends Authenticatable
'status', 'status',
'toc_accepted', 'toc_accepted',
'opt_in', 'opt_in',
'last_ip',
'created_at', 'created_at',
'updated_at', 'updated_at',
]; ];
@@ -94,9 +87,7 @@ class User extends Authenticatable
*/ */
protected $hidden = [ protected $hidden = [
'api_key', 'api_key',
'discord_id',
'password', 'password',
'last_ip',
'remember_token', 'remember_token',
]; ];
@@ -258,7 +249,8 @@ class User extends Authenticatable
public function pireps() public function pireps()
{ {
return $this->hasMany(Pirep::class, 'user_id'); return $this->hasMany(Pirep::class, 'user_id')
->where('state', '!=', PirepState::CANCELLED);
} }
public function rank() public function rank()

View File

@@ -1,145 +0,0 @@
<?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
{
$embeds = [
'title' => $this->title,
'url' => $this->url,
'type' => 'rich',
'description' => $this->description,
'author' => $this->author,
'timestamp' => Carbon::now('UTC'),
];
if (!empty($this->fields)) {
$embeds['fields'] = $this->fields;
}
if (!empty($this->footer)) {
$embeds['footer'] = [
'text' => $this->footer,
];
}
return [
'embeds' => [$embeds],
];
}
}

View File

@@ -1,38 +0,0 @@
<?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 DiscordWebhook
{
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) {
$request = Psr7\Message::toString($e->getRequest());
$response = Psr7\Message::toString($e->getResponse());
Log::error('Error sending Discord notification: request: '.$e->getMessage().', '.$request);
Log::error('Error sending Discord notification: response: '.$response);
}
}
}

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(string $subject, string $template, array $args) public function setMailable($subject, $template, $args)
{ {
$this->mailSubject = $subject; $this->mailSubject = $subject;
$this->mailTemplate = $template; $this->mailTemplate = $template;

View File

@@ -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,19 +23,17 @@ 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 NotificationEventsHandler extends Listener class EventHandler extends Listener
{ {
private static $broadcastNotifyable; private static $broadcastNotifyable;
public static $callbacks = [ public static $callbacks = [
NewsAdded::class => 'onNewsAdded', NewsAdded::class => 'onNewsAdded',
PirepPrefiled::class => 'onPirepPrefile', PirepAccepted::class => 'onPirepAccepted',
PirepStatusChange::class => 'onPirepStatusChange', PirepFiled::class => 'onPirepFile',
PirepAccepted::class => 'onPirepAccepted', PirepRejected::class => 'onPirepRejected',
PirepFiled::class => 'onPirepFile', UserRegistered::class => 'onUserRegister',
PirepRejected::class => 'onPirepRejected', UserStateChanged::class => 'onUserStateChange',
UserRegistered::class => 'onUserRegister',
UserStateChanged::class => 'onUserStateChange',
]; ];
public function __construct() public function __construct()
@@ -48,21 +46,14 @@ class NotificationEventsHandler extends Listener
* *
* @param \App\Contracts\Notification $notification * @param \App\Contracts\Notification $notification
*/ */
protected function notifyAdmins(\App\Contracts\Notification $notification) protected function notifyAdmins($notification)
{ {
$admin_users = User::whereRoleIs('admin')->get(); $admin_users = User::whereRoleIs('admin')->get();
foreach ($admin_users as $user) { try {
if (empty($user->email)) { Notification::send($admin_users, $notification);
continue; } catch (Exception $e) {
} Log::emergency('Error emailing admins, malformed email='.$e->getMessage());
try {
// $this->notifyUser($user, $notification);
Notification::send([$user], $notification);
} catch (Exception $e) {
Log::emergency('Error emailing admin ('.$user->email.'). Error='.$e->getMessage());
}
} }
} }
@@ -70,16 +61,12 @@ class NotificationEventsHandler extends Listener
* @param User $user * @param User $user
* @param \App\Contracts\Notification $notification * @param \App\Contracts\Notification $notification
*/ */
protected function notifyUser(User $user, \App\Contracts\Notification $notification) protected function notifyUser($user, $notification)
{ {
if ($user->state === UserState::DELETED) {
return;
}
try { try {
$user->notify($notification); $user->notify($notification);
} catch (Exception $e) { } catch (Exception $e) {
Log::emergency('Error emailing user, '.$user->ident.'='.$user->email.', error='.$e->getMessage()); Log::emergency('Error emailing admins, malformed email='.$e->getMessage());
} }
} }
@@ -97,15 +84,17 @@ class NotificationEventsHandler extends Listener
} }
/** @var Collection $users */ /** @var Collection $users */
$users = User::where($where)->where('state', '<>', UserState::DELETED)->get(); $users = User::where($where)->get();
if (empty($users) || $users->count() === 0) { if (empty($users) || $users->count() === 0) {
return; return;
} }
Log::info('Sending notification to '.$users->count().' users'); Log::info('Sending notification to '.$users->count().' users');
foreach ($users as $user) { try {
$this->notifyUser($user, $notification); Notification::send($users, $notification);
} catch (Exception $e) {
Log::emergency('Error emailing admins, malformed email='.$e->getMessage());
} }
} }
@@ -120,24 +109,19 @@ class NotificationEventsHandler 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 Messages\UserPending($event->user)); $this->notifyUser($event->user, new 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));
} }
/** /**
@@ -160,34 +144,15 @@ class NotificationEventsHandler 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 PirepFiled $event * @param \App\Events\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 Messages\PirepSubmitted($event->pirep)); $this->notifyAdmins(new PirepSubmitted($event->pirep));
Notification::send([$event->pirep], new Messages\PirepSubmitted($event->pirep));
} }
/** /**
@@ -221,6 +186,5 @@ class NotificationEventsHandler 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));
} }
} }

Some files were not shown because too many files have changed in this diff Show More