From 52e716d6ee2993bdea1182fec8ab326066c6b1b2 Mon Sep 17 00:00:00 2001 From: "B.Fatih KOZ" Date: Tue, 30 Nov 2021 22:36:17 +0300 Subject: [PATCH] Type Ratings | New Feature (#1360) * Type Ratings Adding "Type Rating" definition and assignment possibility to v7 core. * Update ProfileController.php * StyleFix 1 * Update settings.yml Change description text as requested --- ...21_11_23_184532_add_type_rating_tables.php | 53 +++ app/Database/seeds/permissions.yml | 3 + app/Database/seeds/settings.yml | 9 +- .../Controllers/Admin/SubfleetController.php | 312 +++++++++++------- .../Admin/TypeRatingController.php | 168 ++++++++++ app/Http/Controllers/Admin/UserController.php | 110 +++++- .../Frontend/ProfileController.php | 2 +- .../Frontend/SimBriefController.php | 53 ++- app/Http/Requests/CreateTypeRatingRequest.php | 19 ++ app/Http/Requests/UpdateTypeRatingRequest.php | 19 ++ app/Models/Subfleet.php | 5 + app/Models/Typerating.php | 36 ++ app/Models/User.php | 16 +- app/Providers/RouteServiceProvider.php | 29 ++ app/Repositories/TypeRatingRepository.php | 43 +++ app/Services/FleetService.php | 30 ++ app/Services/UserService.php | 68 +++- composer.json | 3 +- composer.lock | 56 +++- resources/views/admin/menu.blade.php | 4 + .../views/admin/subfleets/edit.blade.php | 6 + .../views/admin/subfleets/script.blade.php | 6 + .../admin/subfleets/type_ratings.blade.php | 45 +++ .../views/admin/typeratings/create.blade.php | 12 + .../views/admin/typeratings/edit.blade.php | 26 ++ .../views/admin/typeratings/fields.blade.php | 45 +++ .../views/admin/typeratings/index.blade.php | 18 + .../views/admin/typeratings/scripts.blade.php | 48 +++ .../views/admin/typeratings/show.blade.php | 17 + .../admin/typeratings/show_fields.blade.php | 42 +++ .../admin/typeratings/subfleets.blade.php | 54 +++ .../views/admin/typeratings/table.blade.php | 26 ++ resources/views/admin/users/edit.blade.php | 10 + resources/views/admin/users/script.blade.php | 25 ++ .../views/admin/users/type_ratings.blade.php | 38 +++ 35 files changed, 1275 insertions(+), 181 deletions(-) create mode 100644 app/Database/migrations/2021_11_23_184532_add_type_rating_tables.php create mode 100644 app/Http/Controllers/Admin/TypeRatingController.php create mode 100644 app/Http/Requests/CreateTypeRatingRequest.php create mode 100644 app/Http/Requests/UpdateTypeRatingRequest.php create mode 100644 app/Models/Typerating.php create mode 100644 app/Repositories/TypeRatingRepository.php create mode 100644 resources/views/admin/subfleets/type_ratings.blade.php create mode 100644 resources/views/admin/typeratings/create.blade.php create mode 100644 resources/views/admin/typeratings/edit.blade.php create mode 100644 resources/views/admin/typeratings/fields.blade.php create mode 100644 resources/views/admin/typeratings/index.blade.php create mode 100644 resources/views/admin/typeratings/scripts.blade.php create mode 100644 resources/views/admin/typeratings/show.blade.php create mode 100644 resources/views/admin/typeratings/show_fields.blade.php create mode 100644 resources/views/admin/typeratings/subfleets.blade.php create mode 100644 resources/views/admin/typeratings/table.blade.php create mode 100644 resources/views/admin/users/script.blade.php create mode 100644 resources/views/admin/users/type_ratings.blade.php diff --git a/app/Database/migrations/2021_11_23_184532_add_type_rating_tables.php b/app/Database/migrations/2021_11_23_184532_add_type_rating_tables.php new file mode 100644 index 00000000..e3623e25 --- /dev/null +++ b/app/Database/migrations/2021_11_23_184532_add_type_rating_tables.php @@ -0,0 +1,53 @@ +increments('id'); + $table->string('name'); + $table->string('type'); + $table->string('description')->nullable(); + $table->string('image_url')->nullable(); + $table->boolean('active')->default(true); + $table->timestamps(); + + $table->unique('id'); + $table->unique('name'); + }); + } + + if (!Schema::hasTable('typerating_user')) { + Schema::create('typerating_user', function (Blueprint $table) { + $table->unsignedInteger('typerating_id'); + $table->unsignedInteger('user_id'); + + $table->primary(['typerating_id', 'user_id']); + $table->index(['typerating_id', 'user_id']); + }); + } + + if (!Schema::hasTable('typerating_subfleet')) { + Schema::create('typerating_subfleet', function (Blueprint $table) { + $table->unsignedInteger('typerating_id'); + $table->unsignedInteger('subfleet_id'); + + $table->primary(['typerating_id', 'subfleet_id']); + $table->index(['typerating_id', 'subfleet_id']); + }); + } + } + + public function down() + { + Schema::dropIfExists('typeratings'); + Schema::dropIfExists('typerating_user'); + Schema::dropIfExists('typerating_subfleet'); + } +} diff --git a/app/Database/seeds/permissions.yml b/app/Database/seeds/permissions.yml index 091d1bd7..3c4394e9 100644 --- a/app/Database/seeds/permissions.yml +++ b/app/Database/seeds/permissions.yml @@ -42,6 +42,9 @@ - name: ranks display_name: Ranks description: Create/edit ranks +- name: typeratings + display_name: Type Ratings + description: Create/edit type ratings - name: users display_name: Users description: Create/edit users diff --git a/app/Database/seeds/settings.yml b/app/Database/seeds/settings.yml index 1fd39257..168f4771 100644 --- a/app/Database/seeds/settings.yml +++ b/app/Database/seeds/settings.yml @@ -283,7 +283,14 @@ value: true options: '' type: boolean - description: 'Aircraft that can be flown are restricted to a user''s rank' + description: 'Aircraft restricted to user''s rank' +- key: pireps.restrict_aircraft_to_typerating + name: 'Restrict Aircraft by Type Ratings' + group: pireps + value: false + options: '' + type: boolean + description: 'Aircraft restricted to user type ratings' - key: pireps.only_aircraft_at_dpt_airport name: 'Restrict Aircraft At Departure' group: pireps diff --git a/app/Http/Controllers/Admin/SubfleetController.php b/app/Http/Controllers/Admin/SubfleetController.php index b1ff4caa..3410ca03 100644 --- a/app/Http/Controllers/Admin/SubfleetController.php +++ b/app/Http/Controllers/Admin/SubfleetController.php @@ -17,6 +17,7 @@ use App\Repositories\AircraftRepository; use App\Repositories\FareRepository; use App\Repositories\RankRepository; use App\Repositories\SubfleetRepository; +use App\Repositories\TypeRatingRepository; use App\Services\ExportService; use App\Services\FareService; use App\Services\FleetService; @@ -36,26 +37,29 @@ class SubfleetController extends Controller private $importSvc; private $rankRepo; private $subfleetRepo; + private $typeratingRepo; /** * SubfleetController constructor. * - * @param AircraftRepository $aircraftRepo - * @param FleetService $fleetSvc - * @param FareRepository $fareRepo - * @param FareService $fareSvc - * @param ImportService $importSvc - * @param RankRepository $rankRepo - * @param SubfleetRepository $subfleetRepo + * @param AircraftRepository $aircraftRepo + * @param FareRepository $fareRepo + * @param FareService $fareSvc + * @param FleetService $fleetSvc + * @param ImportService $importSvc + * @param RankRepository $rankRepo + * @param SubfleetRepository $subfleetRepo + * @param TypeRatingRepository $typeratingRepo */ public function __construct( AircraftRepository $aircraftRepo, - FleetService $fleetSvc, FareRepository $fareRepo, FareService $fareSvc, + FleetService $fleetSvc, ImportService $importSvc, RankRepository $rankRepo, - SubfleetRepository $subfleetRepo + SubfleetRepository $subfleetRepo, + TypeRatingRepository $typeratingRepo ) { $this->aircraftRepo = $aircraftRepo; $this->fareRepo = $fareRepo; @@ -64,48 +68,7 @@ class SubfleetController extends Controller $this->importSvc = $importSvc; $this->rankRepo = $rankRepo; $this->subfleetRepo = $subfleetRepo; - } - - /** - * Get the ranks that are available to the subfleet - * - * @param $subfleet - * - * @return array - */ - protected function getAvailRanks($subfleet) - { - $retval = []; - $all_ranks = $this->rankRepo->all(); - $avail_ranks = $all_ranks->except($subfleet->ranks->modelKeys()); - foreach ($avail_ranks as $rank) { - $retval[$rank->id] = $rank->name; - } - - return $retval; - } - - /** - * Get all the fares that haven't been assigned to a given subfleet - * - * @param mixed $subfleet - * - * @return array - */ - protected function getAvailFares($subfleet) - { - $retval = []; - $all_fares = $this->fareRepo->all(); - $avail_fares = $all_fares->except($subfleet->fares->modelKeys()); - foreach ($avail_fares as $fare) { - $retval[$fare->id] = $fare->name. - ' (price: '.$fare->price. - ', type: '.FareType::label($fare->type). - ', cost: '.$fare->cost. - ', capacity: '.$fare->capacity.')'; - } - - return $retval; + $this->typeratingRepo = $typeratingRepo; } /** @@ -152,8 +115,8 @@ class SubfleetController extends Controller { $input = $request->all(); $subfleet = $this->subfleetRepo->create($input); - Flash::success('Subfleet saved successfully.'); + return redirect(route('admin.subfleets.edit', [$subfleet->id])); } @@ -172,10 +135,12 @@ class SubfleetController extends Controller if (empty($subfleet)) { Flash::error('Subfleet not found'); + return redirect(route('admin.subfleets.index')); } $avail_fares = $this->getAvailFares($subfleet); + return view('admin.subfleets.show', [ 'subfleet' => $subfleet, 'avail_fares' => $avail_fares, @@ -192,24 +157,27 @@ class SubfleetController extends Controller public function edit($id) { $subfleet = $this->subfleetRepo - ->with(['fares', 'ranks']) + ->with(['fares', 'ranks', 'typeratings']) ->findWithoutFail($id); if (empty($subfleet)) { Flash::error('Subfleet not found'); + return redirect(route('admin.subfleets.index')); } $avail_fares = $this->getAvailFares($subfleet); $avail_ranks = $this->getAvailRanks($subfleet); + $avail_ratings = $this->getAvailTypeRatings($subfleet); return view('admin.subfleets.edit', [ - 'airlines' => Airline::all()->pluck('name', 'id'), - 'hubs' => Airport::where('hub', 1)->pluck('name', 'id'), - 'fuel_types' => FuelType::labels(), - 'avail_fares' => $avail_fares, - 'avail_ranks' => $avail_ranks, - 'subfleet' => $subfleet, + 'airlines' => Airline::all()->pluck('name', 'id'), + 'hubs' => Airport::where('hub', 1)->pluck('name', 'id'), + 'fuel_types' => FuelType::labels(), + 'avail_fares' => $avail_fares, + 'avail_ranks' => $avail_ranks, + 'avail_ratings' => $avail_ratings, + 'subfleet' => $subfleet, ]); } @@ -229,12 +197,13 @@ class SubfleetController extends Controller if (empty($subfleet)) { Flash::error('Subfleet not found'); + return redirect(route('admin.subfleets.index')); } $this->subfleetRepo->update($request->all(), $id); - Flash::success('Subfleet updated successfully.'); + return redirect(route('admin.subfleets.index')); } @@ -251,6 +220,7 @@ class SubfleetController extends Controller if (empty($subfleet)) { Flash::error('Subfleet not found'); + return redirect(route('admin.subfleets.index')); } @@ -259,12 +229,13 @@ class SubfleetController extends Controller $aircraft = $this->aircraftRepo->findWhere(['subfleet_id' => $id], ['id']); if ($aircraft->count() > 0) { Flash::error('There are aircraft still assigned to this subfleet, you can\'t delete it!')->important(); + return redirect(route('admin.subfleets.index')); } $this->subfleetRepo->delete($id); - Flash::success('Subfleet deleted successfully.'); + return redirect(route('admin.subfleets.index')); } @@ -281,11 +252,8 @@ class SubfleetController extends Controller $subfleets = $this->subfleetRepo->all(); $path = $exporter->exportSubfleets($subfleets); - return response() - ->download($path, 'subfleets.csv', [ - 'content-type' => 'text/csv', - ]) - ->deleteFileAfterSend(true); + + return response()->download($path, 'subfleets.csv', ['content-type' => 'text/csv'])->deleteFileAfterSend(true); } /** @@ -312,77 +280,64 @@ class SubfleetController extends Controller } /** - * @param Subfleet $subfleet + * Get all the fares that haven't been assigned to a given subfleet * - * @return mixed + * @param mixed $subfleet + * + * @return array */ - protected function return_ranks_view(?Subfleet $subfleet) + protected function getAvailFares($subfleet) { - $subfleet->refresh(); + $retval = []; + $all_fares = $this->fareRepo->all(); + $avail_fares = $all_fares->except($subfleet->fares->modelKeys()); + foreach ($avail_fares as $fare) { + $retval[$fare->id] = $fare->name. + ' (price: '.$fare->price. + ', type: '.FareType::label($fare->type). + ', cost: '.$fare->cost. + ', capacity: '.$fare->capacity.')'; + } - $avail_ranks = $this->getAvailRanks($subfleet); - return view('admin.subfleets.ranks', [ - 'subfleet' => $subfleet, - 'avail_ranks' => $avail_ranks, - ]); + return $retval; } /** - * @param Subfleet $subfleet + * Get the ranks that are available to the subfleet * - * @return mixed + * @param $subfleet + * + * @return array */ - protected function return_fares_view(?Subfleet $subfleet) + protected function getAvailRanks($subfleet) { - $subfleet->refresh(); + $retval = []; + $all_ranks = $this->rankRepo->all(); + $avail_ranks = $all_ranks->except($subfleet->ranks->modelKeys()); + foreach ($avail_ranks as $rank) { + $retval[$rank->id] = $rank->name; + } - $avail_fares = $this->getAvailFares($subfleet); - return view('admin.subfleets.fares', [ - 'subfleet' => $subfleet, - 'avail_fares' => $avail_fares, - ]); + return $retval; } /** - * Operations for associating ranks to the subfleet + * Get the type ratings that are available to the subfleet * - * @param $id - * @param Request $request + * @param $subfleet * - * @return mixed + * @return array */ - public function ranks($id, Request $request) + protected function getAvailTypeRatings($subfleet) { - $subfleet = $this->subfleetRepo->findWithoutFail($id); - if (empty($subfleet)) { - return $this->return_ranks_view($subfleet); + $retval = []; + $all_ratings = $this->typeratingRepo->all(); + $avail_ratings = $all_ratings->except($subfleet->typeratings->modelKeys()); + foreach ($avail_ratings as $tr) { + $retval[$tr->id] = $tr->name.' ('.$tr->type.')'; } - if ($request->isMethod('get')) { - return $this->return_ranks_view($subfleet); - } - - /* - * update specific rank data - */ - if ($request->isMethod('post')) { - $rank = $this->rankRepo->find($request->input('rank_id')); - $this->fleetSvc->addSubfleetToRank($subfleet, $rank); - } elseif ($request->isMethod('put')) { - $override = []; - $rank = $this->rankRepo->find($request->input('rank_id')); - $override[$request->name] = $request->value; - - $this->fleetSvc->addSubfleetToRank($subfleet, $rank, $override); - } // dissassociate fare from teh aircraft - elseif ($request->isMethod('delete')) { - $rank = $this->rankRepo->find($request->input('rank_id')); - $this->fleetSvc->removeSubfleetFromRank($subfleet, $rank); - } - - $subfleet->save(); - - return $this->return_ranks_view($subfleet); + return $retval; } /** @@ -398,6 +353,54 @@ class SubfleetController extends Controller ]); } + /** + * @param Subfleet $subfleet + * + * @return mixed + */ + protected function return_fares_view(?Subfleet $subfleet) + { + $subfleet->refresh(); + $avail_fares = $this->getAvailFares($subfleet); + + return view('admin.subfleets.fares', [ + 'subfleet' => $subfleet, + 'avail_fares' => $avail_fares, + ]); + } + + /** + * @param Subfleet $subfleet + * + * @return mixed + */ + protected function return_ranks_view(?Subfleet $subfleet) + { + $subfleet->refresh(); + $avail_ranks = $this->getAvailRanks($subfleet); + + return view('admin.subfleets.ranks', [ + 'subfleet' => $subfleet, + 'avail_ranks' => $avail_ranks, + ]); + } + + /** + * @param Subfleet $subfleet + * + * @return mixed + */ + protected function return_typeratings_view(?Subfleet $subfleet) + { + $subfleet->refresh(); + $avail_ratings = $this->getAvailTypeRatings($subfleet); + + return view('admin.subfleets.type_ratings', [ + 'subfleet' => $subfleet, + 'avail_ratings' => $avail_ratings, + ]); + } + /** * Operations for associating ranks to the subfleet * @@ -479,4 +482,79 @@ class SubfleetController extends Controller return $this->return_fares_view($subfleet); } + + /** + * Operations for associating ranks to the subfleet + * + * @param $id + * @param Request $request + * + * @return mixed + */ + public function ranks($id, Request $request) + { + $subfleet = $this->subfleetRepo->findWithoutFail($id); + if (empty($subfleet)) { + return $this->return_ranks_view($subfleet); + } + + if ($request->isMethod('get')) { + return $this->return_ranks_view($subfleet); + } + + // associate rank with the subfleet + if ($request->isMethod('post')) { + $rank = $this->rankRepo->find($request->input('rank_id')); + $this->fleetSvc->addSubfleetToRank($subfleet, $rank); + } // override definitions + elseif ($request->isMethod('put')) { + $override = []; + $rank = $this->rankRepo->find($request->input('rank_id')); + $override[$request->name] = $request->value; + + $this->fleetSvc->addSubfleetToRank($subfleet, $rank, $override); + } // dissassociate rank from the subfleet + elseif ($request->isMethod('delete')) { + $rank = $this->rankRepo->find($request->input('rank_id')); + $this->fleetSvc->removeSubfleetFromRank($subfleet, $rank); + } + + $subfleet->save(); + + return $this->return_ranks_view($subfleet); + } + + /** + * Operations for associating type ratings to the subfleet + * + * @param $id + * @param Request $request + * + * @return mixed + */ + public function typeratings($id, Request $request) + { + $subfleet = $this->subfleetRepo->findWithoutFail($id); + if (empty($subfleet)) { + return $this->return_typeratings_view($subfleet); + } + + if ($request->isMethod('get')) { + return $this->return_typeratings_view($subfleet); + } + + // associate subfleet with type rating + if ($request->isMethod('post')) { + $typerating = $this->typeratingRepo->find($request->input('typerating_id')); + $this->fleetSvc->addSubfleetToTypeRating($subfleet, $typerating); + } // dissassociate subfleet from the type rating + elseif ($request->isMethod('delete')) { + $typerating = $this->typeratingRepo->find($request->input('typerating_id')); + $this->fleetSvc->removeSubfleetFromTypeRating($subfleet, $typerating); + } + + $subfleet->save(); + + return $this->return_typeratings_view($subfleet); + } } diff --git a/app/Http/Controllers/Admin/TypeRatingController.php b/app/Http/Controllers/Admin/TypeRatingController.php new file mode 100644 index 00000000..dbe4f630 --- /dev/null +++ b/app/Http/Controllers/Admin/TypeRatingController.php @@ -0,0 +1,168 @@ +fleetSvc = $fleetSvc; + $this->subfleetRepo = $subfleetRepo; + $this->typeratingRepo = $typeratingRepo; + } + + public function index(Request $request) + { + $this->typeratingRepo->pushCriteria(new RequestCriteria($request)); + $typeratings = $this->typeratingRepo->all(); + + return view('admin.typeratings.index', [ + 'typeratings' => $typeratings, + ]); + } + + public function create() + { + return view('admin.typeratings.create'); + } + + public function store(CreateTypeRatingRequest $request) + { + $input = $request->all(); + + $model = $this->typeratingRepo->create($input); + Flash::success('Type Rating saved successfully.'); + // Cache::forget(config('cache.keys.RANKS_PILOT_LIST.key')); + + return redirect(route('admin.typeratings.edit', [$model->id])); + } + + public function show($id) + { + $typerating = $this->typeratingRepo->findWithoutFail($id); + + if (empty($typerating)) { + Flash::error('Type Rating not found'); + + return redirect(route('admin.typeratings.index')); + } + + return view('admin.typeratings.show', [ + 'typerating' => $typerating, + ]); + } + + public function edit($id) + { + $typerating = $this->typeratingRepo->findWithoutFail($id); + + if (empty($typerating)) { + Flash::error('Type Rating not found'); + + return redirect(route('admin.typeratings.index')); + } + + $avail_subfleets = $this->getAvailSubfleets($typerating); + + return view('admin.typeratings.edit', [ + 'typerating' => $typerating, + 'avail_subfleets' => $avail_subfleets, + ]); + } + + public function update($id, UpdateTypeRatingRequest $request) + { + $typerating = $this->typeratingRepo->findWithoutFail($id); + + if (empty($typerating)) { + Flash::error('Type Rating not found'); + + return redirect(route('admin.typeratings.index')); + } + + $typerating = $this->typeratingRepo->update($request->all(), $id); + // Cache::forget(config('cache.keys.RANKS_PILOT_LIST.key')); + Flash::success('Type Rating updated successfully.'); + + return redirect(route('admin.typeratings.index')); + } + + public function destroy($id) + { + $typerating = $this->typeratingRepo->findWithoutFail($id); + + if (empty($typerating)) { + Flash::error('Type Rating not found'); + + return redirect(route('admin.typeratings.index')); + } + + $this->typeratingRepo->delete($id); + + Flash::success('Type Rating deleted successfully.'); + + return redirect(route('admin.typeratings.index')); + } + + protected function getAvailSubfleets($typerating) + { + $retval = []; + $all_subfleets = $this->subfleetRepo->all(); + $avail_subfleets = $all_subfleets->except($typerating->subfleets->modelKeys()); + foreach ($avail_subfleets as $subfleet) { + $retval[$subfleet->id] = $subfleet->name.' (Airline: '.$subfleet->airline->code.')'; + } + + return $retval; + } + + protected function return_subfleet_view($typerating) + { + $avail_subfleets = $this->getAvailSubfleets($typerating); + + return view('admin.typeratings.subfleets', [ + 'typerating' => $typerating, + 'avail_subfleets' => $avail_subfleets, + ]); + } + + public function subfleets($id, Request $request) + { + $typerating = $this->typeratingRepo->findWithoutFail($id); + if (empty($typerating)) { + Flash::error('Type Rating not found!'); + return redirect(route('admin.typeratings.index')); + } + + // add subfleet to type rating + if ($request->isMethod('post')) { + $subfleet = $this->subfleetRepo->find($request->input('subfleet_id')); + $this->fleetSvc->addSubfleetToTypeRating($subfleet, $typerating); + } + // remove subfleet from type rating + elseif ($request->isMethod('delete')) { + $subfleet = $this->subfleetRepo->find($request->input('subfleet_id')); + $this->fleetSvc->removeSubfleetFromTypeRating($subfleet, $typerating); + } + + return $this->return_subfleet_view($typerating); + } +} diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index c139949d..7cf2119a 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -12,6 +12,7 @@ use App\Repositories\AirlineRepository; use App\Repositories\AirportRepository; use App\Repositories\PirepRepository; use App\Repositories\RoleRepository; +use App\Repositories\TypeRatingRepository; use App\Repositories\UserRepository; use App\Services\UserService; use App\Support\Timezonelist; @@ -30,24 +31,27 @@ class UserController extends Controller private $airportRepo; private $pirepRepo; private $roleRepo; + private $typeratingRepo; private $userRepo; private $userSvc; /** * UserController constructor. * - * @param AirlineRepository $airlineRepo - * @param AirportRepository $airportRepo - * @param PirepRepository $pirepRepo - * @param RoleRepository $roleRepo - * @param UserRepository $userRepo - * @param UserService $userSvc + * @param AirlineRepository $airlineRepo + * @param AirportRepository $airportRepo + * @param PirepRepository $pirepRepo + * @param RoleRepository $roleRepo + * @param TypeRatingRepository $typeratingRepo + * @param UserRepository $userRepo + * @param UserService $userSvc */ public function __construct( AirlineRepository $airlineRepo, AirportRepository $airportRepo, PirepRepository $pirepRepo, RoleRepository $roleRepo, + TypeRatingRepository $typeratingRepo, UserRepository $userRepo, UserService $userSvc ) { @@ -55,6 +59,7 @@ class UserController extends Controller $this->airportRepo = $airportRepo; $this->pirepRepo = $pirepRepo; $this->roleRepo = $roleRepo; + $this->typeratingRepo = $typeratingRepo; $this->userSvc = $userSvc; $this->userRepo = $userRepo; } @@ -149,7 +154,7 @@ class UserController extends Controller public function edit($id) { $user = $this->userRepo - ->with(['awards', 'fields', 'rank']) + ->with(['awards', 'fields', 'rank', 'typeratings']) ->findWithoutFail($id); if (empty($user)) { @@ -169,17 +174,19 @@ class UserController extends Controller $airlines = $this->airlineRepo->selectBoxList(); $airports = $this->airportRepo->selectBoxList(false); $roles = $this->roleRepo->selectBoxList(false, true); + $avail_ratings = $this->getAvailTypeRatings($user); return view('admin.users.edit', [ - 'user' => $user, - 'pireps' => $pireps, - 'country' => new ISO3166(), - 'countries' => $countries, - 'timezones' => Timezonelist::toArray(), - 'airports' => $airports, - 'airlines' => $airlines, - 'ranks' => Rank::all()->pluck('name', 'id'), - 'roles' => $roles, + 'user' => $user, + 'pireps' => $pireps, + 'country' => new ISO3166(), + 'countries' => $countries, + 'timezones' => Timezonelist::toArray(), + 'airports' => $airports, + 'airlines' => $airlines, + 'ranks' => Rank::all()->pluck('name', 'id'), + 'roles' => $roles, + 'avail_ratings' => $avail_ratings, ]); } @@ -260,6 +267,7 @@ class UserController extends Controller $user = $this->userRepo->findWithoutFail($id); if (empty($user)) { Flash::error('User not found'); + return redirect(route('admin.users.index')); } @@ -283,6 +291,7 @@ class UserController extends Controller $userAward = UserAward::where(['user_id' => $id, 'award_id' => $award_id]); if (empty($userAward)) { Flash::error('The user award could not be found'); + return redirect()->back(); } @@ -311,4 +320,73 @@ class UserController extends Controller return redirect(route('admin.users.edit', [$id])); } + + /** + * Get the type ratings that are available to the user + * + * @param $user + * + * @return array + */ + protected function getAvailTypeRatings($user) + { + $retval = []; + $all_ratings = $this->typeratingRepo->all(); + $avail_ratings = $all_ratings->except($user->typeratings->modelKeys()); + foreach ($avail_ratings as $tr) { + $retval[$tr->id] = $tr->name.' ('.$tr->type.')'; + } + + return $retval; + } + + /** + * @param User $user + * + * @return mixed + */ + protected function return_typeratings_view(?User $user) + { + $user->refresh(); + + $avail_ratings = $this->getAvailTypeRatings($user); + return view('admin.users.type_ratings', [ + 'user' => $user, + 'avail_ratings' => $avail_ratings, + ]); + } + + /** + * Operations for associating type ratings to the user + * + * @param $id + * @param Request $request + * + * @return mixed + */ + public function typeratings($id, Request $request) + { + $user = $this->userRepo->findWithoutFail($id); + if (empty($user)) { + return $this->return_typeratings_view($user); + } + + if ($request->isMethod('get')) { + return $this->return_typeratings_view($user); + } + + // associate user with type rating + if ($request->isMethod('post')) { + $typerating = $this->typeratingRepo->find($request->input('typerating_id')); + $this->userSvc->addUserToTypeRating($user, $typerating); + } // dissassociate user from the type rating + elseif ($request->isMethod('delete')) { + $typerating = $this->typeratingRepo->find($request->input('typerating_id')); + $this->userSvc->removeUserFromTypeRating($user, $typerating); + } + + $user->save(); + + return $this->return_typeratings_view($user); + } } diff --git a/app/Http/Controllers/Frontend/ProfileController.php b/app/Http/Controllers/Frontend/ProfileController.php index a08ead38..1d374f68 100644 --- a/app/Http/Controllers/Frontend/ProfileController.php +++ b/app/Http/Controllers/Frontend/ProfileController.php @@ -80,7 +80,7 @@ class ProfileController extends Controller public function show($id) { /** @var \App\Models\User $user */ - $with = ['airline', 'awards', 'current_airport', 'fields.field', 'home_airport', 'last_pirep', 'rank']; + $with = ['airline', 'awards', 'current_airport', 'fields.field', 'home_airport', 'last_pirep', 'rank', 'typeratings']; $user = User::with($with)->where('id', $id)->first(); if (empty($user)) { diff --git a/app/Http/Controllers/Frontend/SimBriefController.php b/app/Http/Controllers/Frontend/SimBriefController.php index a664e15d..9d234f95 100644 --- a/app/Http/Controllers/Frontend/SimBriefController.php +++ b/app/Http/Controllers/Frontend/SimBriefController.php @@ -80,46 +80,39 @@ class SimBriefController // No aircraft selected, show selection form if (!$aircraft_id) { - // If no subfleets defined for flight get them from user - if ($flight->subfleets->count() > 0) { - $subfleets = $flight->subfleets; - } else { - $subfleets = $this->userSvc->getAllowableSubfleets($user); - } - // Build an array of subfleet id's from the subfleets collection - $sf_ids = $subfleets->map(function ($subfleets) { - return collect($subfleets->toArray()) - ->only(['id']) - ->all(); - }); + // Get user's allowed subfleets and intersect it with flight subfleets + // so we will have a proper list which the user is allowed to fly + $user_subfleets = $this->userSvc->getAllowableSubfleets($user)->pluck('id')->toArray(); + $flight_subfleets = $flight->subfleets->pluck('id')->toArray(); - // Now we can build a proper aircrafts collection - // Contents will be either members of flight->subfleets - // or members of user's allowable subfleets - $aircrafts = Aircraft::whereIn('subfleet_id', $sf_ids) - ->where('state', AircraftState::PARKED) - ->where('status', AircraftStatus::ACTIVE) - ->orderby('icao') - ->orderby('registration') - ->get(); + $subfleet_ids = filled($flight_subfleets) ? array_intersect($user_subfleets, $flight_subfleets) : $user_subfleets; + + // Prepare variables for single aircraft query + $where = []; + $where['state'] = AircraftState::PARKED; + $where['status'] = AircraftStatus::ACTIVE; if (setting('pireps.only_aircraft_at_dpt_airport')) { - $aircrafts = $aircrafts->where('airport_id', $flight->dpt_airport_id); + $where['airport_id'] = $flight->dpt_airport_id; } - if (setting('simbrief.block_aircraft')) { - // Build a list of aircraft_id's being used for active sb packs - $sb_aircraft = SimBrief::whereNotNull('flight_id')->pluck('aircraft_id'); + $withCount = ['simbriefs' => function ($query) { + $query->whereNull('pirep_id'); + }]; - // Filter aircraft list to non used/blocked ones - $aircrafts = $aircrafts->whereNotIn('id', $sb_aircraft); - } + // Build proper aircraft collection considering all possible settings + // Flight subfleets, user subfleet restrictions, pirep restrictions, simbrief blocking etc + $aircraft = Aircraft::withCount($withCount)->where($where) + ->when(setting('simbrief.block_aircraft'), function ($query) { + return $query->having('simbriefs_count', 0); + })->whereIn('subfleet_id', $subfleet_ids) + ->orderby('icao')->orderby('registration') + ->get(); return view('flights.simbrief_aircraft', [ 'flight' => $flight, - 'aircrafts' => $aircrafts, - 'subfleets' => $subfleets, + 'aircrafts' => $aircraft, ]); } diff --git a/app/Http/Requests/CreateTypeRatingRequest.php b/app/Http/Requests/CreateTypeRatingRequest.php new file mode 100644 index 00000000..16ff3b96 --- /dev/null +++ b/app/Http/Requests/CreateTypeRatingRequest.php @@ -0,0 +1,19 @@ +belongsToMany(Rank::class, 'subfleet_rank') ->withPivot('acars_pay', 'manual_pay'); } + + public function typeratings() + { + return $this->belongsToMany(Typerating::class, 'typerating_subfleet', 'subfleet_id', 'typerating_id'); + } } diff --git a/app/Models/Typerating.php b/app/Models/Typerating.php new file mode 100644 index 00000000..e68a0c39 --- /dev/null +++ b/app/Models/Typerating.php @@ -0,0 +1,36 @@ + 'required', + 'type' => 'required', + 'description' => 'nullable', + 'image_url' => 'nullable', + ]; + + // Relationships + public function subfleets() + { + return $this->belongsToMany(Subfleet::class, 'typerating_subfleet', 'typerating_id', 'subfleet_id'); + } + + public function users() + { + return $this->belongsToMany(User::class, 'typerating_user', 'typerating_id', 'user_id'); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 639c1e7d..e135220c 100755 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -7,6 +7,7 @@ use App\Models\Traits\JournalTrait; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laratrust\Traits\LaratrustUserTrait; +use Staudenmeir\EloquentHasManyDeep\HasRelationships; /** * @property int id @@ -42,6 +43,7 @@ use Laratrust\Traits\LaratrustUserTrait; * @property UserFieldValue[] fields * @property Role[] roles * @property Subfleet[] subfleets + * @property TypeRating[] typeratings * * @mixin \Illuminate\Database\Eloquent\Builder * @mixin \Illuminate\Notifications\Notifiable @@ -52,6 +54,7 @@ class User extends Authenticatable use JournalTrait; use LaratrustUserTrait; use Notifiable; + use HasRelationships; public $table = 'users'; @@ -191,8 +194,7 @@ class User extends Authenticatable { $default = config('gravatar.default'); - $uri = config('gravatar.url') - .md5(strtolower(trim($this->email))).'?d='.urlencode($default); + $uri = config('gravatar.url').md5(strtolower(trim($this->email))).'?d='.urlencode($default); if ($size !== null) { $uri .= '&s='.$size; @@ -265,4 +267,14 @@ class User extends Authenticatable { return $this->belongsTo(Rank::class, 'rank_id'); } + + public function typeratings() + { + return $this->belongsToMany(Typerating::class, 'typerating_user', 'user_id', 'typerating_id'); + } + + public function rated_subfleets() + { + return $this->hasManyDeep(Subfleet::class, ['typerating_user', Typerating::class, 'typerating_subfleet']); + } } diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 09330fa0..1241abb5 100755 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -376,6 +376,21 @@ class RouteServiceProvider extends ServiceProvider ], 'settings', 'SettingsController@update') ->name('settings.update')->middleware('ability:admin,settings'); + // Type Ratings + Route::resource('typeratings', 'TypeRatingController')->middleware('ability:admin,typeratings'); + Route::match([ + 'get', + 'post', + 'put', + 'delete', + ], 'typeratings/{id}/subfleets', 'TypeRatingController@subfleets')->middleware('ability:admin,typeratings'); + Route::match([ + 'get', + 'post', + 'put', + 'delete', + ], 'typeratings/{id}/users', 'TypeRatingController@users')->middleware('ability:admin,typeratings'); + // maintenance Route::match(['get'], 'maintenance', 'MaintenanceController@index') ->name('maintenance.index')->middleware('ability:admin,maintenance'); @@ -426,6 +441,13 @@ class RouteServiceProvider extends ServiceProvider 'delete', ], 'subfleets/{id}/ranks', 'SubfleetController@ranks')->middleware('ability:admin,fleet'); + Route::match([ + 'get', + 'post', + 'put', + 'delete', + ], 'subfleets/{id}/typeratings', 'SubfleetController@typeratings')->middleware('ability:admin,fleet'); + Route::resource('subfleets', 'SubfleetController')->middleware('ability:admin,fleet'); /** @@ -439,6 +461,13 @@ class RouteServiceProvider extends ServiceProvider Route::resource('users', 'UserController')->middleware('ability:admin,users'); + Route::match([ + 'get', + 'post', + 'put', + 'delete', + ], 'users/{id}/typeratings', 'UserController@typeratings')->middleware('ability:admin,users'); + // defaults Route::get('', ['uses' => 'DashboardController@index']) ->middleware('update_pending', 'ability:admin,admin-access'); diff --git a/app/Repositories/TypeRatingRepository.php b/app/Repositories/TypeRatingRepository.php new file mode 100644 index 00000000..f47faf79 --- /dev/null +++ b/app/Repositories/TypeRatingRepository.php @@ -0,0 +1,43 @@ + 'like', + 'type' => 'like', + ]; + + public function model() + { + return Typerating::class; + } + + public function selectBoxList($add_blank = false, $only_active = true): array + { + $retval = []; + $where = [ + 'active' => $only_active, + ]; + + $items = $this->findWhere($where); + + if ($add_blank) { + $retval[''] = ''; + } + + foreach ($items as $i) { + $retval[$i->id] = $i->name; + } + + return $retval; + } +} diff --git a/app/Services/FleetService.php b/app/Services/FleetService.php index 2b07a938..fc0e55b6 100644 --- a/app/Services/FleetService.php +++ b/app/Services/FleetService.php @@ -6,6 +6,7 @@ use App\Contracts\Service; use App\Models\Flight; use App\Models\Rank; use App\Models\Subfleet; +use App\Models\Typerating; class FleetService extends Service { @@ -33,7 +34,36 @@ class FleetService extends Service public function removeSubfleetFromRank(Subfleet $subfleet, Rank $rank) { $subfleet->ranks()->detach($rank->id); + $subfleet->save(); + $subfleet->refresh(); + return $subfleet; + } + + /** + * Add the subfleet to a type rating + * + * @param Subfleet $subfleet + * @param Typerating $typerating + */ + public function addSubfleetToTypeRating(Subfleet $subfleet, Typerating $typerating) + { + $subfleet->typeratings()->syncWithoutDetaching([$typerating->id]); + $subfleet->save(); + $subfleet->refresh(); + + return $subfleet; + } + + /** + * Remove the subfleet from a type rating + * + * @param Subfleet $subfleet + * @param Typerating $typerating + */ + public function removeSubfleetFromTypeRating(Subfleet $subfleet, Typerating $typerating) + { + $subfleet->typeratings()->detach($typerating->id); $subfleet->save(); $subfleet->refresh(); diff --git a/app/Services/UserService.php b/app/Services/UserService.php index 5ab2fd97..bd6afb0a 100644 --- a/app/Services/UserService.php +++ b/app/Services/UserService.php @@ -15,6 +15,7 @@ use App\Models\Enums\UserState; use App\Models\Pirep; use App\Models\Rank; use App\Models\Role; +use App\Models\Typerating; use App\Models\User; use App\Models\UserFieldValue; use App\Repositories\AircraftRepository; @@ -343,7 +344,7 @@ class UserService extends Service /** * Return the subfleets this user is allowed access to, - * based on their current rank + * based on their current Rank and/or by Type Rating * * @param $user * @@ -351,14 +352,31 @@ class UserService extends Service */ public function getAllowableSubfleets($user) { - if ($user === null || setting('pireps.restrict_aircraft_to_rank') === false) { - /** @var Collection $subfleets */ - $subfleets = $this->subfleetRepo->with('aircraft')->all(); + $restrict_rank = setting('pireps.restrict_aircraft_to_rank', true); + $restrict_type = setting('pireps.restrict_aircraft_to_typerating', false); + $restricted_to = []; + + if ($user) { + $rank_sf_array = $restrict_rank ? $user->rank->subfleets()->pluck('id')->toArray() : []; + $type_sf_array = $restrict_type ? $user->rated_subfleets->pluck('id')->toArray() : []; + + if ($restrict_rank && !$restrict_type) { + $restricted_to = $rank_sf_array; + } elseif (!$restrict_rank && $restrict_type) { + $restricted_to = $type_sf_array; + } elseif ($restrict_rank && $restrict_type) { + $restricted_to = array_intersect($rank_sf_array, $type_sf_array); + } } else { - /** @var Collection $subfleets */ - $subfleets = $user->rank->subfleets()->with('aircraft')->get(); + $restrict_rank = false; + $restrict_type = false; } + // @var Collection $subfleets + $subfleets = $this->subfleetRepo->when(($restrict_rank || $restrict_type), function ($query) use ($restricted_to) { + return $query->whereIn('id', $restricted_to); + })->with('aircraft')->get(); + // Map the subfleets with the proper fare information return $subfleets->transform(function ($sf, $key) { $sf->fares = $this->fareSvc->getForSubfleet($sf); @@ -398,9 +416,7 @@ class UserService extends Service return $user; } - Log::info('User '.$user->ident.' state changing from ' - .UserState::label($old_state).' to ' - .UserState::label($user->state)); + Log::info('User '.$user->ident.' state changing from '.UserState::label($old_state).' to '.UserState::label($user->state)); event(new UserStateChanged($user, $old_state)); @@ -561,11 +577,39 @@ class UserService extends Service // Recalc the rank $this->calculatePilotRank($user); - Log::info('User '.$user->ident.' updated; pirep count='.$pirep_count - .', rank='.$user->rank->name - .', flight_time='.$user->flight_time.' minutes'); + Log::info('User '.$user->ident.' updated; pirep count='.$pirep_count.', rank='.$user->rank->name.', flight_time='.$user->flight_time.' minutes'); $user->save(); return $user; } + + /** + * Attach a type rating to the user + * + * @param User $user + * @param Typerating $typerating + */ + public function addUserToTypeRating(User $user, Typerating $typerating) + { + $user->typeratings()->syncWithoutDetaching([$typerating->id]); + $user->save(); + $user->refresh(); + + return $user; + } + + /** + * Detach a type rating from the user + * + * @param User $user + * @param Typerating $typerating + */ + public function removeUserFromTypeRating(User $user, Typerating $typerating) + { + $user->typeratings()->detach($typerating->id); + $user->save(); + $user->refresh(); + + return $user; + } } diff --git a/composer.json b/composer.json index 36ec9103..8828093a 100755 --- a/composer.json +++ b/composer.json @@ -70,7 +70,8 @@ "queueworker/sansdaemon": "^1.2", "jpkleemans/attribute-events": "^1.1", "akaunting/laravel-money": "^1.2", - "staudenmeir/belongs-to-through": "^2.5" + "staudenmeir/belongs-to-through": "^2.5", + "staudenmeir/eloquent-has-many-deep": "1.14.3" }, "require-dev": { "barryvdh/laravel-debugbar": "^3.5", diff --git a/composer.lock b/composer.lock index 1f37fcf5..424df990 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "da29c23dc7b0e9f9c4939bbb2fc8359e", + "content-hash": "10a632e92b328969dad32f4d0dcbc65f", "packages": [ { "name": "akaunting/laravel-money", @@ -6524,6 +6524,60 @@ ], "time": "2021-08-19T18:23:06+00:00" }, + { + "name": "staudenmeir/eloquent-has-many-deep", + "version": "v1.14.3", + "source": { + "type": "git", + "url": "https://github.com/staudenmeir/eloquent-has-many-deep.git", + "reference": "c44115684aa831b2b74fec8440f6e811602186ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staudenmeir/eloquent-has-many-deep/zipball/c44115684aa831b2b74fec8440f6e811602186ed", + "reference": "c44115684aa831b2b74fec8440f6e811602186ed", + "shasum": "" + }, + "require": { + "illuminate/database": "^8.0", + "php": "^7.3|^8.0" + }, + "require-dev": { + "illuminate/pagination": "^8.0", + "laravel/homestead": "^11.0|^12.0", + "phpunit/phpunit": "^9.3", + "scrutinizer/ocular": "^1.8", + "staudenmeir/eloquent-eager-limit": "^1.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Staudenmeir\\EloquentHasManyDeep\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonas Staudenmeir", + "email": "mail@jonas-staudenmeir.de" + } + ], + "description": "Laravel Eloquent HasManyThrough relationships with unlimited levels", + "support": { + "issues": "https://github.com/staudenmeir/eloquent-has-many-deep/issues", + "source": "https://github.com/staudenmeir/eloquent-has-many-deep/tree/v1.14.3" + }, + "funding": [ + { + "url": "https://paypal.me/JonasStaudenmeir", + "type": "custom" + } + ], + "time": "2021-08-21T16:45:45+00:00" + }, { "name": "swiftmailer/swiftmailer", "version": "v6.3.0", diff --git a/resources/views/admin/menu.blade.php b/resources/views/admin/menu.blade.php index 5e199150..a7567d71 100644 --- a/resources/views/admin/menu.blade.php +++ b/resources/views/admin/menu.blade.php @@ -62,6 +62,10 @@
  • ranks
  • @endability + @ability('admin', 'typeratings') +
  • type ratings
  • + @endability + @ability('admin', 'awards')
  • awards
  • @endability diff --git a/resources/views/admin/subfleets/edit.blade.php b/resources/views/admin/subfleets/edit.blade.php index 4fd785b1..12df98c7 100644 --- a/resources/views/admin/subfleets/edit.blade.php +++ b/resources/views/admin/subfleets/edit.blade.php @@ -16,6 +16,12 @@ +
    +
    + @include('admin.subfleets.type_ratings') +
    +
    +
    @include('admin.subfleets.fares') diff --git a/resources/views/admin/subfleets/script.blade.php b/resources/views/admin/subfleets/script.blade.php index 01fcfe95..68e60c57 100644 --- a/resources/views/admin/subfleets/script.blade.php +++ b/resources/views/admin/subfleets/script.blade.php @@ -114,6 +114,12 @@ $.pjax.submit(event, '#subfleet_ranks_wrapper', {push: false}); }); + $(document).on('submit', 'form.modify_typerating', function (event) { + event.preventDefault(); + console.log(event); + $.pjax.submit(event, '#subfleet_typeratings_wrapper', {push: false}); + }); + $(document).on('submit', 'form.modify_expense', function (event) { event.preventDefault(); console.log(event); diff --git a/resources/views/admin/subfleets/type_ratings.blade.php b/resources/views/admin/subfleets/type_ratings.blade.php new file mode 100644 index 00000000..aac59e80 --- /dev/null +++ b/resources/views/admin/subfleets/type_ratings.blade.php @@ -0,0 +1,45 @@ +
    +
    +

    type ratings

    + @component('admin.components.info') + These type ratings are allowed to fly aircraft in this subfleet. + @endcomponent +
    +
    + + @if(count($subfleet->typeratings)) + + + + + + + + @endif + + @foreach($subfleet->typeratings as $tr) + + + + + + @endforeach + +
    TypeName
    {{ $tr->type }}{{ $tr->name }} + {{ Form::open(['url' => '/admin/subfleets/'.$subfleet->id.'/typeratings', 'method' => 'delete', 'class' => 'modify_typerating']) }} + {{ Form::hidden('typerating_id', $tr->id) }} + {{ Form::button('', ['type' => 'submit', 'class' => 'btn btn-sm btn-danger btn-icon']) }} + {{ Form::close() }} +
    +
    +
    +
    +
    + {{ Form::open(['url' => '/admin/subfleets/'.$subfleet->id.'/typeratings', 'method' => 'post', 'class' => 'modify_typerating form-inline']) }} + {{ Form::select('typerating_id', $avail_ratings, null, ['placeholder' => 'Select Type Rating', 'class' => 'ac-fare-dropdown form-control input-lg select2']) }} + {{ Form::button(' add', ['type' => 'submit', 'class' => 'btn btn-success btn-s']) }} + {{ Form::close() }} +
    +
    +
    +
    diff --git a/resources/views/admin/typeratings/create.blade.php b/resources/views/admin/typeratings/create.blade.php new file mode 100644 index 00000000..2a574794 --- /dev/null +++ b/resources/views/admin/typeratings/create.blade.php @@ -0,0 +1,12 @@ +@extends('admin.app') +@section('title', 'Add Type Rating') +@section('content') +
    +
    + {{ Form::open(['route' => 'admin.typeratings.store', 'class' => 'add_typerating', 'method'=>'POST', 'autocomplete' => false]) }} + @include('admin.typeratings.fields') + {{ Form::close() }} +
    +
    +@endsection +@include('admin.typeratings.scripts') diff --git a/resources/views/admin/typeratings/edit.blade.php b/resources/views/admin/typeratings/edit.blade.php new file mode 100644 index 00000000..c2e0c4a2 --- /dev/null +++ b/resources/views/admin/typeratings/edit.blade.php @@ -0,0 +1,26 @@ +@extends('admin.app') +@section('title', 'Edit '.$typerating->name) +@section('content') +
    +
    + {{ Form::model($typerating, ['route' => ['admin.typeratings.update', $typerating->id], 'method' => 'patch', 'autocomplete' => false]) }} + @include('admin.typeratings.fields') + {{ Form::close() }} +
    +
    + +
    +
    +
    +

    Subfleets

    + @component('admin.components.info') + These are the subfleets this type rating is allowed to use. + @endcomponent +
    +
    + @include('admin.typeratings.subfleets') +
    +
    +
    +@endsection +@include('admin.typeratings.scripts') diff --git a/resources/views/admin/typeratings/fields.blade.php b/resources/views/admin/typeratings/fields.blade.php new file mode 100644 index 00000000..beedc127 --- /dev/null +++ b/resources/views/admin/typeratings/fields.blade.php @@ -0,0 +1,45 @@ +
    +
    + {{ Form::label('name', 'Name:') }} + {{ Form::text('name', null, ['class' => 'form-control']) }} +

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

    +
    +
    + {{ Form::label('type', 'Type Code:') }} + {{ Form::text('type', null, ['class' => 'form-control']) }} +

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

    +
    +
    + +
    +
    + {{ Form::label('description', 'Description:') }} + {{ Form::text('description', null, ['class' => 'form-control']) }} +

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

    +
    +
    + {{ Form::label('image_url', 'Image Link:') }} + {{ Form::text('image_url', null, ['class' => 'form-control']) }} +

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

    +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    + {{ Form::button('Save', ['type' => 'submit', 'class' => 'btn btn-success']) }} +
    +
    +
    diff --git a/resources/views/admin/typeratings/index.blade.php b/resources/views/admin/typeratings/index.blade.php new file mode 100644 index 00000000..2925403c --- /dev/null +++ b/resources/views/admin/typeratings/index.blade.php @@ -0,0 +1,18 @@ +@extends('admin.app') +@section('title', 'Type Ratings') +@section('actions') +
  • + + + Add New + +
  • +@endsection + +@section('content') +
    +
    + @include('admin.typeratings.table') +
    +
    +@endsection diff --git a/resources/views/admin/typeratings/scripts.blade.php b/resources/views/admin/typeratings/scripts.blade.php new file mode 100644 index 00000000..4289161b --- /dev/null +++ b/resources/views/admin/typeratings/scripts.blade.php @@ -0,0 +1,48 @@ +@section('scripts') + +@endsection diff --git a/resources/views/admin/typeratings/show.blade.php b/resources/views/admin/typeratings/show.blade.php new file mode 100644 index 00000000..04520201 --- /dev/null +++ b/resources/views/admin/typeratings/show.blade.php @@ -0,0 +1,17 @@ +@extends('admin.app') + +@section('content') +
    +

    {{ $typerating->name }}

    +
    +
    +
    +
    +
    + @include('admin.typerating.show_fields') +
    +
    +
    +
    +@endsection +@include('admin.typerating.scripts') diff --git a/resources/views/admin/typeratings/show_fields.blade.php b/resources/views/admin/typeratings/show_fields.blade.php new file mode 100644 index 00000000..4009ae21 --- /dev/null +++ b/resources/views/admin/typeratings/show_fields.blade.php @@ -0,0 +1,42 @@ + +
    + {{ Form::label('id', 'Id:') }} +

    {{ $typerating->id }}

    +
    + + +
    + {{ Form::label('name', 'Name:') }} +

    {{ $typerating->name }}

    +
    + + +
    + {{ Form::label('type', 'Type Code:') }} +

    {{ $typerating->type }}

    +
    + + +
    + {{ Form::label('description', 'Description:') }} +

    {{ $typerating->description }}

    +
    + + +
    + {{ Form::label('image_url', 'Image URL:') }} +

    {{ $typerating->image_url }}

    +
    + + +
    + {{ Form::label('created_at', 'Created At:') }} +

    {{ show_datetime($typerating->created_at) }}

    +
    + + +
    + {{ Form::label('updated_at', 'Updated At:') }} +

    {{ show_datetime($typerating->updated_at) }}

    +
    + diff --git a/resources/views/admin/typeratings/subfleets.blade.php b/resources/views/admin/typeratings/subfleets.blade.php new file mode 100644 index 00000000..830e5507 --- /dev/null +++ b/resources/views/admin/typeratings/subfleets.blade.php @@ -0,0 +1,54 @@ +
    + @if(count($typerating->subfleets) === 0) + @include('admin.common.none_added', ['type' => 'subfleets']) + @endif + + + @if(count($typerating->subfleets)) + + + + + + @endif + + @foreach($typerating->subfleets as $sf) + + + + + + @endforeach + +
    AirlineNameActions
    {{ $sf->airline->name }}{{ $sf->name.' ('.$sf->type.')' }} + {{ Form::open(['url' => '/admin/typeratings/'.$typerating->id.'/subfleets', 'method' => 'delete', 'class' => 'pjax_form']) }} + {{ Form::hidden('subfleet_id', $sf->id) }} +
    + {{ Form::button('', + ['type' => 'submit', + 'class' => 'btn btn-sm btn-danger btn-icon']) + }} +
    + {{ Form::close() }} +
    +
    +
    +
    +
    + {{ Form::open(['url' => url('/admin/typeratings/'.$typerating->id.'/subfleets'), + 'method' => 'post', + 'class' => 'pjax_form form-inline' + ]) + }} + {{ Form::select('subfleet_id', $avail_subfleets, null, [ + 'placeholder' => 'Select Subfleet', + 'class' => 'select2 form-control input-lg']) + }} + {{ Form::button(' Add', + ['type' => 'submit', + 'class' => 'btn btn-success btn-small']) }} + {{ Form::close() }} +
    +
    +
    +
    diff --git a/resources/views/admin/typeratings/table.blade.php b/resources/views/admin/typeratings/table.blade.php new file mode 100644 index 00000000..39d7791e --- /dev/null +++ b/resources/views/admin/typeratings/table.blade.php @@ -0,0 +1,26 @@ +
    + + + + + + + + + @foreach($typeratings as $typerating) + + + + + + + @endforeach + +
    Type CodeNameDescription
    {{ $typerating->type }}{{ $typerating->name }}{{ $typerating->description }} + {{ Form::open(['route' => ['admin.typeratings.destroy', $typerating->id], 'method' => 'delete']) }} + + + {{ Form::button('', ['type' => 'submit', 'class' => 'btn btn-sm btn-danger btn-icon', 'onclick' => "return confirm('Are you sure?')"]) }} + {{ Form::close() }} +
    +
    diff --git a/resources/views/admin/users/edit.blade.php b/resources/views/admin/users/edit.blade.php index 1c7a737b..c0538dac 100644 --- a/resources/views/admin/users/edit.blade.php +++ b/resources/views/admin/users/edit.blade.php @@ -9,6 +9,15 @@
    +
    +
    +
    +

    Type Ratings

    +
    + @include('admin.users.type_ratings') +
    +
    +
    @@ -34,3 +43,4 @@
    @endsection +@include('admin.users.script') diff --git a/resources/views/admin/users/script.blade.php b/resources/views/admin/users/script.blade.php new file mode 100644 index 00000000..e26c4fbd --- /dev/null +++ b/resources/views/admin/users/script.blade.php @@ -0,0 +1,25 @@ +@section('scripts') + +@endsection diff --git a/resources/views/admin/users/type_ratings.blade.php b/resources/views/admin/users/type_ratings.blade.php new file mode 100644 index 00000000..b3b23d37 --- /dev/null +++ b/resources/views/admin/users/type_ratings.blade.php @@ -0,0 +1,38 @@ +
    + + @if(count($user->typeratings)) + + + + + + + + @endif + + @foreach($user->typeratings as $tr) + + + + + + @endforeach + +
    TypeName
    {{ $tr->type }}{{ $tr->name }} + {{ Form::open(['url' => '/admin/users/'.$user->id.'/typeratings', 'method' => 'delete', 'class' => 'modify_typerating']) }} + {{ Form::hidden('typerating_id', $tr->id) }} + {{ Form::button('', ['type' => 'submit', 'class' => 'btn btn-sm btn-danger btn-icon']) }} + {{ Form::close() }} +
    +
    +
    +
    +
    + {{ Form::open(['url' => '/admin/users/'.$user->id.'/typeratings', 'method' => 'post', 'class' => 'modify_typerating form-inline']) }} + {{ Form::select('typerating_id', $avail_ratings, null, ['placeholder' => 'Select Type Rating', 'class' => 'ac-fare-dropdown form-control input-lg select2']) }} + {{ Form::button(' add', ['type' => 'submit', 'class' => 'btn btn-success btn-s']) }} + {{ Form::close() }} +
    +
    +
    +
    \ No newline at end of file