* API level search of flights #484 * Add Subfleet to flights page for search
This commit is contained in:
parent
d03a77bd4b
commit
2415caab54
@ -93,6 +93,7 @@ class FlightController extends Controller
|
||||
return response($e, 503);
|
||||
}
|
||||
|
||||
// TODO: Remove any flights here that a user doesn't have permissions to
|
||||
foreach ($flights as $flight) {
|
||||
$this->flightSvc->filterSubfleets(Auth::user(), $flight);
|
||||
}
|
||||
|
@ -8,50 +8,68 @@ use App\Repositories\AirlineRepository;
|
||||
use App\Repositories\AirportRepository;
|
||||
use App\Repositories\Criteria\WhereCriteria;
|
||||
use App\Repositories\FlightRepository;
|
||||
use App\Repositories\SubfleetRepository;
|
||||
use App\Services\GeoService;
|
||||
use Flash;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Log;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Prettus\Repository\Criteria\RequestCriteria;
|
||||
use Prettus\Repository\Exceptions\RepositoryException;
|
||||
|
||||
/**
|
||||
* Class FlightController
|
||||
*/
|
||||
class FlightController extends Controller
|
||||
{
|
||||
private $airlineRepo;
|
||||
private $airportRepo;
|
||||
private $flightRepo;
|
||||
private $subfleetRepo;
|
||||
private $geoSvc;
|
||||
|
||||
/**
|
||||
* FlightController constructor.
|
||||
*
|
||||
* @param AirlineRepository $airlineRepo
|
||||
* @param AirportRepository $airportRepo
|
||||
* @param FlightRepository $flightRepo
|
||||
* @param GeoService $geoSvc
|
||||
* @param AirlineRepository $airlineRepo
|
||||
* @param AirportRepository $airportRepo
|
||||
* @param FlightRepository $flightRepo
|
||||
* @param GeoService $geoSvc
|
||||
* @param SubfleetRepository $subfleetRepo
|
||||
*/
|
||||
public function __construct(
|
||||
AirlineRepository $airlineRepo,
|
||||
AirportRepository $airportRepo,
|
||||
FlightRepository $flightRepo,
|
||||
GeoService $geoSvc
|
||||
GeoService $geoSvc,
|
||||
SubfleetRepository $subfleetRepo
|
||||
) {
|
||||
$this->airlineRepo = $airlineRepo;
|
||||
$this->airportRepo = $airportRepo;
|
||||
$this->flightRepo = $flightRepo;
|
||||
$this->geoSvc = $geoSvc;
|
||||
$this->subfleetRepo = $subfleetRepo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @throws \Prettus\Repository\Exceptions\RepositoryException
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
return $this->search($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a search request using the Repository search
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @throws \Prettus\Repository\Exceptions\RepositoryException
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function search(Request $request)
|
||||
{
|
||||
$where = [
|
||||
'active' => true,
|
||||
@ -67,14 +85,17 @@ class FlightController extends Controller
|
||||
$where['dpt_airport_id'] = Auth::user()->curr_airport_id;
|
||||
}
|
||||
|
||||
$this->flightRepo->resetCriteria();
|
||||
|
||||
try {
|
||||
$this->flightRepo->searchCriteria($request);
|
||||
$this->flightRepo->pushCriteria(new WhereCriteria($request, $where));
|
||||
$this->flightRepo->pushCriteria(new RequestCriteria($request));
|
||||
} catch (RepositoryException $e) {
|
||||
Log::emergency($e);
|
||||
}
|
||||
|
||||
$flights = $this->flightRepo
|
||||
$flights = $this->flightRepo->searchCriteria($request)
|
||||
->with(['dpt_airport', 'arr_airport', 'airline'])
|
||||
->orderBy('flight_number', 'asc')
|
||||
->orderBy('route_leg', 'asc')
|
||||
@ -84,10 +105,15 @@ class FlightController extends Controller
|
||||
->pluck('flight_id')->toArray();
|
||||
|
||||
return view('flights.index', [
|
||||
'airlines' => $this->airlineRepo->selectBoxList(true),
|
||||
'airports' => $this->airportRepo->selectBoxList(true),
|
||||
'flights' => $flights,
|
||||
'saved' => $saved_flights,
|
||||
'airlines' => $this->airlineRepo->selectBoxList(true),
|
||||
'airports' => $this->airportRepo->selectBoxList(true),
|
||||
'flights' => $flights,
|
||||
'saved' => $saved_flights,
|
||||
'subfleets' => $this->subfleetRepo->selectBoxList(true),
|
||||
'flight_number' => $request->input('flight_number'),
|
||||
'arr_icao' => $request->input('arr_icao'),
|
||||
'dep_icao' => $request->input('dep_icao'),
|
||||
'subfleet_id' => $request->input('subfleet_id'),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -114,62 +140,12 @@ class FlightController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a search request using the Repository search
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @throws \Prettus\Repository\Exceptions\RepositoryException
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function search(Request $request)
|
||||
{
|
||||
$where = [
|
||||
'active' => true,
|
||||
'visible' => true,
|
||||
];
|
||||
|
||||
if (setting('pilots.restrict_to_company')) {
|
||||
$where['airline_id'] = Auth::user()->airline_id;
|
||||
}
|
||||
|
||||
// default restrictions on the flights shown. Handle search differently
|
||||
if (setting('pilots.only_flights_from_current')) {
|
||||
$where['dpt_airport_id'] = Auth::user()->curr_airport_id;
|
||||
}
|
||||
|
||||
$this->flightRepo->resetCriteria();
|
||||
|
||||
try {
|
||||
$this->flightRepo->pushCriteria(new WhereCriteria($request, $where));
|
||||
} catch (RepositoryException $e) {
|
||||
Log::emergency($e);
|
||||
}
|
||||
|
||||
$flights = $this->flightRepo->searchCriteria($request)
|
||||
->with(['dpt_airport', 'arr_airport', 'airline'])
|
||||
->orderBy('flight_number', 'asc')
|
||||
->orderBy('route_leg', 'asc')
|
||||
->paginate();
|
||||
|
||||
$saved_flights = Bid::where('user_id', Auth::id())
|
||||
->pluck('flight_id')->toArray();
|
||||
|
||||
return view('flights.index', [
|
||||
'airlines' => $this->airlineRepo->selectBoxList(true),
|
||||
'airports' => $this->airportRepo->selectBoxList(true),
|
||||
'flights' => $flights,
|
||||
'saved' => $saved_flights,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the flight information page
|
||||
*
|
||||
* @param $id
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
|
||||
* @return mixed
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
|
@ -4,6 +4,7 @@ namespace App\Repositories\Criteria;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use Prettus\Repository\Contracts\CriteriaInterface;
|
||||
use Prettus\Repository\Contracts\RepositoryInterface;
|
||||
|
||||
@ -17,17 +18,20 @@ class WhereCriteria implements CriteriaInterface
|
||||
*/
|
||||
protected $request;
|
||||
protected $where;
|
||||
protected $relations;
|
||||
|
||||
/**
|
||||
* Create a new Where search.
|
||||
*
|
||||
* @param $request
|
||||
* @param $where
|
||||
* @param Request $request
|
||||
* @param array $where
|
||||
* @param array [$relations] Any whereHas (key = table name, value = array of criterea
|
||||
*/
|
||||
public function __construct($request, $where)
|
||||
public function __construct(Request $request, $where, $relations = [])
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->where = $where;
|
||||
$this->relations = $relations;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,6 +50,17 @@ class WhereCriteria implements CriteriaInterface
|
||||
$model = $model->where($this->where);
|
||||
}
|
||||
|
||||
// See if any relationships need to be included in this WHERE
|
||||
if ($this->relations) {
|
||||
foreach ($this->relations as $relation => $criterea) {
|
||||
$model = $model
|
||||
->with($relation)
|
||||
->whereHas($relation, function (Builder $query) use ($criterea) {
|
||||
$query->where($criterea);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
}
|
||||
|
@ -74,6 +74,7 @@ class FlightRepository extends Repository implements CacheableInterface
|
||||
public function searchCriteria(Request $request, bool $only_active = true): self
|
||||
{
|
||||
$where = [];
|
||||
$relations = [];
|
||||
|
||||
if ($only_active === true) {
|
||||
$where['active'] = $only_active;
|
||||
@ -81,48 +82,55 @@ class FlightRepository extends Repository implements CacheableInterface
|
||||
}
|
||||
|
||||
if ($request->filled('flight_id')) {
|
||||
$where['id'] = $request->flight_id;
|
||||
$where['id'] = $request->input('flight_id');
|
||||
}
|
||||
|
||||
if ($request->filled('airline_id')) {
|
||||
$where['airline_id'] = $request->airline_id;
|
||||
$where['airline_id'] = $request->input('airline_id');
|
||||
}
|
||||
|
||||
if ($request->filled('flight_number')) {
|
||||
$where['flight_number'] = $request->flight_number;
|
||||
$where['flight_number'] = $request->input('flight_number');
|
||||
}
|
||||
|
||||
if ($request->filled('route_code')) {
|
||||
$where['route_code'] = $request->route_code;
|
||||
$where['route_code'] = $request->input('route_code');
|
||||
}
|
||||
|
||||
if ($request->filled('dpt_airport_id')) {
|
||||
$where['dpt_airport_id'] = strtoupper($request->dpt_airport_id);
|
||||
$where['dpt_airport_id'] = strtoupper($request->input('dpt_airport_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('dep_icao')) {
|
||||
$where['dpt_airport_id'] = strtoupper($request->dep_icao);
|
||||
$where['dpt_airport_id'] = strtoupper($request->input('dep_icao'));
|
||||
}
|
||||
|
||||
if ($request->filled('arr_airport_id')) {
|
||||
$where['arr_airport_id'] = strtoupper($request->arr_airport_id);
|
||||
$where['arr_airport_id'] = strtoupper($request->input('arr_airport_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('arr_icao')) {
|
||||
$where['arr_airport_id'] = strtoupper($request->arr_icao);
|
||||
$where['arr_airport_id'] = strtoupper($request->input('arr_icao'));
|
||||
}
|
||||
|
||||
// Distance, greater than
|
||||
if ($request->filled('dgt')) {
|
||||
$where[] = ['distance', '>=', $request->dgt];
|
||||
$where[] = ['distance', '>=', $request->input('dgt')];
|
||||
}
|
||||
|
||||
// Distance, less than
|
||||
if ($request->filled('dlt')) {
|
||||
$where[] = ['distance', '<=', $request->dlt];
|
||||
$where[] = ['distance', '<=', $request->input('dlt')];
|
||||
}
|
||||
|
||||
$this->pushCriteria(new WhereCriteria($request, $where));
|
||||
// Do a special query for finding the child subfleets
|
||||
if ($request->filled('subfleet_id')) {
|
||||
$relations['subfleets'] = [
|
||||
'subfleets.id' => $request->input('subfleet_id'),
|
||||
];
|
||||
}
|
||||
|
||||
$this->pushCriteria(new WhereCriteria($request, $where, $relations));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -7,9 +7,6 @@ use App\Models\Subfleet;
|
||||
use Prettus\Repository\Contracts\CacheableInterface;
|
||||
use Prettus\Repository\Traits\CacheableRepository;
|
||||
|
||||
/**
|
||||
* Class SubfleetRepository
|
||||
*/
|
||||
class SubfleetRepository extends Repository implements CacheableInterface
|
||||
{
|
||||
use CacheableRepository;
|
||||
@ -26,4 +23,27 @@ class SubfleetRepository extends Repository implements CacheableInterface
|
||||
{
|
||||
return Subfleet::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of aircraft formatted for a select box
|
||||
*
|
||||
* @param bool $add_blank
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function selectBoxList($add_blank = false): array
|
||||
{
|
||||
$retval = [];
|
||||
$items = $this->all();
|
||||
|
||||
if ($add_blank) {
|
||||
$retval[''] = '';
|
||||
}
|
||||
|
||||
foreach ($items as $i) {
|
||||
$retval[$i->id] = $i->name;
|
||||
}
|
||||
|
||||
return $retval;
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ return [
|
||||
'arrival' => 'Arrival',
|
||||
'aircraft' => 'Aircraft',
|
||||
'airline' => 'Airline',
|
||||
'subfleet' => 'Subfleet',
|
||||
'distance' => 'Distance',
|
||||
'fuel' => 'Fuel',
|
||||
'metar' => 'METAR',
|
||||
|
@ -24,6 +24,7 @@ return [
|
||||
'arrival' => 'Llegada',
|
||||
'aircraft' => 'Aeronave',
|
||||
'airline' => 'Aerolínea',
|
||||
'subfleet' => 'Subfleet',
|
||||
'distance' => 'Distancía',
|
||||
'fuel' => 'Combustible',
|
||||
'metar' => 'METAR',
|
||||
|
@ -24,6 +24,7 @@ return [
|
||||
'arrival' => 'Arrivo',
|
||||
'aircraft' => 'Aereomobile',
|
||||
'airline' => 'Compagnia Aerea',
|
||||
'subfleet' => 'Subfleet',
|
||||
'distance' => 'Distanza',
|
||||
'fuel' => 'Carburante',
|
||||
'metar' => 'METAR',
|
||||
|
@ -22,6 +22,11 @@
|
||||
{{ Form::select('arr_icao', $airports, null , ['class' => 'form-control select2']) }}
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 10px; margin-left: 5px;">
|
||||
<p>@lang('common.subfleet')</p>
|
||||
{{ Form::select('subfleet_id', $subfleets, null , ['class' => 'form-control select2']) }}
|
||||
</div>
|
||||
|
||||
<div class="clear" style="margin-top: 10px; margin-left: 5px;">
|
||||
{{ Form::submit(__('common.find'), ['class' => 'btn btn-primary']) }}
|
||||
<a href="{{ route('frontend.flights.index') }}">@lang('common.reset')</a>
|
||||
|
@ -23,6 +23,11 @@ paths:
|
||||
type: string
|
||||
required: false
|
||||
description: ID of the airline
|
||||
- name: subfleet_id
|
||||
in: query
|
||||
type: string
|
||||
required: false
|
||||
description: 'The subfleet to search on. Flights would be returned, but if the subfleets are empty, that means the pilot doesn\'t have permissions for that flight'
|
||||
- name: flight_number
|
||||
in: query
|
||||
type: string
|
||||
@ -48,11 +53,11 @@ paths:
|
||||
type: integer
|
||||
required: false
|
||||
description: Flights with a distance greater than
|
||||
- name: dgt
|
||||
- name: dlt
|
||||
in: query
|
||||
type: integer
|
||||
required: false
|
||||
description: Flights with a distance greater than
|
||||
description: Flights with a distance less than
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
|
@ -1,6 +1,9 @@
|
||||
<?php
|
||||
|
||||
use App\Cron\Nightly\SetActiveFlights;
|
||||
use App\Events\CronNightly;
|
||||
use App\Models\Enums\Days;
|
||||
use App\Models\Enums\NavaidType;
|
||||
use App\Models\Flight;
|
||||
use App\Models\User;
|
||||
use App\Repositories\SettingRepository;
|
||||
@ -21,6 +24,13 @@ class FlightTest extends TestCase
|
||||
$this->settingsRepo = app(SettingRepository::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single flight
|
||||
*
|
||||
* @param $user
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function addFlight($user)
|
||||
{
|
||||
$flight = factory(App\Models\Flight::class)->create([
|
||||
@ -36,6 +46,25 @@ class FlightTest extends TestCase
|
||||
return $flight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a given number of flights for a subfleet
|
||||
*
|
||||
* @param $subfleet
|
||||
* @param $num_flights
|
||||
*
|
||||
* @return \App\Models\Flight[]
|
||||
*/
|
||||
public function addFlightsForSubfleet($subfleet, $num_flights)
|
||||
{
|
||||
return factory(App\Models\Flight::class, $num_flights)->create([
|
||||
'airline_id' => $subfleet->airline->id,
|
||||
])->each(function (Flight $f) use ($subfleet) {
|
||||
$f->subfleets()->syncWithoutDetaching([
|
||||
$subfleet->id,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test adding a flight and also if there are duplicates
|
||||
*/
|
||||
@ -148,10 +177,7 @@ class FlightTest extends TestCase
|
||||
$this->assertEquals($first_point['id'], $route[0]->id);
|
||||
$this->assertEquals($first_point['name'], $route[0]->name);
|
||||
$this->assertEquals($first_point['type']['type'], $route[0]->type);
|
||||
$this->assertEquals(
|
||||
$first_point['type']['name'],
|
||||
\App\Models\Enums\NavaidType::label($route[0]->type)
|
||||
);
|
||||
$this->assertEquals($first_point['type']['name'], NavaidType::label($route[0]->type));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,6 +199,38 @@ class FlightTest extends TestCase
|
||||
$res->assertJsonCount(5, 'data');
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for flights based on a subfleet. If subfleet is blank
|
||||
*/
|
||||
public function testSearchFlightBySubfleet()
|
||||
{
|
||||
$airline = factory(App\Models\Airline::class)->create();
|
||||
$subfleetA = factory(App\Models\Subfleet::class)->create(['airline_id' => $airline->id]);
|
||||
$subfleetB = factory(App\Models\Subfleet::class)->create(['airline_id' => $airline->id]);
|
||||
|
||||
$rank = $this->createRank(0, [$subfleetB->id]);
|
||||
$this->user = factory(App\Models\User::class)->create([
|
||||
'airline_id' => $airline->id,
|
||||
'rank_id' => $rank->id,
|
||||
]);
|
||||
|
||||
$this->addFlightsForSubfleet($subfleetA, 5);
|
||||
$this->addFlightsForSubfleet($subfleetB, 10);
|
||||
|
||||
// search specifically for a given subfleet
|
||||
//$query = 'subfleet_id='.$subfleetB->id;
|
||||
$query = 'subfleet_id='.$subfleetB->id;
|
||||
$res = $this->get('/api/flights/search?'.$query);
|
||||
$res->assertStatus(200);
|
||||
$res->assertJsonCount(10, 'data');
|
||||
|
||||
$body = $res->json('data');
|
||||
collect($body)->each(function ($flight) use ($subfleetB) {
|
||||
self::assertNotEmpty($flight['subfleets']);
|
||||
self::assertEquals($subfleetB->id, $flight['subfleets'][0]['id']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the bitmasks that they work for setting the day of week and
|
||||
* then retrieving by searching on those
|
||||
@ -227,8 +285,8 @@ class FlightTest extends TestCase
|
||||
]);
|
||||
|
||||
// Run the event that will enable/disable flights
|
||||
$event = new \App\Events\CronNightly();
|
||||
(new \App\Cron\Nightly\SetActiveFlights())->handle($event);
|
||||
$event = new CronNightly();
|
||||
(new SetActiveFlights())->handle($event);
|
||||
|
||||
$res = $this->get('/api/flights');
|
||||
$body = $res->json('data');
|
||||
@ -274,8 +332,8 @@ class FlightTest extends TestCase
|
||||
]);
|
||||
|
||||
// Run the event that will enable/disable flights
|
||||
$event = new \App\Events\CronNightly();
|
||||
(new \App\Cron\Nightly\SetActiveFlights())->handle($event);
|
||||
$event = new CronNightly();
|
||||
(new SetActiveFlights())->handle($event);
|
||||
|
||||
$res = $this->get('/api/flights');
|
||||
$body = $res->json('data');
|
||||
@ -313,8 +371,8 @@ class FlightTest extends TestCase
|
||||
]);
|
||||
|
||||
// Run the event that will enable/disable flights
|
||||
$event = new \App\Events\CronNightly();
|
||||
(new \App\Cron\Nightly\SetActiveFlights())->handle($event);
|
||||
$event = new CronNightly();
|
||||
(new SetActiveFlights())->handle($event);
|
||||
|
||||
$res = $this->get('/api/flights');
|
||||
$body = $res->json('data');
|
||||
|
Loading…
Reference in New Issue
Block a user