Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0419948
Create Vite alias for blades
kjporter Nov 16, 2025
ac8a690
Update error message images
kjporter Nov 16, 2025
1f3008c
Update pilot guide resources
kjporter Nov 16, 2025
9dd9fa3
Update footer resources
kjporter Nov 16, 2025
8d98352
Update landing page resources
kjporter Nov 16, 2025
2923b79
Update resource location
kjporter Nov 16, 2025
6470107
Remove unused graphics
kjporter Nov 16, 2025
0c426b6
Move assets and update path
kjporter Nov 17, 2025
4e4f160
Delete _1541188979.png
kjporter Nov 17, 2025
b0e40cd
Move assets and update path
kjporter Nov 17, 2025
0f45a12
Move assets and update path
kjporter Nov 17, 2025
19ff314
Move assets and update path
kjporter Nov 17, 2025
2fccef8
Remove unused assets
kjporter Nov 18, 2025
bbab8d6
Add img resource imports
kjporter Nov 18, 2025
84220c7
Merge branch 'main' into image-cleanup
kjporter Nov 18, 2025
bde923d
Update app.js
kjporter Nov 18, 2025
80b993c
Update RealopsFlight.php
kjporter Nov 18, 2025
39992f2
Vite image alias
kjporter Nov 18, 2025
db81f18
Fix logo asset checks
kjporter Nov 18, 2025
3e41102
Update footer.blade.php
kjporter Nov 18, 2025
5051a59
Update pilot_passport_certificate.blade.php
kjporter Nov 18, 2025
f11b6ee
Update package.json
kjporter Nov 19, 2025
368aaed
Revert "Update package.json"
kjporter Nov 19, 2025
10f8d04
Add Preferred Routes
kjporter Nov 28, 2025
7e04c99
Add Aircraft Types
kjporter Nov 28, 2025
c086983
Add Aircraft Types
kjporter Nov 28, 2025
122e5d8
Integrate Pre-File Logic
kjporter Nov 28, 2025
df529f5
Merge branch 'main' into realops-prefile-button
kjporter Dec 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions app/Aircraft.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Aircraft extends Model {
protected $table = "aircraft";
public $timestamps = false;
}
149 changes: 149 additions & 0 deletions app/Console/Commands/UpdateFAA.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?php
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please recreate from latest main, all of image cleanup is included


namespace App\Console\Commands;

use GuzzleHttp\Client;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\Console\Helper\ProgressIndicator;
use Symfony\Component\Console\Output\ConsoleOutput;

class UpdateFAA extends Command {
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'FAA:update-faa';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Updates FAA-specific datafiles';

const FAA_DATA_URL = 'https://www.fly.faa.gov/rmt/data_file/';
private $routes = [
[
'name' => 'PRD',
'model' => 'App\PreferredRoute',
'file' => 'prefroutes_db.csv'
]
];
private ProgressIndicator $progressIndicator;
private $path;

/**
* Execute the console command.
*/
public function handle() {
$this->info('Updating FAA-specific datafiles');
$this->path = Storage::disk('local')->path('private/');
$this->setup_progress_indicator();
$this->update_routes();
}

private function update_routes(): void {
foreach ($this->routes as $route) {
$route = (object) $route;
$this->progressIndicator->start("Fetching $route->name info from FAA server...");
$this->call_api(SELF::FAA_DATA_URL . $route->file, $this->path, strtolower($route->name) . '_new.csv');
$this->progressIndicator->finish("Fetching $route->name info from FAA server... done");

// Update table
$this->progressIndicator->start("Updating $route->name table...");
if (($handle = fopen($this->path . strtolower($route->name) . '_new.csv', "r")) !== false) {
$route->model::truncate();
while (($rte_line = fgetcsv($handle, null, ",")) !== false) {
if (!is_array($rte_line)) {
continue;
}
$bom = "\xef\xbb\xbf";
if (substr($rte_line[0], 0, 3) === $bom) {
$rte_line[0] = substr($rte_line[0], 3);
}
if ($rte_line[0] == 'RCode' || $rte_line[0] == 'Orig') { // It's the header line, skip it
continue;
}
if ($route->name == 'CDR') {
$load_arr = [
'route_code' => $rte_line[0],
'origin' => $rte_line[1],
'destination' => $rte_line[2],
'departure_fix' => substr($rte_line[3], 0, 5), // Enforce 5 characters
'route_string' => $rte_line[4],
'departure_center' => $rte_line[5],
'arrival_center' => $rte_line[6],
'transit_centers' => $rte_line[7],
'coordination_required' => $rte_line[8],
'play' => $rte_line[9],
'navigation_equipment' => $rte_line[10]
];
} else {
$load_arr = [
'orig' => $rte_line[0],
'route_string' => $rte_line[1],
'dest' => $rte_line[2],
'hours1' => $rte_line[3],
'hours2' => $rte_line[4],
'hours3' => $rte_line[5],
'type' => $rte_line[6],
'area' => $rte_line[7],
'altitude' => (is_numeric($rte_line[8])) ? $rte_line[8] : null,
'aircraft' => $rte_line[9],
'direction' => $rte_line[10],
'seq' => $rte_line[11],
'dcntr' => $rte_line[12],
'acntr' => $rte_line[13]
];
}
$route->model::create($load_arr);
$this->progressIndicator->advance();
}
fclose($handle);
}
$this->progressIndicator->finish("Updating $route->name table... done");

// Remove, rename file
$this->info("Removing unused local $route->name files");
if (file_exists($this->path . $route->name . '.csv')) {
unlink($this->path . $route->name . '.csv');
$this->info("- Deleted $route->name.csv");
}
if (file_exists($this->path . $route->name . '_new.csv')) {
rename($this->path . $route->name . '_new.csv', $this->path . $route->name . '.csv');
}
$this->info("$route->name file cleanup complete");
}
}

private function call_api($url, $path = null, $write_file = null): string|null {
$progress = $this->progressIndicator;
$write_to_filename = (is_null($write_file)) ? basename($url) : $write_file;
$client = new Client();
$response = $client->get($url, [
'config' => [
'curl' => [
'CURLOPT_RETURNTRANSFER' => true,
'CURLOPT_CONNECTTIMEOUT' => 3,
'CURLOPT_ENCODING' => 'gzip',
'CURLOPT_SSL_VERIFYPEER' => false
]
],
'progress' => function () use ($progress) {
$progress->advance();
},
'sink' => $path . $write_to_filename
]);
if ($response->getStatusCode() == 200) {
return $response->getBody();
}
return null;
}

private function setup_progress_indicator(): void {
$output = new ConsoleOutput;
$this->progressIndicator = new ProgressIndicator($output);
}
}
2 changes: 2 additions & 0 deletions app/Exports/RealopsExport.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public function headings(): array {
'Point of Arrival',
'Arrival Time',
'Gate',
'Aircraft Type',
'Pilot Name',
'Pilot CID',
'Pilot Email'
Expand All @@ -44,6 +45,7 @@ public function map($flight): array {
$flight->arr_airport,
$flight->est_time_enroute,
$flight->gate,
$flight->aircraft_type,
$pilot->full_name,
$flight->assigned_pilot_id,
$pilot->email
Expand Down
10 changes: 5 additions & 5 deletions app/Http/Controllers/RealopsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ class RealopsController extends Controller {
public function index(Request $request) {
$airport_filter = $request->get('airport_filter');
$flightno_filter = $request->get('flightno_filter');
$actype_filter = $request->get('actype_filter');
$date_filter = $request->get('date_filter');
$time_filter = $request->get('time_filter');

$flights = RealopsFlight::where('flight_number', 'like', '%' . $flightno_filter . '%')
->orWhere('callsign', 'like', '%' . $flightno_filter . '%')
->orWhere('aircraft_type', 'like', '%' . $actype_filter . '%')
->when(! is_null($time_filter), function ($query) use ($time_filter) {
$times = $this->timeBetween($time_filter, 15, 45);
$query->whereTime('dep_time', ">=", Carbon::parse($times[0]))
Expand All @@ -38,7 +40,7 @@ public function index(Request $request) {
->orderBy('dep_time', 'ASC')
->paginate(20);

return view('site.realops')->with('flights', $flights)->with('airport_filter', $airport_filter)->with('flightno_filter', $flightno_filter)->with('date_filter', $date_filter)->with('time_filter', $time_filter);
return view('site.realops', compact('flights', 'airport_filter', 'flightno_filter', 'actype_filter', 'date_filter', 'time_filter'));
}

public function bid($id) {
Expand Down Expand Up @@ -148,6 +150,7 @@ public function createFlight(Request $request) {
$flight->arr_airport = $request->input('arr_airport');
$flight->est_time_enroute = $request->input('est_time_enroute');
$flight->gate = $request->input('gate');
$flight->aircraft_type = $request->input('aircraft_type');
$flight->save();

return redirect('/dashboard/admin/realops')->with('success', 'That flight was created successfully');
Expand Down Expand Up @@ -187,6 +190,7 @@ public function editFlight(Request $request, $id) {
$flight->arr_airport = $request->input('arr_airport');
$flight->est_time_enroute = $request->input('est_time_enroute');
$flight->gate = $request->input('gate');
$flight->aircraft_type = $request->input('aircraft_type');
$flight->save();

$pilot = $flight->assigned_pilot;
Expand All @@ -204,17 +208,13 @@ public function bulkUploadFlights(Request $request) {
]);

try {
// what is this for?
// this doesn't do anything
//$contents = file_get_contents($request->file('file')->getRealPath());
Excel::import(new RealopsFlightImporter, request()->file('file'));
} catch (\Maatwebsite\Excel\Validators\ValidationException $e) {
$failures = $e->failures();

$errors = "";

foreach ($failures as $failure) {
// L21#0 Blah blah blah (value: 'fbalsdhj')
Log::info($failure);
$errors = $errors.' L'.$failure->row().'#'.$failure->attribute().': '.join(',', $failure->errors()).' ('.$failure->values()[$failure->attribute()].')';
}
Expand Down
6 changes: 6 additions & 0 deletions app/Importers/RealopsFlightImporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public function model($row) {
}
$est_time_enroute = null;
$gate = null;
$aircraft_type = null;

if (count($row) > 6) {
$est_time_enroute = $row[6];
Expand All @@ -26,6 +27,10 @@ public function model($row) {
$gate = $row[7];
}

if (count($row) > 8) {
$aircraft_type = $row[8];
}

$flight = new RealopsFlight;
$flight->flight_number = $row[0];
$flight->callsign = $row[1];
Expand All @@ -35,6 +40,7 @@ public function model($row) {
$flight->arr_airport = $row[5];
$flight->est_time_enroute = $est_time_enroute;
$flight->gate = $gate;
$flight->aircraft_type = $aircraft_type;

return $flight;
}
Expand Down
31 changes: 31 additions & 0 deletions app/PreferredRoute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class PreferredRoute extends Model {
protected $table = 'prd_route';
protected $guarded = [];

public static function routeLookup(string $departure, string $arrival, string $ac_type = 'jets'): string {
$routes = PreferredRoute::where('orig', substr($departure, 1))->where('dest', substr($arrival, 1))->where(function ($query) use ($ac_type) {
$query->where('aircraft', 'LIKE', '%' . strtoupper($ac_type) . '%')->orWhere('aircraft', '');
})->first();
if (!$routes) {
return '';
}
/*
PRDs normally contain the origin and destination ID as the first and last points.
SimBrief doesn't like this. Remove.
*/
$route = explode(' ', $routes->route_string);
if ($route[0] == substr($departure, 1)) {
unset($route[0]);
}
if (end($route) == substr($arrival, 1)) {
array_pop($route);
}
return implode(' ', $route);
}
}
Loading