Formatting

This commit is contained in:
2025-06-03 21:57:22 -04:00
parent 263c33fd5a
commit 995e86f229
13 changed files with 68 additions and 69 deletions

View File

@@ -2,10 +2,10 @@ use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use super::{SESSION_COOKIE_NAME, Session}; use super::{SESSION_COOKIE_NAME, Session};
use crate::account::user::User;
use crate::error::Error; use crate::error::Error;
use actix_web::{Error as ActixError, FromRequest, HttpRequest, dev::Payload, http}; use actix_web::{Error as ActixError, FromRequest, HttpRequest, dev::Payload, http};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::account::user::User;
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Auth { pub struct Auth {

View File

@@ -1,6 +1,6 @@
use argon2::{ use argon2::{
password_hash::{rand_core::OsRng, SaltString}, Argon2, PasswordHash, PasswordHasher, Argon2, PasswordHash, PasswordHasher, PasswordVerifier,
PasswordVerifier, password_hash::{SaltString, rand_core::OsRng},
}; };
use rand::distr::Alphanumeric; use rand::distr::Alphanumeric;
use rand::prelude::*; use rand::prelude::*;

View File

@@ -2,16 +2,16 @@ use crate::{
account::{SESSION_COOKIE_NAME, Session, verify_hash}, account::{SESSION_COOKIE_NAME, Session, verify_hash},
error::Error, error::Error,
}; };
use actix_web::{HttpRequest, HttpResponse, ResponseError, get, post, put, web, delete}; use actix_web::{HttpRequest, HttpResponse, ResponseError, delete, get, post, put, web};
use serde::Deserialize; use serde::Deserialize;
use utoipa::ToSchema; use utoipa::ToSchema;
use utoipa_actix_web::scope; use utoipa_actix_web::scope;
use utoipa_actix_web::service_config::ServiceConfig; use utoipa_actix_web::service_config::ServiceConfig;
use crate::account::email_token::{EmailToken, send_confirm_email, send_password_reset_email}; use crate::account::email_token::{EmailToken, send_confirm_email, send_password_reset_email};
use crate::account::{Auth, csprng};
use crate::account::user::{LoginRequest, RegisterRequest, UpdateUser, User, UserResponse}; use crate::account::user::{LoginRequest, RegisterRequest, UpdateUser, User, UserResponse};
use crate::account::user_favorites::UserFavorite; use crate::account::user_favorites::UserFavorite;
use crate::account::{Auth, csprng};
#[utoipa::path( #[utoipa::path(
tag = "account", tag = "account",

View File

@@ -1,6 +1,6 @@
use serde::Deserialize;
use crate::db; use crate::db;
use crate::error::ApiResult; use crate::error::ApiResult;
use serde::Deserialize;
const TABLE_NAME: &str = "user_airport_favorites"; const TABLE_NAME: &str = "user_airport_favorites";
@@ -23,10 +23,7 @@ impl UserFavorite {
.fetch_all(pool) .fetch_all(pool)
.await?; .await?;
let favorites = user_favorites let favorites = user_favorites.iter().map(|uf| uf.icao.clone()).collect();
.iter()
.map(|uf| uf.icao.clone())
.collect();
Ok(favorites) Ok(favorites)
} }

View File

@@ -561,11 +561,12 @@ impl Airport {
.collect(); .collect();
for chunk in airport_rows.chunks(chunk_size) { for chunk in airport_rows.chunks(chunk_size) {
let mut query_builder: QueryBuilder<Postgres> = QueryBuilder::new( let mut query_builder: QueryBuilder<Postgres> = QueryBuilder::new(format!(
format!("INSERT INTO {} (icao, iata, local, name, category, \ "INSERT INTO {} (icao, iata, local, name, category, \
iso_country, iso_region, municipality, elevation_ft, \ iso_country, iso_region, municipality, elevation_ft, \
longitude, latitude, geometry, has_tower, has_beacon, public) ", TABLE_NAME), longitude, latitude, geometry, has_tower, has_beacon, public) ",
); TABLE_NAME
));
query_builder.push_values(chunk, |mut b, row| { query_builder.push_values(chunk, |mut b, row| {
b.push_bind(&row.icao) b.push_bind(&row.icao)
.push_bind(&row.iata) .push_bind(&row.iata)

View File

@@ -1,5 +1,6 @@
use futures_util::stream::StreamExt as _; use futures_util::stream::StreamExt as _;
use crate::account::ADMIN_ROLE;
use crate::airports::{AirportQuery, UpdateAirport}; use crate::airports::{AirportQuery, UpdateAirport};
use crate::{ use crate::{
account::{Auth, verify_role}, account::{Auth, verify_role},
@@ -11,7 +12,6 @@ use actix_web::{HttpRequest, HttpResponse, ResponseError, delete, get, post, put
use utoipa::ToSchema; use utoipa::ToSchema;
use utoipa_actix_web::scope; use utoipa_actix_web::scope;
use utoipa_actix_web::service_config::ServiceConfig; use utoipa_actix_web::service_config::ServiceConfig;
use crate::account::ADMIN_ROLE;
#[derive(ToSchema)] #[derive(ToSchema)]
#[allow(unused)] #[allow(unused)]

View File

@@ -139,7 +139,9 @@ impl From<s3::error::S3Error> for Error {
s3::error::S3Error::FromUtf8(err) => { s3::error::S3Error::FromUtf8(err) => {
Self::new(500, format!("Unknown s3 from utf8 error: {:?}", err)) Self::new(500, format!("Unknown s3 from utf8 error: {:?}", err))
} }
s3::error::S3Error::FmtError(err) => Self::new(500, format!("Unknown s3 fmt error: {:?}", err)), s3::error::S3Error::FmtError(err) => {
Self::new(500, format!("Unknown s3 fmt error: {:?}", err))
}
s3::error::S3Error::HeaderToStr(err) => { s3::error::S3Error::HeaderToStr(err) => {
Self::new(500, format!("Unknown s3 header to str error: {:?}", err)) Self::new(500, format!("Unknown s3 header to str error: {:?}", err))
} }

View File

@@ -1,4 +1,5 @@
use crate::account::{hash, ADMIN_ROLE}; use crate::account::User;
use crate::account::{ADMIN_ROLE, hash};
use crate::http_client::HttpClient; use crate::http_client::HttpClient;
use actix_cors::Cors; use actix_cors::Cors;
use actix_web::{App, HttpServer, middleware::Logger, web}; use actix_web::{App, HttpServer, middleware::Logger, web};
@@ -9,7 +10,6 @@ use utoipa::openapi::SecurityRequirement;
use utoipa::openapi::security::{ApiKey, ApiKeyValue, SecurityScheme}; use utoipa::openapi::security::{ApiKey, ApiKeyValue, SecurityScheme};
use utoipa_actix_web::{AppExt, scope}; use utoipa_actix_web::{AppExt, scope};
use utoipa_swagger_ui::{Config, SwaggerUi}; use utoipa_swagger_ui::{Config, SwaggerUi};
use crate::account::User;
mod account; mod account;
mod airports; mod airports;

View File

@@ -8,13 +8,13 @@ use chrono::{DateTime, Utc};
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
use reqwest::header::ETAG; use reqwest::header::ETAG;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{Postgres, QueryBuilder};
use std::collections::HashSet; use std::collections::HashSet;
use std::env; use std::env;
use std::fmt::Display; use std::fmt::Display;
use std::io::{Cursor, Read}; use std::io::{Cursor, Read};
use std::str::FromStr; use std::str::FromStr;
use std::sync::OnceLock; use std::sync::OnceLock;
use sqlx::{Postgres, QueryBuilder};
use utoipa::ToSchema; use utoipa::ToSchema;
static TIME_OFFSET: OnceLock<i64> = OnceLock::new(); static TIME_OFFSET: OnceLock<i64> = OnceLock::new();
@@ -310,9 +310,11 @@ impl MetarRow {
let chunk_size = 1000; let chunk_size = 1000;
for chunk in metars.chunks(chunk_size) { for chunk in metars.chunks(chunk_size) {
let mut query_builder: QueryBuilder<Postgres> = QueryBuilder::new( let mut query_builder: QueryBuilder<Postgres> = QueryBuilder::new(format!(
format!("INSERT INTO {} (icao, observation_time, raw_text, data) ", TABLE_NAME)); "INSERT INTO {} (icao, observation_time, raw_text, data) ",
query_builder.push_values(chunk, |mut b, metar | { TABLE_NAME
));
query_builder.push_values(chunk, |mut b, metar| {
let row: Self = match metar.to_row() { let row: Self = match metar.to_row() {
Ok(row) => row, Ok(row) => row,
Err(e) => { Err(e) => {
@@ -395,11 +397,15 @@ impl Metar {
Ok(datetime) => datetime.with_timezone(&Utc), Ok(datetime) => datetime.with_timezone(&Utc),
Err(err) => return Err(err.into()), Err(err) => return Err(err.into()),
}; };
}, }
Err(err) => { Err(err) => {
return Err(Error::new( return Err(Error::new(
err.status, err.status,
format!("Unexpected observation time field '{}': {}; {}", observation_time, metar_string, err))); format!(
"Unexpected observation time field '{}': {}; {}",
observation_time, metar_string, err
),
));
} }
}; };
@@ -570,7 +576,11 @@ impl Metar {
metar.visibility_statute_mi = Some(format!("{:.2}", visibility)); metar.visibility_statute_mi = Some(format!("{:.2}", visibility));
} }
} else { } else {
log::warn!("Skipping unexpected visibility field '{}' ({})", metar_parts[0], metar_string); log::warn!(
"Skipping unexpected visibility field '{}' ({})",
metar_parts[0],
metar_string
);
} }
} }

View File

@@ -1,7 +1,7 @@
use std::env;
use crate::http_client::HttpClient; use crate::http_client::HttpClient;
use crate::metars::Metar; use crate::metars::Metar;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use std::env;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use tokio::time::interval; use tokio::time::interval;

View File

@@ -26,24 +26,24 @@ export function AirportSearch({ limit = 5 }: AirportSearchProps) {
}); });
const nameResponse = await getAirports({ const nameResponse = await getAirports({
name: debounced, name: debounced,
limit: limit - 1, limit: limit - 1
}); });
let combined = [...icaoResponse.data, ...nameResponse.data]; let combined = [...icaoResponse.data, ...nameResponse.data];
combined = combined.slice(0, limit); combined = combined.slice(0, limit);
return combined.map((airport) => ({ return combined.map((airport) => ({
key: airport.icao, key: airport.icao,
value: airport.icao, value: airport.icao,
label: `${airport.icao} - ${airport.name}`, label: `${airport.icao} - ${airport.name}`
})); }));
} catch (err) { } catch (err) {
console.error('airport search failed', err); console.error('airport search failed', err);
return [] return [];
} }
} }
fetch().then(d => { fetch().then((d) => {
setData(d); setData(d);
console.log(d) console.log(d);
}); });
}, [debounced, limit]); }, [debounced, limit]);
@@ -57,7 +57,6 @@ export function AirportSearch({ limit = 5 }: AirportSearchProps) {
onOptionSubmit={() => {}} onOptionSubmit={() => {}}
radius={'xl'} radius={'xl'}
onBlur={() => setSearch('')} onBlur={() => setSearch('')}
/> />
); );
} }

View File

@@ -15,10 +15,7 @@ import { AirportSearch } from '@components/AirportSearch.tsx';
// { link: '/metars', label: 'Metars' } // { link: '/metars', label: 'Metars' }
// ]; // ];
const protectedPages = [ const protectedPages = ['/administration', '/profile'];
'/administration',
'/profile'
]
export function Header() { export function Header() {
const { user, setUser } = useUserContext(); const { user, setUser } = useUserContext();
@@ -73,11 +70,9 @@ export function Header() {
setUser(undefined); setUser(undefined);
// See if the current page is a protected page // See if the current page is a protected page
const isProtected = protectedPages.some(pattern => const isProtected = protectedPages.some((pattern) => matchPath(pattern, pathname));
matchPath(pattern, pathname)
)
if (isProtected) { if (isProtected) {
navigate('/', { replace: true }) navigate('/', { replace: true });
} }
} }

View File

@@ -14,20 +14,15 @@ export function UserProvider({ children }: { children: ReactNode }) {
async function toggleFavorite(icao: string) { async function toggleFavorite(icao: string) {
setFavorites((prev) => { setFavorites((prev) => {
const isFav = prev.includes(icao) const isFav = prev.includes(icao);
const next = isFav const next = isFav ? prev.filter((i) => i !== icao) : [...prev, icao];
? prev.filter((i) => i !== icao)
: [...prev, icao]
;(isFav (isFav ? removeFavorite(icao) : addFavorite(icao)).catch((err) => {
? removeFavorite(icao) console.error('Sync failed, rolling back', err);
: addFavorite(icao) setFavorites(prev);
).catch((err) => { });
console.error('Sync failed, rolling back', err)
setFavorites(prev)
})
return next return next;
}); });
} }
@@ -57,9 +52,9 @@ export function UserProvider({ children }: { children: ReactNode }) {
useEffect(() => { useEffect(() => {
if (user != undefined) { if (user != undefined) {
getFavorites().then(f => { getFavorites().then((f) => {
setFavorites(f) setFavorites(f);
}) });
} }
}, [user]); }, [user]);