updates
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
RUST_LOG=warn,service=debug
|
RUST_LOG=warn,service=debug
|
||||||
|
|
||||||
DATABASE_CONTAINER=aviation-service
|
DATABASE_CONTAINER=aviation-db
|
||||||
|
|
||||||
DATABASE_USER=aviation
|
DATABASE_USER=aviation
|
||||||
DATABASE_PASSWORD=
|
DATABASE_PASSWORD=
|
||||||
@@ -21,7 +21,7 @@ SERVICE_HOST=localhost
|
|||||||
SERVICE_PORT=5000
|
SERVICE_PORT=5000
|
||||||
|
|
||||||
KEYS_DIR_PATH=
|
KEYS_DIR_PATH=
|
||||||
ACCESS_TOKEN_MAXAGE=5
|
ACCESS_TOKEN_MAXAGE=240
|
||||||
REFRESH_TOKEN_MAXAGE=1440
|
REFRESH_TOKEN_MAXAGE=1440
|
||||||
|
|
||||||
GOV_API_URL=https://aviationweather.gov/cgi-bin/data
|
GOV_API_URL=https://aviationweather.gov/cgi-bin/data
|
||||||
|
|||||||
@@ -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 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 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
|
@openssl rsa -in ../keys/refresh_private_key.pem -pubout -outform PEM -out ../keys/refresh_public_key.pem
|
||||||
|
|
||||||
|
psql: ## Connect to the PSQL DB
|
||||||
|
@docker exec -it ${DATABASE_CONTAINER} psql -U ${DATABASE_USER}
|
||||||
1
service/migrations/000002_airport_metar_cache/down.sql
Normal file
1
service/migrations/000002_airport_metar_cache/down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE airport_metar_cache;
|
||||||
5
service/migrations/000002_airport_metar_cache/up.sql
Normal file
5
service/migrations/000002_airport_metar_cache/up.sql
Normal file
@@ -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
|
||||||
|
);
|
||||||
@@ -45,10 +45,16 @@ pub struct Airport {
|
|||||||
pub has_beacon: Option<bool>,
|
pub has_beacon: Option<bool>,
|
||||||
pub runways: Vec<Runway>,
|
pub runways: Vec<Runway>,
|
||||||
pub frequencies: Vec<Frequency>,
|
pub frequencies: Vec<Frequency>,
|
||||||
pub has_metar: bool,
|
|
||||||
pub public: 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<QueryAirport> for Airport {
|
impl Into<QueryAirport> for Airport {
|
||||||
fn into(self) -> QueryAirport {
|
fn into(self) -> QueryAirport {
|
||||||
return QueryAirport {
|
return QueryAirport {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use postgis_diesel::types::{Polygon, Point};
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
struct GetAllParameters {
|
struct AirportsQuery {
|
||||||
icaos: Option<String>,
|
icaos: Option<String>,
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
bounds: Option<String>,
|
bounds: Option<String>,
|
||||||
@@ -26,7 +26,7 @@ struct GetAllParameters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[post("/import")]
|
#[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") {
|
if let Err(err) = verify_role(&auth, "admin") {
|
||||||
return ResponseError::error_response(&err);
|
return ResponseError::error_response(&err);
|
||||||
};
|
};
|
||||||
@@ -70,8 +70,8 @@ async fn import(mut payload: Multipart, auth: JwtAuth) -> HttpResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[get("")]
|
#[get("")]
|
||||||
async fn get_all(req: HttpRequest) -> HttpResponse {
|
async fn get_airports(req: HttpRequest) -> HttpResponse {
|
||||||
let params = web::Query::<GetAllParameters>::from_query(req.query_string()).unwrap();
|
let params = web::Query::<AirportsQuery>::from_query(req.query_string()).unwrap();
|
||||||
let mut filters = QueryFilters::default();
|
let mut filters = QueryFilters::default();
|
||||||
filters.icaos = match ¶ms.icaos {
|
filters.icaos = match ¶ms.icaos {
|
||||||
Some(i) => Some(i.split(",").map(|s| s.to_string()).collect()),
|
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,
|
Ok(t) => t,
|
||||||
Err(_) => 0,
|
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))
|
match web::block(move || QueryAirport::get_all(&filters, limit, page))
|
||||||
.await
|
.await
|
||||||
@@ -197,7 +196,6 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
|
|||||||
meta: Some(Metadata {
|
meta: Some(Metadata {
|
||||||
page,
|
page,
|
||||||
limit,
|
limit,
|
||||||
pages,
|
|
||||||
total,
|
total,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
@@ -210,19 +208,11 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[get("/{icao}")]
|
#[get("/{icao}")]
|
||||||
async fn get(icao: web::Path<String>) -> HttpResponse {
|
async fn get_airport(icao: web::Path<String>) -> HttpResponse {
|
||||||
match QueryAirport::get(&icao.into_inner()) {
|
match QueryAirport::get(&icao.into_inner()) {
|
||||||
Ok(a) => {
|
Ok(a) => {
|
||||||
let airport: Airport = a.into();
|
let airport: Airport = a.into();
|
||||||
HttpResponse::Ok().json(Response {
|
HttpResponse::Ok().json(airport)
|
||||||
data: airport,
|
|
||||||
meta: Some(Metadata {
|
|
||||||
page: 1,
|
|
||||||
limit: 1,
|
|
||||||
pages: 1,
|
|
||||||
total: 1,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("{}", err);
|
error!("{}", err);
|
||||||
@@ -232,7 +222,7 @@ async fn get(icao: web::Path<String>) -> HttpResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[post("")]
|
#[post("")]
|
||||||
async fn create(airport: web::Json<Airport>, auth: JwtAuth) -> HttpResponse {
|
async fn create_airport(airport: web::Json<Airport>, auth: JwtAuth) -> HttpResponse {
|
||||||
let _ = match verify_role(&auth, "admin") {
|
let _ = match verify_role(&auth, "admin") {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(err) => return ResponseError::error_response(&err),
|
Err(err) => return ResponseError::error_response(&err),
|
||||||
@@ -251,7 +241,7 @@ async fn create(airport: web::Json<Airport>, auth: JwtAuth) -> HttpResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[put("/{icao}")]
|
#[put("/{icao}")]
|
||||||
async fn update(
|
async fn update_airport(
|
||||||
_icao: web::Path<String>,
|
_icao: web::Path<String>,
|
||||||
airport: web::Json<Airport>,
|
airport: web::Json<Airport>,
|
||||||
auth: JwtAuth,
|
auth: JwtAuth,
|
||||||
@@ -274,7 +264,7 @@ async fn update(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[delete("")]
|
#[delete("")]
|
||||||
async fn delete_all(auth: JwtAuth) -> HttpResponse {
|
async fn delete_airports(auth: JwtAuth) -> HttpResponse {
|
||||||
let _ = match verify_role(&auth, "admin") {
|
let _ = match verify_role(&auth, "admin") {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(err) => return ResponseError::error_response(&err),
|
Err(err) => return ResponseError::error_response(&err),
|
||||||
@@ -289,7 +279,7 @@ async fn delete_all(auth: JwtAuth) -> HttpResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[delete("/{icao}")]
|
#[delete("/{icao}")]
|
||||||
async fn delete(icao: web::Path<String>, auth: JwtAuth) -> HttpResponse {
|
async fn delete_airport(icao: web::Path<String>, auth: JwtAuth) -> HttpResponse {
|
||||||
let _ = match verify_role(&auth, "admin") {
|
let _ = match verify_role(&auth, "admin") {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(err) => return ResponseError::error_response(&err),
|
Err(err) => return ResponseError::error_response(&err),
|
||||||
@@ -306,12 +296,12 @@ async fn delete(icao: web::Path<String>, auth: JwtAuth) -> HttpResponse {
|
|||||||
pub fn init_routes(config: &mut web::ServiceConfig) {
|
pub fn init_routes(config: &mut web::ServiceConfig) {
|
||||||
config.service(
|
config.service(
|
||||||
web::scope("airports")
|
web::scope("airports")
|
||||||
.service(get_all)
|
.service(import_airports)
|
||||||
.service(get)
|
.service(get_airports)
|
||||||
.service(create)
|
.service(get_airport)
|
||||||
.service(update)
|
.service(create_airport)
|
||||||
.service(delete)
|
.service(update_airport)
|
||||||
.service(delete_all)
|
.service(delete_airports)
|
||||||
.service(import),
|
.service(delete_airport),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,7 +158,6 @@ pub struct Response<T> {
|
|||||||
pub struct Metadata {
|
pub struct Metadata {
|
||||||
pub page: i32,
|
pub page: i32,
|
||||||
pub limit: i32,
|
pub limit: i32,
|
||||||
pub pages: i64,
|
|
||||||
pub total: i64,
|
pub total: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ async fn main() -> std::io::Result<()> {
|
|||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
env_logger::init_from_env(env_logger::Env::default().filter_or("RUST_LOG", "warn,service=info"));
|
env_logger::init_from_env(env_logger::Env::default().filter_or("RUST_LOG", "warn,service=info"));
|
||||||
db::init().await;
|
db::init().await;
|
||||||
scheduler::update_airports();
|
// scheduler::update_airports();
|
||||||
|
|
||||||
let host = env::var("SERVICE_HOST").unwrap_or("localhost".to_string());
|
let host = env::var("SERVICE_HOST").unwrap_or("localhost".to_string());
|
||||||
let port = env::var("SERVICE_PORT").unwrap_or("5000".to_string());
|
let port = env::var("SERVICE_PORT").unwrap_or("5000".to_string());
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
|
|||||||
None => return HttpResponse::UnprocessableEntity().body("Missing icaos parameter"),
|
None => return HttpResponse::UnprocessableEntity().body("Missing icaos parameter"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let airports =
|
let metars =
|
||||||
match web::block(|| Ok::<_, ServiceError>(async { Metar::get_all(icao_string).await }))
|
match web::block(|| Ok::<_, ServiceError>(async { Metar::get_all(icao_string).await }))
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -37,15 +37,7 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
|
|||||||
return err.to_http_response();
|
return err.to_http_response();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
HttpResponse::Ok().json(MetarsResponse {
|
HttpResponse::Ok().json(metars)
|
||||||
data: airports,
|
|
||||||
meta: Metadata {
|
|
||||||
page: 0,
|
|
||||||
limit: 0,
|
|
||||||
pages: 0,
|
|
||||||
total: 0,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_routes(config: &mut web::ServiceConfig) {
|
pub fn init_routes(config: &mut web::ServiceConfig) {
|
||||||
|
|||||||
@@ -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 '.';
|
import { getRequest, deleteRequest, postRequest, putRequest } from '.';
|
||||||
|
|
||||||
interface GetAirportProps {
|
interface GetAirportProps {
|
||||||
icao: string;
|
icao: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAirport({ icao }: GetAirportProps): Promise<GetAirportResponse> {
|
export async function getAirport({ icao }: GetAirportProps): Promise<Airport> {
|
||||||
const response = await getRequest(`airports/${icao}`);
|
const response = await getRequest(`airports/${icao}`);
|
||||||
return response?.json() || { data: undefined };
|
return response?.json() || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GetAirportsProps {
|
interface GetAirportsProps {
|
||||||
|
|||||||
@@ -86,11 +86,6 @@ export interface Frequency {
|
|||||||
frequency_mhz: number;
|
frequency_mhz: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GetAirportResponse {
|
|
||||||
data: Airport;
|
|
||||||
meta: Metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GetAirportsResponse {
|
export interface GetAirportsResponse {
|
||||||
data: Airport[];
|
data: Airport[];
|
||||||
meta: Metadata;
|
meta: Metadata;
|
||||||
|
|||||||
@@ -75,6 +75,5 @@ export async function deleteRequest(endpoint: string): Promise<Response> {
|
|||||||
export interface Metadata {
|
export interface Metadata {
|
||||||
limit: number;
|
limit: number;
|
||||||
page: number;
|
page: number;
|
||||||
pages: number;
|
|
||||||
total: number;
|
total: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
import { Metar } from './metar.types';
|
import { Metar } from './metar.types';
|
||||||
import { getRequest } from '.';
|
import { getRequest } from '.';
|
||||||
|
|
||||||
interface GetMetarsResponse {
|
export async function getMetars(icaos: string[]): Promise<Metar[]> {
|
||||||
data: Metar[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getMetars(icaos: string[]): Promise<GetMetarsResponse> {
|
|
||||||
if (icaos.length == 0) {
|
if (icaos.length == 0) {
|
||||||
return { data: [] };
|
return [];
|
||||||
}
|
}
|
||||||
const stationICAOs: string = icaos.map((icao) => icao).join(',');
|
const stationICAOs: string = icaos.map((icao) => icao).join(',');
|
||||||
const response = await getRequest(`metars`, { icaos: stationICAOs });
|
const response = await getRequest(`metars`, { icaos: stationICAOs });
|
||||||
return response?.json() || { data: [] };
|
return response?.json() || [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ export default function Page({ params }: { params: { icao: string } }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function loadAirport() {
|
async function loadAirport() {
|
||||||
const { data: airportData } = await getAirport({ icao: params.icao });
|
const airportData = await getAirport({ icao: params.icao });
|
||||||
setAirport(airportData);
|
setAirport(airportData);
|
||||||
const { data: metarData } = await getMetars([airportData.icao]);
|
const metarData = await getMetars([airportData.icao]);
|
||||||
if (metarData.length > 0) {
|
if (metarData.length > 0) {
|
||||||
setMetar(metarData[0]);
|
setMetar(metarData[0]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export default function MapTiles() {
|
|||||||
page: 1
|
page: 1
|
||||||
});
|
});
|
||||||
const airports = airportData.filter((airport) => airport.has_metar);
|
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) => {
|
metars.forEach((metar) => {
|
||||||
airportData.forEach((airport) => {
|
airportData.forEach((airport) => {
|
||||||
if (metar.station_id == airport.icao) {
|
if (metar.station_id == airport.icao) {
|
||||||
|
|||||||
Reference in New Issue
Block a user