diff --git a/Cargo.lock b/Cargo.lock index 1021b64..2638292 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1093,7 +1093,7 @@ dependencies = [ [[package]] name = "fren" -version = "1.9.0" +version = "2.0.0" dependencies = [ "axum 0.8.1", "base64 0.22.1", diff --git a/Cargo.toml b/Cargo.toml index ab0aa80..e38bdbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fren" -version = "1.9.0" +version = "2.0.0" edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/discord/admin.rs b/src/discord/admin.rs index ff451e8..867fa6b 100644 --- a/src/discord/admin.rs +++ b/src/discord/admin.rs @@ -62,7 +62,7 @@ pub async fn load_db( let json_value: JsonValue = match json::parse(&db_string) { Ok(v) => v, Err(e) => { - ctx.reply(format!("Error parsing json: {}", e)).await?; + ctx.reply(format!("Error parsing json: {e}")).await?; return Ok(()); } }; @@ -71,7 +71,7 @@ pub async fn load_db( match ctx.data().db.import_db(json_value) { Ok(_) => ctx.reply("Database imported successfully").await?, Err(err) => { - ctx.reply(format!("Error importing db: {}", err)).await?; + ctx.reply(format!("Error importing db: {err}")).await?; return Ok(()); } }; @@ -262,7 +262,7 @@ pub async fn remove_role( ManagedRole::remove_role(&ctx.data().db, role)?; guild_id.delete_role(ctx, role).await?; - ctx.reply(format!("Finally got rid of '{}', thank GOD", name)) + ctx.reply(format!("Finally got rid of '{name}', thank GOD")) .await?; Ok(()) @@ -278,8 +278,7 @@ pub async fn add_social_credit_phrase( ) -> Result<(), Error> { if upper_limit < lower_limit { ctx.reply(format!( - "Invalid range, upper limit ({}) is less than lower limit ({})", - upper_limit, lower_limit + "Invalid range, upper limit ({upper_limit}) is less than lower limit ({lower_limit})" )) .await?; return Ok(()); @@ -348,7 +347,7 @@ pub async fn remove_movie( ) -> Result<(), Error> { Movie::remove_movie(&ctx.data().db, &movie)?; - ctx.reply(format!("Removed *{}* from the library", movie)) + ctx.reply(format!("Removed *{movie}* from the library")) .await?; Ok(()) } diff --git a/src/discord/album.rs b/src/discord/album.rs index a98ffc8..db1c67c 100644 --- a/src/discord/album.rs +++ b/src/discord/album.rs @@ -23,7 +23,7 @@ pub async fn add_image( let plural = if images.len() > 1 { "s" } else { "" }; - ctx.reply(format!("Image{} added to {}!", plural, album_name)) + ctx.reply(format!("Image{plural} added to {album_name}!")) .await?; Ok(()) @@ -48,7 +48,7 @@ pub async fn list_albums(ctx: Context<'_>) -> Result<(), Error> { message_builder.push_bold_line("Albums:"); for album in &album_names { - message_builder.push_line(format!("* {}", album)); + message_builder.push_line(format!("* {album}")); } ctx.reply(message_builder.build()).await?; diff --git a/src/discord/emoji_race.rs b/src/discord/emoji_race.rs index 498c8e5..cd784ce 100644 --- a/src/discord/emoji_race.rs +++ b/src/discord/emoji_race.rs @@ -23,7 +23,7 @@ fn cleanup_race(db: &Database) -> Result<(), Error> { async fn add_bet(ctx: Context<'_>, bet: Bet, racers: &[Racer]) -> Result<(), RaceError> { User::try_take_funds(&ctx.data().db, bet.author, bet.amount).map_err(|err| match err { Error::UserError(e) => RaceError::BetFundError(e), - _ => panic!("Recv'ed error when trying to bet: {}", err), + _ => panic!("Recv'ed error when trying to bet: {err}"), })?; if !racers.iter().any(|r| r.emoji.id == bet.emoji) { @@ -135,10 +135,7 @@ pub async fn start_race(ctx: Context<'_>) -> Result<(), Error> { } else { payout /= bet_winners.len() as i64; - winner_msg.push_bold_line(format!( - "The following winner(s) got a payout of {}:", - payout - )); + winner_msg.push_bold_line(format!("The following winner(s) got a payout of {payout}:")); for winner in bet_winners { winner_msg.push("* "); @@ -180,7 +177,7 @@ pub async fn bet( bet_amount, racer ), - Err(err) => format!("Yeah something's fucked. {}", err), + Err(err) => format!("Yeah something's fucked. {err}"), }; ctx.reply(resp).await?; diff --git a/src/discord/joke.rs b/src/discord/joke.rs index ecf1803..63f4add 100644 --- a/src/discord/joke.rs +++ b/src/discord/joke.rs @@ -114,7 +114,7 @@ pub async fn random( let response_template_str = match random.get_response(&global_data.db)? { None => { - msg.reply(&ctx, format!("I'm all out of material for {}", random_name)) + msg.reply(&ctx, format!("I'm all out of material for {random_name}")) .await?; return Ok(()); } @@ -146,7 +146,7 @@ pub async fn add_random( ) -> Result<(), Error> { if let Err(err) = render_random(ctx.author().display_name(), ctx.data(), &random_response).await { - ctx.reply(format!("Template failed test render, try again: {}", err)) + ctx.reply(format!("Template failed test render, try again: {err}")) .await?; } else { RandomConfig::add_random(&ctx.data().db, &random_name, &random_response)?; @@ -230,8 +230,8 @@ pub async fn roll( let roll = die_roll.parse::(); let reply = match roll { - Ok(roll) => format!("You rolled: **{}**", roll), - Err(err) => format!("Error parsing dice roll: {}", err), + Ok(roll) => format!("You rolled: **{roll}**"), + Err(err) => format!("Error parsing dice roll: {err}"), }; ctx.reply(reply).await?; @@ -358,7 +358,7 @@ pub async fn insult( if let Some(output) = output { ctx.reply(output).await?; } else { - ctx.reply(format!("No {}s, mr freeman??", target)).await?; + ctx.reply(format!("No {target}s, mr freeman??")).await?; } Ok(()) diff --git a/src/discord/mod.rs b/src/discord/mod.rs index e21c71c..55fabc2 100644 --- a/src/discord/mod.rs +++ b/src/discord/mod.rs @@ -267,10 +267,10 @@ pub async fn help(ctx: Context<'_>, command: Option) -> Result<(), Error for (category, command) in &commands { if !last_category.eq_ignore_ascii_case(category) { last_category = category.clone(); - msg_builder.push_line(format!("### {}", last_category)); + msg_builder.push_line(format!("### {last_category}")); } - msg_builder.push_line(format!("* `!{}`", command)); + msg_builder.push_line(format!("* `!{command}`")); } msg_builder.push_line("-# Made with :sparkling_heart: by Joey"); diff --git a/src/discord/role.rs b/src/discord/role.rs index fc862f3..cb532a8 100644 --- a/src/discord/role.rs +++ b/src/discord/role.rs @@ -35,7 +35,7 @@ pub async fn join_role( let role = if let Some(role) = role { role } else { - ctx.reply(format!("I don't know of this '{}' role. If it exists, only god knows. And I have met god. DO NOT MEET GOD", role_name)).await?; + ctx.reply(format!("I don't know of this '{role_name}' role. If it exists, only god knows. And I have met god. DO NOT MEET GOD")).await?; return Ok(()); }; @@ -53,8 +53,7 @@ pub async fn join_role( .await?; ctx.reply(format!( - "You have been added to the ~~cult~~ role '{}'", - role_name + "You have been added to the ~~cult~~ role '{role_name}'" )) .await?; @@ -72,7 +71,7 @@ pub async fn leave_role( let role = if let Some(role) = role { role } else { - ctx.reply(format!("I don't know of this '{}' role. If it exists, only god knows. And I have met god. DO NOT MEET GOD", role_name)).await?; + ctx.reply(format!("I don't know of this '{role_name}' role. If it exists, only god knows. And I have met god. DO NOT MEET GOD")).await?; return Ok(()); }; @@ -90,8 +89,7 @@ pub async fn leave_role( .await?; ctx.reply(format!( - "You have left '{}'. Its over. All things come to an end. But did it have to be this way?", - role_name + "You have left '{role_name}'. Its over. All things come to an end. But did it have to be this way?" )) .await?; diff --git a/src/discord/shop.rs b/src/discord/shop.rs index 3c405e8..f578ba8 100644 --- a/src/discord/shop.rs +++ b/src/discord/shop.rs @@ -80,7 +80,7 @@ pub async fn buy( let resp = match err { UserError::NotEnoughFunds => "Sorry Link, but I can't give store credit. Come back when you are mhhmm richer.".to_string(), UserError::InvalidTarget => "I don't know who you are or how you got here.".to_string(), - UserError::InventoryError(err) => format!("Something went wrong with that item: {}", err) + UserError::InventoryError(err) => format!("Something went wrong with that item: {err}") }; ctx.reply(resp).await?; @@ -88,7 +88,7 @@ pub async fn buy( return Err(err); } } else { - ctx.reply(format!("Congrats, you now own a '{}'", item)) + ctx.reply(format!("Congrats, you now own a '{item}'")) .await?; } @@ -232,8 +232,7 @@ pub async fn use_item( ctx, CreateMessage::new() .content(format!( - "Your NFT my good friend. It's worth **{} FC**!", - value + "Your NFT my good friend. It's worth **{value} FC**!" )) .add_file( CreateAttachment::file(&file, "nft.jpg".to_string()) @@ -301,7 +300,7 @@ pub async fn use_item( ItemType::Helmet => { ctx.reply("Your trusty helmet regards you helmetly").await?; } - ItemType::TacticalNuke => { + ItemType::EMP => { let mut users: Vec = ctx.data().db.filter(|_, _user: &User| true)?.collect(); for user in &mut users { @@ -318,7 +317,8 @@ pub async fn use_item( ctx.data().db.insert(user.clone())?; } - ctx.reply("I have become cancel, the canceller of worlds. https://tenor.com/view/explosion-mushroom-cloud-atomic-bomb-bomb-boom-gif-4464831").await?; + ctx.reply("All technology is null and void, have fun suckers!") + .await?; } } @@ -416,7 +416,7 @@ pub async fn restock_shop( bot_user .inventory - .give_item(ItemType::TacticalNuke, rng().random_range(0..=1), None); + .give_item(ItemType::EMP, rng().random_range(0..=1), None); loop { let mut dir = tokio::fs::read_dir(&global_data.cfg.nft_path).await?; @@ -437,7 +437,7 @@ pub async fn restock_shop( hasher.write(&nft); let nft_hash = hasher.finish(); - let path = global_data.cfg.nft_path.join(format!("{}.jpg", nft_hash)); + let path = global_data.cfg.nft_path.join(format!("{nft_hash}.jpg")); if path.exists() { continue; diff --git a/src/discord/transit.rs b/src/discord/transit.rs index a34b323..b6bdd88 100644 --- a/src/discord/transit.rs +++ b/src/discord/transit.rs @@ -224,7 +224,7 @@ pub async fn cta_bets(ctx: Context<'_>) -> Result<(), Error> { let payout = (100.0 * outcome.payout_factor()) as u32; let mut winner_msg = MessageBuilder::new(); winner_msg.push_line("## Congrats to our winners:"); - winner_msg.push_line(format!("They each get {} Fren Coins!", payout)); + winner_msg.push_line(format!("They each get {payout} Fren Coins!")); for winner in &winners { User::give_funds(&ctx.data().db, *winner, payout)?; winner_msg.push_line(format!("* {}", winner.mention())); diff --git a/src/discord/voices.rs b/src/discord/voices.rs index 1336db8..12a1857 100644 --- a/src/discord/voices.rs +++ b/src/discord/voices.rs @@ -87,9 +87,9 @@ pub enum VoiceError { impl Display for VoiceError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - VoiceError::VoiceNotFound(v) => write!(f, "{} voice not found", v), - VoiceError::WordNotFound(w) => write!(f, "{} is not in dictionary", w), - VoiceError::Serenity(err) => write!(f, "Serenity error: {}", err), + VoiceError::VoiceNotFound(v) => write!(f, "{v} voice not found"), + VoiceError::WordNotFound(w) => write!(f, "{w} is not in dictionary"), + VoiceError::Serenity(err) => write!(f, "Serenity error: {err}"), VoiceError::NotInVoiceChannel => write!(f, "User not in voice channel"), } } @@ -172,12 +172,10 @@ pub async fn speak( let channel_id = { let guild = ctx.cache().guild(guild_id).unwrap(); - let channel_id = guild + guild .voice_states .get(&user_id) - .and_then(|voice_state| voice_state.channel_id); - - channel_id + .and_then(|voice_state| voice_state.channel_id) }; let connect_to = match channel_id { @@ -245,7 +243,7 @@ pub async fn say( VoiceError::VoiceNotFound(_) | VoiceError::WordNotFound(_) | VoiceError::NotInVoiceChannel => { - ctx.reply(format!("Error: {}", err)).await?; + ctx.reply(format!("Error: {err}")).await?; } _ => return Err(err.into()), } @@ -261,7 +259,7 @@ pub async fn list_words( ) -> Result<(), Error> { match find_voice(&ctx.data().cfg.voice_path, &voice).await? { None => { - ctx.reply(format!("No voice found called '{}'", voice)) + ctx.reply(format!("No voice found called '{voice}'")) .await?; } Some(voice_path) => { @@ -271,7 +269,7 @@ pub async fn list_words( words.sort(); let mut list_msg = MessageBuilder::new(); - list_msg.push_line(format!("Here are the words for {}:", voice)); + list_msg.push_line(format!("Here are the words for {voice}:")); for word in words { list_msg.push("* "); diff --git a/src/error.rs b/src/error.rs index 7eb827d..70606f8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,7 +10,7 @@ use std::fmt::{Display, Formatter}; #[allow(dead_code)] pub enum Error { ConfigError(config::ConfigError), - SerenityError(poise::serenity_prelude::Error), + SerenityError(Box), TeraError(tera::Error), NoAlbumFound, UserError(user::UserError), @@ -21,7 +21,7 @@ pub enum Error { MagickError(magick_rust::MagickError), CommandError(String), IoError(std::io::Error), - VoiceError(VoiceError), + VoiceError(Box), CTAError(cta_api::Error), NoImageFound, PipelineArgumentError(ModifyImageArgError), @@ -38,7 +38,7 @@ impl From for Error { impl From for Error { fn from(err: poise::serenity_prelude::Error) -> Self { - Self::SerenityError(err) + Self::SerenityError(Box::new(err)) } } @@ -80,7 +80,7 @@ impl From for Error { impl From for Error { fn from(value: VoiceError) -> Self { - Self::VoiceError(value) + Self::VoiceError(Box::new(value)) } } @@ -99,22 +99,22 @@ impl From for Error { impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - Error::ConfigError(e) => write!(f, "Config error: {}", e), - Error::SerenityError(e) => write!(f, "Discord error: {}", e), - Error::TeraError(e) => write!(f, "Tera error: {}", e), + Error::ConfigError(e) => write!(f, "Config error: {e}"), + Error::SerenityError(e) => write!(f, "Discord error: {e}"), + Error::TeraError(e) => write!(f, "Tera error: {e}"), Error::NoAlbumFound => write!(f, "No album found"), - Error::UserError(e) => write!(f, "User error: {}", e), - Error::DbError(e) => write!(f, "DB error: {}", e), - Error::ReqwestError(e) => write!(f, "Reqwest Error: {}", e), + Error::UserError(e) => write!(f, "User error: {e}"), + Error::DbError(e) => write!(f, "DB error: {e}"), + Error::ReqwestError(e) => write!(f, "Reqwest Error: {e}"), Error::ParseFailure => write!(f, "Failed to parse something or other"), - Error::RaasError(msg) => write!(f, "Got error from RaaS: {}", msg), - Error::MagickError(err) => write!(f, "ImageMagick error: {}", err), - Error::CommandError(err_msg) => write!(f, "{}", err_msg), - Error::IoError(err) => write!(f, "IO Error: {}", err), - Error::VoiceError(err) => write!(f, "Voice error: {}", err), - Error::CTAError(err) => write!(f, "The CTA had an error, I'm shocked: {}", err), + Error::RaasError(msg) => write!(f, "Got error from RaaS: {msg}"), + Error::MagickError(err) => write!(f, "ImageMagick error: {err}"), + Error::CommandError(err_msg) => write!(f, "{err_msg}"), + Error::IoError(err) => write!(f, "IO Error: {err}"), + Error::VoiceError(err) => write!(f, "Voice error: {err}"), + Error::CTAError(err) => write!(f, "The CTA had an error, I'm shocked: {err}"), Error::NoImageFound => write!(f, "Image not found"), - Error::PipelineArgumentError(err) => write!(f, "{}", err), + Error::PipelineArgumentError(err) => write!(f, "{err}"), Error::NoRandomFound => write!(f, "No random found"), } } diff --git a/src/inventory/mod.rs b/src/inventory/mod.rs index 31620f4..55966bc 100644 --- a/src/inventory/mod.rs +++ b/src/inventory/mod.rs @@ -31,6 +31,7 @@ pub enum ItemData { #[derive( Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq, Copy, poise::ChoiceParameter, )] +#[allow(clippy::upper_case_acronyms)] pub enum ItemType { #[name = "Cancel Insurance"] CancelInsurance, @@ -48,8 +49,8 @@ pub enum ItemType { CancelRay, #[name = "Helmet"] Helmet, - #[name = "Tactical Nuke"] - TacticalNuke, + #[name = "EMP"] + EMP, } impl ItemType { @@ -65,7 +66,7 @@ impl ItemType { ItemType::KillGun => "Used to kill people. `!use kill gun @Austin`".to_string(), ItemType::CancelRay => "Used to cancel people. `!use cancel ray @Austin`".to_string(), ItemType::Helmet => "Automatically used to block being killed".to_string(), - ItemType::TacticalNuke => "Reset everyone back to the stone age".to_string(), + ItemType::EMP => "Disables weapons and defenses".to_string(), } } } @@ -100,8 +101,8 @@ impl FromStr for ItemType { Ok(ItemType::Helmet) } else if item.starts_with("cancelray") { Ok(ItemType::CancelRay) - } else if item.starts_with("tacticalnuke") { - Ok(ItemType::TacticalNuke) + } else if item.starts_with("emp") { + Ok(ItemType::EMP) } else { Err(InventoryError::UnkownItem) } @@ -119,10 +120,10 @@ impl Display for ItemType { ItemType::KillGun => "Kill Gun".to_string(), ItemType::Helmet => "Helmet".to_string(), ItemType::CancelRay => "Cancel Ray".to_string(), - ItemType::TacticalNuke => "Tactical Nuke".to_string(), + ItemType::EMP => "EMP".to_string(), }; - write!(f, "{}", name) + write!(f, "{name}") } } @@ -154,7 +155,7 @@ impl InventorySlot { ItemType::KillGun => 2_000, ItemType::Helmet => 10_000, ItemType::CancelRay => 2_000, - ItemType::TacticalNuke => 100_000, + ItemType::EMP => 50_000, } } diff --git a/src/migrations/migration_9_update_to_emp.rs b/src/migrations/migration_9_update_to_emp.rs new file mode 100644 index 0000000..32a9f8a --- /dev/null +++ b/src/migrations/migration_9_update_to_emp.rs @@ -0,0 +1,37 @@ +use j_db::database::Database; +use j_db::migration::Migration; +use json::JsonValue; + +pub struct Migration9UpdateToEMP {} + +impl Migration for Migration9UpdateToEMP { + fn up(&self, db: &Database) -> j_db::error::Result<()> { + let tree = db.db.open_tree("Users")?; + + for user in tree.iter() { + let (id, user_bytes) = user?; + + let mut user = json::parse(std::str::from_utf8(&user_bytes).unwrap())?; + + for item in user["inventory"]["inventory"].members_mut() { + let item_type = item["item_type"].as_str().unwrap(); + + if item_type == "TacticalNuke" { + item["item_type"] = JsonValue::String("EMP".to_string()); + } + } + + tree.insert(id, user.to_string().into_bytes())?; + } + + Ok(()) + } + + fn down(&self, _db: &Database) -> j_db::error::Result<()> { + Ok(()) + } + + fn version(&self) -> u64 { + 9 + } +} diff --git a/src/migrations/mod.rs b/src/migrations/mod.rs index 720447d..7348b12 100644 --- a/src/migrations/mod.rs +++ b/src/migrations/mod.rs @@ -3,6 +3,7 @@ use crate::migrations::migration_5_update_motivation::Migration5UpdateMotivation use crate::migrations::migration_6_add_social_credit::Migration6AddSocialCredit; use crate::migrations::migration_7_flip_bounds::Migration7FlipBounds; use crate::migrations::migration_8_fix_metadata_id::Migration8FixMetadataId; +use crate::migrations::migration_9_update_to_emp::Migration9UpdateToEMP; use crate::migrations::migration2_remove_imgur::Migration2RemoveImgur; use crate::migrations::migration3_remove_img::Migration3RemoveImage; use j_db::database::Database; @@ -16,8 +17,9 @@ mod migration_5_update_motivation; mod migration_6_add_social_credit; mod migration_7_flip_bounds; mod migration_8_fix_metadata_id; +mod migration_9_update_to_emp; -pub const CURRENT_DB_VERSION: u64 = 8; +pub const CURRENT_DB_VERSION: u64 = 9; #[allow(clippy::single_match)] pub fn do_migration(db: &Database) { @@ -72,6 +74,12 @@ pub fn do_migration(db: &Database) { Direction::Up, ) .unwrap(), + 9 => migration::do_migration::( + db, + Migration9UpdateToEMP {}, + Direction::Up, + ) + .unwrap(), _ => {} } } diff --git a/src/models/race.rs b/src/models/race.rs index cf0f9af..3cabab3 100644 --- a/src/models/race.rs +++ b/src/models/race.rs @@ -23,9 +23,9 @@ impl Display for RaceError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { RaceError::RacerNotFound => write!(f, "Racer not found"), - RaceError::BetFundError(e) => write!(f, "Fund error: {}", e), + RaceError::BetFundError(e) => write!(f, "Fund error: {e}"), RaceError::UserHasBet => write!(f, "User already bet"), - RaceError::GenericError(e) => write!(f, "Sorry the horse died: {}", e), + RaceError::GenericError(e) => write!(f, "Sorry the horse died: {e}"), } } } diff --git a/src/user/mod.rs b/src/user/mod.rs index 3bd80e7..3295631 100644 --- a/src/user/mod.rs +++ b/src/user/mod.rs @@ -19,7 +19,7 @@ impl Display for UserError { match self { UserError::NotEnoughFunds => write!(f, "Not enough funds"), UserError::InvalidTarget => write!(f, "Invalid target"), - UserError::InventoryError(e) => write!(f, "Inventory error: {}", e), + UserError::InventoryError(e) => write!(f, "Inventory error: {e}"), } } }