Check for departure airport restrictions #221

This commit is contained in:
Nabeel Shahzad 2018-03-30 11:08:53 -05:00
parent 35fb6f0e52
commit bd30b1f900
12 changed files with 189 additions and 29 deletions

View File

@ -169,7 +169,7 @@ class CreateSettingsTable extends Migration
'description' => 'Aircraft that can be flown are restricted to a user\'s rank', 'description' => 'Aircraft that can be flown are restricted to a user\'s rank',
]); ]);
$this->addSetting('pireps.only_aircraft_at_dep_airport', [ $this->addSetting('pireps.only_aircraft_at_dpt_airport', [
'name' => 'Restrict Aircraft At Departure', 'name' => 'Restrict Aircraft At Departure',
'group' => 'pireps', 'group' => 'pireps',
'value' => false, 'value' => false,

View File

@ -0,0 +1,13 @@
<?php
namespace App\Exceptions;
/**
* Class AircraftNotAtAirport
* @package App\Exceptions
*/
class AircraftNotAtAirport extends InternalError
{
public const FIELD = 'aircraft_id';
public const MESSAGE = 'The aircraft is not at the departure airport';
}

View File

@ -2,24 +2,12 @@
namespace App\Exceptions; namespace App\Exceptions;
use Symfony\Component\HttpKernel\Exception\HttpException;
/** /**
* Class AircraftPermissionDenied * Class AircraftPermissionDenied
* @package App\Exceptions * @package App\Exceptions
*/ */
class AircraftPermissionDenied extends HttpException class AircraftPermissionDenied extends InternalError
{ {
public function __construct( public const FIELD = 'aircraft_id';
string $message = null, public const MESSAGE = 'User is not allowed to fly this aircraft';
\Exception $previous = null,
int $code = 0,
array $headers = []
) {
parent::__construct(
400,
'User is not allowed to fly this aircraft',
$previous, $headers, $code
);
}
} }

View File

@ -14,18 +14,21 @@ use Log;
*/ */
class InternalError extends ValidationException class InternalError extends ValidationException
{ {
protected const FLASH_FIELD_NAME = 'internal_error_message'; public const FIELD = 'internal_error_message';
public const MESSAGE = '';
/** /**
* InternalError constructor. * InternalError constructor.
* @param string|null $message * @param string|null $message
* @param null $field * @param null $field
*/ */
final public function __construct(string $message = null, $field = null) public function __construct(string $message = null, $field = null)
{ {
Log::error($message); Log::error($message);
$validator = Validator::make([], []); $validator = Validator::make([], []);
$validator->errors()->add($field ?? static::FLASH_FIELD_NAME, $message); $validator->errors()->add(
$field ?? static::FIELD,
$message ?? static::MESSAGE);
parent::__construct($validator); parent::__construct($validator);
} }

View File

@ -0,0 +1,14 @@
<?php
namespace App\Exceptions;
/**
* Class UserNotAtAirport
* @package App\Exceptions
*/
class UserNotAtAirport extends InternalError
{
public const FIELD = 'dpt_airport_id';
public const MESSAGE = 'Pilot is not at the departure airport';
}

View File

@ -2,8 +2,10 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Exceptions\AircraftNotAtAirport;
use App\Exceptions\AircraftPermissionDenied; use App\Exceptions\AircraftPermissionDenied;
use App\Exceptions\PirepCancelled; use App\Exceptions\PirepCancelled;
use App\Exceptions\UserNotAtAirport;
use App\Http\Requests\Acars\CommentRequest; use App\Http\Requests\Acars\CommentRequest;
use App\Http\Requests\Acars\EventRequest; use App\Http\Requests\Acars\EventRequest;
use App\Http\Requests\Acars\FileRequest; use App\Http\Requests\Acars\FileRequest;
@ -155,6 +157,8 @@ class PirepController extends Controller
* *
* @param PrefileRequest $request * @param PrefileRequest $request
* @return PirepResource * @return PirepResource
* @throws \App\Exceptions\AircraftNotAtAirport
* @throws \App\Exceptions\UserNotAtAirport
* @throws \App\Exceptions\PirepCancelled * @throws \App\Exceptions\PirepCancelled
* @throws \App\Exceptions\AircraftPermissionDenied * @throws \App\Exceptions\AircraftPermissionDenied
* @throws \Exception * @throws \Exception
@ -173,12 +177,25 @@ class PirepController extends Controller
$pirep = new Pirep($attrs); $pirep = new Pirep($attrs);
# See if this user is at the current airport
if (setting('pilots.only_flights_from_current')
&& $user->current_airport_id !== $pirep->dpt_airport_id)
{
throw new UserNotAtAirport();
}
# See if this user is allowed to fly this aircraft # See if this user is allowed to fly this aircraft
if (setting('pireps.restrict_aircraft_to_rank', false)) { if (setting('pireps.restrict_aircraft_to_rank', false)
$can_use_ac = $this->userSvc->aircraftAllowed($user, $pirep->aircraft_id); && !$this->userSvc->aircraftAllowed($user, $pirep->aircraft_id))
if (!$can_use_ac) { {
throw new AircraftPermissionDenied(); throw new AircraftPermissionDenied();
} }
# See if this aircraft is at the departure airport
if (setting('pireps.only_aircraft_at_dpt_airport')
&& $pirep->aircraft_id !== $pirep->dpt_airport_id)
{
throw new AircraftNotAtAirport();
} }
# Find if there's a duplicate, if so, let's work on that # Find if there's a duplicate, if so, let's work on that

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Frontend; namespace App\Http\Controllers\Frontend;
use App\Exceptions\UserNotAtAirport;
use App\Facades\Utils; use App\Facades\Utils;
use App\Http\Requests\CreatePirepRequest; use App\Http\Requests\CreatePirepRequest;
use App\Http\Requests\UpdatePirepRequest; use App\Http\Requests\UpdatePirepRequest;
@ -241,12 +242,40 @@ class PirepController extends Controller
$pirep = new Pirep($request->post()); $pirep = new Pirep($request->post());
$pirep->user_id = Auth::user()->id; $pirep->user_id = Auth::user()->id;
# Are they allowed at this airport?
if (setting('pilots.only_flights_from_current')
&& Auth::user()->current_airport_id !== $pirep->dpt_airport_id) {
return $this->flashError(
'You are currently not at the departure airport!',
'frontend.pireps.create'
);
}
# Can they fly this aircraft?
if (setting('pireps.restrict_aircraft_to_rank', false)
&& !$this->userSvc->aircraftAllowed(Auth::user(), $pirep->aircraft_id)) {
return $this->flashError(
'You are not allowed to fly this aircraft!',
'frontend.pireps.create'
);
}
# is the aircraft in the right place?
if (setting('pireps.only_aircraft_at_dpt_airport')
&& $pirep->aircraft_id !== $pirep->dpt_airport_id) {
return $this->flashError(
'This aircraft is not positioned at the departure airport!',
'frontend.pireps.create'
);
}
# Make sure this isn't a duplicate # Make sure this isn't a duplicate
$dupe_pirep = $this->pirepSvc->findDuplicate($pirep); $dupe_pirep = $this->pirepSvc->findDuplicate($pirep);
if ($dupe_pirep !== false) { if ($dupe_pirep !== false) {
flash()->error('This PIREP has already been filed.'); return $this->flashError(
'This PIREP has already been filed.',
return redirect(route('frontend.pireps.create'))->withInput(); 'frontend.pireps.create'
);
} }
// Any special fields // Any special fields

View File

@ -15,6 +15,18 @@ abstract class Controller extends \Illuminate\Routing\Controller
{ {
use AuthorizesRequests, DispatchesJobs, ValidatesRequests; use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
/**
* Write a error to the flash and redirect the user to a route
* @param $message
* @param $route
* @return mixed
*/
public function flashError($message, $route)
{
flash()->error($message);
return redirect(route($route))->withInput();
}
/** /**
* Shortcut function to get the attributes from a request while running the validations * Shortcut function to get the attributes from a request while running the validations
* @param Request $request * @param Request $request

View File

@ -20,10 +20,13 @@ use PhpUnitsOfMeasure\Exception\NonStringUnitName;
* @property string route_leg * @property string route_leg
* @property integer airline_id * @property integer airline_id
* @property integer user_id * @property integer user_id
* @property integer aircraft_id
* @property Aircraft aircraft * @property Aircraft aircraft
* @property Airline airline * @property Airline airline
* @property Airport arr_airport * @property Airport arr_airport
* @property Airport dep_airport * @property string arr_airport_id
* @property Airport dpt_airport
* @property string dpt_airport_id
* @property integer block_time * @property integer block_time
* @property integer flight_time In minutes * @property integer flight_time In minutes
* @property User user * @property User user

View File

@ -15,6 +15,8 @@ use Laratrust\Traits\LaratrustUserTrait;
* @property string $email * @property string $email
* @property string $password * @property string $password
* @property string $api_key * @property string $api_key
* @property string current_airport_id
* @property string home_airport_id
* @property Flight[] $flights * @property Flight[] $flights
* @property string $flight_time * @property string $flight_time
* @property string $remember_token * @property string $remember_token

View File

@ -83,7 +83,7 @@ class FlightService extends Service
/** /**
* Only allow aircraft that are at the current departure airport * Only allow aircraft that are at the current departure airport
*/ */
if (setting('pireps.only_aircraft_at_dep_airport', false)) { if (setting('pireps.only_aircraft_at_dpt_airport', false)) {
foreach ($subfleets as $subfleet) { foreach ($subfleets as $subfleet) {
$subfleet->aircraft = $subfleet->aircraft->filter( $subfleet->aircraft = $subfleet->aircraft->filter(
function ($aircraft, $i) use ($flight) { function ($aircraft, $i) use ($flight) {

View File

@ -92,6 +92,85 @@ class AcarsTest extends TestCase
} }
/**
* Make sure an error is thrown if the pilot is not at the current airport
*/
public function testPilotNotAtAirport(): void
{
$this->settingsRepo->store('pilots.only_flights_from_current', true);
$this->settingsRepo->store('pireps.restrict_aircraft_to_rank', false);
$this->user = factory(App\Models\User::class)->create([
'curr_airport_id' => 'KJFK',
]);
$airport = factory(App\Models\Airport::class)->create();
$airline = factory(App\Models\Airline::class)->create();
$aircraft = factory(App\Models\Aircraft::class)->create();
/**
* INVALID AIRLINE_ID FIELD
*/
$uri = '/api/pireps/prefile';
$pirep = [
'airline_id' => $airline->id,
'aircraft_id' => $aircraft->id,
'dpt_airport_id' => $airport->icao,
'arr_airport_id' => $airport->icao,
'flight_number' => '6000',
'level' => 38000,
'planned_flight_time' => 120,
'route' => 'POINTA POINTB',
'source_name' => 'phpunit',
];
$response = $this->post($uri, $pirep);
$response->assertStatus(400);
$body = $response->json();
$this->assertEquals(\App\Exceptions\UserNotAtAirport::MESSAGE, $body['error']['message']);
}
/**
* Make sure an error is thrown if the pilot is not at the current airport
*/
public function testAircraftNotAtAirport(): void
{
$this->settingsRepo->store('pireps.only_aircraft_at_dpt_airport', true);
$this->settingsRepo->store('pireps.restrict_aircraft_to_rank', false);
$this->settingsRepo->store('pireps.restrict_aircraft_to_rank', false);
$this->user = factory(App\Models\User::class)->create([
'curr_airport_id' => 'KJFK',
]);
$airport = factory(App\Models\Airport::class)->create();
$airline = factory(App\Models\Airline::class)->create();
$aircraft = factory(App\Models\Aircraft::class)->create([
'airport_id' => 'KAUS'
]);
/**
* INVALID AIRLINE_ID FIELD
*/
$uri = '/api/pireps/prefile';
$pirep = [
'airline_id' => $airline->id,
'aircraft_id' => $aircraft->id,
'dpt_airport_id' => $airport->icao,
'arr_airport_id' => $airport->icao,
'flight_number' => '6000',
'level' => 38000,
'planned_flight_time' => 120,
'route' => 'POINTA POINTB',
'source_name' => 'phpunit',
];
$response = $this->post($uri, $pirep);
$response->assertStatus(400);
$body = $response->json();
$this->assertEquals(\App\Exceptions\AircraftNotAtAirport::MESSAGE, $body['error']['message']);
}
/** /**
* Post a PIREP into a PREFILE state and post ACARS * Post a PIREP into a PREFILE state and post ACARS
*/ */