diff --git a/service/.env b/service/.env index 31007e4..ab52185 100644 --- a/service/.env +++ b/service/.env @@ -1,6 +1,6 @@ RUST_LOG=warn,service=debug -DATABASE_CONTAINER=aviation-service +DATABASE_CONTAINER=aviation-db DATABASE_USER=aviation DATABASE_PASSWORD= @@ -21,7 +21,7 @@ SERVICE_HOST=localhost SERVICE_PORT=5000 KEYS_DIR_PATH= -ACCESS_TOKEN_MAXAGE=5 +ACCESS_TOKEN_MAXAGE=240 REFRESH_TOKEN_MAXAGE=1440 GOV_API_URL=https://aviationweather.gov/cgi-bin/data diff --git a/service/Makefile b/service/Makefile index 37dc699..c86079d 100644 --- a/service/Makefile +++ b/service/Makefile @@ -59,4 +59,6 @@ generate-keys: ## Generate RSA keys @openssl rsa -in ../keys/access_private_key.pem -pubout -outform PEM -out ../keys/access_public_key.pem @openssl genrsa -out ../keys/refresh_private_key.pem 4096 @openssl rsa -in ../keys/refresh_private_key.pem -pubout -outform PEM -out ../keys/refresh_public_key.pem - \ No newline at end of file + +psql: ## Connect to the PSQL DB + @docker exec -it ${DATABASE_CONTAINER} psql -U ${DATABASE_USER} \ No newline at end of file diff --git a/service/migrations/000002_airport_metar_cache/down.sql b/service/migrations/000002_airport_metar_cache/down.sql new file mode 100644 index 0000000..51eb513 --- /dev/null +++ b/service/migrations/000002_airport_metar_cache/down.sql @@ -0,0 +1 @@ +DROP TABLE airport_metar_cache; \ No newline at end of file diff --git a/service/migrations/000002_airport_metar_cache/up.sql b/service/migrations/000002_airport_metar_cache/up.sql new file mode 100644 index 0000000..b6e2c83 --- /dev/null +++ b/service/migrations/000002_airport_metar_cache/up.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS airport_metar_cache ( + icao TEXT PRIMARY KEY NOT NULL, + has_metar BOOLEAN NOT NULL DEFAULT FALSE, + last_checked TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); \ No newline at end of file diff --git a/service/migrations/000002_users/down.sql b/service/migrations/000003_users/down.sql similarity index 100% rename from service/migrations/000002_users/down.sql rename to service/migrations/000003_users/down.sql diff --git a/service/migrations/000002_users/up.sql b/service/migrations/000003_users/up.sql similarity index 100% rename from service/migrations/000002_users/up.sql rename to service/migrations/000003_users/up.sql diff --git a/service/src/airports/model.rs b/service/src/airports/model.rs index 72cad50..b9f54e2 100644 --- a/service/src/airports/model.rs +++ b/service/src/airports/model.rs @@ -45,10 +45,16 @@ pub struct Airport { pub has_beacon: Option, pub runways: Vec, pub frequencies: Vec, - pub has_metar: bool, pub public: bool, } +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct AirportMetarCache { + pub icao: String, + pub has_metar: bool, + pub last_checked: chrono::NaiveDateTime, +} + impl Into for Airport { fn into(self) -> QueryAirport { return QueryAirport { diff --git a/service/src/airports/routes.rs b/service/src/airports/routes.rs index 1355d61..14c186f 100644 --- a/service/src/airports/routes.rs +++ b/service/src/airports/routes.rs @@ -13,7 +13,7 @@ use postgis_diesel::types::{Polygon, Point}; use serde::{Serialize, Deserialize}; #[derive(Debug, Serialize, Deserialize)] -struct GetAllParameters { +struct AirportsQuery { icaos: Option, name: Option, bounds: Option, @@ -26,7 +26,7 @@ struct GetAllParameters { } #[post("/import")] -async fn import(mut payload: Multipart, auth: JwtAuth) -> HttpResponse { +async fn import_airports(mut payload: Multipart, auth: JwtAuth) -> HttpResponse { if let Err(err) = verify_role(&auth, "admin") { return ResponseError::error_response(&err); }; @@ -70,8 +70,8 @@ async fn import(mut payload: Multipart, auth: JwtAuth) -> HttpResponse { } #[get("")] -async fn get_all(req: HttpRequest) -> HttpResponse { - let params = web::Query::::from_query(req.query_string()).unwrap(); +async fn get_airports(req: HttpRequest) -> HttpResponse { + let params = web::Query::::from_query(req.query_string()).unwrap(); let mut filters = QueryFilters::default(); filters.icaos = match ¶ms.icaos { Some(i) => Some(i.split(",").map(|s| s.to_string()).collect()), @@ -180,7 +180,6 @@ async fn get_all(req: HttpRequest) -> HttpResponse { Ok(t) => t, Err(_) => 0, }; - let pages = ((total as f64) / (if limit <= 0 { 1 } else { limit } as f64)).ceil() as i64; match web::block(move || QueryAirport::get_all(&filters, limit, page)) .await @@ -197,7 +196,6 @@ async fn get_all(req: HttpRequest) -> HttpResponse { meta: Some(Metadata { page, limit, - pages, total, }), }) @@ -210,19 +208,11 @@ async fn get_all(req: HttpRequest) -> HttpResponse { } #[get("/{icao}")] -async fn get(icao: web::Path) -> HttpResponse { +async fn get_airport(icao: web::Path) -> HttpResponse { match QueryAirport::get(&icao.into_inner()) { Ok(a) => { let airport: Airport = a.into(); - HttpResponse::Ok().json(Response { - data: airport, - meta: Some(Metadata { - page: 1, - limit: 1, - pages: 1, - total: 1, - }), - }) + HttpResponse::Ok().json(airport) } Err(err) => { error!("{}", err); @@ -232,7 +222,7 @@ async fn get(icao: web::Path) -> HttpResponse { } #[post("")] -async fn create(airport: web::Json, auth: JwtAuth) -> HttpResponse { +async fn create_airport(airport: web::Json, auth: JwtAuth) -> HttpResponse { let _ = match verify_role(&auth, "admin") { Ok(_) => {} Err(err) => return ResponseError::error_response(&err), @@ -251,7 +241,7 @@ async fn create(airport: web::Json, auth: JwtAuth) -> HttpResponse { } #[put("/{icao}")] -async fn update( +async fn update_airport( _icao: web::Path, airport: web::Json, auth: JwtAuth, @@ -274,7 +264,7 @@ async fn update( } #[delete("")] -async fn delete_all(auth: JwtAuth) -> HttpResponse { +async fn delete_airports(auth: JwtAuth) -> HttpResponse { let _ = match verify_role(&auth, "admin") { Ok(_) => {} Err(err) => return ResponseError::error_response(&err), @@ -289,7 +279,7 @@ async fn delete_all(auth: JwtAuth) -> HttpResponse { } #[delete("/{icao}")] -async fn delete(icao: web::Path, auth: JwtAuth) -> HttpResponse { +async fn delete_airport(icao: web::Path, auth: JwtAuth) -> HttpResponse { let _ = match verify_role(&auth, "admin") { Ok(_) => {} Err(err) => return ResponseError::error_response(&err), @@ -306,12 +296,12 @@ async fn delete(icao: web::Path, auth: JwtAuth) -> HttpResponse { pub fn init_routes(config: &mut web::ServiceConfig) { config.service( web::scope("airports") - .service(get_all) - .service(get) - .service(create) - .service(update) - .service(delete) - .service(delete_all) - .service(import), + .service(import_airports) + .service(get_airports) + .service(get_airport) + .service(create_airport) + .service(update_airport) + .service(delete_airports) + .service(delete_airport), ); } diff --git a/service/src/db/mod.rs b/service/src/db/mod.rs index e59b94e..7caff52 100644 --- a/service/src/db/mod.rs +++ b/service/src/db/mod.rs @@ -158,7 +158,6 @@ pub struct Response { pub struct Metadata { pub page: i32, pub limit: i32, - pub pages: i64, pub total: i64, } diff --git a/service/src/main.rs b/service/src/main.rs index 5a7b06f..7c3cf77 100644 --- a/service/src/main.rs +++ b/service/src/main.rs @@ -22,7 +22,7 @@ async fn main() -> std::io::Result<()> { dotenv().ok(); env_logger::init_from_env(env_logger::Env::default().filter_or("RUST_LOG", "warn,service=info")); db::init().await; - scheduler::update_airports(); + // scheduler::update_airports(); let host = env::var("SERVICE_HOST").unwrap_or("localhost".to_string()); let port = env::var("SERVICE_PORT").unwrap_or("5000".to_string()); diff --git a/service/src/metars/routes.rs b/service/src/metars/routes.rs index 65a3ffb..2ef37db 100644 --- a/service/src/metars/routes.rs +++ b/service/src/metars/routes.rs @@ -24,7 +24,7 @@ async fn get_all(req: HttpRequest) -> HttpResponse { None => return HttpResponse::UnprocessableEntity().body("Missing icaos parameter"), }; - let airports = + let metars = match web::block(|| Ok::<_, ServiceError>(async { Metar::get_all(icao_string).await })) .await .unwrap() @@ -37,15 +37,7 @@ async fn get_all(req: HttpRequest) -> HttpResponse { return err.to_http_response(); } }; - HttpResponse::Ok().json(MetarsResponse { - data: airports, - meta: Metadata { - page: 0, - limit: 0, - pages: 0, - total: 0, - }, - }) + HttpResponse::Ok().json(metars) } pub fn init_routes(config: &mut web::ServiceConfig) { diff --git a/ui/src/api/airport.ts b/ui/src/api/airport.ts index 2c50239..03efa4d 100644 --- a/ui/src/api/airport.ts +++ b/ui/src/api/airport.ts @@ -1,13 +1,13 @@ -import { Airport, AirportOrderField, Bounds, GetAirportResponse, GetAirportsResponse } from './airport.types'; +import { Airport, AirportOrderField, Bounds, GetAirportsResponse } from './airport.types'; import { getRequest, deleteRequest, postRequest, putRequest } from '.'; interface GetAirportProps { icao: string; } -export async function getAirport({ icao }: GetAirportProps): Promise { +export async function getAirport({ icao }: GetAirportProps): Promise { const response = await getRequest(`airports/${icao}`); - return response?.json() || { data: undefined }; + return response?.json() || {}; } interface GetAirportsProps { diff --git a/ui/src/api/airport.types.ts b/ui/src/api/airport.types.ts index 7f6180c..7d327d1 100644 --- a/ui/src/api/airport.types.ts +++ b/ui/src/api/airport.types.ts @@ -86,11 +86,6 @@ export interface Frequency { frequency_mhz: number; } -export interface GetAirportResponse { - data: Airport; - meta: Metadata; -} - export interface GetAirportsResponse { data: Airport[]; meta: Metadata; diff --git a/ui/src/api/index.ts b/ui/src/api/index.ts index 861b5aa..3954fe0 100644 --- a/ui/src/api/index.ts +++ b/ui/src/api/index.ts @@ -75,6 +75,5 @@ export async function deleteRequest(endpoint: string): Promise { export interface Metadata { limit: number; page: number; - pages: number; total: number; } diff --git a/ui/src/api/metar.ts b/ui/src/api/metar.ts index a98b239..9a50c4e 100644 --- a/ui/src/api/metar.ts +++ b/ui/src/api/metar.ts @@ -1,15 +1,11 @@ import { Metar } from './metar.types'; import { getRequest } from '.'; -interface GetMetarsResponse { - data: Metar[]; -} - -export async function getMetars(icaos: string[]): Promise { +export async function getMetars(icaos: string[]): Promise { if (icaos.length == 0) { - return { data: [] }; + return []; } const stationICAOs: string = icaos.map((icao) => icao).join(','); const response = await getRequest(`metars`, { icaos: stationICAOs }); - return response?.json() || { data: [] }; + return response?.json() || []; } diff --git a/ui/src/app/airport/[icao]/page.tsx b/ui/src/app/airport/[icao]/page.tsx index 1c6cba1..19ac83b 100644 --- a/ui/src/app/airport/[icao]/page.tsx +++ b/ui/src/app/airport/[icao]/page.tsx @@ -13,9 +13,9 @@ export default function Page({ params }: { params: { icao: string } }) { useEffect(() => { async function loadAirport() { - const { data: airportData } = await getAirport({ icao: params.icao }); + const airportData = await getAirport({ icao: params.icao }); setAirport(airportData); - const { data: metarData } = await getMetars([airportData.icao]); + const metarData = await getMetars([airportData.icao]); if (metarData.length > 0) { setMetar(metarData[0]); } diff --git a/ui/src/components/Metars/MapTiles.tsx b/ui/src/components/Metars/MapTiles.tsx index 03b388f..1ef53ee 100644 --- a/ui/src/components/Metars/MapTiles.tsx +++ b/ui/src/components/Metars/MapTiles.tsx @@ -57,7 +57,7 @@ export default function MapTiles() { page: 1 }); const airports = airportData.filter((airport) => airport.has_metar); - const { data: metars } = await getMetars(airports.map((a) => a.icao)); + const metars = await getMetars(airports.map((a) => a.icao)); metars.forEach((metar) => { airportData.forEach((airport) => { if (metar.station_id == airport.icao) {