Refactoring of PIREP submission and field code #146

This commit is contained in:
Nabeel Shahzad 2018-01-23 15:48:30 -06:00
parent 341424ad7e
commit f9efa81bb4
19 changed files with 191 additions and 147 deletions

View File

@ -84,6 +84,7 @@ class CreatePirepTables extends Migration
Schema::create('pirep_fields', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name', 50);
$table->string('slug', 50)->nullable();
$table->boolean('required')->default(false);
});

View File

@ -405,7 +405,12 @@ pireps:
pirep_fields:
- id: 1
name: departure gate
slug: departure_gate
required: 1
- id: 2
name: arrival gate
slug: arrival_gate
required: 0
pirep_field_values:

View File

@ -22,9 +22,9 @@ class PirepFieldController extends BaseController
/**
* Display a listing of the PirepField.
*
* @param Request $request
* @return Response
* @throws \Prettus\Repository\Exceptions\RepositoryException
*/
public function index(Request $request)
{
@ -38,7 +38,6 @@ class PirepFieldController extends BaseController
/**
* Show the form for creating a new PirepField.
*
* @return Response
*/
public function create()
@ -48,9 +47,7 @@ class PirepFieldController extends BaseController
/**
* Store a newly created PirepField in storage.
*
* @param CreatePirepFieldRequest $request
*
* @return Response
* @throws \Prettus\Validator\Exceptions\ValidatorException
*/
@ -67,9 +64,7 @@ class PirepFieldController extends BaseController
/**
* Display the specified PirepField.
*
* @param int $id
*
* @return Response
*/
public function show($id)
@ -88,9 +83,7 @@ class PirepFieldController extends BaseController
/**
* Show the form for editing the specified PirepField.
*
* @param int $id
*
* @return Response
*/
public function edit($id)
@ -130,9 +123,7 @@ class PirepFieldController extends BaseController
/**
* Remove the specified PirepField from storage.
*
* @param int $id
*
* @return Response
*/
public function destroy($id)

View File

@ -2,7 +2,6 @@
namespace App\Http\Controllers\Api;
use App\Rules\Minutes;
use Log;
use Auth;
use Illuminate\Database\Eloquent\ModelNotFoundException;
@ -78,8 +77,8 @@ class PirepController extends RestController
'flight_number' => 'required',
'route_code' => 'nullable',
'route_leg' => 'nullable',
'flight_time' => ['nullable', new Minutes],
'planned_flight_time' => ['nullable', new Minutes],
'flight_time' => ['nullable', 'integer'],
'planned_flight_time' => ['nullable', 'integer'],
'level' => 'required|integer',
'route' => 'nullable',
'notes' => 'nullable',
@ -133,7 +132,7 @@ class PirepController extends RestController
$file_rules = [
# actual flight time is required
'flight_time' => ['required', new Minutes],
'flight_time' => ['required', 'integer'],
'flight_number' => 'nullable',
'dpt_airport_id' => 'nullable',
'arr_airport_id' => 'nullable',
@ -142,7 +141,7 @@ class PirepController extends RestController
'flight_id' => 'nullable',
'route_code' => 'nullable',
'route_leg' => 'nullable',
'planned_flight_time' => ['nullable', new Minutes],
'planned_flight_time' => ['nullable', 'integer'],
'level' => 'nullable',
'route' => 'nullable',
'notes' => 'nullable',

View File

@ -2,7 +2,9 @@
namespace App\Http\Controllers\Frontend;
use Log;
use App\Facades\Utils;
use App\Http\Requests\CreatePirepRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
@ -61,11 +63,15 @@ class PirepController extends Controller
* @param null $user
* @return array
*/
public function aircraftList($user=null)
public function aircraftList($user=null, $add_blank=false)
{
$aircraft = [];
$subfleets = $this->userSvc->getAllowableSubfleets($user);
if($add_blank) {
$aircraft[''] = '';
}
foreach ($subfleets as $subfleet) {
$tmp = [];
foreach ($subfleet->aircraft as $ac) {
@ -107,49 +113,56 @@ class PirepController extends Controller
$user = Auth::user();
return $this->view('pireps.create', [
'aircraft' => $this->aircraftList($user),
'airports' => $this->airportRepo->selectBoxList(),
'airlines' => $this->airlineRepo->selectBoxList(),
'pirepfields' => $this->pirepFieldRepo->all(),
'fieldvalues' => [],
'airlines' => $this->airlineRepo->selectBoxList(true),
'aircraft' => $this->aircraftList($user, true),
'airports' => $this->airportRepo->selectBoxList(true),
'pirep_fields' => $this->pirepFieldRepo->all(),
'field_values' => [],
]);
}
public function store(Request $request)
/**
*
* @param CreatePirepRequest $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function store(CreatePirepRequest $request)
{
$pirep_fields = $request->all();
// Create the main PIREP
$pirep = new Pirep($pirep_fields);
$pirep = new Pirep($request->all());
$pirep->user_id = Auth::user()->id;
# Make sure this isn't a duplicate
$dupe_pirep = $this->pirepSvc->findDuplicate($pirep);
if ($dupe_pirep !== false) {
flash()->error('This PIREP has already been filed.');
return redirect(route('frontend.pireps.create'))->withInput();
}
// Any special fields
$pirep->pilot()->associate(Auth::user());
$pirep->flight_time = ((int) Utils::hoursToMinutes($request['hours']))
+ ((int) $request['minutes']);
// The custom fields from the form
$custom_fields = [];
foreach($pirep_fields as $field_name => $field_val)
{
if (strpos($field_name, 'field_') === false) {
$pirep_fields = $this->pirepFieldRepo->all();
foreach ($pirep_fields as $field) {
if(!$request->filled($field->slug)) {
continue;
}
$field_id = explode('field_', $field_name)[1];
$cfield = PirepField::find($field_id);
$custom_fields[] = [
'name' => $cfield->name,
'value' => $field_val,
'name' => $field->name,
'value' => $request->input($field->slug),
'source' => PirepSource::MANUAL
];
}
Log::info('PIREP Custom Fields', $custom_fields);
$pirep = $this->pirepSvc->create($pirep, $custom_fields);
$this->pirepSvc->saveRoute($pirep);
//Flash::success('PIREP submitted successfully!');
return redirect(route('frontend.pireps.index'));
return redirect(route('frontend.pireps.show', ['id' => $pirep->id]));
}
public function show($id)

View File

@ -2,13 +2,14 @@
namespace App\Http\Requests;
use App\Models\Pirep;
use Log;
use Illuminate\Foundation\Http\FormRequest;
use App\Models\Pirep;
use App\Repositories\PirepFieldRepository;
class CreatePirepRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
@ -26,6 +27,21 @@ class CreatePirepRequest extends FormRequest
*/
public function rules()
{
return Pirep::$rules;
$field_rules = Pirep::$rules;
$field_rules['hours'] = 'nullable|integer';
$field_rules['minutes'] = 'required|integer';
# Add the validation rules for the custom fields
$pirepFieldRepo = app(PirepFieldRepository::class);
$custom_fields = $pirepFieldRepo->all();
foreach ($custom_fields as $field) {
$field_rules[$field->slug] = $field->required ? 'required' : 'nullable';
}
Log::debug('createPirepFormRequest::rules', $field_rules);
return $field_rules;
}
}

View File

@ -57,11 +57,13 @@ class Pirep extends BaseModel
];
public static $rules = [
'flight_number' => 'required',
'dpt_airport_id' => 'required',
'arr_airport_id' => 'required',
'notes' => 'nullable',
'route' => 'nullable',
'airline_id' => 'required|exists:airlines,id',
'aircraft_id' => 'required|exists:aircraft,id',
'flight_number' => 'required',
'dpt_airport_id' => 'required',
'arr_airport_id' => 'required',
'notes' => 'nullable',
'route' => 'nullable',
];
/**
@ -71,12 +73,14 @@ class Pirep extends BaseModel
public function getIdentAttribute()
{
$flight_id = $this->airline->code;
if(!empty($this->flight_number)) {
$flight_id .= $this->flight_number;
} else {
if ($this->flight_id) {
$flight_id .= $this->flight->flight_number;
}
$flight_id .= $this->flight_number;
if(filled($this->route_code)) {
$flight_id .= '/C'.$this->route_code;
}
if(filled($this->route_leg)) {
$flight_id .= '/L'.$this->route_leg;
}
return $flight_id;

View File

@ -14,6 +14,7 @@ class PirepField extends BaseModel
public $fillable = [
'name',
'slug',
'required',
];
@ -24,4 +25,30 @@ class PirepField extends BaseModel
public static $rules = [
'name' => 'required',
];
/**
* Create/update the field slug
*/
protected static function boot()
{
parent::boot();
/**
* On creation
*/
static::creating(function (PirepField $model) {
if (!empty($model->slug)) {
$model->slug = str_slug($model->name);
}
});
/**
* When updating
*/
static::updating(function(PirepField $model) {
if (!empty($model->slug)) {
$model->slug = str_slug($model->name);
}
});
}
}

View File

@ -31,7 +31,7 @@ class AirlineRepository extends BaseRepository implements CacheableInterface
$items = $this->all();
if($add_blank) {
$retval[] = '';
$retval[''] = '';
}
foreach ($items as $i) {

View File

@ -1,25 +0,0 @@
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
/**
* Class Minutes
* @package App\Rules
*
* Make sure that a given value is an integer, but the custom
* validation message is what really matters here
*/
class Minutes implements Rule
{
public function passes($attribute, $value): bool
{
return \is_int(filter_var($value, FILTER_VALIDATE_INT));
}
public function message(): string
{
return ':attribute must be an integer, in minutes';
}
}

View File

@ -73,11 +73,11 @@ class PIREPService extends BaseService
'flight_number' => $pirep->flight_number,
];
if(!empty($pirep->route_code)) {
if(filled($pirep->route_code)) {
$where['route_code'] = $pirep->route_code;
}
if(!empty($pirep->route_leg)) {
if(filled($pirep->route_leg)) {
$where['route_leg'] = $pirep->route_leg;
}

View File

@ -2,16 +2,9 @@
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
/**
* Validation Language Lines
*/
'accepted' => 'The :attribute must be accepted.',
'active_url' => 'The :attribute is not a valid URL.',
@ -39,7 +32,7 @@ return [
'email' => 'The :attribute must be a valid email address.',
'exists' => 'The selected :attribute is invalid.',
'file' => 'The :attribute must be a file.',
'filled' => 'The :attribute field is required.',
'filled' => 'The ":attribute" is required.',
'image' => 'The :attribute must be an image.',
'in' => 'The selected :attribute is invalid.',
'in_array' => 'The :attribute field does not exist in :other.',
@ -63,7 +56,7 @@ return [
'numeric' => 'The :attribute must be a number.',
'present' => 'The :attribute field must be present.',
'regex' => 'The :attribute format is invalid.',
'required' => 'The :attribute field is required.',
'required' => 'The ":attribute" field is required.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
@ -82,33 +75,38 @@ return [
'unique' => 'The :attribute has already been taken.',
'url' => 'The :attribute format is invalid.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
/**
* Custom Validation Language Lines
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
'airline_id' => [
'required' => 'An airline is required',
'exists' => 'The airline doesn\'t exist',
],
'aircraft_id' => [
'required' => 'An aircraft is required',
'exists' => 'The aircraft doesn\'t exist',
],
'arr_airport_id' => [
'required' => 'An arrival airport is required',
],
'dpt_airport_id' => [
'required' => 'A departure airport is required',
],
'flight_time' => [
'required' => 'Flight time, in minutes, is required',
'integer' => 'Flight time, in minutes, is required',
],
'planned_flight_time' => [
'required' => 'Flight time, in minutes, is required',
'integer' => 'Flight time, in minutes, is required',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap attribute place-holders
| with something more reader friendly such as E-Mail Address instead
| of "email". This simply helps us make messages a little cleaner.
|
*/
/**
* Custom Validation Attributes
*/
'attributes' => [],

View File

@ -1,4 +1,12 @@
<div class="content table-responsive table-full-width">
<div class="header">
<p class="category">
<i class="icon fa fa-info">&nbsp;&nbsp;</i>
PIREP fields are only shown for manual PIREPs.
</p>
</div>
<table class="table table-hover table-responsive" id="pirepFields-table">
<thead>
<th>Name</th>

View File

@ -13,7 +13,7 @@
<td>
<a class="inline" href="#" data-pk="{!! $field->id !!}" data-name="{!! $field->name !!}">{!! $field->value !!}</a>
</td>
<td>{!! $field->source !!}</td>
<td>{!! PirepSource::label($field->source) !!}</td>
<td style="width: 10%; text-align: right;" class="form-inline">
{!! Form::open(['url' => '/admin/pireps/'.$pirep->id.'/fields',
'method' => 'delete',

View File

@ -5,7 +5,7 @@
<div class="col-sm-2 text-center">
<h5>
<a class="text-c"
href="{!! route('admin.pireps.show', [$pirep->id]) !!}">
href="{!! route('admin.pireps.edit', [$pirep->id]) !!}">
{!! $pirep->ident !!}
</a>
</h5>

View File

@ -12,6 +12,7 @@
<div class="input-group form-group">
{!! Form::select('airline_id', $airlines, null, ['class' => 'custom-select select2']) !!}
</div>
<p class="text-danger">{{ $errors->first('airline_id') }}</p>
</td>
</tr>
@ -23,6 +24,9 @@
{!! Form::text('route_code', null, ['placeholder' => 'Code (optional)', 'class' => 'form-control']) !!}
{!! Form::text('route_leg', null, ['placeholder' => 'Leg (optional)', 'class' => 'form-control']) !!}
</div>
<p class="text-danger">{{ $errors->first('flight_number') }}</p>
<p class="text-danger">{{ $errors->first('route_code') }}</p>
<p class="text-danger">{{ $errors->first('route_leg') }}</p>
</td>
</tr>
@ -32,6 +36,7 @@
<div class="input-group form-group">
{!! Form::select('aircraft_id', $aircraft, null, ['class' => 'custom-select select2']) !!}
</div>
<p class="text-danger">{{ $errors->first('aircraft_id') }}</p>
</td>
</tr>
@ -41,6 +46,7 @@
<div class="input-group form-group">
{!! Form::select('dpt_airport_id', $airports, null, ['class' => 'custom-select select2']) !!}
</div>
<p class="text-danger">{{ $errors->first('dpt_airport_id') }}</p>
</td>
</tr>
@ -50,6 +56,7 @@
<div class="input-group form-group">
{!! Form::select('arr_airport_id', $airports, null, ['class' => 'custom-select select2']) !!}
</div>
<p class="text-danger">{{ $errors->first('arr_airport_id') }}</p>
</td>
</tr>
@ -60,46 +67,50 @@
{!! Form::number('hours', null, ['class' => 'form-control', 'placeholder' => 'hours']) !!}
{!! Form::number('minutes', null, ['class' => 'form-control', 'placeholder' => 'minutes']) !!}
</div>
<p class="text-danger">{{ $errors->first('hours') }}</p>
<p class="text-danger">{{ $errors->first('minutes') }}</p>
</td>
</tr>
{{--
Write out the custom fields, and label if they're required
--}}
@foreach($pirep_fields as $field)
<tr>
<td>
{!! $field->name !!}
@if($field->required === true)
<span class="text-danger">*</span>
@endif
</td>
<td>
<div class="input-group form-group">
{!! Form::text($field->slug, null, [
'class' => 'form-control'
]) !!}
</div>
<p class="text-danger">{{ $errors->first($field->slug) }}</p>
</td>
</tr>
@endforeach
<tr>
<td class="align-text-top">Route</td>
<td>
<div class="input-group form-group">
{!! Form::textarea('route', null, ['class' => 'form-control', 'placeholder' => 'Route']) !!}
</div>
<p class="text-danger">{{ $errors->first('route') }}</p>
</td>
</tr>
{{--
Write out the custom fields, and label if they're required
--}}
@foreach($pirepfields as $field)
<tr>
<td>
{!! $field->name !!}
<span class="label label-danger">required</span>
</td>
<td>
<div class="input-group form-group">
<!--<span class="input-group-addon">
<i class="now-ui-icons users_single-02"></i>
</span>-->
{!! Form::text('field_'.$field->id, null, [
'class' => 'form-control'
]) !!}
</div>
</td>
</tr>
@endforeach
<tr>
<td class="align-text-top"><p class="">Notes</p></td>
<td>
<div class="input-group form-group">
{!! Form::textarea('notes', null, ['class' => 'form-control', 'placeholder' => 'Notes']) !!}
</div>
<p class="text-danger">{{ $errors->first('notes') }}</p>
</td>
</tr>
</tbody>

View File

@ -4,12 +4,7 @@
<div class="col-sm-2 text-center">
<h5>
<a class="text-c" href="{!! route('frontend.pireps.show', [$pirep->id]) !!}">
{!! $pirep->airline->code !!}
@if($pirep->flight_id)
{!! $pirep->flight->flight_number !!}
@else
{!! $pirep->flight_number !!}
@endif
{!! $pirep->ident !!}
</a>
</h5>
<div>

View File

@ -77,16 +77,14 @@
<h3 class="description">fields</h3>
<table class="table">
<thead>
<th>Name</th>
<th>Value</th>
<th>Source</th>
<th>Name</th>
<th>Value</th>
</thead>
<tbody>
@foreach($pirep->fields as $field)
<tr>
<td>{!! $field->name !!}</td>
<td>{!! $field->value !!}</td>
<td>{!! $field->source !!}</td>
</tr>
@endforeach
</tbody>

View File

@ -55,7 +55,7 @@ class AcarsTest extends TestCase
}
/**
* Post a PIREP into a PREFILE state and post ACARS
* Test some prefile error conditions
*/
public function testPrefileErrors()
{
@ -65,6 +65,9 @@ class AcarsTest extends TestCase
$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,