Fixed airport responses

This commit is contained in:
2023-12-01 17:30:29 -05:00
parent 1feb713a47
commit 91d8e6c910
7 changed files with 68 additions and 23 deletions

View File

@@ -22,7 +22,7 @@ pub struct Airport {
pub iata_code: String, pub iata_code: String,
pub local_code: String, pub local_code: String,
pub point: Point, pub point: Point,
pub tower: Option<bool>, pub has_tower: Option<bool>,
} }
impl Into<QueryAirport> for Airport { impl Into<QueryAirport> for Airport {

View File

@@ -106,10 +106,17 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
let pages = ((total as f64) / (if limit <= 0 { 1 } else { limit} as f64)).ceil() as i64; 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.unwrap() { match web::block(move || QueryAirport::get_all(&filters, limit, page)).await.unwrap() {
Ok(a) => HttpResponse::Ok().json(Response { Ok(a) => {
data: a, // Convert Vec<QueryAirport> to Vec<Airport>
meta: Some(Metadata { page, limit, pages, total }) let mut airports: Vec<Airport> = vec![];
}), for airport in a {
airports.push(airport.into());
}
HttpResponse::Ok().json(Response {
data: airports,
meta: Some(Metadata { page, limit, pages, total })
})
},
Err(err) => { Err(err) => {
error!("{}", err); error!("{}", err);
err.to_http_response() err.to_http_response()
@@ -120,10 +127,13 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
#[get("/{icao}")] #[get("/{icao}")]
async fn get(icao: web::Path<String>) -> HttpResponse { async fn get(icao: web::Path<String>) -> HttpResponse {
match QueryAirport::find(icao.into_inner()) { match QueryAirport::find(icao.into_inner()) {
Ok(a) => HttpResponse::Ok().json(Response { Ok(a) => {
data: a, let airport: Airport = a.into();
meta: Some(Metadata { page: 1, limit: 1, pages: 1, total: 1 }) HttpResponse::Ok().json(Response {
}), data: airport,
meta: Some(Metadata { page: 1, limit: 1, pages: 1, total: 1 })
})
},
Err(err) => { Err(err) => {
error!("{}", err); error!("{}", err);
err.to_http_response() err.to_http_response()
@@ -139,7 +149,10 @@ async fn create(airport: web::Json<Airport>, auth: JwtAuth) -> HttpResponse {
}; };
let query_airport: QueryAirport = airport.into_inner().into(); let query_airport: QueryAirport = airport.into_inner().into();
match QueryAirport::insert(query_airport) { match QueryAirport::insert(query_airport) {
Ok(a) => HttpResponse::Created().json(a), Ok(a) => {
let airport: Airport = a.into();
HttpResponse::Ok().json(airport)
},
Err(err) => { Err(err) => {
error!("{}", err); error!("{}", err);
err.to_http_response() err.to_http_response()
@@ -155,7 +168,10 @@ async fn update(icao: web::Path<String>, airport: web::Json<Airport>, auth: JwtA
}; };
let query_airport: QueryAirport = airport.into_inner().into(); let query_airport: QueryAirport = airport.into_inner().into();
match QueryAirport::update(icao.into_inner(), query_airport) { match QueryAirport::update(icao.into_inner(), query_airport) {
Ok(a) => HttpResponse::Ok().json(a), Ok(a) => {
let airport: Airport = a.into();
HttpResponse::Ok().json(airport)
},
Err(err) => { Err(err) => {
error!("{}", err); error!("{}", err);
err.to_http_response() err.to_http_response()

View File

@@ -8,10 +8,15 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct QualityControlFlags { pub struct QualityControlFlags {
#[serde(skip_serializing_if = "Option::is_none")]
pub auto: Option<bool>, pub auto: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub auto_station_without_precipication: Option<bool>, pub auto_station_without_precipication: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub auto_station_with_precipication: Option<bool>, pub auto_station_with_precipication: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub maintenance_indicator_on: Option<bool>, pub maintenance_indicator_on: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub corrected: Option<bool> pub corrected: Option<bool>
} }
@@ -30,6 +35,7 @@ impl Default for QualityControlFlags {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct SkyCondition { pub struct SkyCondition {
pub sky_cover: String, pub sky_cover: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub cloud_base_ft_agl: Option<i32> pub cloud_base_ft_agl: Option<i32>
} }
@@ -45,8 +51,11 @@ impl Default for SkyCondition {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct RunwayVisualRange { pub struct RunwayVisualRange {
pub runway: String, pub runway: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub visibility_ft: Option<String>, pub visibility_ft: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub variable_visibility_high_ft: Option<String>, pub variable_visibility_high_ft: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub variable_visibility_low_ft: Option<String> pub variable_visibility_low_ft: Option<String>
} }
@@ -75,23 +84,36 @@ pub struct Metar {
pub raw_text: String, pub raw_text: String,
pub station_id: String, pub station_id: String,
pub observation_time: chrono::NaiveDateTime, pub observation_time: chrono::NaiveDateTime,
#[serde(skip_serializing_if = "Option::is_none")]
pub temp_c: Option<f64>, pub temp_c: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dewpoint_c: Option<f64>, pub dewpoint_c: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub wind_dir_degrees: Option<String>, pub wind_dir_degrees: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub wind_speed_kt: Option<i32>, pub wind_speed_kt: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub wind_gust_kt: Option<i32>, pub wind_gust_kt: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub variable_wind_dir_degrees: Option<String>, pub variable_wind_dir_degrees: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visibility_statute_mi: Option<String>, pub visibility_statute_mi: Option<String>,
pub runway_visual_range: Vec<RunwayVisualRange>, pub runway_visual_range: Vec<RunwayVisualRange>,
#[serde(skip_serializing_if = "Option::is_none")]
pub altim_in_hg: Option<f64>, pub altim_in_hg: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sea_level_pressure_mb: Option<f64>, pub sea_level_pressure_mb: Option<f64>,
pub quality_control_flags: QualityControlFlags, pub quality_control_flags: QualityControlFlags,
pub weather_phenomena: Vec<String>, pub weather_phenomena: Vec<String>,
pub sky_condition: Vec<SkyCondition>, pub sky_condition: Vec<SkyCondition>,
pub flight_category: FlightCategory, pub flight_category: FlightCategory,
#[serde(skip_serializing_if = "Option::is_none")]
pub three_hr_pressure_tendency_mb: Option<f64>, pub three_hr_pressure_tendency_mb: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_t_c: Option<f64>, pub max_t_c: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub min_t_c: Option<f64>, pub min_t_c: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub precip_in: Option<f64>, pub precip_in: Option<f64>,
} }

View File

@@ -37,7 +37,7 @@ export interface Metar {
sky_condition: SkyCondition[]; sky_condition: SkyCondition[];
flight_category: 'VFR' | 'MVFR' | 'LIFR' | 'IFR' | 'UNKN'; flight_category: 'VFR' | 'MVFR' | 'LIFR' | 'IFR' | 'UNKN';
three_hr_pressure_tendency_mb: number; three_hr_pressure_tendency_mb: number;
maxT_c: number; max_t_c: number;
minT_c: number; min_t_c: number;
precip_in: number; precip_in: number;
} }

View File

@@ -70,7 +70,7 @@ export default function MapTiles() {
} }
function metarIcon(airport: Airport) { function metarIcon(airport: Airport) {
function innerIcon({ tag, color, size = 'sm' }: { tag: string; color: string; size?: string }) { function innerIcon({ tag, color, size = 'xs' }: { tag: string; color: string; size?: string }) {
return new DivIcon({ return new DivIcon({
html: ReactDOMServer.renderToString( html: ReactDOMServer.renderToString(
<MantineProvider> <MantineProvider>

View File

@@ -48,7 +48,13 @@ export default function MetarModal({ airport, isOpen, onClose }: MetarModalProps
} }
return ( return (
<Modal opened={isOpen} onClose={onClose} withCloseButton={false} size={'50%'} className='modal'> <Modal
opened={isOpen}
onClose={onClose}
withCloseButton={false}
size={'50%'}
className='modal'
>
<span className='title'> <span className='title'>
<Link href={`/airport/${airport.icao}`}> <Link href={`/airport/${airport.icao}`}>
{airport.icao} {airport.full_name} {airport.icao} {airport.full_name}
@@ -163,13 +169,14 @@ function MetarInfo({ metar }: { metar: Metar }) {
</Grid> </Grid>
</Grid.Col> </Grid.Col>
<Grid.Col className='gutter-row' span={12}> <Grid.Col className='gutter-row' span={12}>
<Grid style={{ paddingTop: '1em', paddingBottom: '1em' }} gutter={48}> <Grid gutter={18}>
{metar.weather_phenomena && <Grid.Col className='gutter-row' span={12}>
metar.weather_phenomena.map((wx) => ( <Card shadow='sm' padding='sm' radius='md' style={{ textAlign: 'center' }}>
<Grid.Col span={1}> <Card.Section>
<MetarIcon wx={wx} />
</Grid.Col> </Card.Section>
))} </Card>
</Grid.Col>
</Grid> </Grid>
</Grid.Col> </Grid.Col>
</Grid.Col> </Grid.Col>

View File

@@ -15,4 +15,4 @@
.modal .star { .modal .star {
cursor: pointer; cursor: pointer;
} }