use crate::commands::add_location::AddLocation; use crate::commands::find::FindCommand; use crate::commands::register::Register; use crate::context::Context; use crate::Result; use geoffrey_models::models::response::APIResponse; use geoffrey_models::models::CommandLevel; use serde::de::DeserializeOwned; use serde::Serialize; use std::fmt::Debug; use std::sync::Arc; use warp::filters::BoxedFilter; use warp::Filter; use geoffrey_models::models::player::Player; use crate::helper::get_player_from_req; use geoffrey_models::models::response::api_error::GeoffreyAPIError; use geoffrey_models::models::parameters::CommandRequest; pub mod add_location; pub mod find; pub mod register; #[derive(Debug, Clone, PartialEq)] #[allow(clippy::upper_case_acronyms)] pub enum RequestType { POST, GET, } pub trait Command { type Req: CommandRequest; type Resp: Serialize + DeserializeOwned + Send; fn command_name() -> String; fn request_type() -> RequestType; fn command_level() -> CommandLevel; fn run_command(ctx: Arc, req: Self::Req, user: Option) -> Result; fn user_is_authorized(user: &Option) -> Result<()> { if Self::command_level() == CommandLevel::ALL { Ok(()) } else { if let Some(user) = user { if user.auth_level >= Self::command_level() { Ok(()) } else { Err(GeoffreyAPIError::PermissionInsufficient) } } else { Err(GeoffreyAPIError::PlayerNotRegistered) } } } } pub fn handle_command(ctx: Arc, req: T::Req) -> Result { log::info!("Running command {}", T::command_name()); log::debug!("Request: {:?}", req); let user = get_player_from_req(&ctx.db, &req)?; match T::user_is_authorized(&user) { Ok(_) => T::run_command(ctx, req, user), Err(e) => Err(e) } } #[allow(clippy::needless_return)] pub fn create_command_filter(ctx: Arc) -> BoxedFilter<(impl warp::Reply,)> { let filter = warp::path(T::command_name()) .and(warp::any().map(move || ctx.clone())) .and(warp::body::json()) .map(|ctx: Arc, req: T::Req| { let reply = handle_command::(ctx, req); if let Ok(reply) = reply { log::debug!("Successfully processed command"); warp::reply::json(&APIResponse::Response::(reply)) } else { let e = reply.err().unwrap(); log::warn!("Got error when processing command: {:?}", e); warp::reply::json(&APIResponse::::Error(e)) } }); if T::request_type() == RequestType::POST { return filter.and(warp::post()).boxed(); } else { return filter.and(warp::get()).boxed(); } } pub fn command_filter( ctx: Arc, ) -> impl Filter + Clone { warp::path("command").and( create_command_filter::(ctx.clone()) .or(create_command_filter::(ctx.clone())) .or(create_command_filter::(ctx)), ) }