diff --git a/geoffrey_api/src/commands/mod.rs b/geoffrey_api/src/commands/mod.rs index b11cbcd..67f600f 100644 --- a/geoffrey_api/src/commands/mod.rs +++ b/geoffrey_api/src/commands/mod.rs @@ -5,6 +5,7 @@ use crate::commands::edit::Edit; use crate::commands::find::FindCommand; use crate::commands::link::LinkCommand; use crate::commands::register::Register; +use crate::commands::remove_item::RemoveItem; use crate::commands::selling::Selling; use crate::commands::set_portal::SetPortal; use crate::context::Context; @@ -31,6 +32,7 @@ pub mod edit; pub mod find; pub mod link; pub mod register; +pub mod remove_item; pub mod selling; pub mod set_portal; @@ -137,6 +139,7 @@ pub fn command_filter( .or(create_command_filter::(ctx.clone())) .or(create_command_filter::(ctx.clone())) .or(create_command_filter::(ctx.clone())) + .or(create_command_filter::(ctx.clone())) .or(create_command_filter::(ctx)), ) } diff --git a/geoffrey_api/src/commands/remove_item.rs b/geoffrey_api/src/commands/remove_item.rs new file mode 100644 index 0000000..033c0b7 --- /dev/null +++ b/geoffrey_api/src/commands/remove_item.rs @@ -0,0 +1,52 @@ +use crate::commands::{Command, RequestType}; +use crate::context::Context; +use crate::Result; +use geoffrey_db::helper::{find_location_by_name_type, load_location}; +use geoffrey_models::models::locations::{Location, LocationDataDb, LocationType}; +use geoffrey_models::models::parameters::remove_item_params::RemoveItemParameters; +use geoffrey_models::models::player::Player; +use geoffrey_models::models::response::api_error::GeoffreyAPIError; +use geoffrey_models::models::CommandLevel; +use std::sync::Arc; + +pub struct RemoveItem {} + +impl Command for RemoveItem { + type Req = RemoveItemParameters; + type Resp = Location; + + fn command_name() -> String { + "remove_item".to_string() + } + + fn request_type() -> RequestType { + RequestType::POST + } + + fn command_level() -> CommandLevel { + CommandLevel::REGISTERED + } + + fn run_command(ctx: Arc, req: &Self::Req, user: Option) -> Result { + let user = user.unwrap(); + + let mut shop = find_location_by_name_type( + &ctx.db, + &req.shop_name, + user.id.unwrap(), + LocationType::Shop, + )?; + + if let LocationDataDb::Shop(shop_data) = &mut shop.loc_data { + shop_data + .item_listings + .retain(|item| item.item.name.to_lowercase() != req.item_name.to_lowercase()); + + let shop = ctx.db.insert(shop)?; + + load_location(&ctx.db, &shop).map_err(|err| err.into()) + } else { + Err(GeoffreyAPIError::EntryNotFound) + } + } +} diff --git a/geoffrey_bot/src/bot/commands/add_item.rs b/geoffrey_bot/src/bot/commands/add_item.rs index fdad761..40f7fb8 100644 --- a/geoffrey_bot/src/bot/commands/add_item.rs +++ b/geoffrey_bot/src/bot/commands/add_item.rs @@ -9,7 +9,7 @@ use geoffrey_models::models::parameters::add_item_params::AddItemParams; use crate::bot::arg_parse::{option_to_i64, option_to_string}; use crate::bot::commands::{BotCommand, CommandError}; -use crate::bot::formatters::display_loc; +use crate::bot::formatters::display_loc_full; use crate::bot::lang::{PLAYER_ALREADY_SELLS_ITEM, PLAYER_DOES_NOT_HAVE_MATCHING_SHOP}; use geoffrey_models::models::response::api_error::GeoffreyAPIError; use serenity::builder::CreateApplicationCommand; @@ -94,7 +94,7 @@ impl BotCommand for AddItemCommand { format!( "**{}** has been updated:\n{}", resp.name, - display_loc(&resp) + display_loc_full(&resp) ) } } diff --git a/geoffrey_bot/src/bot/commands/add_location.rs b/geoffrey_bot/src/bot/commands/add_location.rs index 5efb8e4..cac167f 100644 --- a/geoffrey_bot/src/bot/commands/add_location.rs +++ b/geoffrey_bot/src/bot/commands/add_location.rs @@ -12,7 +12,7 @@ use crate::bot::arg_parse::{ add_z_position_argument, option_to_dim, option_to_i64, option_to_loc_type, option_to_string, }; use crate::bot::commands::{BotCommand, CommandError}; -use crate::bot::formatters::display_loc; +use crate::bot::formatters::display_loc_full; use serenity::builder::CreateApplicationCommand; pub struct AddLocationCommand; @@ -80,7 +80,7 @@ impl BotCommand for AddLocationCommand { format!( "**{}** has been added to Geoffrey:\n{}", resp.name, - display_loc(&resp) + display_loc_full(&resp) ) } } diff --git a/geoffrey_bot/src/bot/commands/mod.rs b/geoffrey_bot/src/bot/commands/mod.rs index f8831b1..9fb4afc 100644 --- a/geoffrey_bot/src/bot/commands/mod.rs +++ b/geoffrey_bot/src/bot/commands/mod.rs @@ -24,6 +24,7 @@ pub mod edit_name; pub mod edit_pos; pub mod find; pub mod register; +pub mod remove_item; pub mod selling; pub mod set_portal; diff --git a/geoffrey_bot/src/bot/commands/remove_item.rs b/geoffrey_bot/src/bot/commands/remove_item.rs new file mode 100644 index 0000000..13eac06 --- /dev/null +++ b/geoffrey_bot/src/bot/commands/remove_item.rs @@ -0,0 +1,79 @@ +use async_trait::async_trait; +use reqwest::Method; +use serenity::model::interactions::application_command::{ + ApplicationCommandInteraction, ApplicationCommandOptionType, +}; + +use geoffrey_models::models::locations::Location; +use geoffrey_models::models::parameters::remove_item_params::RemoveItemParameters; + +use crate::bot::arg_parse::option_to_string; +use crate::bot::commands::{BotCommand, CommandError}; +use crate::bot::formatters::display_loc_full; +use crate::bot::lang::PLAYER_DOES_NOT_HAVE_MATCHING_SHOP; +use geoffrey_models::models::response::api_error::GeoffreyAPIError; +use serenity::builder::CreateApplicationCommand; + +pub struct RemoveItemCommand; + +#[async_trait] +impl BotCommand for RemoveItemCommand { + type ApiParams = RemoveItemParameters; + type ApiResp = Location; + + fn command_name() -> String { + "remove_item".to_string() + } + + fn request_type() -> Method { + Method::POST + } + + fn custom_err_resp(e: &CommandError) -> Option { + match e { + CommandError::GeoffreyApi(GeoffreyAPIError::EntryNotFound) => { + Some(PLAYER_DOES_NOT_HAVE_MATCHING_SHOP.to_string()) + } + _ => None, + } + } + + fn create_app_command(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { + command + .name(Self::command_name()) + .description("Remove an item from a shop") + .create_option(|option| { + option + .name("shop_name") + .description("Shop to list the item at") + .kind(ApplicationCommandOptionType::String) + .required(true) + }) + .create_option(|option| { + option + .name("item_name") + .description("Name of the item to remove") + .kind(ApplicationCommandOptionType::String) + .required(true) + }) + } + + async fn process_arguments( + command_interaction: ApplicationCommandInteraction, + ) -> Result { + let options = command_interaction.data.options; + + Ok(Self::ApiParams::new( + option_to_string(options.get(0), "shop_name")?, + option_to_string(options.get(1), "item_name")?, + )) + } + + fn build_response(resp: Self::ApiResp) -> String { + format!( + "**{}** has been updated:\n{}", + resp.name, + display_loc_full(&resp) + ) + } +} diff --git a/geoffrey_bot/src/bot/commands/selling.rs b/geoffrey_bot/src/bot/commands/selling.rs index 5380872..85fb020 100644 --- a/geoffrey_bot/src/bot/commands/selling.rs +++ b/geoffrey_bot/src/bot/commands/selling.rs @@ -79,10 +79,10 @@ impl BotCommand for SellingCommand { for item in resp { writeln!( resp_str, - "**{}**, {}D for {}: {} {}", + "**{}**, {} for {}D: {} {}", item.listing.item.name, item.listing.count_per_price, - item.listing.count_per_price, + item.listing.price, item.shop_name, item.shop_loc ) diff --git a/geoffrey_bot/src/bot/formatters.rs b/geoffrey_bot/src/bot/formatters.rs index 10da14a..571a035 100644 --- a/geoffrey_bot/src/bot/formatters.rs +++ b/geoffrey_bot/src/bot/formatters.rs @@ -1,4 +1,4 @@ -use geoffrey_models::models::locations::Location; +use geoffrey_models::models::locations::{Location, LocationData}; use geoffrey_models::models::player::Player; use geoffrey_models::models::Portal; @@ -53,3 +53,30 @@ pub fn display_loc(loc: &Location) -> String { display_owners(&loc.owners, 3), ) } + +pub fn display_loc_full(loc: &Location) -> String { + let info = match &loc.loc_data { + LocationData::Shop(shop) => { + if !shop.item_listings.is_empty() { + format!( + "\n**Inventory**:\n{}", + shop.item_listings + .iter() + .map(|item| { + format!( + "**{}**, {} for {}D", + item.item.name, item.count_per_price, item.price + ) + }) + .collect::>() + .join("\n") + ) + } else { + "".to_string() + } + } + _ => "".to_string(), + }; + + format!("{}\n{}", display_loc(loc), info) +} diff --git a/geoffrey_bot/src/bot/mod.rs b/geoffrey_bot/src/bot/mod.rs index 803c0f9..f882b94 100644 --- a/geoffrey_bot/src/bot/mod.rs +++ b/geoffrey_bot/src/bot/mod.rs @@ -5,6 +5,7 @@ use crate::bot::commands::delete::DeleteCommand; use crate::bot::commands::edit_name::EditNameCommand; use crate::bot::commands::edit_pos::EditPosCommand; use crate::bot::commands::register::RegisterCommand; +use crate::bot::commands::remove_item::RemoveItemCommand; use crate::bot::commands::GeoffreyCommandFn; use crate::context::GeoffreyContext; use commands::add_item::AddItemCommand; @@ -95,6 +96,8 @@ pub async fn build_commands( .add_command::(ctx) .await? .add_command::(ctx) + .await? + .add_command::(ctx) .await?; Ok(()) diff --git a/geoffrey_models/src/models/parameters/mod.rs b/geoffrey_models/src/models/parameters/mod.rs index 739d1fc..2a26399 100644 --- a/geoffrey_models/src/models/parameters/mod.rs +++ b/geoffrey_models/src/models/parameters/mod.rs @@ -6,6 +6,7 @@ pub mod edit_params; pub mod find_params; pub mod link_params; pub mod register_params; +pub mod remove_item_params; pub mod selling_params; pub mod set_portal_params; diff --git a/geoffrey_models/src/models/parameters/remove_item_params.rs b/geoffrey_models/src/models/parameters/remove_item_params.rs new file mode 100644 index 0000000..a43349f --- /dev/null +++ b/geoffrey_models/src/models/parameters/remove_item_params.rs @@ -0,0 +1,19 @@ +use crate::models::parameters::GeoffreyParam; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct RemoveItemParameters { + pub shop_name: String, + pub item_name: String, +} + +impl RemoveItemParameters { + pub fn new(shop_name: String, item_name: String) -> Self { + Self { + shop_name, + item_name, + } + } +} + +impl GeoffreyParam for RemoveItemParameters {}