Bot code cleanup
+ Added functions for parsing Application Command options into different types + Added formatters for common message formats + Clippy + Fmtmain
parent
8d858bdfd3
commit
a655146c81
|
@ -0,0 +1,72 @@
|
|||
use crate::bot::commands::CommandError;
|
||||
use geoffrey_models::models::locations::LocationType;
|
||||
use geoffrey_models::models::parameters::selling_params::{ItemSort, Order};
|
||||
use geoffrey_models::models::Dimension;
|
||||
use serenity::model::prelude::application_command::{
|
||||
ApplicationCommandInteractionDataOption, ApplicationCommandInteractionDataOptionValue,
|
||||
};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn option_to_i64(
|
||||
option: Option<&ApplicationCommandInteractionDataOption>,
|
||||
field: &str,
|
||||
) -> Result<i64, CommandError> {
|
||||
if let Some(option) = option {
|
||||
let option = option.resolved.as_ref();
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::Integer(i)) = option {
|
||||
return Ok(*i);
|
||||
}
|
||||
}
|
||||
Err(CommandError::ArgumentParse(field.to_string()))
|
||||
}
|
||||
|
||||
pub fn option_to_string(
|
||||
option: Option<&ApplicationCommandInteractionDataOption>,
|
||||
field: &str,
|
||||
) -> Result<String, CommandError> {
|
||||
if let Some(option) = option {
|
||||
let option = option.resolved.as_ref();
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::String(s)) = option {
|
||||
return Ok(s.clone());
|
||||
}
|
||||
}
|
||||
Err(CommandError::ArgumentParse(field.to_string()))
|
||||
}
|
||||
|
||||
pub fn option_to_loc_type(
|
||||
option: Option<&ApplicationCommandInteractionDataOption>,
|
||||
field: &str,
|
||||
) -> Result<LocationType, CommandError> {
|
||||
let loc_type = option_to_string(option, field)?;
|
||||
|
||||
LocationType::from_str(&loc_type).map_err(|_| CommandError::ArgumentParse(field.to_string()))
|
||||
}
|
||||
|
||||
pub fn option_to_dim(
|
||||
option: Option<&ApplicationCommandInteractionDataOption>,
|
||||
field: &str,
|
||||
) -> Result<Dimension, CommandError> {
|
||||
let loc_type = option_to_string(option, field)?;
|
||||
|
||||
Dimension::from_str(&loc_type).map_err(|_| CommandError::ArgumentParse(field.to_string()))
|
||||
}
|
||||
|
||||
pub fn option_to_sort(
|
||||
option: Option<&ApplicationCommandInteractionDataOption>,
|
||||
field: &str,
|
||||
) -> Result<ItemSort, CommandError> {
|
||||
let loc_type = option_to_string(option, field)?;
|
||||
|
||||
ItemSort::from_str(&loc_type).map_err(|_| CommandError::ArgumentParse(field.to_string()))
|
||||
}
|
||||
|
||||
pub fn option_to_order(
|
||||
option: Option<&ApplicationCommandInteractionDataOption>,
|
||||
field: &str,
|
||||
) -> Result<Order, CommandError> {
|
||||
let loc_type = option_to_string(option, field)?;
|
||||
|
||||
Order::from_str(&loc_type).map_err(|_| CommandError::ArgumentParse(field.to_string()))
|
||||
}
|
|
@ -4,12 +4,13 @@ use serenity::client::Context;
|
|||
use serenity::model::interactions::application_command::{
|
||||
ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType,
|
||||
};
|
||||
use serenity::model::prelude::application_command::ApplicationCommandInteractionDataOptionValue;
|
||||
|
||||
use geoffrey_models::models::locations::Location;
|
||||
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 geoffrey_models::models::response::api_error::GeoffreyAPIError;
|
||||
|
||||
pub struct AddItemCommand;
|
||||
|
||||
|
@ -72,60 +73,25 @@ impl BotCommand for AddItemCommand {
|
|||
) -> Result<Self::ApiParams, CommandError> {
|
||||
let options = command_interaction.data.options;
|
||||
|
||||
let mut item_name = String::default();
|
||||
let mut price = 0;
|
||||
let mut quanity = 0;
|
||||
let mut shop = String::default();
|
||||
|
||||
if let Some(option) = options.get(0) {
|
||||
let option = option.resolved.as_ref();
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::String(s)) = option {
|
||||
item_name = s.clone();
|
||||
} else {
|
||||
return Err(CommandError::ArgumentParse("item_name".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(option) = options.get(1) {
|
||||
let option = option.resolved.as_ref();
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::Integer(p)) = option {
|
||||
price = *p;
|
||||
} else {
|
||||
return Err(CommandError::ArgumentParse("price".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(option) = options.get(2) {
|
||||
let option = option.resolved.as_ref();
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::Integer(q)) = option {
|
||||
quanity = *q;
|
||||
} else {
|
||||
return Err(CommandError::ArgumentParse("quantity".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(option) = options.get(3) {
|
||||
let option = option.resolved.as_ref();
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::String(s)) = option {
|
||||
shop = s.clone();
|
||||
} else {
|
||||
return Err(CommandError::ArgumentParse("shop".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self::ApiParams::new(
|
||||
item_name,
|
||||
price as u32,
|
||||
quanity as u32,
|
||||
shop,
|
||||
option_to_string(options.get(0), "item_name")?,
|
||||
option_to_i64(options.get(1), "price")? as u32,
|
||||
option_to_i64(options.get(2), "quantity")? as u32,
|
||||
option_to_string(options.get(3), "shop")?,
|
||||
))
|
||||
}
|
||||
|
||||
fn build_response(resp: Self::ApiResp) -> String {
|
||||
format!("{} has been updated", resp.name)
|
||||
}
|
||||
|
||||
fn custom_err_resp(e: &CommandError) -> Option<String> {
|
||||
if let CommandError::GeoffreyApi(err) = e {
|
||||
if matches!(err, GeoffreyAPIError::EntryNotFound) {
|
||||
return Some("You don't have a shop by that name ding dong!".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,18 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use geoffrey_models::models::locations::{Location, LocationType};
|
||||
use geoffrey_models::models::parameters::add_location_params::AddLocationParams;
|
||||
use geoffrey_models::models::{Dimension, Position};
|
||||
use reqwest::Method;
|
||||
use serenity::client::Context;
|
||||
use serenity::model::interactions::application_command::{
|
||||
ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandInteractionDataOption,
|
||||
ApplicationCommandOptionType,
|
||||
ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType,
|
||||
};
|
||||
use serenity::model::prelude::application_command::ApplicationCommandInteractionDataOptionValue;
|
||||
|
||||
use geoffrey_models::models::{Dimension, Position};
|
||||
use geoffrey_models::models::locations::{Location, LocationType};
|
||||
use geoffrey_models::models::parameters::add_location_params::AddLocationParams;
|
||||
|
||||
use crate::bot::arg_parse::{option_to_dim, option_to_i64, option_to_loc_type, option_to_string};
|
||||
use crate::bot::commands::{BotCommand, CommandError};
|
||||
|
||||
pub struct AddLocationCommand;
|
||||
|
||||
fn option_to_i64(option: &ApplicationCommandInteractionDataOption) -> Option<i64> {
|
||||
let option = option.resolved.as_ref();
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::Integer(s)) = option {
|
||||
Some(*s)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl BotCommand for AddLocationCommand {
|
||||
type ApiParams = AddLocationParams;
|
||||
|
@ -120,55 +106,16 @@ impl BotCommand for AddLocationCommand {
|
|||
command_interaction: ApplicationCommandInteraction,
|
||||
) -> Result<Self::ApiParams, CommandError> {
|
||||
let options = command_interaction.data.options;
|
||||
let mut name = String::new();
|
||||
let mut loc_type = LocationType::Base;
|
||||
let x;
|
||||
let _y;
|
||||
let z;
|
||||
let dimension;
|
||||
let name = option_to_string(options.get(0), "name")?;
|
||||
let loc_type = option_to_loc_type(options.get(1), "loc_type")?;
|
||||
let x = option_to_i64(options.get(2), "x")?;
|
||||
let _y = option_to_i64(options.get(3), "x")?;
|
||||
let z = option_to_i64(options.get(4), "x")?;
|
||||
let dim = option_to_dim(options.get(5), "dimension").unwrap_or(Dimension::Overworld);
|
||||
|
||||
if let Some(option) = options.get(0) {
|
||||
let option = option.resolved.as_ref();
|
||||
let position = Position::new(x as i32, z as i32, dim);
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::String(s)) = option {
|
||||
loc_type = LocationType::from_str(s).unwrap();
|
||||
} else {
|
||||
return Err(CommandError::ArgumentParse("loc_type".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(option) = options.get(1) {
|
||||
let option = option.resolved.as_ref();
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::String(s)) = option {
|
||||
name = s.clone();
|
||||
} else {
|
||||
return Err(CommandError::ArgumentParse("name".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
x = option_to_i64(&options[2]).unwrap() as i32;
|
||||
_y = option_to_i64(&options[3]).unwrap() as i32;
|
||||
z = option_to_i64(&options[4]).unwrap() as i32;
|
||||
|
||||
if let Some(option) = options.get(5) {
|
||||
let option = option.resolved.as_ref();
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::String(s)) = option {
|
||||
dimension = Dimension::from_str(s.as_str()).unwrap();
|
||||
} else {
|
||||
return Err(CommandError::ArgumentParse("dimension".to_string()));
|
||||
}
|
||||
} else {
|
||||
dimension = Dimension::default();
|
||||
}
|
||||
|
||||
Ok(Self::ApiParams::new(
|
||||
name,
|
||||
Position::new(x, z, dimension),
|
||||
loc_type,
|
||||
None,
|
||||
))
|
||||
Ok(Self::ApiParams::new(name, position, loc_type, None))
|
||||
}
|
||||
|
||||
fn build_response(resp: Self::ApiResp) -> String {
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use reqwest::Method;
|
||||
use serenity::client::Context;
|
||||
use serenity::model::interactions::application_command::{
|
||||
ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType,
|
||||
};
|
||||
use serenity::model::prelude::application_command::ApplicationCommandInteractionDataOptionValue;
|
||||
use std::fmt::Write;
|
||||
|
||||
use geoffrey_models::models::locations::Location;
|
||||
use geoffrey_models::models::parameters::find_params::FindParams;
|
||||
|
||||
use crate::bot::arg_parse::option_to_string;
|
||||
use crate::bot::commands::{BotCommand, CommandError};
|
||||
use crate::bot::formatters::display_loc;
|
||||
|
||||
pub struct FindCommand;
|
||||
|
||||
|
@ -50,16 +50,9 @@ impl BotCommand for FindCommand {
|
|||
command_interaction: ApplicationCommandInteraction,
|
||||
) -> Result<Self::ApiParams, CommandError> {
|
||||
let options = command_interaction.data.options;
|
||||
let query = option_to_string(options.get(0), "query")?;
|
||||
|
||||
if let Some(option) = options.get(0) {
|
||||
let query = option.resolved.as_ref();
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::String(s)) = query {
|
||||
return Ok(FindParams::new(s.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
Err(CommandError::ArgumentParse("query".to_string()))
|
||||
Ok(FindParams::new(query))
|
||||
}
|
||||
|
||||
fn build_response(resp: Self::ApiResp) -> String {
|
||||
|
@ -69,7 +62,7 @@ impl BotCommand for FindCommand {
|
|||
let mut resp_str = String::new();
|
||||
writeln!(resp_str, "The following locations match:").unwrap();
|
||||
for loc in resp {
|
||||
writeln!(resp_str, "**{}**, {}", loc.name, loc.position).unwrap();
|
||||
writeln!(display_loc(loc)).unwrap();
|
||||
}
|
||||
resp_str
|
||||
}
|
||||
|
|
|
@ -5,8 +5,10 @@ use reqwest::Error;
|
|||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use serenity::client::Context;
|
||||
use serenity::model::interactions::application_command::{
|
||||
ApplicationCommand, ApplicationCommandInteraction,
|
||||
};
|
||||
use serenity::Error as SerenityError;
|
||||
use serenity::model::interactions::application_command::{ApplicationCommand, ApplicationCommandInteraction};
|
||||
|
||||
use geoffrey_models::models::parameters::CommandRequest;
|
||||
use geoffrey_models::models::player::UserID;
|
||||
|
@ -17,7 +19,6 @@ use crate::context::GeoffreyContext;
|
|||
|
||||
pub mod add_item;
|
||||
pub mod add_location;
|
||||
mod arg_parse;
|
||||
pub mod find;
|
||||
pub mod selling;
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std::fmt::Write;
|
||||
use std::str::FromStr;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use reqwest::Method;
|
||||
|
@ -7,11 +6,11 @@ use serenity::client::Context;
|
|||
use serenity::model::interactions::application_command::{
|
||||
ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType,
|
||||
};
|
||||
use serenity::model::prelude::application_command::ApplicationCommandInteractionDataOptionValue;
|
||||
|
||||
use geoffrey_models::models::parameters::selling_params::{ItemSort, Order, SellingParams};
|
||||
use geoffrey_models::models::response::selling_listing::SellingListing;
|
||||
|
||||
use crate::bot::arg_parse::{option_to_order, option_to_sort, option_to_string};
|
||||
use crate::bot::commands::{BotCommand, CommandError};
|
||||
|
||||
pub struct SellingCommand;
|
||||
|
@ -69,39 +68,9 @@ impl BotCommand for SellingCommand {
|
|||
command_interaction: ApplicationCommandInteraction,
|
||||
) -> Result<Self::ApiParams, CommandError> {
|
||||
let options = command_interaction.data.options;
|
||||
let mut query = String::new();
|
||||
let mut sort = None;
|
||||
let mut order = None;
|
||||
|
||||
if let Some(option) = options.get(0) {
|
||||
let option = option.resolved.as_ref();
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::String(s)) = option {
|
||||
query = s.clone();
|
||||
} else {
|
||||
return Err(CommandError::ArgumentParse("query".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(option) = options.get(1) {
|
||||
let option = option.resolved.as_ref();
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::String(s)) = option {
|
||||
sort = Some(ItemSort::from_str(s).unwrap());
|
||||
} else {
|
||||
return Err(CommandError::ArgumentParse("sort".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(option) = options.get(2) {
|
||||
let option = option.resolved.as_ref();
|
||||
|
||||
if let Some(ApplicationCommandInteractionDataOptionValue::String(s)) = option {
|
||||
order = Some(Order::from_str(s).unwrap());
|
||||
} else {
|
||||
return Err(CommandError::ArgumentParse("order".to_string()));
|
||||
}
|
||||
}
|
||||
let query = option_to_string(options.get(0), "query")?;
|
||||
let sort = option_to_sort(options.get(1), "sort").ok();
|
||||
let order = option_to_order(options.get(2), "order").ok();
|
||||
|
||||
Ok(SellingParams::new(query, sort, order))
|
||||
}
|
||||
|
@ -111,7 +80,7 @@ impl BotCommand for SellingCommand {
|
|||
"No shops were found selling that, maybe I should start selling it...".to_string()
|
||||
} else {
|
||||
let mut resp_str = String::new();
|
||||
writeln!(resp_str, "The items match:").unwrap();
|
||||
writeln!(resp_str, "The following items match:").unwrap();
|
||||
for item in resp {
|
||||
writeln!(
|
||||
resp_str,
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
use geoffrey_models::models::locations::Location;
|
||||
use geoffrey_models::models::player::Player;
|
||||
|
||||
pub fn display_owners(owners: Vec<Player>, limit: usize) -> String {
|
||||
let mut plural = "";
|
||||
let mut ellipses = "";
|
||||
|
||||
if owners.len() > 1 {
|
||||
plural = "s"
|
||||
}
|
||||
|
||||
let range = if owners.len() > limit {
|
||||
ellipses = "...";
|
||||
limit
|
||||
} else {
|
||||
owners.len()
|
||||
};
|
||||
|
||||
format!(
|
||||
"Owner{}: {}{}",
|
||||
plural,
|
||||
owners[0..range]
|
||||
.iter()
|
||||
.map(|owner| owner.name.clone())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
ellipses
|
||||
)
|
||||
}
|
||||
|
||||
pub fn display_loc(loc: Location) -> String {
|
||||
format!(
|
||||
"**{}**, {}, Owner(s): **{}**",
|
||||
loc.name,
|
||||
loc.position,
|
||||
display_owners(loc.owners, 3)
|
||||
)
|
||||
}
|
|
@ -1,13 +1,15 @@
|
|||
use serenity::model::interactions::application_command::ApplicationCommand;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use commands::{BotCommand, CommandError};
|
||||
use commands::add_item::AddItemCommand;
|
||||
use commands::add_location::AddLocationCommand;
|
||||
use commands::find::FindCommand;
|
||||
use commands::selling::SellingCommand;
|
||||
use commands::{BotCommand, CommandError};
|
||||
|
||||
pub mod arg_parse;
|
||||
pub mod commands;
|
||||
pub mod formatters;
|
||||
|
||||
pub async fn create_commands(ctx: &Context) -> Result<Vec<ApplicationCommand>, CommandError> {
|
||||
let mut commands: Vec<ApplicationCommand> = Vec::new();
|
||||
|
|
|
@ -2,14 +2,14 @@ mod bot;
|
|||
mod configs;
|
||||
mod context;
|
||||
|
||||
use bot::commands::add_item::AddItemCommand;
|
||||
use bot::commands::add_location::AddLocationCommand;
|
||||
use bot::commands::BotCommand;
|
||||
use crate::bot::create_commands;
|
||||
use bot::commands::find::FindCommand;
|
||||
use bot::commands::selling::SellingCommand;
|
||||
use crate::configs::GeoffreyBotConfig;
|
||||
use crate::context::GeoffreyContext;
|
||||
use bot::commands::add_item::AddItemCommand;
|
||||
use bot::commands::add_location::AddLocationCommand;
|
||||
use bot::commands::find::FindCommand;
|
||||
use bot::commands::selling::SellingCommand;
|
||||
use bot::commands::BotCommand;
|
||||
use geoffrey_models::models::player::UserID;
|
||||
use serenity::utils::{content_safe, ContentSafeOptions};
|
||||
use serenity::{
|
||||
|
|
Loading…
Reference in New Issue