Implemented sorting an ordering for selling
+ Added parameter validation as well + Currently, Restock and Price are the two sorting methods availablemain
parent
ebaf28e39e
commit
e1b362aa1c
|
@ -28,6 +28,14 @@ impl Command for AddItem {
|
|||
CommandLevel::REGISTERED
|
||||
}
|
||||
|
||||
fn validate_parameters(req: &Self::Req) -> Result<()> {
|
||||
if req.quantity == 0 {
|
||||
Err(GeoffreyAPIError::ParameterInvalid("quantity".to_string()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn run_command(ctx: Arc<Context>, req: Self::Req, user: Option<Player>) -> Result<Self::Resp> {
|
||||
let user = user.unwrap();
|
||||
|
||||
|
|
|
@ -42,6 +42,10 @@ pub trait Command {
|
|||
fn command_level() -> CommandLevel;
|
||||
fn run_command(ctx: Arc<Context>, req: Self::Req, user: Option<Player>) -> Result<Self::Resp>;
|
||||
|
||||
fn validate_parameters(_: &Self::Req) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn user_is_authorized(token: &Option<Token>, user: &Option<Player>) -> Result<()> {
|
||||
if let Some(token) = token {
|
||||
if !match Self::command_level() {
|
||||
|
@ -77,7 +81,10 @@ pub fn handle_command<T: Command>(ctx: Arc<Context>, req: T::Req) -> Result<T::R
|
|||
let token = get_token_from_req(&ctx.db, &req)?;
|
||||
|
||||
match T::user_is_authorized(&token, &user) {
|
||||
Ok(_) => T::run_command(ctx, req, user),
|
||||
Ok(_) => {
|
||||
T::validate_parameters(&req)?;
|
||||
T::run_command(ctx, req, user)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use crate::commands::{Command, RequestType};
|
||||
use crate::context::Context;
|
||||
use crate::Result;
|
||||
use geoffrey_models::models::item::ItemListing;
|
||||
use geoffrey_models::models::locations::{LocationDataDb, LocationDb};
|
||||
use geoffrey_models::models::parameters::selling_params::SellingParams;
|
||||
use geoffrey_models::models::parameters::selling_params::{ItemSort, Order, SellingParams};
|
||||
use geoffrey_models::models::player::Player;
|
||||
use geoffrey_models::models::response::selling_listing::SellingListing;
|
||||
use geoffrey_models::models::CommandLevel;
|
||||
|
@ -27,7 +28,7 @@ impl Command for Selling {
|
|||
}
|
||||
|
||||
fn run_command(ctx: Arc<Context>, req: Self::Req, _: Option<Player>) -> Result<Self::Resp> {
|
||||
let shops: Vec<SellingListing> = ctx
|
||||
let mut listings: Vec<SellingListing> = ctx
|
||||
.db
|
||||
.filter(|_, loc: &LocationDb| {
|
||||
if let LocationDataDb::Shop(shop_data) = loc.loc_data.clone() {
|
||||
|
@ -68,7 +69,31 @@ impl Command for Selling {
|
|||
.flatten()
|
||||
.collect();
|
||||
|
||||
Ok(shops)
|
||||
let sort = req.sort.unwrap_or(ItemSort::Restock);
|
||||
|
||||
match sort {
|
||||
ItemSort::Price => {
|
||||
listings.sort_by(|a, b| ItemListing::order_by_price(&a.listing, &b.listing))
|
||||
}
|
||||
ItemSort::Restock => {
|
||||
listings.sort_by(|a, b| ItemListing::order_by_restock(&a.listing, &b.listing))
|
||||
}
|
||||
}
|
||||
|
||||
let ordering = if let Some(order) = req.order {
|
||||
order
|
||||
} else {
|
||||
match sort {
|
||||
ItemSort::Price => Order::Low,
|
||||
ItemSort::Restock => Order::High,
|
||||
}
|
||||
};
|
||||
|
||||
if ordering == Order::High {
|
||||
listings.reverse();
|
||||
}
|
||||
|
||||
Ok(listings)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)]
|
||||
pub struct Item {
|
||||
|
@ -33,4 +34,24 @@ impl ItemListing {
|
|||
restocked_time: Utc::now(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn normalized_price(&self) -> f32 {
|
||||
if self.count_per_price == 0 {
|
||||
f32::MAX
|
||||
} else {
|
||||
(self.price as f32) / (self.count_per_price as f32)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn order_by_price(a: &Self, b: &Self) -> Ordering {
|
||||
// Bit of a hack so we can using integer ordering
|
||||
let a_price = (a.normalized_price() * 1000.0) as u64;
|
||||
let b_price = (b.normalized_price() * 1000.0) as u64;
|
||||
|
||||
a_price.cmp(&b_price)
|
||||
}
|
||||
|
||||
pub fn order_by_restock(a: &Self, b: &Self) -> Ordering {
|
||||
a.restocked_time.cmp(&b.restocked_time)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ pub enum ItemSort {
|
|||
Restock,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub enum Order {
|
||||
High,
|
||||
Low,
|
||||
|
|
|
@ -10,6 +10,7 @@ pub enum GeoffreyAPIError {
|
|||
DatabaseError(String),
|
||||
TokenNotAuthorized,
|
||||
MultipleLocationsMatch,
|
||||
ParameterInvalid(String),
|
||||
}
|
||||
|
||||
impl Display for GeoffreyAPIError {
|
||||
|
@ -30,6 +31,9 @@ impl Display for GeoffreyAPIError {
|
|||
GeoffreyAPIError::MultipleLocationsMatch => {
|
||||
"The location query returned multiple locations.".to_string()
|
||||
}
|
||||
GeoffreyAPIError::ParameterInvalid(param) => {
|
||||
format!("Parameter \"{}\" is invalid", param)
|
||||
}
|
||||
};
|
||||
write!(f, "{}", string)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue