Geoffrey-rs/geoffrey_bot/src/bot/formatters.rs

171 lines
4.5 KiB
Rust

use chrono::{Duration, Utc};
use geoffrey_models::models::item::ItemListing;
use geoffrey_models::models::locations::{Location, LocationData, LocationType};
use geoffrey_models::models::player::Player;
use geoffrey_models::models::settings::GeoffreySettings;
use geoffrey_models::models::Portal;
use serenity::client::Cache;
use serenity::utils::{content_safe, ContentSafeOptions, MessageBuilder};
pub struct GeoffreyFormatter {
msg: String,
settings: GeoffreySettings,
}
impl GeoffreyFormatter {
pub fn new(settings: GeoffreySettings) -> Self {
Self {
msg: String::new(),
settings,
}
}
pub fn build(&mut self) -> String {
self.msg.clone()
}
pub fn push(&mut self, string: &str) -> &mut Self {
self.msg.push_str(string);
self
}
pub fn push_new_line(&mut self) -> &mut Self {
self.push("\n")
}
pub fn push_owners(&mut self, owners: &[Player]) -> &mut Self {
let mut plural = "";
let mut ellipses = "";
if owners.len() > 1 {
plural = "s"
}
let range = if owners.len() > self.settings.max_owners_to_display as usize {
ellipses = "...";
self.settings.max_owners_to_display as usize
} else {
owners.len()
};
self.msg = MessageBuilder::new()
.push(self.msg.clone())
.push("Owner")
.push(plural)
.push(": ")
.push(
owners[0..range]
.iter()
.map(|owner| owner.name.clone())
.collect::<Vec<String>>()
.join(", "),
)
.push(ellipses)
.build();
self
}
pub fn push_portal(&mut self, portal: &Portal) -> &mut Self {
self.push(&format!(
"Portal: {} {} (x={}, z={})",
portal.direction(),
portal.tunnel_addr(),
portal.x,
portal.z
))
}
pub fn push_loc(&mut self, loc: &Location) -> &mut Self {
self.push(
&MessageBuilder::new()
.push_bold_safe(&loc.name)
.push(", ")
.push(&loc.position)
.push(", ")
.build(),
);
match &loc.portal {
None => {}
Some(p) => {
self.push_portal(p).push(", ");
}
};
let loc_type: LocationType = LocationType::from(&loc.loc_data);
self.push_owners(&loc.owners).push(", ");
self.push("Type: ").push(&loc_type.to_string())
}
pub fn push_item_listing(&mut self, listing: &ItemListing) -> &mut Self {
let stocked_diff = Utc::now() - listing.restocked_time;
let time_str = if stocked_diff < Duration::days(1) {
"today".to_string()
} else if stocked_diff < Duration::days(2) {
"1 day ago".to_string()
} else {
format!("{} days ago", stocked_diff.num_days())
};
let msg = MessageBuilder::new()
.push_bold_safe(&listing.item.name)
.push(", ")
.push(&listing.count_per_price)
.push(" for ")
.push(listing.price)
.push("D. Restocked ")
.push(time_str)
.build();
let msg = if listing.is_out_of_stock(self.settings.min_out_of_stock_votes) {
MessageBuilder::new().push_strike_safe(msg).to_string()
} else {
msg
};
self.push(&msg)
}
pub fn push_loc_full(&mut self, loc: &Location) -> &mut Self {
self.push_loc(loc);
match &loc.loc_data {
LocationData::Shop(shop) => {
if !shop.item_listings.is_empty() {
self.push_new_line()
.push(&MessageBuilder::new().push_bold("Inventory:").to_string())
.push_new_line();
for listing in &shop.item_listings {
self.push_item_listing(listing).push_new_line();
}
self
} else {
self
}
}
_ => self,
}
}
}
pub async fn clean_message(cache: impl AsRef<Cache>, msg: &str) -> String {
content_safe(
cache,
msg,
&ContentSafeOptions::new()
.clean_channel(true)
.clean_user(true)
.clean_everyone(true)
.clean_here(true)
.clean_role(true),
)
.await
}