2021-10-29 18:42:04 +02:00
|
|
|
use serde::{Deserialize, Serialize};
|
2021-09-07 20:26:59 +02:00
|
|
|
use std::convert::Infallible;
|
|
|
|
|
|
2021-09-07 19:29:51 +02:00
|
|
|
use warp;
|
|
|
|
|
use warp::http::StatusCode;
|
2021-09-07 20:26:59 +02:00
|
|
|
use warp::Filter;
|
|
|
|
|
|
2021-09-07 19:29:51 +02:00
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct InvalidUuid;
|
|
|
|
|
|
|
|
|
|
impl warp::reject::Reject for InvalidUuid {}
|
|
|
|
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
|
|
struct ErrorMessage {
|
|
|
|
|
code: u16,
|
|
|
|
|
success: bool,
|
|
|
|
|
message: String,
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-29 18:42:04 +02:00
|
|
|
#[derive(Deserialize, Clone)]
|
|
|
|
|
#[serde(deny_unknown_fields)]
|
|
|
|
|
struct JsonListItem {
|
|
|
|
|
name: String,
|
|
|
|
|
count: i32,
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-07 19:29:51 +02:00
|
|
|
pub fn new() -> warp::filters::BoxedFilter<(impl warp::Reply,)> {
|
|
|
|
|
let accept_json = warp::header::exact("accept", "application/json");
|
2021-10-29 18:42:04 +02:00
|
|
|
let content_json = warp::header::exact("content-type", "application/json");
|
|
|
|
|
let cors = warp::cors()
|
|
|
|
|
.allow_any_origin()
|
|
|
|
|
.allow_methods(&[
|
|
|
|
|
warp::http::Method::GET,
|
|
|
|
|
warp::http::Method::POST,
|
|
|
|
|
warp::http::Method::DELETE,
|
|
|
|
|
])
|
|
|
|
|
.allow_headers(vec!["accept", "content-type"]);
|
|
|
|
|
|
|
|
|
|
fn json_body() -> impl Filter<Extract = (JsonListItem,), Error = warp::Rejection> + Clone {
|
|
|
|
|
warp::body::content_length_limit(1024 * 16).and(warp::body::json())
|
|
|
|
|
}
|
2021-09-07 19:29:51 +02:00
|
|
|
|
2021-09-07 20:26:59 +02:00
|
|
|
let root = warp::path::end().map(|| "Hi");
|
2021-09-07 19:29:51 +02:00
|
|
|
|
|
|
|
|
let v1 = warp::path!("v1")
|
|
|
|
|
.and(warp::get())
|
|
|
|
|
.and(warp::path::end())
|
2021-09-07 20:26:59 +02:00
|
|
|
.map(warp::reply);
|
2021-09-07 19:29:51 +02:00
|
|
|
|
|
|
|
|
let lists = warp::path!("v1" / "lists")
|
|
|
|
|
.and(warp::path::end())
|
|
|
|
|
.and(warp::get())
|
|
|
|
|
.and(accept_json)
|
|
|
|
|
.map(|| warp::reply::json(&super::get_lists()))
|
2021-09-07 20:26:59 +02:00
|
|
|
.with(&cors);
|
2021-09-07 19:29:51 +02:00
|
|
|
|
|
|
|
|
let list = warp::path!("v1" / "lists" / String)
|
|
|
|
|
.and(warp::path::end())
|
|
|
|
|
.and(warp::get())
|
|
|
|
|
.and(accept_json)
|
|
|
|
|
.and_then(|id: String| async move {
|
|
|
|
|
match Uuid::parse_str(&id) {
|
|
|
|
|
Ok(uuid) => {
|
|
|
|
|
let list = &super::get_list(uuid);
|
|
|
|
|
match list {
|
|
|
|
|
Some(l) => Ok(warp::reply::json(l)),
|
|
|
|
|
None => Err(warp::reject::not_found()),
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-09-07 20:26:59 +02:00
|
|
|
Err(_) => Err(warp::reject::custom(InvalidUuid)),
|
2021-09-07 19:29:51 +02:00
|
|
|
}
|
|
|
|
|
})
|
2021-09-07 20:26:59 +02:00
|
|
|
.with(&cors);
|
2021-09-07 19:29:51 +02:00
|
|
|
|
2021-10-29 18:42:04 +02:00
|
|
|
let list_items = warp::path!("v1" / "lists" / String / "items")
|
|
|
|
|
.and(warp::path::end())
|
|
|
|
|
.and(warp::get())
|
|
|
|
|
.and(accept_json)
|
|
|
|
|
.and_then(|list_id: String| async move {
|
|
|
|
|
match Uuid::parse_str(&list_id) {
|
|
|
|
|
Ok(uuid) => {
|
|
|
|
|
let items = &super::get_packagelist_items(uuid);
|
|
|
|
|
Ok(warp::reply::json(items))
|
|
|
|
|
}
|
|
|
|
|
Err(_) => Err(warp::reject::custom(InvalidUuid)),
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.with(&cors);
|
|
|
|
|
|
|
|
|
|
let preparation = warp::path!("v1" / "lists" / String / "items" / String / "preparation")
|
|
|
|
|
.and(warp::path::end())
|
|
|
|
|
.and(warp::get())
|
|
|
|
|
.and(accept_json)
|
|
|
|
|
.and_then(|list_id: String, item_id: String| async move {
|
|
|
|
|
match Uuid::parse_str(&list_id) {
|
|
|
|
|
Ok(list_id) => match Uuid::parse_str(&item_id) {
|
|
|
|
|
Err(_) => Err(warp::reject::custom(InvalidUuid)),
|
|
|
|
|
Ok(item_id) => {
|
|
|
|
|
let items = &super::get_preparation(list_id, item_id);
|
|
|
|
|
Ok(warp::reply::json(items))
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
Err(_) => Err(warp::reject::custom(InvalidUuid)),
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.with(&cors);
|
|
|
|
|
|
|
|
|
|
let new_item = warp::path!("v1" / "lists" / String / "items")
|
|
|
|
|
.and(warp::path::end())
|
|
|
|
|
.and(warp::post())
|
|
|
|
|
.and(accept_json)
|
|
|
|
|
.and(content_json)
|
|
|
|
|
.and(json_body())
|
|
|
|
|
.and_then(|list_id: String, item: JsonListItem| async move {
|
|
|
|
|
match Uuid::parse_str(&list_id) {
|
|
|
|
|
Ok(list_id) => {
|
|
|
|
|
let new_item = &super::new_item(list_id, item.name, item.count);
|
|
|
|
|
Ok(warp::reply::json(new_item))
|
|
|
|
|
}
|
|
|
|
|
Err(_) => Err(warp::reject::custom(InvalidUuid)),
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.with(&cors);
|
|
|
|
|
|
2021-09-07 20:26:59 +02:00
|
|
|
let trips = warp::path!("v1" / "trips")
|
|
|
|
|
.and(warp::path::end())
|
|
|
|
|
.and(warp::get())
|
|
|
|
|
.and(accept_json)
|
|
|
|
|
.map(|| warp::reply::json(&super::get_trips()))
|
|
|
|
|
.with(&cors);
|
2021-09-07 19:29:51 +02:00
|
|
|
|
2021-09-07 20:26:59 +02:00
|
|
|
root.or(v1)
|
|
|
|
|
.or(lists)
|
|
|
|
|
.or(list)
|
2021-10-29 18:42:04 +02:00
|
|
|
.or(new_item)
|
|
|
|
|
.or(list_items)
|
|
|
|
|
.or(preparation)
|
2021-09-07 20:26:59 +02:00
|
|
|
.or(trips)
|
|
|
|
|
.recover(handle_rejection)
|
|
|
|
|
.boxed()
|
2021-09-07 19:29:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// See https://github.com/seanmonstar/warp/blob/master/examples/rejections.rs
|
|
|
|
|
async fn handle_rejection(err: warp::Rejection) -> Result<impl warp::Reply, Infallible> {
|
|
|
|
|
let code;
|
|
|
|
|
let message;
|
|
|
|
|
|
|
|
|
|
if err.is_not_found() {
|
|
|
|
|
message = "NOT_FOUND";
|
|
|
|
|
code = StatusCode::NOT_FOUND;
|
|
|
|
|
} else if let Some(InvalidUuid) = err.find() {
|
|
|
|
|
code = StatusCode::BAD_REQUEST;
|
|
|
|
|
message = "INVALID_UUID";
|
2021-10-29 18:42:35 +02:00
|
|
|
} else if err
|
|
|
|
|
.find::<warp::filters::body::BodyDeserializeError>()
|
|
|
|
|
.is_some()
|
|
|
|
|
{
|
2021-09-07 19:29:51 +02:00
|
|
|
message = "BAD_REQUEST";
|
|
|
|
|
code = StatusCode::BAD_REQUEST;
|
2021-10-29 18:42:04 +02:00
|
|
|
} else if err.find::<warp::reject::MethodNotAllowed>().is_some() {
|
2021-09-07 19:29:51 +02:00
|
|
|
message = "METHOD_NOT_ALLOWED";
|
|
|
|
|
code = StatusCode::METHOD_NOT_ALLOWED;
|
|
|
|
|
} else {
|
|
|
|
|
// We should have expected this... Just log and say its a 500
|
|
|
|
|
eprintln!("unhandled rejection: {:?}", err);
|
|
|
|
|
message = "UNHANDLED_REJECTION";
|
|
|
|
|
code = StatusCode::INTERNAL_SERVER_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let json = warp::reply::json(&ErrorMessage {
|
|
|
|
|
success: false,
|
|
|
|
|
code: code.as_u16(),
|
|
|
|
|
message: message.into(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Ok(warp::reply::with_status(json, code))
|
|
|
|
|
}
|