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
|
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> {
|
fn run_command(ctx: Arc<Context>, req: Self::Req, user: Option<Player>) -> Result<Self::Resp> {
|
||||||
let user = user.unwrap();
|
let user = user.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,10 @@ pub trait Command {
|
||||||
fn command_level() -> CommandLevel;
|
fn command_level() -> CommandLevel;
|
||||||
fn run_command(ctx: Arc<Context>, req: Self::Req, user: Option<Player>) -> Result<Self::Resp>;
|
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<()> {
|
fn user_is_authorized(token: &Option<Token>, user: &Option<Player>) -> Result<()> {
|
||||||
if let Some(token) = token {
|
if let Some(token) = token {
|
||||||
if !match Self::command_level() {
|
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)?;
|
let token = get_token_from_req(&ctx.db, &req)?;
|
||||||
|
|
||||||
match T::user_is_authorized(&token, &user) {
|
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),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use crate::commands::{Command, RequestType};
|
use crate::commands::{Command, RequestType};
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
use geoffrey_models::models::item::ItemListing;
|
||||||
use geoffrey_models::models::locations::{LocationDataDb, LocationDb};
|
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::player::Player;
|
||||||
use geoffrey_models::models::response::selling_listing::SellingListing;
|
use geoffrey_models::models::response::selling_listing::SellingListing;
|
||||||
use geoffrey_models::models::CommandLevel;
|
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> {
|
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
|
.db
|
||||||
.filter(|_, loc: &LocationDb| {
|
.filter(|_, loc: &LocationDb| {
|
||||||
if let LocationDataDb::Shop(shop_data) = loc.loc_data.clone() {
|
if let LocationDataDb::Shop(shop_data) = loc.loc_data.clone() {
|
||||||
|
@ -68,7 +69,31 @@ impl Command for Selling {
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect();
|
.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 chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
|
@ -33,4 +34,24 @@ impl ItemListing {
|
||||||
restocked_time: Utc::now(),
|
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,
|
Restock,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
pub enum Order {
|
pub enum Order {
|
||||||
High,
|
High,
|
||||||
Low,
|
Low,
|
||||||
|
|
|
@ -10,6 +10,7 @@ pub enum GeoffreyAPIError {
|
||||||
DatabaseError(String),
|
DatabaseError(String),
|
||||||
TokenNotAuthorized,
|
TokenNotAuthorized,
|
||||||
MultipleLocationsMatch,
|
MultipleLocationsMatch,
|
||||||
|
ParameterInvalid(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for GeoffreyAPIError {
|
impl Display for GeoffreyAPIError {
|
||||||
|
@ -30,6 +31,9 @@ impl Display for GeoffreyAPIError {
|
||||||
GeoffreyAPIError::MultipleLocationsMatch => {
|
GeoffreyAPIError::MultipleLocationsMatch => {
|
||||||
"The location query returned multiple locations.".to_string()
|
"The location query returned multiple locations.".to_string()
|
||||||
}
|
}
|
||||||
|
GeoffreyAPIError::ParameterInvalid(param) => {
|
||||||
|
format!("Parameter \"{}\" is invalid", param)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
write!(f, "{}", string)
|
write!(f, "{}", string)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue