Add api routes to get/add/remove bids for a user #172
This commit is contained in:
parent
e176772512
commit
6dfab75f08
20
app/Exceptions/BidExists.php
Normal file
20
app/Exceptions/BidExists.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
|
|
||||||
|
class BidExists extends HttpException
|
||||||
|
{
|
||||||
|
public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = [])
|
||||||
|
{
|
||||||
|
parent::__construct(
|
||||||
|
409,
|
||||||
|
'A bid already exists for this flight',
|
||||||
|
$previous, $headers, $code
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -9,9 +9,11 @@ use App\Http\Resources\User as UserResource;
|
|||||||
use App\Models\Enums\PirepState;
|
use App\Models\Enums\PirepState;
|
||||||
use App\Models\UserBid;
|
use App\Models\UserBid;
|
||||||
use App\Repositories\Criteria\WhereCriteria;
|
use App\Repositories\Criteria\WhereCriteria;
|
||||||
|
use App\Repositories\FlightRepository;
|
||||||
use App\Repositories\PirepRepository;
|
use App\Repositories\PirepRepository;
|
||||||
use App\Repositories\SubfleetRepository;
|
use App\Repositories\SubfleetRepository;
|
||||||
use App\Repositories\UserRepository;
|
use App\Repositories\UserRepository;
|
||||||
|
use App\Services\FlightService;
|
||||||
use App\Services\UserService;
|
use App\Services\UserService;
|
||||||
use Auth;
|
use Auth;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -21,24 +23,32 @@ use Prettus\Repository\Exceptions\RepositoryException;
|
|||||||
|
|
||||||
class UserController extends RestController
|
class UserController extends RestController
|
||||||
{
|
{
|
||||||
protected $pirepRepo,
|
protected $flightRepo,
|
||||||
|
$flightSvc,
|
||||||
|
$pirepRepo,
|
||||||
$subfleetRepo,
|
$subfleetRepo,
|
||||||
$userRepo,
|
$userRepo,
|
||||||
$userSvc;
|
$userSvc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UserController constructor.
|
* UserController constructor.
|
||||||
|
* @param FlightRepository $flightRepo
|
||||||
|
* @param FlightService $flightSvc
|
||||||
* @param PirepRepository $pirepRepo
|
* @param PirepRepository $pirepRepo
|
||||||
* @param SubfleetRepository $subfleetRepo
|
* @param SubfleetRepository $subfleetRepo
|
||||||
* @param UserRepository $userRepo
|
* @param UserRepository $userRepo
|
||||||
* @param UserService $userSvc
|
* @param UserService $userSvc
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
FlightRepository $flightRepo,
|
||||||
|
FlightService $flightSvc,
|
||||||
PirepRepository $pirepRepo,
|
PirepRepository $pirepRepo,
|
||||||
SubfleetRepository $subfleetRepo,
|
SubfleetRepository $subfleetRepo,
|
||||||
UserRepository $userRepo,
|
UserRepository $userRepo,
|
||||||
UserService $userSvc
|
UserService $userSvc
|
||||||
) {
|
) {
|
||||||
|
$this->flightRepo = $flightRepo;
|
||||||
|
$this->flightSvc = $flightSvc;
|
||||||
$this->pirepRepo = $pirepRepo;
|
$this->pirepRepo = $pirepRepo;
|
||||||
$this->subfleetRepo = $subfleetRepo;
|
$this->subfleetRepo = $subfleetRepo;
|
||||||
$this->userRepo = $userRepo;
|
$this->userRepo = $userRepo;
|
||||||
@ -80,13 +90,31 @@ class UserController extends RestController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all of the bids for the passed-in user
|
* Return all of the bids for the passed-in user
|
||||||
* @param $id
|
* @param Request $request
|
||||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
* @return mixed
|
||||||
|
* @throws \App\Exceptions\BidExists
|
||||||
|
* @throws \App\Services\Exception
|
||||||
*/
|
*/
|
||||||
public function bids($id)
|
public function bids(Request $request)
|
||||||
{
|
{
|
||||||
$flights = UserBid::where(['user_id' => $id])->get()
|
$user = $this->userRepo->find($this->getUserId($request));
|
||||||
->pluck('flight');
|
|
||||||
|
# Add a bid
|
||||||
|
if ($request->isMethod('PUT')) {
|
||||||
|
$flight_id = $request->input('flight_id');
|
||||||
|
$flight = $this->flightRepo->find($flight_id);
|
||||||
|
$this->flightSvc->addBid($flight, $user);
|
||||||
|
}
|
||||||
|
|
||||||
|
elseif ($request->isMethod('DELETE')) {
|
||||||
|
$flight_id = $request->input('flight_id');
|
||||||
|
$flight = $this->flightRepo->find($flight_id);
|
||||||
|
$this->flightSvc->removeBid($flight, $user);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Return the flights they currently have bids on
|
||||||
|
$flights = UserBid::where(['user_id' => $user->id])
|
||||||
|
->get()->pluck('flight');
|
||||||
|
|
||||||
return FlightResource::collection($flights);
|
return FlightResource::collection($flights);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ use App\Repositories\AirlineRepository;
|
|||||||
use App\Repositories\AirportRepository;
|
use App\Repositories\AirportRepository;
|
||||||
use App\Repositories\Criteria\WhereCriteria;
|
use App\Repositories\Criteria\WhereCriteria;
|
||||||
use App\Repositories\FlightRepository;
|
use App\Repositories\FlightRepository;
|
||||||
|
use App\Services\FlightService;
|
||||||
use App\Services\GeoService;
|
use App\Services\GeoService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
@ -26,17 +27,20 @@ class FlightController extends Controller
|
|||||||
* @param AirlineRepository $airlineRepo
|
* @param AirlineRepository $airlineRepo
|
||||||
* @param AirportRepository $airportRepo
|
* @param AirportRepository $airportRepo
|
||||||
* @param FlightRepository $flightRepo
|
* @param FlightRepository $flightRepo
|
||||||
|
* @param FlightService $flightSvc
|
||||||
* @param GeoService $geoSvc
|
* @param GeoService $geoSvc
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
AirlineRepository $airlineRepo,
|
AirlineRepository $airlineRepo,
|
||||||
AirportRepository $airportRepo,
|
AirportRepository $airportRepo,
|
||||||
FlightRepository $flightRepo,
|
FlightRepository $flightRepo,
|
||||||
|
FlightService $flightSvc,
|
||||||
GeoService $geoSvc
|
GeoService $geoSvc
|
||||||
) {
|
) {
|
||||||
$this->airlineRepo = $airlineRepo;
|
$this->airlineRepo = $airlineRepo;
|
||||||
$this->airportRepo = $airportRepo;
|
$this->airportRepo = $airportRepo;
|
||||||
$this->flightRepo = $flightRepo;
|
$this->flightRepo = $flightRepo;
|
||||||
|
$this->flightSvc = $flightSvc;
|
||||||
$this->geoSvc = $geoSvc;
|
$this->geoSvc = $geoSvc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,9 +65,15 @@ Route::group(['middleware' => ['api.auth']], function ()
|
|||||||
Route::get('user/fleet', 'UserController@fleet');
|
Route::get('user/fleet', 'UserController@fleet');
|
||||||
Route::get('user/pireps', 'UserController@pireps');
|
Route::get('user/pireps', 'UserController@pireps');
|
||||||
|
|
||||||
|
Route::get('user/bids', 'UserController@bids');
|
||||||
|
Route::put('user/bids', 'UserController@bids');
|
||||||
|
Route::delete('user/bids', 'UserController@bids');
|
||||||
|
|
||||||
Route::get('users/{id}', 'UserController@get');
|
Route::get('users/{id}', 'UserController@get');
|
||||||
Route::get('users/{id}/bids', 'UserController@bids');
|
|
||||||
Route::get('users/{id}/fleet', 'UserController@fleet');
|
Route::get('users/{id}/fleet', 'UserController@fleet');
|
||||||
Route::get('users/{id}/pireps', 'UserController@pireps');
|
Route::get('users/{id}/pireps', 'UserController@pireps');
|
||||||
|
|
||||||
|
Route::get('users/{id}/bids', 'UserController@bids');
|
||||||
|
Route::put('users/{id}/bids', 'UserController@bids');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Exceptions\BidExists;
|
||||||
use App\Models\Flight;
|
use App\Models\Flight;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\UserBid;
|
use App\Models\UserBid;
|
||||||
@ -129,13 +130,14 @@ class FlightService extends BaseService
|
|||||||
* @param Flight $flight
|
* @param Flight $flight
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @return UserBid|null
|
* @return UserBid|null
|
||||||
|
* @throws \App\Exceptions\BidExists
|
||||||
*/
|
*/
|
||||||
public function addBid(Flight $flight, User $user)
|
public function addBid(Flight $flight, User $user)
|
||||||
{
|
{
|
||||||
# If it's already been bid on, then it can't be bid on again
|
# If it's already been bid on, then it can't be bid on again
|
||||||
if($flight->has_bid && setting('bids.disable_flight_on_bid')) {
|
if($flight->has_bid && setting('bids.disable_flight_on_bid')) {
|
||||||
Log::info($flight->id . ' already has a bid, skipping');
|
Log::info($flight->id . ' already has a bid, skipping');
|
||||||
return null;
|
throw new BidExists();
|
||||||
}
|
}
|
||||||
|
|
||||||
# See if we're allowed to have multiple bids or not
|
# See if we're allowed to have multiple bids or not
|
||||||
@ -170,7 +172,6 @@ class FlightService extends BaseService
|
|||||||
* Remove a bid from a given flight
|
* Remove a bid from a given flight
|
||||||
* @param Flight $flight
|
* @param Flight $flight
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
public function removeBid(Flight $flight, User $user)
|
public function removeBid(Flight $flight, User $user)
|
||||||
{
|
{
|
||||||
|
@ -1,348 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* @type {{render_airspace_map, render_live_map, render_route_map}}
|
|
||||||
*/
|
|
||||||
|
|
||||||
const phpvms = (function() {
|
|
||||||
|
|
||||||
const PLAN_ROUTE_COLOR = '#36b123';
|
|
||||||
const ACTUAL_ROUTE_COLOR = '#172aea';
|
|
||||||
|
|
||||||
const draw_base_map = (opts) => {
|
|
||||||
|
|
||||||
opts = _.defaults(opts, {
|
|
||||||
render_elem: 'map',
|
|
||||||
center: [29.98139, -95.33374],
|
|
||||||
zoom: 5,
|
|
||||||
maxZoom: 10,
|
|
||||||
layers: [],
|
|
||||||
set_marker: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
let feature_groups = [];
|
|
||||||
/*var openaip_airspace_labels = new L.TileLayer.WMS(
|
|
||||||
"http://{s}.tile.maps.openaip.net/geowebcache/service/wms", {
|
|
||||||
maxZoom: 14,
|
|
||||||
minZoom: 12,
|
|
||||||
layers: 'openaip_approved_airspaces_labels',
|
|
||||||
tileSize: 1024,
|
|
||||||
detectRetina: true,
|
|
||||||
subdomains: '12',
|
|
||||||
format: 'image/png',
|
|
||||||
transparent: true
|
|
||||||
});
|
|
||||||
|
|
||||||
openaip_airspace_labels.addTo(map);*/
|
|
||||||
|
|
||||||
const opencyclemap_phys_osm = new L.TileLayer(
|
|
||||||
'http://{s}.tile.thunderforest.com/landscape/{z}/{x}/{y}.png?apikey=f09a38fa87514de4890fc96e7fe8ecb1', {
|
|
||||||
maxZoom: 14,
|
|
||||||
minZoom: 4,
|
|
||||||
format: 'image/png',
|
|
||||||
transparent: true
|
|
||||||
});
|
|
||||||
|
|
||||||
feature_groups.push(opencyclemap_phys_osm);
|
|
||||||
|
|
||||||
/*const openaip_cached_basemap = new L.TileLayer("http://{s}.tile.maps.openaip.net/geowebcache/service/tms/1.0.0/openaip_basemap@EPSG%3A900913@png/{z}/{x}/{y}.png", {
|
|
||||||
maxZoom: 14,
|
|
||||||
minZoom: 4,
|
|
||||||
tms: true,
|
|
||||||
detectRetina: true,
|
|
||||||
subdomains: '12',
|
|
||||||
format: 'image/png',
|
|
||||||
transparent: true
|
|
||||||
});
|
|
||||||
|
|
||||||
feature_groups.push(openaip_cached_basemap);
|
|
||||||
*/
|
|
||||||
|
|
||||||
const openaip_basemap_phys_osm = L.featureGroup(feature_groups);
|
|
||||||
|
|
||||||
let map = L.map('map', {
|
|
||||||
layers: [openaip_basemap_phys_osm],
|
|
||||||
center: opts.center,
|
|
||||||
zoom: opts.zoom,
|
|
||||||
scrollWheelZoom: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const attrib = L.control.attribution({position: 'bottomleft'});
|
|
||||||
attrib.addAttribution("<a href=\"https://www.thunderforest.com\" target=\"_blank\" style=\"\">Thunderforest</a>");
|
|
||||||
attrib.addAttribution("<a href=\"https://www.openaip.net\" target=\"_blank\" style=\"\">openAIP</a>");
|
|
||||||
attrib.addAttribution("<a href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\" style=\"\">OpenStreetMap</a> contributors");
|
|
||||||
attrib.addAttribution("<a href=\"https://www.openweathermap.org\" target=\"_blank\" style=\"\">OpenWeatherMap</a>");
|
|
||||||
|
|
||||||
attrib.addTo(map);
|
|
||||||
|
|
||||||
return map;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show some popup text when a feature is clicked on
|
|
||||||
* @param feature
|
|
||||||
* @param layer
|
|
||||||
*/
|
|
||||||
const onFeaturePointClick = (feature, layer) => {
|
|
||||||
let popup_html = "";
|
|
||||||
if (feature.properties && feature.properties.popup) {
|
|
||||||
popup_html += feature.properties.popup;
|
|
||||||
}
|
|
||||||
|
|
||||||
layer.bindPopup(popup_html);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show each point as a marker
|
|
||||||
* @param feature
|
|
||||||
* @param latlng
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
const pointToLayer = (feature, latlng) => {
|
|
||||||
return L.circleMarker(latlng, {
|
|
||||||
radius: 12,
|
|
||||||
fillColor: "#ff7800",
|
|
||||||
color: "#000",
|
|
||||||
weight: 1,
|
|
||||||
opacity: 1,
|
|
||||||
fillOpacity: 0.8
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param opts
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
const _render_route_map = (opts) => {
|
|
||||||
|
|
||||||
opts = _.defaults(opts, {
|
|
||||||
route_points: null,
|
|
||||||
planned_route_line: null,
|
|
||||||
actual_route_points: null,
|
|
||||||
actual_route_line: null,
|
|
||||||
render_elem: 'map',
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(opts);
|
|
||||||
|
|
||||||
let map = draw_base_map(opts);
|
|
||||||
|
|
||||||
let geodesicLayer = L.geodesic([], {
|
|
||||||
weight: 7,
|
|
||||||
opacity: 0.9,
|
|
||||||
color: PLAN_ROUTE_COLOR,
|
|
||||||
steps: 50,
|
|
||||||
wrap: false,
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
geodesicLayer.geoJson(opts.planned_route_line);
|
|
||||||
|
|
||||||
try {
|
|
||||||
map.fitBounds(geodesicLayer.getBounds());
|
|
||||||
} catch (e) { console.log(e); }
|
|
||||||
|
|
||||||
// Draw the route points after
|
|
||||||
if (opts.route_points !== null) {
|
|
||||||
let route_points = L.geoJSON(opts.route_points, {
|
|
||||||
onEachFeature: onFeaturePointClick,
|
|
||||||
pointToLayer: pointToLayer,
|
|
||||||
style: {
|
|
||||||
"color": PLAN_ROUTE_COLOR,
|
|
||||||
"weight": 5,
|
|
||||||
"opacity": 0.65,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
route_points.addTo(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* draw the actual route
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (opts.actual_route_line !== null && opts.actual_route_line.features.length > 0) {
|
|
||||||
let geodesicLayer = L.geodesic([], {
|
|
||||||
weight: 7,
|
|
||||||
opacity: 0.9,
|
|
||||||
color: ACTUAL_ROUTE_COLOR,
|
|
||||||
steps: 50,
|
|
||||||
wrap: false,
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
geodesicLayer.geoJson(opts.actual_route_line);
|
|
||||||
|
|
||||||
try {
|
|
||||||
map.fitBounds(geodesicLayer.getBounds());
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.actual_route_points !== null && opts.actual_route_points.features.length > 0) {
|
|
||||||
let route_points = L.geoJSON(opts.actual_route_points, {
|
|
||||||
onEachFeature: onFeaturePointClick,
|
|
||||||
pointToLayer: pointToLayer,
|
|
||||||
style: {
|
|
||||||
"color": ACTUAL_ROUTE_COLOR,
|
|
||||||
"weight": 5,
|
|
||||||
"opacity": 0.65,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
route_points.addTo(map);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render a map with the airspace, etc around a given set of coords
|
|
||||||
* e.g, the airport map
|
|
||||||
* @param opts
|
|
||||||
*/
|
|
||||||
const _render_airspace_map = (opts) => {
|
|
||||||
opts = _.defaults(opts, {
|
|
||||||
render_elem: 'map',
|
|
||||||
overlay_elem: '',
|
|
||||||
lat: 0,
|
|
||||||
lon: 0,
|
|
||||||
zoom: 12,
|
|
||||||
layers: [],
|
|
||||||
set_marker: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
let map = draw_base_map(opts);
|
|
||||||
const coords = [opts.lat, opts.lon];
|
|
||||||
console.log('Applying coords', coords);
|
|
||||||
|
|
||||||
map.setView(coords, opts.zoom);
|
|
||||||
if (opts.set_marker === true) {
|
|
||||||
L.marker(coords).addTo(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render the live map
|
|
||||||
* @param opts
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
const _render_live_map = (opts) => {
|
|
||||||
|
|
||||||
opts = _.defaults(opts, {
|
|
||||||
update_uri: '/api/acars',
|
|
||||||
pirep_uri: '/api/pireps/{id}/acars',
|
|
||||||
positions: null,
|
|
||||||
render_elem: 'map',
|
|
||||||
aircraft_icon: '/assets/img/acars/aircraft.png',
|
|
||||||
});
|
|
||||||
|
|
||||||
const map = draw_base_map(opts);
|
|
||||||
const aircraftIcon = L.icon({
|
|
||||||
iconUrl: opts.aircraft_icon,
|
|
||||||
iconSize: [42, 42],
|
|
||||||
iconAnchor: [21, 21],
|
|
||||||
});
|
|
||||||
|
|
||||||
let layerFlights = null;
|
|
||||||
let layerSelFlight = null;
|
|
||||||
let layerSelFlightFeature = null;
|
|
||||||
let layerSelFlightLayer = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When a flight is clicked on, show the path, etc for that flight
|
|
||||||
* @param feature
|
|
||||||
* @param layer
|
|
||||||
*/
|
|
||||||
const onFlightClick = (feature, layer) => {
|
|
||||||
|
|
||||||
const uri = opts.pirep_uri.replace('{id}', feature.properties.pirep_id);
|
|
||||||
|
|
||||||
const flight_route = $.ajax({
|
|
||||||
url: uri,
|
|
||||||
dataType: "json",
|
|
||||||
error: console.log
|
|
||||||
});
|
|
||||||
|
|
||||||
$.when(flight_route).done((routeJson) => {
|
|
||||||
if(layerSelFlight !== null) {
|
|
||||||
map.removeLayer(layerSelFlight);
|
|
||||||
}
|
|
||||||
|
|
||||||
layerSelFlight = L.geodesic([], {
|
|
||||||
weight: 7,
|
|
||||||
opacity: 0.9,
|
|
||||||
color: ACTUAL_ROUTE_COLOR,
|
|
||||||
wrap: false,
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
layerSelFlight.geoJson(routeJson.line);
|
|
||||||
|
|
||||||
layerSelFlightFeature = feature;
|
|
||||||
layerSelFlightLayer = layer;
|
|
||||||
//map.fitBounds(layerSelFlight.getBounds());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateMap = () => {
|
|
||||||
|
|
||||||
console.log('reloading flights from acars...');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AJAX UPDATE
|
|
||||||
*/
|
|
||||||
|
|
||||||
let flights = $.ajax({
|
|
||||||
url: opts.update_uri,
|
|
||||||
dataType: "json",
|
|
||||||
error: console.log
|
|
||||||
});
|
|
||||||
|
|
||||||
$.when(flights).done(function (flightGeoJson) {
|
|
||||||
|
|
||||||
if (layerFlights !== null) {
|
|
||||||
layerFlights.clearLayers();
|
|
||||||
}
|
|
||||||
|
|
||||||
layerFlights = L.geoJSON(flightGeoJson, {
|
|
||||||
onEachFeature: (feature, layer) => {
|
|
||||||
|
|
||||||
layer.on({
|
|
||||||
click: (e) => {
|
|
||||||
onFlightClick(feature, layer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let popup_html = "";
|
|
||||||
if (feature.properties && feature.properties.popup) {
|
|
||||||
popup_html += feature.properties.popup;
|
|
||||||
}
|
|
||||||
|
|
||||||
layer.bindPopup(popup_html);
|
|
||||||
},
|
|
||||||
pointToLayer: function(feature, latlon) {
|
|
||||||
return L.marker(latlon, {
|
|
||||||
icon: aircraftIcon,
|
|
||||||
rotationAngle: feature.properties.heading
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
layerFlights.addTo(map);
|
|
||||||
|
|
||||||
if (layerSelFlight !== null) {
|
|
||||||
onFlightClick(layerSelFlightFeature, layerSelFlightLayer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
updateMap();
|
|
||||||
setInterval(updateMap, 10000);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
render_airspace_map: _render_airspace_map,
|
|
||||||
render_live_map: _render_live_map,
|
|
||||||
render_route_map: _render_route_map,
|
|
||||||
}
|
|
||||||
})();
|
|
@ -155,8 +155,8 @@ class FlightTest extends TestCase
|
|||||||
$this->assertTrue($flight->has_bid);
|
$this->assertTrue($flight->has_bid);
|
||||||
|
|
||||||
# Check the table and make sure thee entry is there
|
# Check the table and make sure thee entry is there
|
||||||
$user_bid = UserBid::where(['flight_id'=>$flight->id, 'user_id'=>$user->id])->get();
|
$this->expectException(\App\Exceptions\BidExists::class);
|
||||||
$this->assertNotNull($user_bid);
|
$this->flightSvc->addBid($flight, $user);
|
||||||
|
|
||||||
$user->refresh();
|
$user->refresh();
|
||||||
$this->assertEquals(1, $user->bids->count());
|
$this->assertEquals(1, $user->bids->count());
|
||||||
@ -216,10 +216,39 @@ class FlightTest extends TestCase
|
|||||||
$flight = $this->addFlight($user1);
|
$flight = $this->addFlight($user1);
|
||||||
|
|
||||||
# Put bid on the flight to block it off
|
# Put bid on the flight to block it off
|
||||||
$bid = $this->flightSvc->addBid($flight, $user1);
|
$this->flightSvc->addBid($flight, $user1);
|
||||||
|
|
||||||
$bidRepeat = $this->flightSvc->addBid($flight, $user2);
|
# Try adding again, should throw an exception
|
||||||
$this->assertNull($bidRepeat);
|
$this->expectException(\App\Exceptions\BidExists::class);
|
||||||
|
$this->flightSvc->addBid($flight, $user2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a flight bid VIA the API
|
||||||
|
*/
|
||||||
|
public function testAddBidApi()
|
||||||
|
{
|
||||||
|
$this->user = factory(User::class)->create();
|
||||||
|
$user2 = factory(User::class)->create();
|
||||||
|
$flight = $this->addFlight($this->user);
|
||||||
|
|
||||||
|
$uri = '/api/user/bids';
|
||||||
|
$data = ['flight_id' => $flight->id];
|
||||||
|
|
||||||
|
$body = $this->put($uri, $data)->json('data');
|
||||||
|
|
||||||
|
$this->assertCount(1, $body);
|
||||||
|
$this->assertEquals($body[0]['id'], $flight->id);
|
||||||
|
|
||||||
|
# Now try to have the second user bid on it
|
||||||
|
# Should return a 409 error
|
||||||
|
$response = $this->put($uri, $data, [], $user2);
|
||||||
|
$response->assertStatus(409);
|
||||||
|
|
||||||
|
# Try now deleting the bid from the user
|
||||||
|
$response = $this->delete($uri, $data);
|
||||||
|
$body = $response->json('data');
|
||||||
|
$this->assertCount(0, $body);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,6 +127,24 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
|
|||||||
return $req;
|
return $req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the PUT calls to inject the user API key
|
||||||
|
* @param string $uri
|
||||||
|
* @param array $data
|
||||||
|
* @param array $headers
|
||||||
|
* @param null $user
|
||||||
|
* @return \Illuminate\Foundation\Testing\TestResponse
|
||||||
|
*/
|
||||||
|
public function put($uri, array $data = [], array $headers = [], $user = null)
|
||||||
|
{
|
||||||
|
$req = parent::put($uri, $data, $this->headers($user, $headers));
|
||||||
|
if ($req->isClientError() || $req->isServerError()) {
|
||||||
|
Log::error('PUT Error: ' . $uri, $req->json());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $req;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override the DELETE calls to inject the user API key
|
* Override the DELETE calls to inject the user API key
|
||||||
* @param string $uri
|
* @param string $uri
|
||||||
|
Loading…
Reference in New Issue
Block a user