Updated queries/endpoints, made admin page
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
RUST_LOG=waren,service=info
|
||||
RUST_LOG=warn,service=debug
|
||||
|
||||
DATABASE_CONTAINER=weather-service
|
||||
|
||||
DATABASE_USER=weather
|
||||
DATABASE_PASSWORD=
|
||||
@@ -9,6 +11,12 @@ DATABASE_PORT=5432
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
|
||||
MINIO_ROOT_USER=siren
|
||||
MINIO_ROOT_PASSWORD=7LtSkxU15ix40nu
|
||||
MINIO_HOST=localhost
|
||||
MINIO_PORT=9000
|
||||
MINIO_PORT_INTERNAL=9001
|
||||
|
||||
SERVICE_HOST=localhost
|
||||
SERVICE_PORT=5000
|
||||
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
FROM rust:1.72.1-bookworm
|
||||
|
||||
WORKDIR /service
|
||||
USER root
|
||||
# =========
|
||||
# Builder
|
||||
# =========
|
||||
FROM rust:bookworm as builder
|
||||
WORKDIR /builder
|
||||
|
||||
COPY migrations ./migrations
|
||||
COPY src ./src
|
||||
COPY airport-codes.json Cargo.toml diesel.toml ./
|
||||
COPY Cargo.toml ./
|
||||
|
||||
RUN apt-get update && apt-get install -y cmake
|
||||
RUN cargo build --release
|
||||
|
||||
CMD ["./target/release/weather-service"]
|
||||
# =========
|
||||
# Runtime
|
||||
# =========
|
||||
FROM debian:bookworm-slim as runtime
|
||||
WORKDIR /service
|
||||
USER root
|
||||
|
||||
COPY --from=builder /builder/target/release/service /usr/local/bin/service
|
||||
COPY --from=packages /packages /usr/bin
|
||||
|
||||
CMD ["service"]
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#!make
|
||||
SHELL := /bin/bash
|
||||
|
||||
include .env
|
||||
|
||||
SHELL := /bin/bash
|
||||
|
||||
.PHONY: help build start stop lint
|
||||
|
||||
help: ## This info
|
||||
@@ -11,17 +10,17 @@ help: ## This info
|
||||
@cat Makefile | grep -E '^[a-zA-Z\/_-]+:.*?## .*$$' | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
@echo
|
||||
|
||||
build: ## Build Docker containers
|
||||
build: ## Build the Docker image
|
||||
docker compose build
|
||||
|
||||
utils: ## Start the utils
|
||||
docker compose up -d db
|
||||
docker compose up -d redis
|
||||
|
||||
up: ## Start Docker containers
|
||||
up: ## Start the Docker containers
|
||||
docker compose up -d
|
||||
|
||||
down: ## Stop Docker containers
|
||||
down: ## Stop the Docker containers
|
||||
docker compose down
|
||||
|
||||
connect: ## Connect to the Weather DB
|
||||
|
||||
@@ -63666,7 +63666,7 @@
|
||||
"local_code": "W43"
|
||||
},
|
||||
{
|
||||
"icao": "KW45",
|
||||
"icao": "KLUA",
|
||||
"category": "small_airport",
|
||||
"full_name": "Luray Caverns Airport",
|
||||
"point":
|
||||
|
||||
@@ -27,6 +27,21 @@ services:
|
||||
networks:
|
||||
- backend
|
||||
restart: unless-stopped
|
||||
minio:
|
||||
image: minio/minio
|
||||
container_name: weather-minio
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||
volumes:
|
||||
- minio:/data
|
||||
ports:
|
||||
- ${MINIO_PORT:-9000}:9000
|
||||
- ${MINIO_PORT_INTERNAL:-9001}:9001
|
||||
networks:
|
||||
- backend
|
||||
command: server --console-address ":9001" /data
|
||||
restart: unless-stopped
|
||||
|
||||
service:
|
||||
container_name: weather-service
|
||||
@@ -54,6 +69,7 @@ services:
|
||||
volumes:
|
||||
db:
|
||||
db_logs:
|
||||
minio:
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::db;
|
||||
use crate::error_handler::ServiceError;
|
||||
use crate::db::schema::airports;
|
||||
use diesel::dsl::count_star;
|
||||
use diesel::prelude::*;
|
||||
// use log::trace;
|
||||
use postgis_diesel::types::*;
|
||||
use postgis_diesel::functions::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -25,6 +25,79 @@ pub struct InsertAirport {
|
||||
pub point: Point
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct QueryFilters {
|
||||
pub name: Option<String>,
|
||||
pub icao: Option<String>,
|
||||
pub bounds: Option<Polygon<Point>>,
|
||||
pub category: Option<String>,
|
||||
pub order_field: Option<QueryOrderField>,
|
||||
pub order_by: Option<QueryOrderBy>
|
||||
}
|
||||
|
||||
impl Default for QueryFilters {
|
||||
fn default() -> Self {
|
||||
QueryFilters {
|
||||
name: None,
|
||||
icao: None,
|
||||
bounds: None,
|
||||
category: None,
|
||||
order_field: None,
|
||||
order_by: None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum QueryOrderBy {
|
||||
Asc,
|
||||
Desc
|
||||
}
|
||||
|
||||
impl FromStr for QueryOrderBy {
|
||||
type Err = ();
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"asc" => Ok(QueryOrderBy::Asc),
|
||||
"desc" => Ok(QueryOrderBy::Desc),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum QueryOrderField {
|
||||
Icao,
|
||||
Name,
|
||||
Category,
|
||||
Continent,
|
||||
Country,
|
||||
Region,
|
||||
Municipality,
|
||||
GPS,
|
||||
Iata,
|
||||
Local,
|
||||
}
|
||||
|
||||
impl FromStr for QueryOrderField {
|
||||
type Err = ();
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"icao" => Ok(QueryOrderField::Icao),
|
||||
"name" => Ok(QueryOrderField::Name),
|
||||
"category" => Ok(QueryOrderField::Category),
|
||||
"continent" => Ok(QueryOrderField::Continent),
|
||||
"iso_country" => Ok(QueryOrderField::Country),
|
||||
"iso_region" => Ok(QueryOrderField::Region),
|
||||
"municipality" => Ok(QueryOrderField::Municipality),
|
||||
"gps_code" => Ok(QueryOrderField::GPS),
|
||||
"iata_code" => Ok(QueryOrderField::Iata),
|
||||
"local_code" => Ok(QueryOrderField::Local),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Queryable, QueryableByName)]
|
||||
#[diesel(table_name = airports)]
|
||||
pub struct QueryAirport {
|
||||
@@ -44,51 +117,95 @@ pub struct QueryAirport {
|
||||
}
|
||||
|
||||
impl QueryAirport {
|
||||
pub fn get_all(bounds: &Option<Polygon<Point>>, category: &Option<String>, filter: &Option<String>, order_by: bool, limit: i32, page: i32) -> Result<Vec<Self>, ServiceError> {
|
||||
pub fn get_all(filters: &QueryFilters, limit: i32, page: i32) -> Result<Vec<Self>, ServiceError> {
|
||||
let mut conn = db::connection()?;
|
||||
|
||||
let mut query = airports::table
|
||||
.limit(limit as i64)
|
||||
.into_boxed();
|
||||
query = query.filter(airports::id.gt(std::cmp::max(0, page - 1) * limit));
|
||||
let mut query = airports::table.limit(limit as i64).into_boxed();
|
||||
// Limit query to page and limit
|
||||
let offset = (page - 1) * limit;
|
||||
query = query.offset(offset as i64);
|
||||
|
||||
if let Some(bounds) = bounds {
|
||||
if let Some(bounds) = &filters.bounds {
|
||||
query = query.filter(st_contains(bounds, airports::point));
|
||||
}
|
||||
if let Some(category) = category {
|
||||
if let Some(category) = &filters.category {
|
||||
query = query.filter(airports::category.eq(category));
|
||||
}
|
||||
if let Some(filter) = filter {
|
||||
query = query.filter(airports::icao
|
||||
.ilike(format!("%{}%", filter))
|
||||
.or(airports::full_name.ilike(format!("%{}%", filter)))
|
||||
)
|
||||
if let Some(icao) = &filters.icao {
|
||||
if let Some(name) = &filters.name {
|
||||
query = query.filter(
|
||||
airports::icao.ilike(format!("%{}%", icao)).or(
|
||||
airports::full_name.ilike(format!("%{}%", name))
|
||||
)
|
||||
)
|
||||
} else {
|
||||
query = query.filter(airports::icao.ilike(format!("%{}%", icao)))
|
||||
}
|
||||
}
|
||||
if order_by {
|
||||
query = query.order(airports::category.asc());
|
||||
|
||||
if let Some(order_by) = &filters.order_by {
|
||||
match order_by {
|
||||
QueryOrderBy::Asc => {
|
||||
if let Some(order_field) = &filters.order_field {
|
||||
query = match order_field {
|
||||
QueryOrderField::Icao => query.order(airports::icao.asc()),
|
||||
QueryOrderField::Name => query.order(airports::full_name.asc()),
|
||||
QueryOrderField::Category => query.order(airports::category.asc()),
|
||||
QueryOrderField::Continent => query.order(airports::continent.asc()),
|
||||
QueryOrderField::Country => query.order(airports::iso_country.asc()),
|
||||
QueryOrderField::Region => query.order(airports::iso_region.asc()),
|
||||
QueryOrderField::Municipality => query.order(airports::municipality.asc()),
|
||||
QueryOrderField::GPS => query.order(airports::gps_code.asc()),
|
||||
QueryOrderField::Iata => query.order(airports::iata_code.asc()),
|
||||
QueryOrderField::Local => query.order(airports::local_code.asc()),
|
||||
};
|
||||
};
|
||||
},
|
||||
QueryOrderBy::Desc => {
|
||||
if let Some(order_field) = &filters.order_field {
|
||||
query = match order_field {
|
||||
QueryOrderField::Icao => query.order(airports::icao.desc()),
|
||||
QueryOrderField::Name => query.order(airports::full_name.desc()),
|
||||
QueryOrderField::Category => query.order(airports::category.desc()),
|
||||
QueryOrderField::Continent => query.order(airports::continent.desc()),
|
||||
QueryOrderField::Country => query.order(airports::iso_country.desc()),
|
||||
QueryOrderField::Region => query.order(airports::iso_region.desc()),
|
||||
QueryOrderField::Municipality => query.order(airports::municipality.desc()),
|
||||
QueryOrderField::GPS => query.order(airports::gps_code.desc()),
|
||||
QueryOrderField::Iata => query.order(airports::iata_code.desc()),
|
||||
QueryOrderField::Local => query.order(airports::local_code.desc()),
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
let airports: Vec<QueryAirport> = query.load::<QueryAirport>(&mut conn)?;
|
||||
Ok(airports)
|
||||
}
|
||||
|
||||
pub fn get_count(bounds: &Option<Polygon<Point>>, category: &Option<String>, filter: &Option<String>) -> Result<i64, ServiceError> {
|
||||
pub fn get_count(filters: &QueryFilters) -> Result<i64, ServiceError> {
|
||||
let mut conn = db::connection()?;
|
||||
let mut query = airports::table.select(count_star()).into_boxed();
|
||||
let mut query = airports::table.count().into_boxed();
|
||||
|
||||
if let Some(bounds) = bounds {
|
||||
if let Some(bounds) = &filters.bounds {
|
||||
query = query.filter(st_contains(bounds, airports::point));
|
||||
}
|
||||
if let Some(category) = category {
|
||||
if let Some(category) = &filters.category {
|
||||
query = query.filter(airports::category.eq(category));
|
||||
}
|
||||
if let Some(filter) = filter {
|
||||
query = query.filter(airports::icao
|
||||
.ilike(format!("%{}%", filter))
|
||||
.or(airports::full_name.ilike(format!("%{}%", filter)))
|
||||
)
|
||||
if let Some(icao) = &filters.icao {
|
||||
if let Some(name) = &filters.name {
|
||||
query = query.filter(
|
||||
airports::icao.ilike(format!("%{}%", icao)).or(
|
||||
airports::full_name.ilike(format!("%{}%", name))
|
||||
)
|
||||
)
|
||||
} else {
|
||||
query = query.filter(airports::icao.ilike(format!("%{}%", icao)))
|
||||
}
|
||||
}
|
||||
|
||||
let count: i64 = query.first(&mut conn)?;
|
||||
let count: i64 = query.get_result(&mut conn)?;
|
||||
return Ok(count);
|
||||
}
|
||||
|
||||
@@ -96,29 +213,32 @@ impl QueryAirport {
|
||||
let mut conn = db::connection()?;
|
||||
let airport = airports::table.filter(airports::icao.eq(icao)).first(&mut conn)?;
|
||||
Ok(airport)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(airport: InsertAirport) -> Result<Self, ServiceError> {
|
||||
pub fn create(airport: InsertAirport) -> Result<Self, ServiceError> {
|
||||
let mut conn = db::connection()?;
|
||||
let airport = InsertAirport::from(airport);
|
||||
let airport = diesel::insert_into(airports::table)
|
||||
.values(airport)
|
||||
.get_result(&mut conn)?;
|
||||
Ok(airport)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(id: i32, airport: InsertAirport) -> Result<Self, ServiceError> {
|
||||
pub fn update(id: i32, airport: InsertAirport) -> Result<Self, ServiceError> {
|
||||
let mut conn = db::connection()?;
|
||||
let airport = diesel::update(airports::table)
|
||||
.filter(airports::id.eq(id))
|
||||
.set(airport)
|
||||
.get_result(&mut conn)?;
|
||||
Ok(airport)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete(id: i32) -> Result<usize, ServiceError> {
|
||||
pub fn delete(id: Option<i32>) -> Result<usize, ServiceError> {
|
||||
let mut conn = db::connection()?;
|
||||
let res = diesel::delete(airports::table.filter(airports::id.eq(id))).execute(&mut conn)?;
|
||||
let res = match id {
|
||||
Some(id) => diesel::delete(airports::table.filter(airports::id.eq(id))).execute(&mut conn)?,
|
||||
None => diesel::delete(airports::table).execute(&mut conn)?
|
||||
};
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::{airports::{InsertAirport, QueryAirport}, db::{self, Metadata}, auth::{JwtAuth, verify_role}};
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::{airports::{InsertAirport, QueryAirport, QueryFilters, QueryOrderField, QueryOrderBy}, db::{self, Response, Metadata}, auth::{JwtAuth, verify_role}};
|
||||
use actix_web::{delete, get, post, put, web, HttpResponse, HttpRequest, ResponseError};
|
||||
use log::{error, warn};
|
||||
use postgis_diesel::types::{Polygon, Point};
|
||||
@@ -6,9 +8,12 @@ use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct GetAllParameters {
|
||||
filter: Option<String>,
|
||||
name: Option<String>,
|
||||
icao: Option<String>,
|
||||
bounds: Option<String>,
|
||||
category: Option<String>,
|
||||
order_field: Option<String>,
|
||||
order_by: Option<String>,
|
||||
limit: Option<i32>,
|
||||
page: Option<i32>
|
||||
}
|
||||
@@ -19,20 +24,21 @@ async fn import(auth: JwtAuth) -> HttpResponse {
|
||||
Ok(_) => {},
|
||||
Err(err) => return ResponseError::error_response(&err)
|
||||
};
|
||||
db::import_data();
|
||||
HttpResponse::Ok().body({})
|
||||
let count = db::import_data();
|
||||
HttpResponse::Ok().json(Response {
|
||||
data: count,
|
||||
meta: None
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AirportsResponse {
|
||||
pub data: Vec<QueryAirport>,
|
||||
pub meta: Metadata
|
||||
}
|
||||
|
||||
#[get("/airports")]
|
||||
#[get("/search")]
|
||||
async fn get_all(req: HttpRequest) -> HttpResponse {
|
||||
let params = web::Query::<GetAllParameters>::from_query(req.query_string()).unwrap();
|
||||
let polygon: Option<Polygon<Point>> = match ¶ms.bounds {
|
||||
let mut filters = QueryFilters::default();
|
||||
filters.name = params.name.clone();
|
||||
filters.icao = params.icao.clone();
|
||||
filters.category = params.category.clone();
|
||||
filters.bounds = match ¶ms.bounds {
|
||||
Some(b) => {
|
||||
let bounds: Vec<&str> = b.split(",").collect();
|
||||
if bounds.len() != 4 {
|
||||
@@ -77,12 +83,13 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
|
||||
},
|
||||
None => None
|
||||
};
|
||||
let category = match ¶ms.category {
|
||||
Some(c) => Some(c.to_string()),
|
||||
|
||||
filters.order_by = match ¶ms.order_by {
|
||||
Some(o) => Some(QueryOrderBy::from_str(&o).unwrap()),
|
||||
None => None
|
||||
};
|
||||
let filter = match ¶ms.filter {
|
||||
Some(f) => Some(f.to_string()),
|
||||
filters.order_field = match ¶ms.order_field {
|
||||
Some(o) => Some(QueryOrderField::from_str(&o).unwrap()),
|
||||
None => None
|
||||
};
|
||||
|
||||
@@ -94,16 +101,16 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
|
||||
Some(p) => p,
|
||||
None => 1
|
||||
};
|
||||
let total = match QueryAirport::get_count(&polygon, &category, &filter) {
|
||||
let total = match QueryAirport::get_count(&filters) {
|
||||
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(&polygon, &category, &filter, true, limit, page)).await.unwrap() {
|
||||
Ok(a) => HttpResponse::Ok().json(AirportsResponse {
|
||||
match web::block(move || QueryAirport::get_all(&filters, limit, page)).await.unwrap() {
|
||||
Ok(a) => HttpResponse::Ok().json(Response {
|
||||
data: a,
|
||||
meta: Metadata { page, limit, pages, total }
|
||||
meta: Some(Metadata { page, limit, pages, total })
|
||||
}),
|
||||
Err(err) => {
|
||||
error!("{}", err);
|
||||
@@ -112,18 +119,12 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AirportResponse {
|
||||
pub data: QueryAirport,
|
||||
pub meta: Metadata
|
||||
}
|
||||
|
||||
#[get("/airports/{icao}")]
|
||||
#[get("/search/{icao}")]
|
||||
async fn get(icao: web::Path<String>) -> HttpResponse {
|
||||
match QueryAirport::find(icao.into_inner()) {
|
||||
Ok(a) => HttpResponse::Ok().json(AirportResponse {
|
||||
Ok(a) => HttpResponse::Ok().json(Response {
|
||||
data: a,
|
||||
meta: Metadata { page: 1, limit: 1, pages: 1, total: 1 }
|
||||
meta: Some(Metadata { page: 1, limit: 1, pages: 1, total: 1 })
|
||||
}),
|
||||
Err(err) => {
|
||||
error!("{}", err);
|
||||
@@ -132,7 +133,7 @@ async fn get(icao: web::Path<String>) -> HttpResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/airports")]
|
||||
#[post("/create")]
|
||||
async fn create(airport: web::Json<InsertAirport>, auth: JwtAuth) -> HttpResponse {
|
||||
let _ = match verify_role(&auth, "admin") {
|
||||
Ok(_) => {},
|
||||
@@ -147,7 +148,7 @@ async fn create(airport: web::Json<InsertAirport>, auth: JwtAuth) -> HttpRespons
|
||||
}
|
||||
}
|
||||
|
||||
#[put("/airports/{icao}")]
|
||||
#[put("/update/{icao}")]
|
||||
async fn update(icao: web::Path<i32>, airport: web::Json<InsertAirport>, auth: JwtAuth) -> HttpResponse {
|
||||
let _ = match verify_role(&auth, "admin") {
|
||||
Ok(_) => {},
|
||||
@@ -162,13 +163,28 @@ async fn update(icao: web::Path<i32>, airport: web::Json<InsertAirport>, auth: J
|
||||
}
|
||||
}
|
||||
|
||||
#[delete("/airports/{icao}")]
|
||||
async fn delete(icao: web::Path<i32>, auth: JwtAuth) -> HttpResponse {
|
||||
#[delete("/remove")]
|
||||
async fn remove_all(auth: JwtAuth) -> HttpResponse {
|
||||
let _ = match verify_role(&auth, "admin") {
|
||||
Ok(_) => {},
|
||||
Err(err) => return ResponseError::error_response(&err)
|
||||
};
|
||||
match QueryAirport::delete(icao.into_inner()) {
|
||||
match QueryAirport::delete(None) {
|
||||
Ok(_) => HttpResponse::NoContent().finish(),
|
||||
Err(err) => {
|
||||
error!("{}", err);
|
||||
err.to_http_response()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[delete("/remove/{icao}")]
|
||||
async fn remove(icao: web::Path<i32>, auth: JwtAuth) -> HttpResponse {
|
||||
let _ = match verify_role(&auth, "admin") {
|
||||
Ok(_) => {},
|
||||
Err(err) => return ResponseError::error_response(&err)
|
||||
};
|
||||
match QueryAirport::delete(Some(icao.into_inner())) {
|
||||
Ok(_) => HttpResponse::NoContent().finish(),
|
||||
Err(err) => {
|
||||
error!("{}", err);
|
||||
@@ -178,10 +194,13 @@ async fn delete(icao: web::Path<i32>, auth: JwtAuth) -> HttpResponse {
|
||||
}
|
||||
|
||||
pub fn init_routes(config: &mut web::ServiceConfig) {
|
||||
config.service(get_all);
|
||||
config.service(get);
|
||||
config.service(create);
|
||||
config.service(update);
|
||||
config.service(delete);
|
||||
config.service(import);
|
||||
config.service(web::scope("airports")
|
||||
.service(get_all)
|
||||
.service(get)
|
||||
.service(create)
|
||||
.service(update)
|
||||
.service(remove)
|
||||
.service(remove_all)
|
||||
.service(import)
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ use actix_web::{get, post, web, HttpResponse, ResponseError, cookie::{Cookie, ti
|
||||
use log::error;
|
||||
use redis::AsyncCommands;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::error_handler::ServiceError;
|
||||
use crate::{error_handler::ServiceError, db::Response};
|
||||
|
||||
use crate::{auth::{LoginRequest, RegisterUser, InsertUser, QueryUser, verify_password, JwtAuth, verify_token, generate_access_token, generate_refresh_token}, db};
|
||||
|
||||
@@ -342,7 +342,10 @@ async fn me(auth: JwtAuth) -> HttpResponse {
|
||||
|
||||
#[get("/roles")]
|
||||
async fn roles() -> HttpResponse {
|
||||
HttpResponse::Ok().json(vec!["admin", "user"])
|
||||
HttpResponse::Ok().json(Response {
|
||||
data: vec!["admin", "user"],
|
||||
meta: None
|
||||
})
|
||||
}
|
||||
|
||||
pub fn init_routes(config: &mut web::ServiceConfig) {
|
||||
|
||||
@@ -59,18 +59,26 @@ pub async fn redis_async_connection() -> Result<RedisConnection, ServiceError> {
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
pub fn import_data() {
|
||||
pub fn import_data() -> i32 {
|
||||
let path = "airport-codes.json";
|
||||
debug!("Importing data from {}", path);
|
||||
let contents: String = std::fs::read_to_string(path).expect("Failed to read file");
|
||||
let airports: Vec<InsertAirport> = serde_json::from_str(&contents).expect("JSON was not well formed.");
|
||||
let mut count = 0;
|
||||
for airport in airports {
|
||||
match QueryAirport::create(airport) {
|
||||
Ok(_) => {},
|
||||
Ok(_) => count += 1,
|
||||
Err(err) => error!("Error inserting airport; {}", err)
|
||||
};
|
||||
}
|
||||
debug!("Import complete");
|
||||
return count;
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Response<T> {
|
||||
pub data: T,
|
||||
pub meta: Option<Metadata>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use tokio::time::{sleep, Duration};
|
||||
use log::{warn, debug, trace};
|
||||
|
||||
use crate::airports::QueryAirport;
|
||||
use crate::airports::{QueryAirport, QueryFilters};
|
||||
use crate::metars::Metar;
|
||||
|
||||
pub fn update_airports() {
|
||||
tokio::spawn(async {
|
||||
loop {
|
||||
debug!("METAR update start");
|
||||
let total = match QueryAirport::get_count(&None, &None, &None) {
|
||||
let total = match QueryAirport::get_count(&QueryFilters::default()) {
|
||||
Ok(t) => t,
|
||||
Err(err) => {
|
||||
warn!("{}", err);
|
||||
@@ -19,7 +19,7 @@ pub fn update_airports() {
|
||||
let pages = ((total as f32) / (if limit <= 0 { 1 } else { limit} as f32)).ceil() as i32;
|
||||
let mut airports: Vec<QueryAirport> = vec![];
|
||||
for page in 1..(pages + 1) {
|
||||
match QueryAirport::get_all(&None, &None, &None, false, limit, page) {
|
||||
match QueryAirport::get_all(&QueryFilters::default(), limit, page) {
|
||||
Ok(mut a) => {
|
||||
airports.append(&mut a)
|
||||
},
|
||||
|
||||
@@ -4,7 +4,6 @@ use crate::auth::{JwtAuth, QueryUser, InsertUser};
|
||||
|
||||
#[get("users/favorites")]
|
||||
async fn get_favorites(auth: JwtAuth) -> HttpResponse {
|
||||
println!("{:?}", auth);
|
||||
match QueryUser::get_by_email(&auth.user.email) {
|
||||
Ok(user) => {
|
||||
return HttpResponse::Ok().json(user.favorites)
|
||||
|
||||
Reference in New Issue
Block a user