use std::process; use crate::{Context, Error}; use crate::messages::{send_embed, send_msg, edit_msg, EmbedOptions}; use poise::serenity_prelude::{GetMessages, OnlineStatus, Timestamp, UserId}; use rand::{seq::IteratorRandom, Rng}; #[poise::command(slash_command, prefix_command)] pub async fn ping( ctx: Context<'_>, #[description = "The text to echo back."] text: Option, ) -> Result<(), Error> { send_msg(ctx, text.unwrap_or_else(|| "Pong".to_string()), true, true).await; return Ok(()); } #[poise::command(slash_command, prefix_command, default_member_permissions = "ADMINISTRATOR")] pub async fn stop( ctx: Context<'_>, #[description = "Type \"i want to stop the bot now\" to confirm."] confirmation: Option, ) -> Result<(), Error> { let dev_enabled = ctx.data().dev; let should_stop = dev_enabled || confirmation.unwrap_or_else(|| "".to_string()).to_lowercase() == "i want to stop the bot now"; let is_creator = ctx.author().id == UserId::new(ctx.data().creator_id); if should_stop && is_creator { send_msg(ctx, "Shutting down...".to_string(), true, true).await; ctx.serenity_context().set_presence(None, OnlineStatus::Invisible); ctx.framework().shard_manager.shutdown_all().await; process::exit(0); } else if !is_creator { send_msg(ctx, "Failed to shut down: Invalid permissions.".to_string(), true, true).await; } else if !should_stop { send_msg(ctx, "Failed to shut down: Invalid confirmation.".to_string(), true, true).await; } return Ok(()); } #[poise::command( slash_command, prefix_command, default_member_permissions = "ADMINISTRATOR" )] pub async fn embed( ctx: Context<'_>, #[description = "Title of embed."] title: Option, #[description = "Body text of embed."] description: String, #[description = "Color of side strip."] color: Option, #[description = "A URL the title is bound to."] url: Option, #[description = "Timestamp at bottom (best to leave empty)."] timestamp: Option, #[description = "Empheral (only visible to you)."] empheral: Option, #[description = "Shows \"used {Command}\" reply text."] reply: Option ) -> Result<(), Error> { let reply_unwrap = reply.unwrap_or_else(|| false); send_embed( ctx, EmbedOptions { desc: description, title, col: color, url, ts: timestamp, empheral: empheral.unwrap_or_else(|| false) }, reply_unwrap ).await; if !reply_unwrap { send_msg(ctx, "Mandatory success response.".to_string(), true, true).await; } return Ok(()); } #[poise::command(slash_command, prefix_command)] pub async fn eight_ball( ctx: Context<'_>, #[description = "Question to ask."] question: String ) -> Result<(), Error> { let is_quirky = rand::rng().random_bool(0.2); let list = &ctx.data().ball_prompts[if is_quirky { 1 } else { 0 }]; let rand_item = list.iter().choose(&mut rand::rng()); send_msg( ctx, format!("Q: {}\nA: {}", question, rand_item.unwrap()), true, true ).await; return Ok(()); } #[poise::command( slash_command, prefix_command, default_member_permissions = "ADMINISTRATOR" )] pub async fn write_json( ctx: Context<'_>, #[description = "Delete all messages sent by the bot in the selected channel."] remove_all: Option, #[description = "Includes \"Use '/rule {rule}' to view rules individually\" preset message"] include_rule_command: Option, #[description = "JSON (empty is preset file)"] json: Option ) -> Result<(), Error> { let rm_all = remove_all.unwrap_or_else(|| false); let include_cmd = include_rule_command.unwrap_or_else(|| false); if rm_all { let progress = send_msg(ctx, "Deleting all messages in channel...".to_string(), true, true).await; let builder = GetMessages::new().limit(100); let msgs = ctx.channel_id().messages(ctx.http(), builder).await?; for msg in msgs { if msg.author.id == ctx.framework().bot_id { msg.delete(ctx.http()).await?; } } edit_msg(ctx, progress.unwrap(), "Deleting all messages in channel... Done!".to_string()).await; } let json_str = json.clone().unwrap_or_else(|| std::fs::read_to_string("./data/write_json.json") .expect("No JSON preset file exists.") ).to_string(); let json_json: serde_json::Value = serde_json::from_str(&json_str).expect("JSON was improperly formatted"); if !json_json.is_array() { send_msg(ctx, "JSON is not an array of strings".to_string(), true, true).await; return Ok(()); } for i in json_json.as_array().unwrap() { if !i.is_object() { continue; } let title = i["title"].to_string(); let title_str = title[1..title.len() - 1].to_string(); let desc = i["desc"].to_string(); let desc_str = desc[1..desc.len() - 1].to_string(); let index_str = i["index"].to_string(); let title_format = if index_str.len() > 0 { format!("{} - {}", index_str, title_str) } else { title_str }; let embed = EmbedOptions { title: Some(title_format), desc: desc_str, ..Default::default() }; send_embed(ctx, embed, false).await; } if include_cmd && json.is_none() { send_msg(ctx, "Use /rules thank you".to_string(), false, false).await; } return Ok(()); } /* async fn autocomplete_rule_list(_: Context<'_>, _partial: &str) -> Vec { let json_str = std::fs::read_to_string("./data/write_json.json") .expect("No JSON preset file exists."); let json_json: serde_json::Value = serde_json::from_str(&json_str).expect("JSON was improperly formatted"); if json_json.is_array() { let mut titles: Vec = vec![]; for i in json_json.as_array().unwrap() { let title = i["title"].to_string(); let title_str = title[1..title.len() - 1].to_string(); let index_str = i["index"].to_string(); let title_format = if index_str.len() > 0 { format!("{} - {}", index_str, title_str) } else { title_str }; titles.push(title_format); } return titles; } else { return vec!["JSON data not found".to_string()]; } } #[poise::command(slash_command, prefix_command)] pub async fn rule( _ctx: Context<'_>, #[description = "The name of the rule to display"] #[autocomplete = "autocomplete_rule_list"] _rule: Vec ) -> Result<(), Error> { return Ok(()); } */