From f5183babf6eebe43a380e6b7bf11fb64246a550b Mon Sep 17 00:00:00 2001 From: Nabeel S Date: Tue, 5 Nov 2019 11:44:31 -0500 Subject: [PATCH] #406 Refactor bids (#432) * Add flight_id column to pireps table * Refactor PIREPs and bids closes 406 * Formatting --- app/Database/factories/PirepFactory.php | 31 +- ...2017_06_17_214650_create_flight_tables.php | 9 +- .../2017_06_28_195426_create_pirep_tables.php | 9 +- .../2017_12_12_174519_create_bids_table.php | 3 +- ...2019_10_30_141152_pireps_add_flight_id.php | 31 + app/Exceptions/UserBidLimit.php | 45 ++ app/Http/Controllers/Api/FlightController.php | 7 +- app/Http/Controllers/Api/PirepController.php | 10 +- app/Http/Controllers/Api/UserController.php | 22 +- .../Controllers/Frontend/PirepController.php | 21 +- app/Http/Requests/Acars/CommentRequest.php | 3 - app/Http/Requests/Acars/EventRequest.php | 14 +- app/Http/Requests/Acars/FieldsRequest.php | 5 +- app/Http/Requests/Acars/FileRequest.php | 16 +- app/Http/Requests/Acars/LogRequest.php | 9 +- app/Http/Requests/Acars/PositionRequest.php | 24 +- app/Http/Requests/Acars/PrefileRequest.php | 30 +- app/Http/Requests/Acars/RouteRequest.php | 9 +- app/Http/Requests/Acars/UpdateRequest.php | 9 +- app/Listeners/BidEvents.php | 19 +- app/Models/Flight.php | 3 + app/Models/Pirep.php | 37 +- app/Models/User.php | 1 + app/Services/BidService.php | 145 +++++ app/Services/FlightService.php | 108 ---- app/Services/PirepService.php | 138 ++-- resources/lang/en/pireps.php | 1 + resources/lang/es/pireps.php | 1 + resources/lang/it/pireps.php | 1 + .../layouts/default/flights/table.blade.php | 11 +- .../layouts/default/pireps/create.blade.php | 21 +- .../layouts/default/pireps/fields.blade.php | 595 +++++++++--------- tests/BidTest.php | 212 +++++++ tests/FlightTest.php | 160 ----- tests/PIREPTest.php | 5 +- 35 files changed, 967 insertions(+), 798 deletions(-) create mode 100644 app/Database/migrations/2019_10_30_141152_pireps_add_flight_id.php create mode 100644 app/Exceptions/UserBidLimit.php create mode 100644 app/Services/BidService.php create mode 100644 tests/BidTest.php diff --git a/app/Database/factories/PirepFactory.php b/app/Database/factories/PirepFactory.php index 6268e7d0..b4f8cfe5 100644 --- a/app/Database/factories/PirepFactory.php +++ b/app/Database/factories/PirepFactory.php @@ -1,5 +1,8 @@ define(App\Models\Pirep::class, function (Faker $faker) { + $airline = factory(App\Models\Airline::class)->create(); + $flight = factory(App\Models\Flight::class)->create([ + 'airline_id' => $airline->id, + ]); + return [ 'id' => $faker->unique()->numberBetween(10, 10000000), - 'airline_id' => function () { - return factory(App\Models\Airline::class)->create()->id; + 'airline_id' => function () use ($airline) { + return $airline->id; }, 'user_id' => function () { return factory(App\Models\User::class)->create()->id; @@ -18,18 +26,19 @@ $factory->define(App\Models\Pirep::class, function (Faker $faker) { 'aircraft_id' => function () { return factory(App\Models\Aircraft::class)->create()->id; }, - 'flight_number' => function (array $pirep) { - return factory(App\Models\Flight::class)->create([ - 'airline_id' => $pirep['airline_id'], - ])->flight_number; + 'flight_id' => function () use ($flight) { + return $flight->id; + }, + 'flight_number' => function () use ($flight) { + return $flight->flight_number; }, 'route_code' => null, 'route_leg' => null, - 'dpt_airport_id' => function () { - return factory(App\Models\Airport::class)->create()->id; + 'dpt_airport_id' => function () use ($flight) { + return $flight->dpt_airport_id; }, - 'arr_airport_id' => function () { - return factory(App\Models\Airport::class)->create()->id; + 'arr_airport_id' => function () use ($flight) { + return $flight->arr_airport_id; }, 'level' => $faker->numberBetween(20, 400), 'distance' => $faker->randomFloat(2, 0, 6000), @@ -48,7 +57,7 @@ $factory->define(App\Models\Pirep::class, function (Faker $faker) { 'route' => $faker->text(200), 'notes' => $faker->text(200), 'source' => $faker->randomElement([PirepSource::MANUAL, PirepSource::ACARS]), - 'source_name' => 'Test Factory', + 'source_name' => 'TestFactory', 'state' => PirepState::PENDING, 'status' => PirepStatus::SCHEDULED, 'submitted_at' => Carbon::now('UTC')->toDateTimeString(), diff --git a/app/Database/migrations/2017_06_17_214650_create_flight_tables.php b/app/Database/migrations/2017_06_17_214650_create_flight_tables.php index b249bdd9..bde9c08d 100644 --- a/app/Database/migrations/2017_06_17_214650_create_flight_tables.php +++ b/app/Database/migrations/2017_06_17_214650_create_flight_tables.php @@ -1,6 +1,7 @@ string('id', \App\Contracts\Model::ID_MAX_LENGTH); + $table->string('id', Model::ID_MAX_LENGTH); $table->unsignedInteger('airline_id'); $table->unsignedInteger('flight_number'); $table->string('route_code', 5)->nullable(); @@ -47,7 +48,7 @@ class CreateFlightTables extends Migration }); Schema::create('flight_fare', function (Blueprint $table) { - $table->string('flight_id', \App\Contracts\Model::ID_MAX_LENGTH); + $table->string('flight_id', Model::ID_MAX_LENGTH); $table->unsignedInteger('fare_id'); $table->string('price', 10)->nullable(); $table->string('cost', 10)->nullable(); @@ -71,7 +72,7 @@ class CreateFlightTables extends Migration */ Schema::create('flight_field_values', function (Blueprint $table) { $table->bigIncrements('id'); - $table->string('flight_id', \App\Contracts\Model::ID_MAX_LENGTH); + $table->string('flight_id', Model::ID_MAX_LENGTH); $table->string('name', 50); $table->string('slug', 50)->nullable(); $table->text('value'); @@ -83,7 +84,7 @@ class CreateFlightTables extends Migration Schema::create('flight_subfleet', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedInteger('subfleet_id'); - $table->string('flight_id', \App\Contracts\Model::ID_MAX_LENGTH); + $table->string('flight_id', Model::ID_MAX_LENGTH); $table->index(['subfleet_id', 'flight_id']); $table->index(['flight_id', 'subfleet_id']); diff --git a/app/Database/migrations/2017_06_28_195426_create_pirep_tables.php b/app/Database/migrations/2017_06_28_195426_create_pirep_tables.php index 5041485a..00c2c818 100644 --- a/app/Database/migrations/2017_06_28_195426_create_pirep_tables.php +++ b/app/Database/migrations/2017_06_28_195426_create_pirep_tables.php @@ -1,6 +1,7 @@ string('id', \App\Contracts\Model::ID_MAX_LENGTH); + $table->string('id', Model::ID_MAX_LENGTH); $table->unsignedInteger('user_id'); $table->unsignedInteger('airline_id'); $table->unsignedInteger('aircraft_id')->nullable(); @@ -57,7 +58,7 @@ class CreatePirepTables extends Migration Schema::create('pirep_comments', function (Blueprint $table) { $table->bigIncrements('id'); - $table->string('pirep_id', \App\Contracts\Model::ID_MAX_LENGTH); + $table->string('pirep_id', Model::ID_MAX_LENGTH); $table->unsignedInteger('user_id'); $table->text('comment'); $table->timestamps(); @@ -65,7 +66,7 @@ class CreatePirepTables extends Migration Schema::create('pirep_fares', function (Blueprint $table) { $table->bigIncrements('id'); - $table->string('pirep_id', \App\Contracts\Model::ID_MAX_LENGTH); + $table->string('pirep_id', Model::ID_MAX_LENGTH); $table->unsignedInteger('fare_id'); $table->unsignedInteger('count')->nullable()->default(0); @@ -81,7 +82,7 @@ class CreatePirepTables extends Migration Schema::create('pirep_field_values', function (Blueprint $table) { $table->bigIncrements('id'); - $table->string('pirep_id', \App\Contracts\Model::ID_MAX_LENGTH); + $table->string('pirep_id', Model::ID_MAX_LENGTH); $table->string('name', 50); $table->string('slug', 50)->nullable(); $table->string('value')->nullable(); diff --git a/app/Database/migrations/2017_12_12_174519_create_bids_table.php b/app/Database/migrations/2017_12_12_174519_create_bids_table.php index 5682ac60..adc321de 100644 --- a/app/Database/migrations/2017_12_12_174519_create_bids_table.php +++ b/app/Database/migrations/2017_12_12_174519_create_bids_table.php @@ -1,6 +1,7 @@ increments('id'); $table->unsignedInteger('user_id'); - $table->string('flight_id', \App\Contracts\Model::ID_MAX_LENGTH); + $table->string('flight_id', Model::ID_MAX_LENGTH); $table->timestamps(); $table->index('user_id'); diff --git a/app/Database/migrations/2019_10_30_141152_pireps_add_flight_id.php b/app/Database/migrations/2019_10_30_141152_pireps_add_flight_id.php new file mode 100644 index 00000000..ca8be667 --- /dev/null +++ b/app/Database/migrations/2019_10_30_141152_pireps_add_flight_id.php @@ -0,0 +1,31 @@ +string('flight_id', Model::ID_MAX_LENGTH)->nullable()->after('aircraft_id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('pireps', function (Blueprint $table) { + $table->dropColumn('flight_id'); + }); + } +} diff --git a/app/Exceptions/UserBidLimit.php b/app/Exceptions/UserBidLimit.php new file mode 100644 index 00000000..22b82809 --- /dev/null +++ b/app/Exceptions/UserBidLimit.php @@ -0,0 +1,45 @@ +user = $user; + parent::__construct( + 409, + 'User '.$user->ident.' has the maximum number of bids' + ); + } + + /** + * Return the RFC 7807 error type (without the URL root) + */ + public function getErrorType(): string + { + return 'user-bid-limit'; + } + + /** + * 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 [ + 'user_id' => $this->user->id, + ]; + } +} diff --git a/app/Http/Controllers/Api/FlightController.php b/app/Http/Controllers/Api/FlightController.php index 8ef5a922..12f21557 100644 --- a/app/Http/Controllers/Api/FlightController.php +++ b/app/Http/Controllers/Api/FlightController.php @@ -8,8 +8,8 @@ use App\Http\Resources\Navdata as NavdataResource; use App\Repositories\Criteria\WhereCriteria; use App\Repositories\FlightRepository; use App\Services\FlightService; -use Auth; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; use Prettus\Repository\Criteria\RequestCriteria; use Prettus\Repository\Exceptions\RepositoryException; @@ -44,6 +44,9 @@ class FlightController extends Controller */ public function index(Request $request) { + /** + * @var $user \App\Models\User + */ $user = Auth::user(); $where = [ @@ -52,7 +55,7 @@ class FlightController extends Controller ]; if (setting('pilots.restrict_to_company')) { - $where['airline_id'] = Auth::user()->airline_id; + $where['airline_id'] = $user->airline_id; } if (setting('pilots.only_flights_from_current', false)) { $where['dpt_airport_id'] = $user->curr_airport_id; diff --git a/app/Http/Controllers/Api/PirepController.php b/app/Http/Controllers/Api/PirepController.php index 445b1f1c..9571f214 100644 --- a/app/Http/Controllers/Api/PirepController.php +++ b/app/Http/Controllers/Api/PirepController.php @@ -20,6 +20,7 @@ use App\Http\Resources\PirepComment as PirepCommentResource; use App\Http\Resources\PirepFieldCollection; use App\Models\Acars; use App\Models\Enums\AcarsType; +use App\Models\Enums\FlightType; use App\Models\Enums\PirepFieldSource; use App\Models\Enums\PirepSource; use App\Models\Enums\PirepState; @@ -93,6 +94,10 @@ class PirepController extends Controller $attrs['created_at'] = Carbon::createFromTimeString($attrs['created_at']); } + if (array_key_exists('updated_at', $attrs)) { + $attrs['updated_at'] = Carbon::createFromTimeString($attrs['updated_at']); + } + return $attrs; } @@ -186,6 +191,9 @@ class PirepController extends Controller { Log::info('PIREP Prefile, user '.Auth::id(), $request->post()); + /** + * @var $user \App\Models\User + */ $user = Auth::user(); $attrs = $this->parsePirep($request); @@ -228,7 +236,7 @@ class PirepController extends Controller // Default to a scheduled passenger flight if (!array_key_exists('flight_type', $attrs)) { - $attrs['flight_type'] = 'J'; + $attrs['flight_type'] = FlightType::SCHED_PAX; } $pirep->save(); diff --git a/app/Http/Controllers/Api/UserController.php b/app/Http/Controllers/Api/UserController.php index 491e7d37..092399a0 100644 --- a/app/Http/Controllers/Api/UserController.php +++ b/app/Http/Controllers/Api/UserController.php @@ -13,18 +13,17 @@ use App\Repositories\Criteria\WhereCriteria; use App\Repositories\FlightRepository; use App\Repositories\PirepRepository; use App\Repositories\UserRepository; +use App\Services\BidService; use App\Services\FlightService; use App\Services\UserService; -use Auth; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; use Prettus\Repository\Criteria\RequestCriteria; use Prettus\Repository\Exceptions\RepositoryException; -/** - * Class UserController - */ class UserController extends Controller { + private $bidSvc; private $flightRepo; private $flightSvc; private $pirepRepo; @@ -32,8 +31,7 @@ class UserController extends Controller private $userSvc; /** - * UserController constructor. - * + * @param BidService $bidSvc * @param FlightRepository $flightRepo * @param FlightService $flightSvc * @param PirepRepository $pirepRepo @@ -41,12 +39,14 @@ class UserController extends Controller * @param UserService $userSvc */ public function __construct( + BidService $bidSvc, FlightRepository $flightRepo, FlightService $flightSvc, PirepRepository $pirepRepo, UserRepository $userRepo, UserService $userSvc ) { + $this->bidSvc = $bidSvc; $this->flightRepo = $flightRepo; $this->flightSvc = $flightSvc; $this->pirepRepo = $pirepRepo; @@ -61,11 +61,11 @@ class UserController extends Controller */ protected function getUserId(Request $request) { - if ($request->id === null) { + if ($request->get('id') === null) { return Auth::user()->id; } - return $request->id; + return $request->get('id'); } /** @@ -110,7 +110,7 @@ class UserController extends Controller if ($request->isMethod('PUT') || $request->isMethod('POST')) { $flight_id = $request->input('flight_id'); $flight = $this->flightRepo->find($flight_id); - $bid = $this->flightSvc->addBid($flight, $user); + $bid = $this->bidSvc->addBid($flight, $user); return new BidResource($bid); } @@ -124,11 +124,11 @@ class UserController extends Controller } $flight = $this->flightRepo->find($flight_id); - $this->flightSvc->removeBid($flight, $user); + $this->bidSvc->removeBid($flight, $user); } // Return the flights they currently have bids on - $bids = Bid::where(['user_id' => $user->id])->get(); + $bids = $this->bidSvc->findBidsForUser($user); return BidResource::collection($bids); } diff --git a/app/Http/Controllers/Frontend/PirepController.php b/app/Http/Controllers/Frontend/PirepController.php index 0ebfde17..2ab1113e 100644 --- a/app/Http/Controllers/Frontend/PirepController.php +++ b/app/Http/Controllers/Frontend/PirepController.php @@ -14,6 +14,7 @@ use App\Repositories\AircraftRepository; use App\Repositories\AirlineRepository; use App\Repositories\AirportRepository; use App\Repositories\Criteria\WhereCriteria; +use App\Repositories\FlightRepository; use App\Repositories\PirepFieldRepository; use App\Repositories\PirepRepository; use App\Services\FareService; @@ -35,6 +36,7 @@ class PirepController extends Controller private $aircraftRepo; private $airlineRepo; private $fareSvc; + private $flightRepo; private $geoSvc; private $pirepRepo; private $airportRepo; @@ -43,12 +45,11 @@ class PirepController extends Controller private $userSvc; /** - * PirepController constructor. - * * @param AircraftRepository $aircraftRepo * @param AirlineRepository $airlineRepo * @param AirportRepository $airportRepo * @param FareService $fareSvc + * @param FlightRepository $flightRepo * @param GeoService $geoSvc * @param PirepRepository $pirepRepo * @param PirepFieldRepository $pirepFieldRepo @@ -60,6 +61,7 @@ class PirepController extends Controller AirlineRepository $airlineRepo, AirportRepository $airportRepo, FareService $fareSvc, + FlightRepository $flightRepo, GeoService $geoSvc, PirepRepository $pirepRepo, PirepFieldRepository $pirepFieldRepo, @@ -73,6 +75,7 @@ class PirepController extends Controller $this->pirepFieldRepo = $pirepFieldRepo; $this->fareSvc = $fareSvc; + $this->flightRepo = $flightRepo; $this->geoSvc = $geoSvc; $this->pirepSvc = $pirepSvc; $this->userSvc = $userSvc; @@ -231,12 +234,24 @@ class PirepController extends Controller /** * Create a new flight report * + * @param \Illuminate\Http\Request $request + * * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ - public function create() + public function create(Request $request) { + $pirep = null; + + // See if request has a ?flight_id, so we can pre-populate the fields from the flight + // Makes filing easier, but we can also more easily find a bid and close it + if ($request->has('flight_id')) { + $flight = $this->flightRepo->find($request->get('flight_id')); + $pirep = Pirep::fromFlight($flight); + } + return view('pireps.create', [ 'aircraft' => null, + 'pirep' => $pirep, 'read_only' => false, 'airline_list' => $this->airlineRepo->selectBoxList(true), 'aircraft_list' => $this->aircraftList(true), diff --git a/app/Http/Requests/Acars/CommentRequest.php b/app/Http/Requests/Acars/CommentRequest.php index c8052b7b..380ad66c 100644 --- a/app/Http/Requests/Acars/CommentRequest.php +++ b/app/Http/Requests/Acars/CommentRequest.php @@ -4,9 +4,6 @@ namespace App\Http\Requests\Acars; use App\Contracts\FormRequest; -/** - * Class CommentRequest - */ class CommentRequest extends FormRequest { public function rules(): array diff --git a/app/Http/Requests/Acars/EventRequest.php b/app/Http/Requests/Acars/EventRequest.php index da747e45..3d49e9b6 100644 --- a/app/Http/Requests/Acars/EventRequest.php +++ b/app/Http/Requests/Acars/EventRequest.php @@ -4,25 +4,17 @@ namespace App\Http\Requests\Acars; use App\Contracts\FormRequest; use App\Models\Pirep; -use Auth; +use Illuminate\Support\Facades\Auth; -/** - * Class EventRequest - */ class EventRequest extends FormRequest { - /** - * @throws \Illuminate\Database\Eloquent\ModelNotFoundException - * - * @return bool - */ - public function authorize() + public function authorize(): bool { $pirep = Pirep::findOrFail($this->route('pirep_id'), ['user_id']); return $pirep->user_id === Auth::id(); } - public function rules() + public function rules(): array { $rules = [ 'events' => 'required|array', diff --git a/app/Http/Requests/Acars/FieldsRequest.php b/app/Http/Requests/Acars/FieldsRequest.php index f5045bf2..76d0a935 100644 --- a/app/Http/Requests/Acars/FieldsRequest.php +++ b/app/Http/Requests/Acars/FieldsRequest.php @@ -9,10 +9,7 @@ use App\Contracts\FormRequest; */ class FieldsRequest extends FormRequest { - /** - * @return array - */ - public function rules() + public function rules(): array { return [ 'fields' => 'required|array', diff --git a/app/Http/Requests/Acars/FileRequest.php b/app/Http/Requests/Acars/FileRequest.php index 1c7a54f0..725961b5 100644 --- a/app/Http/Requests/Acars/FileRequest.php +++ b/app/Http/Requests/Acars/FileRequest.php @@ -4,26 +4,22 @@ namespace App\Http\Requests\Acars; use App\Contracts\FormRequest; use App\Models\Pirep; -use Auth; +use Illuminate\Support\Facades\Auth; -/** - * Class FileRequest - */ class FileRequest extends FormRequest { - public function authorize() + public function authorize(): bool { $pirep = Pirep::findOrFail($this->route('pirep_id'), ['user_id']); return $pirep->user_id === Auth::id(); } - public function rules() + public function rules(): array { $rules = [ - 'distance' => 'required|numeric', - 'flight_time' => 'required|integer', - 'fuel_used' => 'required|numeric', - + 'distance' => 'required|numeric', + 'flight_time' => 'required|integer', + 'fuel_used' => 'required|numeric', 'block_time' => 'nullable|integer', 'airline_id' => 'nullable|exists:airlines,id', 'aircraft_id' => 'nullable|exists:aircraft,id', diff --git a/app/Http/Requests/Acars/LogRequest.php b/app/Http/Requests/Acars/LogRequest.php index a0ddaf4e..bc179cf5 100644 --- a/app/Http/Requests/Acars/LogRequest.php +++ b/app/Http/Requests/Acars/LogRequest.php @@ -4,20 +4,17 @@ namespace App\Http\Requests\Acars; use App\Contracts\FormRequest; use App\Models\Pirep; -use Auth; +use Illuminate\Support\Facades\Auth; -/** - * Class LogRequest - */ class LogRequest extends FormRequest { - public function authorize() + public function authorize(): bool { $pirep = Pirep::findOrFail($this->route('pirep_id'), ['user_id']); return $pirep->user_id === Auth::id(); } - public function rules() + public function rules(): array { $rules = [ 'logs' => 'required|array', diff --git a/app/Http/Requests/Acars/PositionRequest.php b/app/Http/Requests/Acars/PositionRequest.php index f46e2836..977371ac 100644 --- a/app/Http/Requests/Acars/PositionRequest.php +++ b/app/Http/Requests/Acars/PositionRequest.php @@ -4,36 +4,20 @@ namespace App\Http\Requests\Acars; use App\Contracts\FormRequest; use App\Models\Pirep; -use Auth; +use Illuminate\Support\Facades\Auth; -/** - * Class PositionRequest - */ class PositionRequest extends FormRequest { /** - * @return bool + * Is the user allowed to do this? */ - public function authorize() + public function authorize(): bool { $pirep = Pirep::findOrFail($this->route('pirep_id'), ['user_id']); return $pirep->user_id === Auth::id(); } - /** - * @return array - */ - /*public function sanitize() - { - return [ - 'positions.*.sim_time' => Acars::$sanitize['sim_time'], - ]; - }*/ - - /** - * @return array - */ - public function rules() + public function rules(): array { $rules = [ 'positions' => 'required|array', diff --git a/app/Http/Requests/Acars/PrefileRequest.php b/app/Http/Requests/Acars/PrefileRequest.php index 9c2c81de..fae3aa5f 100644 --- a/app/Http/Requests/Acars/PrefileRequest.php +++ b/app/Http/Requests/Acars/PrefileRequest.php @@ -4,32 +4,18 @@ namespace App\Http\Requests\Acars; use App\Contracts\FormRequest; -/** - * Class PrefileRequest - */ class PrefileRequest extends FormRequest { - /** - * @return array|void - */ - /*public function sanitize() - { - return Pirep::$sanitize; - }*/ - - /** - * @return array - */ - public function rules() + public function rules(): array { $rules = [ - 'airline_id' => 'required|exists:airlines,id', - 'aircraft_id' => 'required|exists:aircraft,id', - 'flight_number' => 'required', - 'dpt_airport_id' => 'required', - 'arr_airport_id' => 'required', - 'source_name' => 'required', - + 'airline_id' => 'required|exists:airlines,id', + 'aircraft_id' => 'required|exists:aircraft,id', + 'flight_number' => 'required', + 'dpt_airport_id' => 'required', + 'arr_airport_id' => 'required', + 'flight_id' => 'nullable', + 'source_name' => 'required', 'alt_airport_id' => 'nullable', 'status' => 'nullable', 'level' => 'nullable|numeric', diff --git a/app/Http/Requests/Acars/RouteRequest.php b/app/Http/Requests/Acars/RouteRequest.php index 7195a947..84a7439c 100644 --- a/app/Http/Requests/Acars/RouteRequest.php +++ b/app/Http/Requests/Acars/RouteRequest.php @@ -4,20 +4,17 @@ namespace App\Http\Requests\Acars; use App\Contracts\FormRequest; use App\Models\Pirep; -use Auth; +use Illuminate\Support\Facades\Auth; -/** - * Class RouteRequest - */ class RouteRequest extends FormRequest { - public function authorize() + public function authorize(): bool { $pirep = Pirep::findOrFail($this->route('pirep_id'), ['user_id']); return $pirep->user_id === Auth::id(); } - public function rules() + public function rules(): array { $rules = [ 'route' => 'required|array', diff --git a/app/Http/Requests/Acars/UpdateRequest.php b/app/Http/Requests/Acars/UpdateRequest.php index 320ecab7..67d4c87d 100644 --- a/app/Http/Requests/Acars/UpdateRequest.php +++ b/app/Http/Requests/Acars/UpdateRequest.php @@ -4,20 +4,17 @@ namespace App\Http\Requests\Acars; use App\Contracts\FormRequest; use App\Models\Pirep; -use Auth; +use Illuminate\Support\Facades\Auth; -/** - * Class UpdateRequest - */ class UpdateRequest extends FormRequest { - public function authorize() + public function authorize(): bool { $pirep = Pirep::findOrFail($this->route('pirep_id'), ['user_id']); return $pirep->user_id === Auth::id(); } - public function rules() + public function rules(): array { $rules = [ 'airline_id' => 'nullable|exists:airlines,id', diff --git a/app/Listeners/BidEvents.php b/app/Listeners/BidEvents.php index 9e208f3e..2aed462d 100644 --- a/app/Listeners/BidEvents.php +++ b/app/Listeners/BidEvents.php @@ -4,7 +4,7 @@ namespace App\Listeners; use App\Contracts\Listener; use App\Events\PirepAccepted; -use App\Services\PirepService; +use App\Services\BidService; use Illuminate\Contracts\Events\Dispatcher; /** @@ -12,17 +12,11 @@ use Illuminate\Contracts\Events\Dispatcher; */ class BidEvents extends Listener { - private $pirepSvc; + private $bidSvc; - /** - * FinanceEvents constructor. - * - * @param PirepService $pirepSvc - */ - public function __construct( - PirepService $pirepSvc - ) { - $this->pirepSvc = $pirepSvc; + public function __construct(BidService $bidSvc) + { + $this->bidSvc = $bidSvc; } /** @@ -44,10 +38,9 @@ class BidEvents extends Listener * @throws \UnexpectedValueException * @throws \InvalidArgumentException * @throws \Exception - * @throws \Prettus\Validator\Exceptions\ValidatorException */ public function onPirepAccept(PirepAccepted $event): void { - $this->pirepSvc->removeBid($event->pirep); + $this->bidSvc->removeBidForPirep($event->pirep); } } diff --git a/app/Models/Flight.php b/app/Models/Flight.php index b3c22230..13457a65 100644 --- a/app/Models/Flight.php +++ b/app/Models/Flight.php @@ -22,7 +22,10 @@ use Illuminate\Support\Collection; * @property Collection fares * @property Collection subfleets * @property int days + * @property int distance + * @property int flight_time * @property string route + * @property int level * @property Airport dpt_airport * @property Airport arr_airport * @property Airport alt_airport diff --git a/app/Models/Pirep.php b/app/Models/Pirep.php index f3de2467..f19221b5 100644 --- a/app/Models/Pirep.php +++ b/app/Models/Pirep.php @@ -150,6 +150,28 @@ class Pirep extends Model PirepState::DELETED, ]; + /** + * Create a new PIREP model from a given flight. Pre-populates the fields + * + * @param \App\Models\Flight $flight + * + * @return \App\Models\Pirep + */ + public static function fromFlight(Flight $flight) + { + return new self([ + 'flight_id' => $flight->id, + 'airline_id' => $flight->airline_id, + 'flight_number' => $flight->flight_number, + 'route_code' => $flight->route_code, + 'route_leg' => $flight->route_leg, + 'dpt_airport_id' => $flight->dpt_airport_id, + 'arr_airport_id' => $flight->arr_airport_id, + 'route' => $flight->route, + 'level' => $flight->level, + ]); + } + /** * Get the flight ident, e.,g JBU1900 * @@ -277,10 +299,16 @@ class Pirep extends Model /** * Look up the flight, based on the PIREP flight info * + * @param mixed $value + * * @return Flight|null */ - public function getFlightAttribute(): ?Flight + /*public function getFlightAttribute(): ?Flight { + if (!empty($this->flight_id)) { + return Flight::find($this->flight_id); + } + $where = [ 'airline_id' => $this->airline_id, 'flight_number' => $this->flight_number, @@ -296,7 +324,7 @@ class Pirep extends Model } return Flight::where($where)->first(); - } + }*/ /** * Set the amount of fuel used @@ -412,6 +440,11 @@ class Pirep extends Model return $this->belongsTo(Airline::class, 'airline_id'); } + public function flight() + { + return $this->belongsTo(Flight::class, 'flight_id'); + } + public function arr_airport() { return $this->belongsTo(Airport::class, 'arr_airport_id'); diff --git a/app/Models/User.php b/app/Models/User.php index 0aeef63b..69a1f67d 100755 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -12,6 +12,7 @@ use Laratrust\Traits\LaratrustUserTrait; /** * @property int id * @property int pilot_id + * @property int airline_id * @property string name * @property string email * @property string password diff --git a/app/Services/BidService.php b/app/Services/BidService.php new file mode 100644 index 00000000..9e3e5ef6 --- /dev/null +++ b/app/Services/BidService.php @@ -0,0 +1,145 @@ + $user->id])->get(); + return $bids; + } + + /** + * Allow a user to bid on a flight. Check settings and all that good stuff + * + * @param Flight $flight + * @param User $user + * + * @throws \App\Exceptions\BidExistsForFlight + * + * @return mixed + */ + public function addBid(Flight $flight, User $user) + { + // Get all of the bids for this user. See if they're allowed to have multiple + // bids + $bid_count = Bid::where(['user_id' => $user->id])->count(); + if ($bid_count > 0 && setting('bids.allow_multiple_bids') === false) { + throw new UserBidLimit($user); + } + + // Get all of the bids for this flight + $bids = Bid::where(['flight_id' => $flight->id])->get(); + if ($bids->count() > 0) { + // Does the flight have a bid set? + if ($flight->has_bid === false) { + $flight->has_bid = true; + $flight->save(); + } + + // Check all the bids for one of this user + foreach ($bids as $bid) { + if ($bid->user_id === $user->id) { + Log::info('Bid exists, user='.$user->ident.', flight='.$flight->id); + + return $bid; + } + } + + // Check if the flight should be blocked off + if (setting('bids.disable_flight_on_bid') === true) { + throw new BidExistsForFlight($flight); + } + + if (setting('bids.allow_multiple_bids') === false) { + throw new BidExistsForFlight($flight); + } + } else { + /* @noinspection NestedPositiveIfStatementsInspection */ + if ($flight->has_bid === true) { + Log::info('Bid exists, flight='.$flight->id.'; no entry in bids table, cleaning up'); + } + } + + $bid = Bid::firstOrCreate([ + 'user_id' => $user->id, + 'flight_id' => $flight->id, + ]); + + $flight->has_bid = true; + $flight->save(); + + return $bid; + } + + /** + * Remove a bid from a given flight + * + * @param Flight $flight + * @param User $user + */ + public function removeBid(Flight $flight, User $user) + { + $bids = Bid::where([ + 'flight_id' => $flight->id, + 'user_id' => $user->id, + ])->get(); + + foreach ($bids as $bid) { + $bid->forceDelete(); + } + + // Only flip the flag if there are no bids left for this flight + $bid_count = Bid::where(['flight_id' => $flight->id])->count(); + if ($bid_count === 0) { + $flight->has_bid = false; + $flight->save(); + } + } + + /** + * If the setting is enabled, remove the bid + * + * @param Pirep $pirep + * + * @throws \Exception + */ + public function removeBidForPirep(Pirep $pirep) + { + if (!setting('pireps.remove_bid_on_accept')) { + return; + } + + $flight = $pirep->flight; + if (!$flight) { + return; + } + + $bid = Bid::where([ + 'user_id' => $pirep->user->id, + 'flight_id' => $flight->id, + ]); + + if ($bid) { + Log::info('Bid for user: '.$pirep->user->ident.' on flight '.$flight->ident); + $bid->delete(); + } + } +} diff --git a/app/Services/FlightService.php b/app/Services/FlightService.php index d30cbc2f..14786a3f 100644 --- a/app/Services/FlightService.php +++ b/app/Services/FlightService.php @@ -3,17 +3,14 @@ namespace App\Services; use App\Contracts\Service; -use App\Exceptions\BidExistsForFlight; use App\Exceptions\DuplicateFlight; use App\Models\Bid; use App\Models\Enums\Days; use App\Models\Flight; use App\Models\FlightFieldValue; -use App\Models\User; use App\Repositories\FlightRepository; use App\Repositories\NavdataRepository; use App\Support\Units\Time; -use Illuminate\Support\Facades\Log; class FlightService extends Service { @@ -123,24 +120,6 @@ class FlightService extends Service return $fields; } - /** - * Filter out any flights according to different settings - * - * @param $user - * - * @return FlightRepository - */ - public function filterFlights($user) - { - $where = []; - if (setting('pilots.only_flights_from_current', false)) { - $where['dpt_airport_id'] = $user->curr_airport_id; - } - - return $this->flightRepo - ->whereOrder($where, 'flight_number', 'asc'); - } - /** * Filter out subfleets to only include aircraft that a user has access to * @@ -276,91 +255,4 @@ class FlightService extends Service return collect($return_points); } - - /** - * Allow a user to bid on a flight. Check settings and all that good stuff - * - * @param Flight $flight - * @param User $user - * - *@throws \App\Exceptions\BidExistsForFlight - * - * @return mixed - */ - public function addBid(Flight $flight, User $user) - { - // Get all of the bids for this user. See if they're allowed to have multiple - // bids - $bids = Bid::where('user_id', $user->id)->get(); - if ($bids->count() > 0 && setting('bids.allow_multiple_bids') === false) { - throw new BidExistsForFlight('User "'.$user->ident.'" already has bids, skipping'); - } - - // Get all of the bids for this flight - $bids = Bid::where('flight_id', $flight->id)->get(); - if ($bids->count() > 0) { - // Does the flight have a bid set? - if ($flight->has_bid === false) { - $flight->has_bid = true; - $flight->save(); - } - - // Check all the bids for one of this user - foreach ($bids as $bid) { - if ($bid->user_id === $user->id) { - Log::info('Bid exists, user='.$user->ident.', flight='.$flight->id); - return $bid; - } - } - - // Check if the flight should be blocked off - if (setting('bids.disable_flight_on_bid') === true) { - throw new BidExistsForFlight($flight); - } - - if (setting('bids.allow_multiple_bids') === false) { - throw new BidExistsForFlight($flight); - } - } else { - /* @noinspection NestedPositiveIfStatementsInspection */ - if ($flight->has_bid === true) { - Log::info('Bid exists, flight='.$flight->id.'; no entry in bids table, cleaning up'); - } - } - - $bid = Bid::firstOrCreate([ - 'user_id' => $user->id, - 'flight_id' => $flight->id, - ]); - - $flight->has_bid = true; - $flight->save(); - - return $bid; - } - - /** - * Remove a bid from a given flight - * - * @param Flight $flight - * @param User $user - */ - public function removeBid(Flight $flight, User $user) - { - $bids = Bid::where([ - 'flight_id' => $flight->id, - 'user_id' => $user->id, - ])->get(); - - foreach ($bids as $bid) { - $bid->forceDelete(); - } - - // Only flip the flag if there are no bids left for this flight - $bids = Bid::where('flight_id', $flight->id)->get(); - if ($bids->count() === 0) { - $flight->has_bid = false; - $flight->save(); - } - } } diff --git a/app/Services/PirepService.php b/app/Services/PirepService.php index 1a41b78c..0602087c 100644 --- a/app/Services/PirepService.php +++ b/app/Services/PirepService.php @@ -9,7 +9,6 @@ use App\Events\PirepRejected; use App\Events\UserStatsChanged; use App\Exceptions\PirepCancelNotAllowed; use App\Models\Acars; -use App\Models\Bid; use App\Models\Enums\AcarsType; use App\Models\Enums\PirepSource; use App\Models\Enums\PirepState; @@ -20,12 +19,10 @@ use App\Models\PirepFieldValue; use App\Models\User; use App\Repositories\PirepRepository; use Carbon\Carbon; +use function count; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Facades\Log; -/** - * Class PirepService - */ class PirepService extends Service { private $geoSvc; @@ -33,8 +30,6 @@ class PirepService extends Service private $pirepRepo; /** - * PirepService constructor. - * * @param GeoService $geoSvc * @param PirepRepository $pirepRepo * @param UserService $pilotSvc @@ -49,6 +44,60 @@ class PirepService extends Service $this->pirepRepo = $pirepRepo; } + /** + * Create a new PIREP with some given fields + * + * @param Pirep $pirep + * @param array PirepFieldValue[] $field_values + * + * @return Pirep + */ + public function create(Pirep $pirep, array $field_values = []): Pirep + { + if (empty($field_values)) { + $field_values = []; + } + + // Check the block times. If a block on (arrival) time isn't + // specified, then use the time that it was submitted. It won't + // be the most accurate, but that might be OK + if (!$pirep->block_on_time) { + if ($pirep->submitted_at) { + $pirep->block_on_time = $pirep->submitted_at; + } else { + $pirep->block_on_time = Carbon::now('UTC'); + } + } + + // If the depart time isn't set, then try to calculate it by + // subtracting the flight time from the block_on (arrival) time + if (!$pirep->block_off_time && $pirep->flight_time > 0) { + $pirep->block_off_time = $pirep->block_on_time->subMinutes($pirep->flight_time); + } + + // Check that there's a submit time + if (!$pirep->submitted_at) { + $pirep->submitted_at = Carbon::now('UTC'); + } + + $pirep->status = PirepStatus::ARRIVED; + + // Copy some fields over from Flight if we have it + if ($pirep->flight) { + $pirep->planned_distance = $pirep->flight->distance; + $pirep->planned_flight_time = $pirep->flight->flight_time; + } + + $pirep->save(); + $pirep->refresh(); + + if (count($field_values) > 0) { + $this->updateCustomFields($pirep->id, $field_values); + } + + return $pirep; + } + /** * Find if there are duplicates to a given PIREP. Ideally, the passed * in PIREP hasn't been saved or gone through the create() method @@ -149,54 +198,6 @@ class PirepService extends Service return $pirep; } - /** - * Create a new PIREP with some given fields - * - * @param Pirep $pirep - * @param array PirepFieldValue[] $field_values - * - * @return Pirep - */ - public function create(Pirep $pirep, array $field_values = []): Pirep - { - if (empty($field_values)) { - $field_values = []; - } - - // Check the block times. If a block on (arrival) time isn't - // specified, then use the time that it was submitted. It won't - // be the most accurate, but that might be OK - if (!$pirep->block_on_time) { - if ($pirep->submitted_at) { - $pirep->block_on_time = $pirep->submitted_at; - } else { - $pirep->block_on_time = Carbon::now('UTC'); - } - } - - // If the depart time isn't set, then try to calculate it by - // subtracting the flight time from the block_on (arrival) time - if (!$pirep->block_off_time && $pirep->flight_time > 0) { - $pirep->block_off_time = $pirep->block_on_time->subMinutes($pirep->flight_time); - } - - // Check that there's a submit time - if (!$pirep->submitted_at) { - $pirep->submitted_at = Carbon::now('UTC'); - } - - $pirep->status = PirepStatus::ARRIVED; - - $pirep->save(); - $pirep->refresh(); - - if (\count($field_values) > 0) { - $this->updateCustomFields($pirep->id, $field_values); - } - - return $pirep; - } - /** * Submit the PIREP. Figure out its default state * @@ -421,33 +422,4 @@ class PirepService extends Service event(new UserStatsChanged($pilot, 'airport', $previous_airport)); } - - /** - * If the setting is enabled, remove the bid - * - * @param Pirep $pirep - * - * @throws \Exception - */ - public function removeBid(Pirep $pirep) - { - if (!setting('pireps.remove_bid_on_accept')) { - return; - } - - $flight = $pirep->flight; - if (!$flight) { - return; - } - - $bid = Bid::where([ - 'user_id' => $pirep->user->id, - 'flight_id' => $flight->id, - ]); - - if ($bid) { - Log::info('Bid for user: '.$pirep->user->ident.' on flight '.$flight->ident); - $bid->delete(); - } - } } diff --git a/resources/lang/en/pireps.php b/resources/lang/en/pireps.php index 3d56b983..1b734d72 100644 --- a/resources/lang/en/pireps.php +++ b/resources/lang/en/pireps.php @@ -7,6 +7,7 @@ return [ 'submitpirep' => 'Submit PIREP', 'fileflightreport' => 'File New Report', 'filenewpirep' => 'File New PIREP', + 'newpirep' => 'New PIREP', 'pilotreport' => 'Pilot Report|Pilot Reports', 'arrived' => 'Arrived', 'source' => 'Source', diff --git a/resources/lang/es/pireps.php b/resources/lang/es/pireps.php index c0de6599..234652c2 100644 --- a/resources/lang/es/pireps.php +++ b/resources/lang/es/pireps.php @@ -7,6 +7,7 @@ return [ 'submitpirep' => 'Enviar PIREP', 'fileflightreport' => 'Archivo informe de vuelo', 'filenewpirep' => 'Archivo nuevo PIREP', + 'newpirep' => 'Nuevo PIREP', 'pilotreport' => 'Informe de piloto|Informes de piloto', 'arrived' => 'Llegó', 'source' => 'Origen', diff --git a/resources/lang/it/pireps.php b/resources/lang/it/pireps.php index 2f8e506c..283dc3b6 100644 --- a/resources/lang/it/pireps.php +++ b/resources/lang/it/pireps.php @@ -2,6 +2,7 @@ return [ 'filenewpirep' => 'Inserici Nuovo PIREP', + 'newpirep' => 'Nuovo PIREP', 'pilotreport' => 'Rapporto Pilota|Rapporti Pilota', 'arrived' => 'Arrivato', 'source' => 'Fonte', diff --git a/resources/views/layouts/default/flights/table.blade.php b/resources/views/layouts/default/flights/table.blade.php index fd1ee42a..3a20885a 100644 --- a/resources/views/layouts/default/flights/table.blade.php +++ b/resources/views/layouts/default/flights/table.blade.php @@ -23,8 +23,7 @@ x-id="{{ $flight->id }}" x-saved-class="btn-info" type="button" - title="@lang('flights.addremovebid')" - > + title="@lang('flights.addremovebid')"> @endif @@ -64,6 +63,14 @@ @endif +
+ +
diff --git a/resources/views/layouts/default/pireps/create.blade.php b/resources/views/layouts/default/pireps/create.blade.php index dac20474..24ea30ff 100644 --- a/resources/views/layouts/default/pireps/create.blade.php +++ b/resources/views/layouts/default/pireps/create.blade.php @@ -2,17 +2,22 @@ @section('title', __('pireps.fileflightreport')) @section('content') -
-
-

@lang('pireps.newflightreport')

- @include('flash::message') - {{ Form::open(['route' => 'frontend.pireps.store']) }} +
+
+

@lang('pireps.newflightreport')

+ @include('flash::message') + @if(!empty($pirep)) + wee + {{ Form::model($pirep, ['route' => 'frontend.pireps.store']) }} + @else + {{ Form::open(['route' => 'frontend.pireps.store']) }} + @endif - @include('pireps.fields') + @include('pireps.fields') - {{ Form::close() }} -
+ {{ Form::close() }}
+
@endsection @include('pireps.scripts') diff --git a/resources/views/layouts/default/pireps/fields.blade.php b/resources/views/layouts/default/pireps/fields.blade.php index 1209e8ea..e23ccb84 100644 --- a/resources/views/layouts/default/pireps/fields.blade.php +++ b/resources/views/layouts/default/pireps/fields.blade.php @@ -9,323 +9,326 @@ flight reports that have been filed. You've been warned! --}} @if(!empty($pirep) && $pirep->read_only) -
-
- @component('components.info') - @lang('pireps.fieldsreadonly') - @endcomponent -
+
+
+ @component('components.info') + @lang('pireps.fieldsreadonly') + @endcomponent
+
@endif
-
-
-
-  @lang('pireps.flightinformations') -
-
-
-
- {{ Form::label('airline_id', __('common.airline')) }} - @if(!empty($pirep) && $pirep->read_only) -

{{ $pirep->airline->name }}

- {{ Form::hidden('airline_id') }} - @else -
- {{ Form::select('airline_id', $airline_list, null, [ - 'class' => 'custom-select select2', - 'style' => 'width: 100%', - 'readonly' => (!empty($pirep) && $pirep->read_only), - ]) }} -
-

{{ $errors->first('airline_id') }}

- @endif -
-
- {{ Form::label('flight_number', __('pireps.flightident')) }} - @if(!empty($pirep) && $pirep->read_only) -

{{ $pirep->ident }} - {{ Form::hidden('flight_number') }} - {{ Form::hidden('flight_code') }} - {{ Form::hidden('flight_leg') }} -

- @else -
- {{ Form::text('flight_number', null, [ - 'placeholder' => __('flights.flightnumber'), - 'class' => 'form-control', - 'readonly' => (!empty($pirep) && $pirep->read_only), - ]) }} -   - {{ Form::text('route_code', null, [ - 'placeholder' => __('pireps.codeoptional'), - 'class' => 'form-control', - 'readonly' => (!empty($pirep) && $pirep->read_only), - ]) }} -   - {{ Form::text('route_leg', null, [ - 'placeholder' => __('pireps.legoptional'), - 'class' => 'form-control', - 'readonly' => (!empty($pirep) && $pirep->read_only), - ]) }} -
-

{{ $errors->first('flight_number') }}

-

{{ $errors->first('route_code') }}

-

{{ $errors->first('route_leg') }}

- @endif -
-
- {{ Form::label('flight_type', __('flights.flighttype')) }} - @if(!empty($pirep) && $pirep->read_only) -

{{ \App\Models\Enums\FlightType::label($pirep->flight_type) }}

- {{ Form::hidden('flight_type') }} - @else -
- {{ Form::select('flight_type', - \App\Models\Enums\FlightType::select(), null, [ - 'class' => 'custom-select select2', - 'style' => 'width: 100%', - 'readonly' => (!empty($pirep) && $pirep->read_only), - ]) - }} -
-

{{ $errors->first('flight_type') }}

- @endif -
-
- -
-
- {{ Form::label('hours', __('flights.flighttime')) }} - @if(!empty($pirep) && $pirep->read_only) -

- {{ $pirep->hours.' '.trans_choice('common.hour', $pirep->hours) }}, {{ $pirep->minutes.' '.trans_choice('common.minute', $pirep->minutes) }} - {{ Form::hidden('hours') }} - {{ Form::hidden('minutes') }} -

- @else -
- {{ Form::number('hours', null, [ - 'class' => 'form-control', - 'placeholder' => trans_choice('common.hour', 2), - 'min' => '0', - 'readonly' => (!empty($pirep) && $pirep->read_only), - ]) }} - - {{ Form::number('minutes', null, [ - 'class' => 'form-control', - 'placeholder' => trans_choice('common.minute', 2), - 'min' => 0, - 'readonly' => (!empty($pirep) && $pirep->read_only), - ]) }} -
-

{{ $errors->first('hours') }}

-

{{ $errors->first('minutes') }}

- @endif -
-
-
+
+
+
+  @lang('pireps.flightinformations') +
+
+
+
+ {{ Form::label('airline_id', __('common.airline')) }} + @if(!empty($pirep) && $pirep->read_only) +

{{ $pirep->airline->name }}

+ {{ Form::hidden('airline_id') }} + @else +
+ {{ Form::select('airline_id', $airline_list, null, [ + 'class' => 'custom-select select2', + 'style' => 'width: 100%', + 'readonly' => (!empty($pirep) && $pirep->read_only), + ]) }} +
+

{{ $errors->first('airline_id') }}

+ @endif +
+
+ {{ Form::label('flight_number', __('pireps.flightident')) }} + @if(!empty($pirep) && $pirep->read_only) +

{{ $pirep->ident }} + {{ Form::hidden('flight_number') }} + {{ Form::hidden('flight_code') }} + {{ Form::hidden('flight_leg') }} +

+ @else +
+ {{ Form::text('flight_number', null, [ + 'placeholder' => __('flights.flightnumber'), + 'class' => 'form-control', + 'readonly' => (!empty($pirep) && $pirep->read_only), + ]) }} +   + {{ Form::text('route_code', null, [ + 'placeholder' => __('pireps.codeoptional'), + 'class' => 'form-control', + 'readonly' => (!empty($pirep) && $pirep->read_only), + ]) }} +   + {{ Form::text('route_leg', null, [ + 'placeholder' => __('pireps.legoptional'), + 'class' => 'form-control', + 'readonly' => (!empty($pirep) && $pirep->read_only), + ]) }} +
+

{{ $errors->first('flight_number') }}

+

{{ $errors->first('route_code') }}

+

{{ $errors->first('route_leg') }}

+ @endif +
+
+ {{ Form::label('flight_type', __('flights.flighttype')) }} + @if(!empty($pirep) && $pirep->read_only) +

{{ \App\Models\Enums\FlightType::label($pirep->flight_type) }}

+ {{ Form::hidden('flight_type') }} + @else +
+ {{ Form::select('flight_type', + \App\Models\Enums\FlightType::select(), null, [ + 'class' => 'custom-select select2', + 'style' => 'width: 100%', + 'readonly' => (!empty($pirep) && $pirep->read_only), + ]) + }} +
+

{{ $errors->first('flight_type') }}

+ @endif +
+
+
+ {{ Form::label('hours', __('flights.flighttime')) }} + @if(!empty($pirep) && $pirep->read_only) +

+ {{ $pirep->hours.' '.trans_choice('common.hour', $pirep->hours) }} + , {{ $pirep->minutes.' '.trans_choice('common.minute', $pirep->minutes) }} + {{ Form::hidden('hours') }} + {{ Form::hidden('minutes') }} +

+ @else +
+ {{ Form::number('hours', null, [ + 'class' => 'form-control', + 'placeholder' => trans_choice('common.hour', 2), + 'min' => '0', + 'readonly' => (!empty($pirep) && $pirep->read_only), + ]) }} -
-
-  @lang('pireps.deparrinformations') -
-
-
-
- {{ Form::label('dpt_airport_id', __('airports.departure')) }} - @if(!empty($pirep) && $pirep->read_only) - {{ $pirep->dpt_airport->name }} - ({{ $errors->first('hours') }}

+

{{ $errors->first('minutes') }}

+ @endif +
+
+
+
+ + +
+
+  @lang('pireps.deparrinformations') +
+
+
+
+ {{ Form::label('dpt_airport_id', __('airports.departure')) }} + @if(!empty($pirep) && $pirep->read_only) + {{ $pirep->dpt_airport->name }} + ({{$pirep->dpt_airport->icao}}) - {{ Form::hidden('dpt_airport_id') }} - @else -
- {{ Form::select('dpt_airport_id', $airport_list, null, [ - 'class' => 'custom-select select2', - 'style' => 'width: 100%', - 'readonly' => (!empty($pirep) && $pirep->read_only), - ]) }} -
-

{{ $errors->first('dpt_airport_id') }}

- @endif -
+ {{ Form::hidden('dpt_airport_id') }} + @else +
+ {{ Form::select('dpt_airport_id', $airport_list, null, [ + 'class' => 'custom-select select2', + 'style' => 'width: 100%', + 'readonly' => (!empty($pirep) && $pirep->read_only), + ]) }} +
+

{{ $errors->first('dpt_airport_id') }}

+ @endif +
-
- {{ Form::label('arr_airport_id', __('airports.arrival')) }} - @if(!empty($pirep) && $pirep->read_only) - {{ $pirep->arr_airport->name }} - ( + {{ Form::label('arr_airport_id', __('airports.arrival')) }} + @if(!empty($pirep) && $pirep->read_only) + {{ $pirep->arr_airport->name }} + ({{$pirep->arr_airport->icao}}) - {{ Form::hidden('arr_airport_id') }} - @else -
- {{ Form::select('arr_airport_id', $airport_list, null, [ - 'class' => 'custom-select select2', - 'style' => 'width: 100%', - 'readonly' => (!empty($pirep) && $pirep->read_only), - ]) }} -
-

{{ $errors->first('arr_airport_id') }}

- @endif -
-
-
-
- -
-
-  @lang('pireps.aircraftinformations') -
-
-
-
- {{ Form::label('aircraft_id', __('common.aircraft')) }} - @if(!empty($pirep) && $pirep->read_only) -

{{ $pirep->aircraft->name }}

- {{ Form::hidden('aircraft_id') }} - @else -
- {{-- You probably don't want to change this ID if you want the fare select to work --}} - {{ Form::select('aircraft_id', $aircraft_list, null, [ - 'id' => 'aircraft_select', - 'class' => 'custom-select select2', - 'readonly' => (!empty($pirep) && $pirep->read_only), - ]) }} -
-

{{ $errors->first('aircraft_id') }}

- @endif -
-
- {{ Form::label('block_fuel', __('pireps.block_fuel')) }} ({{config('phpvms.internal_units.fuel')}}) - @if(!empty($pirep) && $pirep->read_only) -

{{ $pirep->block_fuel }}

- @else -
- {{ Form::number('block_fuel', null, [ - 'class' => 'form-control', - 'min' => '0', - 'step' => '0.01', - 'readonly' => (!empty($pirep) && $pirep->read_only), - ]) }} -
-

{{ $errors->first('block_fuel') }}

- @endif -
-
- {{ Form::label('fuel_used', __('pireps.fuel_used')) }} ({{config('phpvms.internal_units.fuel')}}) - @if(!empty($pirep) && $pirep->read_only) -

{{ $pirep->fuel_used }}

- @else -
- {{ Form::number('fuel_used', null, [ - 'class' => 'form-control', - 'min' => '0', - 'step' => '0.01', - 'readonly' => (!empty($pirep) && $pirep->read_only), - ]) }} -
-

{{ $errors->first('fuel_used') }}

- @endif -
-
-
-
- -
- @include('pireps.fares') -
- -
-
-  @lang('flights.route') -
-
-
-
-
- {{ Form::textarea('route', null, [ - 'class' => 'form-control', - 'placeholder' => __('flights.route'), - 'readonly' => (!empty($pirep) && $pirep->read_only), - ]) }} -

{{ $errors->first('route') }}

-
-
-
-
-
- -
-
-  {{ trans_choice('common.remark', 2) }} -
-
-
-
-
- {{ Form::textarea('notes', null, ['class' => 'form-control', 'placeholder' => trans_choice('common.note', 2)]) }} -

{{ $errors->first('notes') }}

-
-
-
-
+ {{ Form::hidden('arr_airport_id') }} + @else +
+ {{ Form::select('arr_airport_id', $airport_list, null, [ + 'class' => 'custom-select select2', + 'style' => 'width: 100%', + 'readonly' => (!empty($pirep) && $pirep->read_only), + ]) }} +
+

{{ $errors->first('arr_airport_id') }}

+ @endif +
+
- {{-- - Write out the custom fields, and label if they're required - --}} -
-
-
-  {{ trans_choice('common.field', 2) }} -
-
- @if(isset($pirep) && $pirep->fields) - @each('pireps.custom_fields', $pirep->fields, 'field') - @else - @each('pireps.custom_fields', $pirep_fields, 'field') - @endif -
+
+
+  @lang('pireps.aircraftinformations') +
+
+
+
+ {{ Form::label('aircraft_id', __('common.aircraft')) }} + @if(!empty($pirep) && $pirep->read_only) +

{{ $pirep->aircraft->name }}

+ {{ Form::hidden('aircraft_id') }} + @else +
+ {{-- You probably don't want to change this ID if you want the fare select to work --}} + {{ Form::select('aircraft_id', $aircraft_list, null, [ + 'id' => 'aircraft_select', + 'class' => 'custom-select select2', + 'readonly' => (!empty($pirep) && $pirep->read_only), + ]) }} +
+

{{ $errors->first('aircraft_id') }}

+ @endif +
+
+ {{ Form::label('block_fuel', __('pireps.block_fuel')) }} ({{config('phpvms.internal_units.fuel')}}) + @if(!empty($pirep) && $pirep->read_only) +

{{ $pirep->block_fuel }}

+ @else +
+ {{ Form::number('block_fuel', null, [ + 'class' => 'form-control', + 'min' => '0', + 'step' => '0.01', + 'readonly' => (!empty($pirep) && $pirep->read_only), + ]) }} +
+

{{ $errors->first('block_fuel') }}

+ @endif +
+
+ {{ Form::label('fuel_used', __('pireps.fuel_used')) }} ({{config('phpvms.internal_units.fuel')}}) + @if(!empty($pirep) && $pirep->read_only) +

{{ $pirep->fuel_used }}

+ @else +
+ {{ Form::number('fuel_used', null, [ + 'class' => 'form-control', + 'min' => '0', + 'step' => '0.01', + 'readonly' => (!empty($pirep) && $pirep->read_only), + ]) }} +
+

{{ $errors->first('fuel_used') }}

+ @endif +
+
+ +
+ @include('pireps.fares') +
+ +
+
+  @lang('flights.route') +
+
+
+
+
+ {{ Form::textarea('route', null, [ + 'class' => 'form-control', + 'placeholder' => __('flights.route'), + 'readonly' => (!empty($pirep) && $pirep->read_only), + ]) }} +

{{ $errors->first('route') }}

+
+
+
+
+
+ +
+
+  {{ trans_choice('common.remark', 2) }} +
+
+
+
+
+ {{ Form::textarea('notes', null, ['class' => 'form-control', 'placeholder' => trans_choice('common.note', 2)]) }} +

{{ $errors->first('notes') }}

+
+
+
+
+
+
+ + {{-- + Write out the custom fields, and label if they're required + --}} +
+
+
+  {{ trans_choice('common.field', 2) }} +
+
+ @if(isset($pirep) && $pirep->fields) + @each('pireps.custom_fields', $pirep->fields, 'field') + @else + @each('pireps.custom_fields', $pirep_fields, 'field') + @endif +
+
+
-
-
-
+
+
+
- @if(isset($pirep) && !$pirep->read_only) - {{ Form::button(__('pireps.deletepirep'), [ - 'name' => 'submit', - 'value' => 'Delete', - 'class' => 'btn btn-warning', - 'type' => 'submit']) - }} - @endif + {{ Form::hidden('flight_id') }} - {{ Form::button(__('pireps.savepirep'), [ - 'name' => 'submit', - 'value' => 'Save', - 'class' => 'btn btn-info', - 'type' => 'submit']) - }} + @if(isset($pirep) && !$pirep->read_only) + {{ Form::button(__('pireps.deletepirep'), [ + 'name' => 'submit', + 'value' => 'Delete', + 'class' => 'btn btn-warning', + 'type' => 'submit']) + }} + @endif - @if(!isset($pirep) || (filled($pirep) && !$pirep->read_only)) - {{ Form::button(__('pireps.submitpirep'), [ - 'name' => 'submit', - 'value' => 'Submit', - 'class' => 'btn btn-success', - 'type' => 'submit']) - }} - @endif -
-
+ {{ Form::button(__('pireps.savepirep'), [ + 'name' => 'submit', + 'value' => 'Save', + 'class' => 'btn btn-info', + 'type' => 'submit']) + }} + + @if(!isset($pirep) || (filled($pirep) && !$pirep->read_only)) + {{ Form::button(__('pireps.submitpirep'), [ + 'name' => 'submit', + 'value' => 'Submit', + 'class' => 'btn btn-success', + 'type' => 'submit']) + }} + @endif +
+
diff --git a/tests/BidTest.php b/tests/BidTest.php new file mode 100644 index 00000000..5a202785 --- /dev/null +++ b/tests/BidTest.php @@ -0,0 +1,212 @@ +addData('base'); + + $this->bidSvc = app(BidService::class); + $this->flightSvc = app(FlightService::class); + $this->settingsRepo = app(SettingRepository::class); + } + + public function addFlight($user) + { + $flight = factory(App\Models\Flight::class)->create([ + 'airline_id' => $user->airline_id, + ]); + + $flight->subfleets()->syncWithoutDetaching([ + factory(App\Models\Subfleet::class)->create([ + 'airline_id' => $user->airline_id, + ])->id, + ]); + + return $flight; + } + + /** + * Add/remove a bid, test the API, etc + * + * @throws \App\Services\Exception + */ + public function testBids() + { + $this->settingsRepo->store('bids.allow_multiple_bids', true); + $this->settingsRepo->store('bids.disable_flight_on_bid', false); + + $user = factory(User::class)->create(); + $user2 = factory(User::class)->create(); + $headers = $this->headers($user); + + $flight = $this->addFlight($user); + + $bid = $this->bidSvc->addBid($flight, $user); + $this->assertEquals($user->id, $bid->user_id); + $this->assertEquals($flight->id, $bid->flight_id); + $this->assertTrue($flight->has_bid); + + // Refresh + $flight = Flight::find($flight->id); + $this->assertTrue($flight->has_bid); + + // Check the table and make sure the entry is there + $bid_retrieved = $this->bidSvc->addBid($flight, $user); + $this->assertEquals($bid->id, $bid_retrieved->id); + + $user->refresh(); + $bids = $user->bids; + $this->assertEquals(1, $bids->count()); + + // Query the API and see that the user has the bids + // And pull the flight details for the user/bids + $req = $this->get('/api/user', $headers); + $req->assertStatus(200); + + $body = $req->json()['data']; + $this->assertCount(1, $body['bids']); + $this->assertEquals($flight->id, $body['bids'][0]['flight_id']); + + $req = $this->get('/api/users/'.$user->id.'/bids', $headers); + + $body = $req->json()['data']; + $req->assertStatus(200); + $this->assertEquals($flight->id, $body[0]['flight_id']); + + // have a second user bid on it + $bid_user2 = $this->bidSvc->addBid($flight, $user2); + $this->assertNotNull($bid_user2); + $this->assertNotEquals($bid_retrieved->id, $bid_user2->id); + + // Now remove the flight and check API + + $this->bidSvc->removeBid($flight, $user); + + $flight = Flight::find($flight->id); + + // user2 still has a bid on it + $this->assertTrue($flight->has_bid); + + // Remove it from 2nd user + $this->bidSvc->removeBid($flight, $user2); + $flight->refresh(); + $this->assertFalse($flight->has_bid); + + $user->refresh(); + $bids = $user->bids()->get(); + $this->assertTrue($bids->isEmpty()); + + $req = $this->get('/api/user', $headers); + $req->assertStatus(200); + + $body = $req->json()['data']; + $this->assertEquals($user->id, $body['id']); + $this->assertCount(0, $body['bids']); + + $req = $this->get('/api/users/'.$user->id.'/bids', $headers); + $req->assertStatus(200); + $body = $req->json()['data']; + + $this->assertCount(0, $body); + } + + public function testMultipleBidsSingleFlight() + { + $this->settingsRepo->store('bids.disable_flight_on_bid', true); + + $user1 = factory(User::class)->create(); + $user2 = factory(User::class)->create([ + 'airline_id' => $user1->airline_id, + ]); + + $flight = $this->addFlight($user1); + + // Put bid on the flight to block it off + $this->bidSvc->addBid($flight, $user1); + + // Try adding again, should throw an exception + $this->expectException(\App\Exceptions\BidExistsForFlight::class); + $this->bidSvc->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); + $body = $body->json('data'); + + $this->assertEquals($body['flight_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); + } + + /** + * Delete a flight and make sure all the bids are gone + */ + public function testDeleteFlightWithBids() + { + $user = factory(User::class)->create(); + $headers = $this->headers($user); + + $flight = $this->addFlight($user); + + $bid = $this->bidSvc->addBid($flight, $user); + $this->assertEquals($user->id, $bid->user_id); + $this->assertEquals($flight->id, $bid->flight_id); + $this->assertTrue($flight->has_bid); + + $this->flightSvc->deleteFlight($flight); + + $empty_flight = Flight::find($flight->id); + $this->assertNull($empty_flight); + + // Make sure no bids exist + $user_bids_count = Bid::where(['flight_id' => $flight->id])->count(); + $this->assertEquals(0, $user_bids_count); + + // Query the API and see that the user has the bids + // And pull the flight details for the user/bids + $req = $this->get('/api/user', $headers); + $req->assertStatus(200); + + $body = $req->json()['data']; + $this->assertEquals($user->id, $body['id']); + $this->assertCount(0, $body['bids']); + + $req = $this->get('/api/users/'.$user->id.'/bids', $headers); + $req->assertStatus(200); + + $body = $req->json()['data']; + $this->assertCount(0, $body); + } +} diff --git a/tests/FlightTest.php b/tests/FlightTest.php index 7fc31306..3e087473 100644 --- a/tests/FlightTest.php +++ b/tests/FlightTest.php @@ -1,6 +1,5 @@ assertCount(1, $found); } - /** - * Add/remove a bid, test the API, etc - * - * @throws \App\Services\Exception - */ - public function testBids() - { - $this->settingsRepo->store('bids.allow_multiple_bids', true); - $this->settingsRepo->store('bids.disable_flight_on_bid', false); - - $user = factory(User::class)->create(); - $user2 = factory(User::class)->create(); - $headers = $this->headers($user); - - $flight = $this->addFlight($user); - - $bid = $this->flightSvc->addBid($flight, $user); - $this->assertEquals($user->id, $bid->user_id); - $this->assertEquals($flight->id, $bid->flight_id); - $this->assertTrue($flight->has_bid); - - // Refresh - $flight = Flight::find($flight->id); - $this->assertTrue($flight->has_bid); - - // Check the table and make sure the entry is there - $bid_retrieved = $this->flightSvc->addBid($flight, $user); - $this->assertEquals($bid->id, $bid_retrieved->id); - - $user->refresh(); - $bids = $user->bids; - $this->assertEquals(1, $bids->count()); - - // Query the API and see that the user has the bids - // And pull the flight details for the user/bids - $req = $this->get('/api/user', $headers); - $req->assertStatus(200); - - $body = $req->json()['data']; - $this->assertCount(1, $body['bids']); - $this->assertEquals($flight->id, $body['bids'][0]['flight_id']); - - $req = $this->get('/api/users/'.$user->id.'/bids', $headers); - - $body = $req->json()['data']; - $req->assertStatus(200); - $this->assertEquals($flight->id, $body[0]['flight_id']); - - // have a second user bid on it - $bid_user2 = $this->flightSvc->addBid($flight, $user2); - $this->assertNotNull($bid_user2); - $this->assertNotEquals($bid_retrieved->id, $bid_user2->id); - - // Now remove the flight and check API - - $this->flightSvc->removeBid($flight, $user); - - $flight = Flight::find($flight->id); - - // user2 still has a bid on it - $this->assertTrue($flight->has_bid); - - // Remove it from 2nd user - $this->flightSvc->removeBid($flight, $user2); - $flight->refresh(); - $this->assertFalse($flight->has_bid); - - $user->refresh(); - $bids = $user->bids()->get(); - $this->assertTrue($bids->isEmpty()); - - $req = $this->get('/api/user', $headers); - $req->assertStatus(200); - - $body = $req->json()['data']; - $this->assertEquals($user->id, $body['id']); - $this->assertCount(0, $body['bids']); - - $req = $this->get('/api/users/'.$user->id.'/bids', $headers); - $req->assertStatus(200); - $body = $req->json()['data']; - - $this->assertCount(0, $body); - } - - public function testMultipleBidsSingleFlight() - { - $this->settingsRepo->store('bids.disable_flight_on_bid', true); - - $user1 = factory(User::class)->create(); - $user2 = factory(User::class)->create([ - 'airline_id' => $user1->airline_id, - ]); - - $flight = $this->addFlight($user1); - - // Put bid on the flight to block it off - $this->flightSvc->addBid($flight, $user1); - - // Try adding again, should throw an exception - $this->expectException(\App\Exceptions\BidExistsForFlight::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); - $body = $body->json('data'); - - $this->assertEquals($body['flight_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); - } - /** * Delete a flight and make sure all the bids are gone */ public function testDeleteFlight() { $user = factory(User::class)->create(); - $headers = $this->headers($user); $flight = $this->addFlight($user); - - $bid = $this->flightSvc->addBid($flight, $user); - $this->assertEquals($user->id, $bid->user_id); - $this->assertEquals($flight->id, $bid->flight_id); - $this->assertTrue($flight->has_bid); - $this->flightSvc->deleteFlight($flight); $empty_flight = Flight::find($flight->id); $this->assertNull($empty_flight); - - // Make sure no bids exist - $user_bids = Bid::where('flight_id', $flight->id)->get(); - - //$this->assertEquals(0, $user_bid->count()); - - // Query the API and see that the user has the bids - // And pull the flight details for the user/bids - $req = $this->get('/api/user', $headers); - $req->assertStatus(200); - - $body = $req->json()['data']; - $this->assertEquals($user->id, $body['id']); - $this->assertCount(0, $body['bids']); - - $req = $this->get('/api/users/'.$user->id.'/bids', $headers); - $req->assertStatus(200); - - $body = $req->json()['data']; - $this->assertCount(0, $body); } public function testAirportDistance() diff --git a/tests/PIREPTest.php b/tests/PIREPTest.php index 771a1054..622a64fa 100644 --- a/tests/PIREPTest.php +++ b/tests/PIREPTest.php @@ -7,6 +7,7 @@ use App\Models\Enums\PirepState; use App\Models\Pirep; use App\Models\User; use App\Repositories\SettingRepository; +use App\Services\BidService; use App\Services\FlightService; use App\Services\PirepService; use Carbon\Carbon; @@ -358,6 +359,7 @@ class PIREPTest extends TestCase */ public function testPirepBidRemoved() { + $bidSvc = app(BidService::class); $flightSvc = app(FlightService::class); $this->settingsRepo->store('pireps.remove_bid_on_accept', true); @@ -370,11 +372,12 @@ class PIREPTest extends TestCase 'route_leg' => null, ]); - $flightSvc->addBid($flight, $user); + $bidSvc->addBid($flight, $user); $pirep = factory(App\Models\Pirep::class)->create([ 'user_id' => $user->id, 'airline_id' => $flight->airline_id, + 'flight_id' => $flight->id, 'flight_number' => $flight->flight_number, ]);