105 lines
3.2 KiB
Rust
105 lines
3.2 KiB
Rust
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<Context>, req: Self::Req, user: Option<Player>) -> Result<Self::Resp>;
|
|
|
|
fn user_is_authorized(user: &Option<Player>) -> 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<T: Command>(ctx: Arc<Context>, req: T::Req) -> Result<T::Resp> {
|
|
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<T: Command>(ctx: Arc<Context>) -> 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<Context>, req: T::Req| {
|
|
let reply = handle_command::<T>(ctx, req);
|
|
if let Ok(reply) = reply {
|
|
log::debug!("Successfully processed command");
|
|
warp::reply::json(&APIResponse::Response::<T::Resp>(reply))
|
|
} else {
|
|
let e = reply.err().unwrap();
|
|
log::warn!("Got error when processing command: {:?}", e);
|
|
warp::reply::json(&APIResponse::<T::Resp>::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<Context>,
|
|
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
|
|
warp::path("command").and(
|
|
create_command_filter::<FindCommand>(ctx.clone())
|
|
.or(create_command_filter::<AddLocation>(ctx.clone()))
|
|
.or(create_command_filter::<Register>(ctx)),
|
|
)
|
|
}
|