From 31255d4a526e63df52073b13efeb2842c993674e Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 19 Jun 2022 17:55:17 +0200 Subject: [PATCH 1/8] migrate prison commands to poise --- Cargo.lock | 76 ++++++++++++++++++- Cargo.toml | 1 + src/handler.rs | 199 ++++++++++++++++++++++++++++--------------------- src/main.rs | 4 +- 4 files changed, 192 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6fcab73..19a3531 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -164,6 +164,7 @@ dependencies = [ "libc", "num-integer", "num-traits", + "serde", "time 0.1.44", "winapi", ] @@ -203,6 +204,7 @@ dependencies = [ "dotenv", "mongodb", "nougat", + "poise", "serde", "serde_json", "serenity", @@ -239,14 +241,38 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c" +dependencies = [ + "darling_core 0.12.4", + "darling_macro 0.12.4", +] + [[package]] name = "darling" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + +[[package]] +name = "darling_core" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", ] [[package]] @@ -263,13 +289,24 @@ dependencies = [ "syn", ] +[[package]] +name = "darling_macro" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a" +dependencies = [ + "darling_core 0.12.4", + "quote", + "syn", +] + [[package]] name = "darling_macro" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ - "darling_core", + "darling_core 0.13.4", "quote", "syn", ] @@ -1038,6 +1075,36 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "poise" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8af8ef2efaa133d674482f40665db3424cb2c5660a2707918c869603c843b7ad" +dependencies = [ + "async-trait", + "derivative", + "futures-core", + "futures-util", + "log", + "once_cell", + "poise_macros", + "regex", + "serenity", + "tokio", +] + +[[package]] +name = "poise_macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d99712c7e3cef666f344ccf5c5c729939331096d16c35eba3275028191a1af" +dependencies = [ + "darling 0.12.4", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ppv-lite86" version = "0.2.16" @@ -1368,7 +1435,7 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ - "darling", + "darling 0.13.4", "proc-macro2", "quote", "syn", @@ -1386,6 +1453,7 @@ dependencies = [ "bitflags", "bytes", "cfg-if", + "chrono", "dashmap", "flate2", "futures", diff --git a/Cargo.toml b/Cargo.toml index 13fdd38..b4d9d59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ tracing-subscriber = { version = "0.3.11", features = ["env-filter"] } serde = { version = "1.0.137", features = ["derive"] } nougat = "0.1.0" serde_json = "1.0.81" +poise = "0.2.2" [dependencies.serenity] version = "0.11.2" diff --git a/src/handler.rs b/src/handler.rs index fb89d80..0f7d7e9 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -1,3 +1,5 @@ +use std::fmt::{Debug, Formatter}; + use color_eyre::eyre::{eyre, ContextCompat}; use mongodb::bson::Uuid; use serenity::{ @@ -14,7 +16,7 @@ use tracing::{debug, error, info}; use crate::{ lawsuit::{Lawsuit, LawsuitCtx}, model::SnowflakeId, - Mongo, WrapErr, + Mongo, Report, WrapErr, }; fn slash_commands(commands: &mut CreateApplicationCommands) -> &mut CreateApplicationCommands { @@ -156,6 +158,12 @@ pub struct Handler { pub mongo: Mongo, } +impl Debug for Handler { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str("HandlerData") + } +} + pub enum Response { EphemeralStr(&'static str), Ephemeral(String), @@ -212,7 +220,6 @@ impl Handler { let response = match command.data.name.as_str() { "lawsuit" => lawsuit_command_handler(&command, &ctx, &self.mongo).await, - "prison" => prison_command_handler(&command, &ctx, &self.mongo).await, _ => Ok(Response::EphemeralStr("not implemented :(")), }; @@ -451,105 +458,131 @@ async fn lawsuit_command_handler( } } -async fn prison_command_handler( - command: &ApplicationCommandInteraction, - ctx: &Context, - mongo_client: &Mongo, -) -> color_eyre::Result { - let options = &command.data.options; - let subcommand = options.get(0).wrap_err("needs subcommand")?; +#[poise::command( + slash_command, + subcommands("prison_set_role", "prison_arrest", "prison_release") +)] +async fn prison(_: crate::Context<'_>) -> color_eyre::Result<()> { + unreachable!() +} - let options = &subcommand.options; - let guild_id = command.guild_id.wrap_err("guild_id not found")?; +/// Die Rolle für Gefangene setzen +#[poise::command( + slash_command, + required_permissions = "MANAGE_GUILD", + on_error = "error_handler" +)] +async fn prison_set_role( + ctx: crate::Context<'_>, + #[description = "Die rolle"] role: Role, +) -> color_eyre::Result<()> { + prison_set_role_impl(ctx, role) + .await + .wrap_err("prison_set_role") +} - let member = command - .member - .as_ref() - .wrap_err("command must be used my member")?; - let permissions = member.permissions.wrap_err("must be in interaction")?; +async fn prison_set_role_impl(ctx: crate::Context<'_>, role: Role) -> color_eyre::Result<()> { + ctx.data() + .mongo + .set_prison_role( + ctx.guild_id().wrap_err("guild_id not found")?.into(), + role.id.into(), + ) + .await?; - match subcommand.name.as_str() { - "set_role" => { - if !permissions.contains(Permissions::MANAGE_GUILD) { - return Ok(Response::NoPermissions); - } + ctx.say("isch gsetzt").await.wrap_err("reply")?; - let role = RoleOption::get(options.get(0))?; + Ok(()) +} - mongo_client - .set_prison_role(guild_id.into(), role.id.into()) - .await?; +/// Jemanden einsperren +#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] +async fn prison_arrest( + ctx: crate::Context<'_>, + #[description = "Die Person zum einsperren"] user: User, +) -> color_eyre::Result<()> { + prison_arrest_impl(ctx, user) + .await + .wrap_err("prison_arrest") +} - Ok(Response::EphemeralStr("isch gsetzt")) +async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> color_eyre::Result<()> { + let mongo_client = &ctx.data().mongo; + let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; + let http = &ctx.discord().http; + + let state = mongo_client.find_or_insert_state(guild_id.into()).await?; + let role = state.prison_role; + + let role = match role { + Some(role) => role, + None => { + ctx.say("du mosch zerst e rolle setze mit /prison set_role"); + return Ok(()); } - "arrest" => { - if !permissions.contains(Permissions::MANAGE_GUILD) { - return Ok(Response::NoPermissions); - } + }; - let (user, _) = UserOption::get(options.get(0))?; + mongo_client + .add_to_prison(guild_id.into(), user.id.into()) + .await?; - let state = mongo_client.find_or_insert_state(guild_id.into()).await?; - let role = state.prison_role; + guild_id + .member(http, user.id) + .await + .wrap_err("fetching guild member")? + .add_role(http, role) + .await + .wrap_err("add guild member role")?; + Ok(()) +} - let role = match role { - Some(role) => role, - None => { - return Ok(Response::EphemeralStr( - "du mosch zerst e rolle setze mit /prison set_role", - )) - } - }; +/// Einen Gefangenen freilassen +#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] +async fn prison_release( + ctx: crate::Context<'_>, + #[description = "Die Person zum freilassen"] user: User, +) -> color_eyre::Result<()> { + prison_release_impl(ctx, user) + .await + .wrap_err("prison_release") +} - mongo_client - .add_to_prison(guild_id.into(), user.id.into()) +async fn prison_release_impl(ctx: crate::Context<'_>, user: User) -> color_eyre::Result<()> { + let mongo_client = &ctx.data().mongo; + let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; + let http = &ctx.discord().http; + + let state = mongo_client.find_or_insert_state(guild_id.into()).await?; + let role = state.prison_role; + + let role = match role { + Some(role) => role, + None => { + ctx.say("du mosch zerst e rolle setze mit /prison set_role") .await?; - - guild_id - .member(&ctx.http, user.id) - .await - .wrap_err("fetching guild member")? - .add_role(&ctx.http, role) - .await - .wrap_err("add guild member role")?; - - Ok(Response::EphemeralStr("hani igsperrt")) + return Ok(()); } - "release" => { - if !permissions.contains(Permissions::MANAGE_GUILD) { - return Ok(Response::NoPermissions); - } + }; - let (user, _) = UserOption::get(options.get(0))?; + mongo_client + .remove_from_prison(guild_id.into(), user.id.into()) + .await?; - let state = mongo_client.find_or_insert_state(guild_id.into()).await?; - let role = state.prison_role; + guild_id + .member(http, user.id) + .await + .wrap_err("fetching guild member")? + .remove_role(http, role) + .await + .wrap_err("remove guild member role")?; - let role = match role { - Some(role) => role, - None => { - return Ok(Response::EphemeralStr( - "du mosch zerst e rolle setze mit /prison set_role", - )) - } - }; + ctx.say("d'freiheit wartet").await?; - mongo_client - .remove_from_prison(guild_id.into(), user.id.into()) - .await?; + Ok(()) +} - guild_id - .member(&ctx.http, user.id) - .await - .wrap_err("fetching guild member")? - .remove_role(&ctx.http, role) - .await - .wrap_err("remove guild member role")?; - - Ok(Response::EphemeralStr("d'freiheit wartet")) - } - _ => Err(eyre!("Unknown subcommand")), - } +async fn error_handler(error: poise::FrameworkError<'_, Handler, Report>) { + error!(?error, "Error during command execution"); } #[nougat::gat] diff --git a/src/main.rs b/src/main.rs index 89366df..0fe79cd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,13 +6,15 @@ mod model; use std::env; -use color_eyre::{eyre::WrapErr, Result}; +use color_eyre::{eyre::WrapErr, Report, Result}; use serenity::{model::prelude::*, prelude::*}; use tracing::info; use tracing_subscriber::EnvFilter; use crate::{handler::Handler, model::Mongo}; +type Context<'a> = poise::Context<'a, Handler, Report>; + #[tokio::main] async fn main() -> Result<()> { color_eyre::install()?; From d4cae5b572880be77fee879a2d87d5b5a53a7d63 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 19 Jun 2022 17:55:59 +0200 Subject: [PATCH 2/8] no nougat :ferrisSob: --- Cargo.toml | 1 - src/handler.rs | 103 +------------------------------------------------ 2 files changed, 1 insertion(+), 103 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b4d9d59..6bfbadb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ tokio = { version = "1.19.2", features = ["full"] } tracing = "0.1.35" tracing-subscriber = { version = "0.3.11", features = ["env-filter"] } serde = { version = "1.0.137", features = ["derive"] } -nougat = "0.1.0" serde_json = "1.0.81" poise = "0.2.2" diff --git a/src/handler.rs b/src/handler.rs index 0f7d7e9..c72c753 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -517,7 +517,7 @@ async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> color_eyre:: let role = match role { Some(role) => role, None => { - ctx.say("du mosch zerst e rolle setze mit /prison set_role"); + ctx.say("du mosch zerst e rolle setze mit /prison set_role").await?; return Ok(()); } }; @@ -584,104 +584,3 @@ async fn prison_release_impl(ctx: crate::Context<'_>, user: User) -> color_eyre: async fn error_handler(error: poise::FrameworkError<'_, Handler, Report>) { error!(?error, "Error during command execution"); } - -#[nougat::gat] -trait GetOption { - type Get<'a>; - - fn extract( - command: &ApplicationCommandInteractionDataOptionValue, - ) -> color_eyre::Result>; - - fn get( - option: Option<&ApplicationCommandInteractionDataOption>, - ) -> color_eyre::Result> { - let option = Self::get_optional(option); - match option { - Ok(Some(get)) => Ok(get), - Ok(None) => Err(eyre!("Expected value!")), - Err(err) => Err(err), - } - } - fn get_optional( - option: Option<&ApplicationCommandInteractionDataOption>, - ) -> color_eyre::Result>> { - if let Some(option) = option { - if let Some(command) = option.resolved.as_ref() { - Self::extract(command).map(Some) - } else { - Ok(None) - } - } else { - Ok(None) - } - } -} - -struct UserOption; - -#[nougat::gat] -impl GetOption for UserOption { - type Get<'a> = (&'a User, &'a Option); - - fn extract( - command: &ApplicationCommandInteractionDataOptionValue, - ) -> crate::Result> { - if let ApplicationCommandInteractionDataOptionValue::User(user, member) = command { - Ok((user, member)) - } else { - Err(eyre!("Expected user!")) - } - } -} - -struct StringOption; - -#[nougat::gat] -impl GetOption for StringOption { - type Get<'a> = &'a str; - - fn extract( - command: &ApplicationCommandInteractionDataOptionValue, - ) -> crate::Result> { - if let ApplicationCommandInteractionDataOptionValue::String(str) = command { - Ok(str) - } else { - Err(eyre!("Expected string!")) - } - } -} - -struct ChannelOption; - -#[nougat::gat] -impl GetOption for ChannelOption { - type Get<'a> = &'a PartialChannel; - - fn extract( - command: &ApplicationCommandInteractionDataOptionValue, - ) -> crate::Result> { - if let ApplicationCommandInteractionDataOptionValue::Channel(channel) = command { - Ok(channel) - } else { - Err(eyre!("Expected string!")) - } - } -} - -struct RoleOption; - -#[nougat::gat] -impl GetOption for RoleOption { - type Get<'a> = &'a Role; - - fn extract( - command: &ApplicationCommandInteractionDataOptionValue, - ) -> crate::Result> { - if let ApplicationCommandInteractionDataOptionValue::Role(role) = command { - Ok(role) - } else { - Err(eyre!("Expected string!")) - } - } -} From ccdc51f826aca19db41f999d61847f7f2e30a10a Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 19 Jun 2022 18:19:48 +0200 Subject: [PATCH 3/8] migrate lawsuit commands to poise --- Cargo.lock | 44 ---- src/handler.rs | 631 ++++++++++++++++++++----------------------------- 2 files changed, 258 insertions(+), 417 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19a3531..344de05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -203,7 +203,6 @@ dependencies = [ "color-eyre", "dotenv", "mongodb", - "nougat", "poise", "serde", "serde_json", @@ -785,22 +784,6 @@ dependencies = [ "linked-hash-map", ] -[[package]] -name = "macro_rules_attribute" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422a6e082b3d33461030d68a243af2482eefded078eaaf8ac401777d21cae32b" -dependencies = [ - "macro_rules_attribute-proc_macro", - "paste", -] - -[[package]] -name = "macro_rules_attribute-proc_macro" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb4091d2e7f515b3a7ae8dda39417cd2b81d5c8814f68361c3e15b24e2d40b4a" - [[package]] name = "match_cfg" version = "0.1.0" @@ -920,27 +903,6 @@ dependencies = [ "webpki-roots", ] -[[package]] -name = "nougat" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dafa3a476b709b3930ca280fe980fa583a9904735b76045ca328f2c7382ca10" -dependencies = [ - "macro_rules_attribute", - "nougat-proc_macros", -] - -[[package]] -name = "nougat-proc_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aad0b7693b89a294713bf27d8664b86a9fee198e44bd683533215e256dc3176" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "num-integer" version = "0.1.45" @@ -1042,12 +1004,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "paste" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" - [[package]] name = "pbkdf2" version = "0.10.1" diff --git a/src/handler.rs b/src/handler.rs index c72c753..fc4d5fa 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -1,4 +1,4 @@ -use std::fmt::{Debug, Formatter}; +use std::fmt::{Debug, Display, Formatter}; use color_eyre::eyre::{eyre, ContextCompat}; use mongodb::bson::Uuid; @@ -20,136 +20,17 @@ use crate::{ }; fn slash_commands(commands: &mut CreateApplicationCommands) -> &mut CreateApplicationCommands { - commands - .create_application_command(|command| { - command - .name("lawsuit") - .description("Einen Gerichtsprozess starten") - .create_option(|option| { - option - .name("create") - .description("Einen neuen Gerichtsprozess anfangen") - .kind(ApplicationCommandOptionType::SubCommand) - .create_sub_option(|option| { - option - .name("plaintiff") - .description("Der Kläger") - .kind(ApplicationCommandOptionType::User) - .required(true) - }) - .create_sub_option(|option| { - option - .name("accused") - .description("Der Angeklagte") - .kind(ApplicationCommandOptionType::User) - .required(true) - }) - .create_sub_option(|option| { - option - .name("judge") - .description("Der Richter") - .kind(ApplicationCommandOptionType::User) - .required(true) - }) - .create_sub_option(|option| { - option - .name("reason") - .description("Der Grund für die Klage") - .kind(ApplicationCommandOptionType::String) - .required(true) - }) - .create_sub_option(|option| { - option - .name("plaintiff_lawyer") - .description("Der Anwalt des Klägers") - .kind(ApplicationCommandOptionType::User) - .required(false) - }) - .create_sub_option(|option| { - option - .name("accused_lawyer") - .description("Der Anwalt des Angeklagten") - .kind(ApplicationCommandOptionType::User) - .required(false) - }) - }) - .create_option(|option| { - option - .name("set_category") - .description("Die Gerichtskategorie setzen") - .kind(ApplicationCommandOptionType::SubCommand) - .create_sub_option(|option| { - option - .name("category") - .description("Die Kategorie") - .kind(ApplicationCommandOptionType::Channel) - .required(true) - }) - }) - .create_option(|option| { - option - .name("close") - .description("Den Prozess abschliessen") - .kind(ApplicationCommandOptionType::SubCommand) - .create_sub_option(|option| { - option - .name("verdict") - .description("Das Urteil") - .kind(ApplicationCommandOptionType::String) - .required(true) - }) - }) - .create_option(|option| { - option - .name("clear") - .description("Alle Rechtsprozessdaten löschen") - .kind(ApplicationCommandOptionType::SubCommand) - }) - }) - .create_application_command(|command| { - command - .name("prison") - .description("Leute im Gefängnis einsperren") - .create_option(|option| { - option - .name("arrest") - .description("Jemanden einsperren") - .kind(ApplicationCommandOptionType::SubCommand) - .create_sub_option(|option| { - option - .name("user") - .description("Die Person zum einsperren") - .kind(ApplicationCommandOptionType::User) - .required(true) - }) - }) - .create_option(|option| { - option - .name("release") - .description("Jemanden freilassen") - .kind(ApplicationCommandOptionType::SubCommand) - .create_sub_option(|option| { - option - .name("user") - .description("Die Person zum freilassen") - .kind(ApplicationCommandOptionType::User) - .required(true) - }) - }) - .create_option(|option| { - option - .name("set_role") - .description("Die Rolle für Gefangene setzen") - .kind(ApplicationCommandOptionType::SubCommand) - .create_sub_option(|option| { - option - .name("role") - .description("Die Rolle") - .kind(ApplicationCommandOptionType::Role) - .required(true) - }) - }) - }) + commands.create_application_command(|command| { + command + .name("lawsuit") + .description("Einen Gerichtsprozess starten") + .create_option(|option| { + option + .name("clear") + .description("Alle Rechtsprozessdaten löschen") + .kind(ApplicationCommandOptionType::SubCommand) + }) + }) } pub struct Handler { @@ -170,6 +51,16 @@ pub enum Response { NoPermissions, } +impl Display for Response { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::EphemeralStr(str) => f.write_str(str), + Self::Ephemeral(str) => f.write_str(str), + Self::NoPermissions => f.write_str("du häsch kei recht für da!"), + } + } +} + #[async_trait] impl EventHandler for Handler { async fn guild_member_addition(&self, ctx: Context, new_member: Member) { @@ -201,42 +92,9 @@ impl EventHandler for Handler { } } } - - async fn interaction_create(&self, ctx: Context, interaction: Interaction) { - if let Interaction::ApplicationCommand(command) = interaction { - if let Err(err) = self.handle_interaction(ctx, command).await { - error!(?err, "An error occurred in interaction_create handler"); - } - } - } } + impl Handler { - async fn handle_interaction( - &self, - ctx: Context, - command: ApplicationCommandInteraction, - ) -> color_eyre::Result<()> { - debug!(name = %command.data.name, "Received command interaction"); - - let response = match command.data.name.as_str() { - "lawsuit" => lawsuit_command_handler(&command, &ctx, &self.mongo).await, - _ => Ok(Response::EphemeralStr("not implemented :(")), - }; - - match response { - Ok(response) => self.send_response(ctx, command, response).await, - Err(err) => { - error!(?err, "Error during command execution"); - self.send_response( - ctx, - command, - Response::EphemeralStr("An internal error occurred"), - ) - .await - } - } - } - async fn handle_guild_member_join( &self, ctx: Context, @@ -266,196 +124,78 @@ impl Handler { Ok(()) } - - async fn send_response( - &self, - ctx: Context, - command: ApplicationCommandInteraction, - response: Response, - ) -> color_eyre::Result<()> { - command - .create_interaction_response(&ctx.http, |res| match response { - Response::EphemeralStr(content) => res - .kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| { - message - .content(content) - .flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL) - }), - Response::Ephemeral(content) => res - .kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| { - message - .content(content) - .flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL) - }), - Response::NoPermissions => res - .kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|message| { - message - .content("du häsch kei recht für da!") - .flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL) - }), - }) - .await - .wrap_err("sending response")?; - Ok(()) - } } -async fn lawsuit_command_handler( - command: &ApplicationCommandInteraction, - ctx: &Context, - mongo_client: &Mongo, -) -> color_eyre::Result { - let options = &command.data.options; - let subcommand = options.get(0).wrap_err("needs subcommand")?; +#[poise::command( + slash_command, + subcommands("prison_set_role", "prison_arrest", "prison_release") +)] +async fn lawsuit(_: crate::Context<'_>) -> color_eyre::Result<()> { + unreachable!() +} - let options = &subcommand.options; - let guild_id = command.guild_id.wrap_err("guild_id not found")?; +/// Einen neuen Gerichtsprozess erstellen +#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] +async fn lawsuit_create( + ctx: crate::Context<'_>, + #[description = "Der Kläger"] plaintiff: User, + #[description = "Der Angeklagte"] accused: User, + #[description = "Der Richter"] judge: User, + #[description = "Der Grund für die Klage"] reason: String, + #[description = "Der Anwalt des Klägers"] plaintiff_lawyer: Option, + #[description = "Der Anwalt des Angeklagten"] accused_lawyer: Option, +) -> color_eyre::Result<()> { + lawsuit_create_impl( + ctx, + plaintiff, + accused, + judge, + reason, + plaintiff_lawyer, + accused_lawyer, + ) + .await + .wrap_err("lawsuit_create") +} - let member = command - .member - .as_ref() - .wrap_err("command must be used my member")?; - let permissions = member.permissions.wrap_err("must be in interaction")?; +/// Die Rolle für Gefangene setzen +#[poise::command( + slash_command, + required_permissions = "MANAGE_GUILD", + on_error = "error_handler" +)] +async fn lawsuit_set_category( + ctx: crate::Context<'_>, + #[description = "Die Kategorie"] category: Channel, +) -> color_eyre::Result<()> { + lawsuit_set_category_impl(ctx, category) + .await + .wrap_err("lawsuit_set_category") +} - match subcommand.name.as_str() { - "create" => { - if !permissions.contains(Permissions::MANAGE_GUILD) { - return Ok(Response::NoPermissions); - } +/// Den Gerichtsprozess abschliessen und ein Urteil fällen +#[poise::command( + slash_command, + required_permissions = "MANAGE_GUILD", + on_error = "error_handler" +)] +async fn lawsuit_close( + ctx: crate::Context<'_>, + #[description = "Das Urteil"] verdict: String, +) -> color_eyre::Result<()> { + lawsuit_close_impl(ctx, verdict) + .await + .wrap_err("lawsuit_close") +} - let plaintiff = UserOption::get(options.get(0)).wrap_err("plaintiff")?; - let accused = UserOption::get(options.get(1)).wrap_err("accused")?; - let judge = UserOption::get(options.get(2)).wrap_err("judge")?; - let reason = StringOption::get(options.get(3)).wrap_err("reason")?; - let plaintiff_layer = - UserOption::get_optional(options.get(4)).wrap_err("plaintiff_layer")?; - let accused_layer = - UserOption::get_optional(options.get(5)).wrap_err("accused_layer")?; - - let lawsuit = Lawsuit { - id: Uuid::new(), - plaintiff: plaintiff.0.id.into(), - accused: accused.0.id.into(), - judge: judge.0.id.into(), - plaintiff_lawyer: plaintiff_layer.map(|user| user.0.id.into()), - accused_lawyer: accused_layer.map(|user| user.0.id.into()), - reason: reason.to_owned(), - verdict: None, - court_room: SnowflakeId(0), - }; - - let lawsuit_ctx = LawsuitCtx { - lawsuit, - mongo_client: mongo_client.clone(), - http: ctx.http.clone(), - guild_id, - }; - - let response = lawsuit_ctx - .initialize() - .await - .wrap_err("initialize lawsuit")?; - - Ok(response) - } - "set_category" => { - if !permissions.contains(Permissions::MANAGE_GUILD) { - return Ok(Response::NoPermissions); - } - - let channel = ChannelOption::get(options.get(0))?; - - let channel = channel - .id - .to_channel(&ctx.http) - .await - .wrap_err("fetch category for set_category")?; - match channel.category() { - Some(category) => { - let id = category.id; - mongo_client - .set_court_category(guild_id.into(), id.into()) - .await?; - } - None => return Ok(Response::EphemeralStr("Das ist keine Kategorie!")), - } - - Ok(Response::EphemeralStr("isch gsetzt")) - } - "close" => { - let permission_override = permissions.contains(Permissions::MANAGE_GUILD); - - let verdict = StringOption::get(options.get(0))?; - - let room_id = command.channel_id; - - let state = mongo_client - .find_or_insert_state(guild_id.into()) - .await - .wrap_err("find guild for verdict")?; - - let lawsuit = state - .lawsuits - .iter() - .find(|l| l.court_room == room_id.into() && l.verdict.is_none()); - - let lawsuit = match lawsuit { - Some(lawsuit) => lawsuit.clone(), - None => { - return Ok(Response::EphemeralStr( - "i dem channel lauft kein aktive prozess!", - )) - } - }; - - let room = state - .court_rooms - .iter() - .find(|r| r.channel_id == room_id.into()); - let room = match room { - Some(room) => room.clone(), - None => { - return Ok(Response::EphemeralStr( - "i dem channel lauft kein aktive prozess!", - )) - } - }; - - let mut lawsuit_ctx = LawsuitCtx { - lawsuit, - mongo_client: mongo_client.clone(), - http: ctx.http.clone(), - guild_id, - }; - - let response = lawsuit_ctx - .rule_verdict( - permission_override, - member.user.id, - verdict.to_string(), - room, - ) - .await?; - - if let Err(response) = response { - return Ok(response); - } - - Ok(Response::EphemeralStr("ich han en dir abschlosse")) - } - "clear" => { - if !permissions.contains(Permissions::MANAGE_GUILD) { - return Ok(Response::NoPermissions); - } - - mongo_client.delete_guild(guild_id.into()).await?; - Ok(Response::EphemeralStr("alles weg")) - } - _ => Err(eyre!("Unknown subcommand")), - } +/// Alle Rechtsprozessdaten löschen +#[poise::command( + slash_command, + required_permissions = "MANAGE_GUILD", + on_error = "error_handler" +)] +async fn lawsuit_clear(ctx: crate::Context<'_>) -> color_eyre::Result<()> { + lawsuit_clear_impl(ctx).await.wrap_err("lawsuit_clear") } #[poise::command( @@ -474,13 +214,179 @@ async fn prison(_: crate::Context<'_>) -> color_eyre::Result<()> { )] async fn prison_set_role( ctx: crate::Context<'_>, - #[description = "Die rolle"] role: Role, + #[description = "Die Rolle"] role: Role, ) -> color_eyre::Result<()> { prison_set_role_impl(ctx, role) .await .wrap_err("prison_set_role") } +/// Jemanden einsperren +#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] +async fn prison_arrest( + ctx: crate::Context<'_>, + #[description = "Die Person zum einsperren"] user: User, +) -> color_eyre::Result<()> { + prison_arrest_impl(ctx, user) + .await + .wrap_err("prison_arrest") +} + +/// Einen Gefangenen freilassen +#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] +async fn prison_release( + ctx: crate::Context<'_>, + #[description = "Die Person zum freilassen"] user: User, +) -> color_eyre::Result<()> { + prison_release_impl(ctx, user) + .await + .wrap_err("prison_release") +} + +async fn lawsuit_create_impl( + ctx: crate::Context<'_>, + plaintiff: User, + accused: User, + judge: User, + reason: String, + plaintiff_lawyer: Option, + accused_lawyer: Option, +) -> color_eyre::Result<()> { + let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; + + let lawsuit = Lawsuit { + id: Uuid::new(), + plaintiff: plaintiff.id.into(), + accused: accused.id.into(), + judge: judge.id.into(), + plaintiff_lawyer: plaintiff_lawyer.map(|user| user.id.into()), + accused_lawyer: accused_lawyer.map(|user| user.id.into()), + reason: reason.to_owned(), + verdict: None, + court_room: SnowflakeId(0), + }; + + let lawsuit_ctx = LawsuitCtx { + lawsuit, + mongo_client: ctx.data().mongo.clone(), + http: ctx.discord().http.clone(), + guild_id, + }; + + let response = lawsuit_ctx + .initialize() + .await + .wrap_err("initialize lawsuit")?; + + ctx.say(response.to_string()).await?; + + Ok(()) +} + +async fn lawsuit_set_category_impl( + ctx: crate::Context<'_>, + category: Channel, +) -> color_eyre::Result<()> { + let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; + + //let channel = channel + // .id + // .to_channel(&ctx.http) + // .await + // .wrap_err("fetch category for set_category")?; + match category.category() { + Some(category) => { + let id = category.id; + ctx.data() + .mongo + .set_court_category(guild_id.into(), id.into()) + .await?; + ctx.say("isch gsetzt").await?; + } + None => { + ctx.say("Das ist keine Kategorie!").await?; + } + } + + Ok(()) +} + +async fn lawsuit_close_impl(ctx: crate::Context<'_>, verdict: String) -> color_eyre::Result<()> { + let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; + + let member = ctx.author_member().await.wrap_err("member not found")?; + let permission_override = member + .permissions + .wrap_err("permissions not found")? + .contains(Permissions::MANAGE_GUILD); + + let room_id = ctx.channel_id(); + let mongo_client = &ctx.data().mongo; + + let state = mongo_client + .find_or_insert_state(guild_id.into()) + .await + .wrap_err("find guild for verdict")?; + + let lawsuit = state + .lawsuits + .iter() + .find(|l| l.court_room == room_id.into() && l.verdict.is_none()); + + let lawsuit = match lawsuit { + Some(lawsuit) => lawsuit.clone(), + None => { + ctx.say("i dem channel lauft kein aktive prozess!").await?; + return Ok(()); + } + }; + + let room = state + .court_rooms + .iter() + .find(|r| r.channel_id == room_id.into()); + let room = match room { + Some(room) => room.clone(), + None => { + ctx.say("i dem channel lauft kein aktive prozess!").await?; + return Ok(()); + } + }; + + let mut lawsuit_ctx = LawsuitCtx { + lawsuit, + mongo_client: mongo_client.clone(), + http: ctx.discord().http.clone(), + guild_id, + }; + + let response = lawsuit_ctx + .rule_verdict( + permission_override, + member.user.id, + verdict.to_string(), + room, + ) + .await?; + + if let Err(response) = response { + ctx.say(response.to_string()).await?; + return Ok(()); + } + + ctx.say("ich han en dir abschlosse").await?; + + Ok(()) +} + +async fn lawsuit_clear_impl(ctx: crate::Context<'_>) -> color_eyre::Result<()> { + let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; + + ctx.data().mongo.delete_guild(guild_id.into()).await?; + ctx.say("alles weg").await?; + Ok(()) +} + async fn prison_set_role_impl(ctx: crate::Context<'_>, role: Role) -> color_eyre::Result<()> { ctx.data() .mongo @@ -495,17 +401,6 @@ async fn prison_set_role_impl(ctx: crate::Context<'_>, role: Role) -> color_eyre Ok(()) } -/// Jemanden einsperren -#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] -async fn prison_arrest( - ctx: crate::Context<'_>, - #[description = "Die Person zum einsperren"] user: User, -) -> color_eyre::Result<()> { - prison_arrest_impl(ctx, user) - .await - .wrap_err("prison_arrest") -} - async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> color_eyre::Result<()> { let mongo_client = &ctx.data().mongo; let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; @@ -517,7 +412,8 @@ async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> color_eyre:: let role = match role { Some(role) => role, None => { - ctx.say("du mosch zerst e rolle setze mit /prison set_role").await?; + ctx.say("du mosch zerst e rolle setze mit /prison set_role") + .await?; return Ok(()); } }; @@ -536,17 +432,6 @@ async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> color_eyre:: Ok(()) } -/// Einen Gefangenen freilassen -#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] -async fn prison_release( - ctx: crate::Context<'_>, - #[description = "Die Person zum freilassen"] user: User, -) -> color_eyre::Result<()> { - prison_release_impl(ctx, user) - .await - .wrap_err("prison_release") -} - async fn prison_release_impl(ctx: crate::Context<'_>, user: User) -> color_eyre::Result<()> { let mongo_client = &ctx.data().mongo; let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; From 36b4a9d5b0b72ccb9ee1aea7946bfa66001a762a Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 19 Jun 2022 19:47:08 +0200 Subject: [PATCH 4/8] switch --- Cargo.lock | 1 - Cargo.toml | 5 -- src/handler.rs | 131 +++++++++++++++++++++---------------------------- src/lawsuit.rs | 7 +-- src/main.rs | 33 +++++++++---- src/model.rs | 2 +- 6 files changed, 81 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 344de05..6df0ff2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,7 +206,6 @@ dependencies = [ "poise", "serde", "serde_json", - "serenity", "tokio", "tracing", "tracing-subscriber", diff --git a/Cargo.toml b/Cargo.toml index 6bfbadb..704074f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,3 @@ tracing-subscriber = { version = "0.3.11", features = ["env-filter"] } serde = { version = "1.0.137", features = ["derive"] } serde_json = "1.0.81" poise = "0.2.2" - -[dependencies.serenity] -version = "0.11.2" -default-features = false -features = ["builder", "cache", "client", "gateway", "collector", "http", "rustls_backend", "tokio", "typemap_rev", "utils"] diff --git a/src/handler.rs b/src/handler.rs index fc4d5fa..02c6ab9 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -1,16 +1,8 @@ use std::fmt::{Debug, Display, Formatter}; -use color_eyre::eyre::{eyre, ContextCompat}; +use color_eyre::{eyre::ContextCompat, Result}; use mongodb::bson::Uuid; -use serenity::{ - async_trait, - builder::CreateApplicationCommands, - model::{ - interactions::application_command::ApplicationCommandOptionType, - prelude::{application_command::*, *}, - }, - prelude::*, -}; +use poise::{serenity::model::prelude::*, serenity_prelude as serenity, Event}; use tracing::{debug, error, info}; use crate::{ @@ -19,20 +11,6 @@ use crate::{ Mongo, Report, WrapErr, }; -fn slash_commands(commands: &mut CreateApplicationCommands) -> &mut CreateApplicationCommands { - commands.create_application_command(|command| { - command - .name("lawsuit") - .description("Einen Gerichtsprozess starten") - .create_option(|option| { - option - .name("clear") - .description("Alle Rechtsprozessdaten löschen") - .kind(ApplicationCommandOptionType::SubCommand) - }) - }) -} - pub struct Handler { pub dev_guild_id: Option, pub set_global_commands: bool, @@ -60,15 +38,9 @@ impl Display for Response { } } } - +/* #[async_trait] impl EventHandler for Handler { - async fn guild_member_addition(&self, ctx: Context, new_member: Member) { - if let Err(err) = self.handle_guild_member_join(ctx, new_member).await { - error!(?err, "An error occurred in guild_member_addition handler"); - } - } - async fn ready(&self, ctx: Context, ready: Ready) { info!(name = %ready.user.name, "Bot is connected!"); @@ -93,13 +65,13 @@ impl EventHandler for Handler { } } } - +*/ impl Handler { async fn handle_guild_member_join( &self, - ctx: Context, - mut member: Member, - ) -> color_eyre::Result<()> { + ctx: &serenity::Context, + member: &Member, + ) -> Result<()> { let guild_id = member.guild_id; let user_id = member.user.id; let state = self.mongo.find_or_insert_state(guild_id.into()).await?; @@ -116,6 +88,7 @@ impl Handler { info!("New member was in prison, giving them the prison role"); member + .clone() .add_role(&ctx.http, role_id) .await .wrap_err("add role to member in prison")?; @@ -128,9 +101,14 @@ impl Handler { #[poise::command( slash_command, - subcommands("prison_set_role", "prison_arrest", "prison_release") + subcommands( + "lawsuit_create", + "lawsuit_set_category", + "lawsuit_close", + "lawsuit_clear" + ) )] -async fn lawsuit(_: crate::Context<'_>) -> color_eyre::Result<()> { +pub async fn lawsuit(_: crate::Context<'_>) -> Result<()> { unreachable!() } @@ -144,7 +122,7 @@ async fn lawsuit_create( #[description = "Der Grund für die Klage"] reason: String, #[description = "Der Anwalt des Klägers"] plaintiff_lawyer: Option, #[description = "Der Anwalt des Angeklagten"] accused_lawyer: Option, -) -> color_eyre::Result<()> { +) -> Result<()> { lawsuit_create_impl( ctx, plaintiff, @@ -159,42 +137,30 @@ async fn lawsuit_create( } /// Die Rolle für Gefangene setzen -#[poise::command( - slash_command, - required_permissions = "MANAGE_GUILD", - on_error = "error_handler" -)] +#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] async fn lawsuit_set_category( ctx: crate::Context<'_>, #[description = "Die Kategorie"] category: Channel, -) -> color_eyre::Result<()> { +) -> Result<()> { lawsuit_set_category_impl(ctx, category) .await .wrap_err("lawsuit_set_category") } /// Den Gerichtsprozess abschliessen und ein Urteil fällen -#[poise::command( - slash_command, - required_permissions = "MANAGE_GUILD", - on_error = "error_handler" -)] +#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] async fn lawsuit_close( ctx: crate::Context<'_>, #[description = "Das Urteil"] verdict: String, -) -> color_eyre::Result<()> { +) -> Result<()> { lawsuit_close_impl(ctx, verdict) .await .wrap_err("lawsuit_close") } /// Alle Rechtsprozessdaten löschen -#[poise::command( - slash_command, - required_permissions = "MANAGE_GUILD", - on_error = "error_handler" -)] -async fn lawsuit_clear(ctx: crate::Context<'_>) -> color_eyre::Result<()> { +#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] +async fn lawsuit_clear(ctx: crate::Context<'_>) -> Result<()> { lawsuit_clear_impl(ctx).await.wrap_err("lawsuit_clear") } @@ -202,20 +168,16 @@ async fn lawsuit_clear(ctx: crate::Context<'_>) -> color_eyre::Result<()> { slash_command, subcommands("prison_set_role", "prison_arrest", "prison_release") )] -async fn prison(_: crate::Context<'_>) -> color_eyre::Result<()> { +pub async fn prison(_: crate::Context<'_>) -> Result<()> { unreachable!() } /// Die Rolle für Gefangene setzen -#[poise::command( - slash_command, - required_permissions = "MANAGE_GUILD", - on_error = "error_handler" -)] +#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] async fn prison_set_role( ctx: crate::Context<'_>, #[description = "Die Rolle"] role: Role, -) -> color_eyre::Result<()> { +) -> Result<()> { prison_set_role_impl(ctx, role) .await .wrap_err("prison_set_role") @@ -226,7 +188,7 @@ async fn prison_set_role( async fn prison_arrest( ctx: crate::Context<'_>, #[description = "Die Person zum einsperren"] user: User, -) -> color_eyre::Result<()> { +) -> Result<()> { prison_arrest_impl(ctx, user) .await .wrap_err("prison_arrest") @@ -237,7 +199,7 @@ async fn prison_arrest( async fn prison_release( ctx: crate::Context<'_>, #[description = "Die Person zum freilassen"] user: User, -) -> color_eyre::Result<()> { +) -> Result<()> { prison_release_impl(ctx, user) .await .wrap_err("prison_release") @@ -251,7 +213,7 @@ async fn lawsuit_create_impl( reason: String, plaintiff_lawyer: Option, accused_lawyer: Option, -) -> color_eyre::Result<()> { +) -> Result<()> { let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; let lawsuit = Lawsuit { @@ -283,10 +245,7 @@ async fn lawsuit_create_impl( Ok(()) } -async fn lawsuit_set_category_impl( - ctx: crate::Context<'_>, - category: Channel, -) -> color_eyre::Result<()> { +async fn lawsuit_set_category_impl(ctx: crate::Context<'_>, category: Channel) -> Result<()> { let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; //let channel = channel @@ -311,7 +270,7 @@ async fn lawsuit_set_category_impl( Ok(()) } -async fn lawsuit_close_impl(ctx: crate::Context<'_>, verdict: String) -> color_eyre::Result<()> { +async fn lawsuit_close_impl(ctx: crate::Context<'_>, verdict: String) -> Result<()> { let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; let member = ctx.author_member().await.wrap_err("member not found")?; @@ -379,7 +338,7 @@ async fn lawsuit_close_impl(ctx: crate::Context<'_>, verdict: String) -> color_e Ok(()) } -async fn lawsuit_clear_impl(ctx: crate::Context<'_>) -> color_eyre::Result<()> { +async fn lawsuit_clear_impl(ctx: crate::Context<'_>) -> Result<()> { let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; ctx.data().mongo.delete_guild(guild_id.into()).await?; @@ -387,7 +346,7 @@ async fn lawsuit_clear_impl(ctx: crate::Context<'_>) -> color_eyre::Result<()> { Ok(()) } -async fn prison_set_role_impl(ctx: crate::Context<'_>, role: Role) -> color_eyre::Result<()> { +async fn prison_set_role_impl(ctx: crate::Context<'_>, role: Role) -> Result<()> { ctx.data() .mongo .set_prison_role( @@ -401,7 +360,7 @@ async fn prison_set_role_impl(ctx: crate::Context<'_>, role: Role) -> color_eyre Ok(()) } -async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> color_eyre::Result<()> { +async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> Result<()> { let mongo_client = &ctx.data().mongo; let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; let http = &ctx.discord().http; @@ -432,7 +391,7 @@ async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> color_eyre:: Ok(()) } -async fn prison_release_impl(ctx: crate::Context<'_>, user: User) -> color_eyre::Result<()> { +async fn prison_release_impl(ctx: crate::Context<'_>, user: User) -> Result<()> { let mongo_client = &ctx.data().mongo; let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; let http = &ctx.discord().http; @@ -466,6 +425,26 @@ async fn prison_release_impl(ctx: crate::Context<'_>, user: User) -> color_eyre: Ok(()) } -async fn error_handler(error: poise::FrameworkError<'_, Handler, Report>) { +pub async fn listener( + ctx: &serenity::Context, + event: &Event<'_>, + _: poise::FrameworkContext<'_, Handler, Report>, + data: &Handler, +) -> Result<()> { + match event { + Event::GuildMemberAddition { new_member } => { + if let Err(err) = data.handle_guild_member_join(ctx, &new_member).await { + error!(?err, "An error occurred in guild_member_addition handler"); + } + } + Event::Ready { data_about_bot } => { + info!(name = %data_about_bot.user.name, "Bot is connected!"); + } + _ => {} + } + Ok(()) +} + +pub async fn error_handler(error: poise::FrameworkError<'_, Handler, Report>) { error!(?error, "Error during command execution"); } diff --git a/src/lawsuit.rs b/src/lawsuit.rs index 9beb0e3..ce3369e 100644 --- a/src/lawsuit.rs +++ b/src/lawsuit.rs @@ -2,12 +2,9 @@ use std::sync::Arc; use color_eyre::Result; use mongodb::bson::{doc, Uuid}; +use poise::{serenity::model::prelude::*, serenity_prelude::Http}; +use poise::serenity_prelude::CreateMessage; use serde::{Deserialize, Serialize}; -use serenity::{ - builder::CreateMessage, - http::Http, - model::{channel::PermissionOverwriteType, prelude::*, Permissions}, -}; use tracing::{error, info}; use crate::{ diff --git a/src/main.rs b/src/main.rs index 0fe79cd..5dfb9f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ mod model; use std::env; use color_eyre::{eyre::WrapErr, Report, Result}; -use serenity::{model::prelude::*, prelude::*}; +use poise::serenity_prelude as serenity; use tracing::info; use tracing_subscriber::EnvFilter; @@ -41,7 +41,7 @@ async fn main() -> Result<()> { let token = env::var("DISCORD_TOKEN").wrap_err("DISCORD_TOKEN not found in environment")?; let dev_guild_id = if env::var("DEV").is_ok() { - Some(GuildId( + Some(serenity::GuildId( env::var("GUILD_ID") .wrap_err("GUILD_ID not found in environment, must be set when DEV is set")? .parse() @@ -53,15 +53,28 @@ async fn main() -> Result<()> { let set_global_commands = env::var("SET_GLOBAL").is_ok(); - let mut client = Client::builder(token, GatewayIntents::empty()) - .event_handler(Handler { - dev_guild_id, - set_global_commands, - mongo, + poise::Framework::build() + .token(token) + .user_data_setup(move |_, _, _| { + Box::pin(async move { + Ok(Handler { + dev_guild_id, + set_global_commands, + mongo, + }) + }) }) - .intents(GatewayIntents::GUILD_MEMBERS) + .options(poise::FrameworkOptions { + commands: vec![handler::lawsuit(), handler::prison()], + on_error: |err| Box::pin(async { handler::error_handler(err).await }), + listener: |ctx, event, ctx2, data| { + Box::pin(async move { handler::listener(ctx, event, ctx2, data).await }) + }, + ..Default::default() + }) + .intents(serenity::GatewayIntents::GUILD_MEMBERS) + .run() .await .wrap_err("failed to create discord client")?; - - client.start().await.wrap_err("running client") + Ok(()) } diff --git a/src/model.rs b/src/model.rs index 3132786..0a7d1d1 100644 --- a/src/model.rs +++ b/src/model.rs @@ -11,8 +11,8 @@ use mongodb::{ options::{ClientOptions, Credential, UpdateOptions}, Client, Collection, Database, }; +use poise::serenity::model::id::{ChannelId, GuildId, RoleId, UserId}; use serde::{Deserialize, Serialize}; -use serenity::model::id::{ChannelId, GuildId, RoleId, UserId}; use tracing::info; use crate::{lawsuit::Lawsuit, WrapErr}; From d9ca14c64256414c228192cb9b38c9f0f14f6487 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 19 Jun 2022 20:23:56 +0200 Subject: [PATCH 5/8] works --- src/handler.rs | 6 ++-- src/main.rs | 84 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 79 insertions(+), 11 deletions(-) diff --git a/src/handler.rs b/src/handler.rs index 02c6ab9..c817b8a 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -431,15 +431,13 @@ pub async fn listener( _: poise::FrameworkContext<'_, Handler, Report>, data: &Handler, ) -> Result<()> { + #[allow(clippy::single_match)] match event { Event::GuildMemberAddition { new_member } => { - if let Err(err) = data.handle_guild_member_join(ctx, &new_member).await { + if let Err(err) = data.handle_guild_member_join(ctx, new_member).await { error!(?err, "An error occurred in guild_member_addition handler"); } } - Event::Ready { data_about_bot } => { - info!(name = %data_about_bot.user.name, "Bot is connected!"); - } _ => {} } Ok(()) diff --git a/src/main.rs b/src/main.rs index 5dfb9f5..d4768f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,11 @@ mod model; use std::env; use color_eyre::{eyre::WrapErr, Report, Result}; -use poise::serenity_prelude as serenity; -use tracing::info; +use poise::{ + serenity_prelude as serenity, + serenity_prelude::{Activity, GatewayIntents, GuildId}, +}; +use tracing::{error, info}; use tracing_subscriber::EnvFilter; use crate::{handler::Handler, model::Mongo}; @@ -55,26 +58,93 @@ async fn main() -> Result<()> { poise::Framework::build() .token(token) - .user_data_setup(move |_, _, _| { + .user_data_setup(move |ctx, ready, framework| { Box::pin(async move { - Ok(Handler { + let data = Handler { dev_guild_id, set_global_commands, mongo, - }) + }; + + let commands = &framework.options().commands; + let create_commands = poise::builtins::create_application_commands(commands); + + if data.set_global_commands { + info!("Installing global slash commands..."); + let guild_commands = + serenity::ApplicationCommand::set_global_application_commands(ctx, |b| { + *b = create_commands.clone(); + b + }) + .await; + match guild_commands { + Ok(commands) => info!(?commands, "Created global commands"), + Err(error) => error!(?error, "Failed to create global commands"), + } + } + + if let Some(guild_id) = data.dev_guild_id { + info!("Installing guild commands..."); + let guild_commands = GuildId::set_application_commands(&guild_id, ctx, |b| { + *b = create_commands; + b + }) + .await; + + match guild_commands { + Ok(_) => info!("Installed guild slash commands"), + Err(error) => error!(?error, "Failed to create global commands"), + } + } + + ctx.set_activity(Activity::playing("für Recht und Ordnung sorgen")) + .await; + + info!(name = %ready.user.name, "Bot is connected!"); + + Ok(data) }) }) .options(poise::FrameworkOptions { - commands: vec![handler::lawsuit(), handler::prison()], + commands: vec![handler::lawsuit(), handler::prison(), hello()], on_error: |err| Box::pin(async { handler::error_handler(err).await }), listener: |ctx, event, ctx2, data| { Box::pin(async move { handler::listener(ctx, event, ctx2, data).await }) }, + pre_command: |ctx| { + Box::pin(async move { + let channel_name = ctx + .channel_id() + .name(&ctx.discord()) + .await + .unwrap_or_else(|| "".to_owned()); + let author = ctx.author().tag(); + + match ctx { + Context::Application(ctx) => { + let command_name = &ctx.interaction.data().name; + + info!(?author, ?channel_name, ?command_name, "Command called"); + } + Context::Prefix(_) => { + tracing::warn!("Prefix command called!"); + // we don't use prefix commands + } + } + }) + }, ..Default::default() }) - .intents(serenity::GatewayIntents::GUILD_MEMBERS) + .intents(GatewayIntents::non_privileged() | GatewayIntents::GUILD_MEMBERS) .run() .await .wrap_err("failed to create discord client")?; Ok(()) } + +/// Sag Karin hallo. +#[poise::command(slash_command)] +async fn hello(ctx: Context<'_>) -> Result<()> { + ctx.say("hoi!").await?; + Ok(()) +} From 0605eda466dd1db68462e3b639b56d2190b1c9fe Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 19 Jun 2022 20:27:31 +0200 Subject: [PATCH 6/8] submodules handlers --- src/handler.rs | 625 ++++++++++++++++++++++++------------------------- src/main.rs | 4 +- 2 files changed, 305 insertions(+), 324 deletions(-) diff --git a/src/handler.rs b/src/handler.rs index c817b8a..264aa7a 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -38,34 +38,7 @@ impl Display for Response { } } } -/* -#[async_trait] -impl EventHandler for Handler { - async fn ready(&self, ctx: Context, ready: Ready) { - info!(name = %ready.user.name, "Bot is connected!"); - if let Some(guild_id) = self.dev_guild_id { - let guild_commands = - GuildId::set_application_commands(&guild_id, &ctx.http, slash_commands).await; - - match guild_commands { - Ok(_) => info!("Installed guild slash commands"), - Err(error) => error!(?error, "Failed to create global commands"), - } - } - - if self.set_global_commands { - let guild_commands = - ApplicationCommand::set_global_application_commands(&ctx.http, slash_commands) - .await; - match guild_commands { - Ok(commands) => info!(?commands, "Created global commands"), - Err(error) => error!(?error, "Failed to create global commands"), - } - } - } -} -*/ impl Handler { async fn handle_guild_member_join( &self, @@ -99,330 +72,338 @@ impl Handler { } } -#[poise::command( - slash_command, - subcommands( - "lawsuit_create", - "lawsuit_set_category", - "lawsuit_close", - "lawsuit_clear" - ) -)] -pub async fn lawsuit(_: crate::Context<'_>) -> Result<()> { - unreachable!() -} +pub mod lawsuit { + use super::*; -/// Einen neuen Gerichtsprozess erstellen -#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] -async fn lawsuit_create( - ctx: crate::Context<'_>, - #[description = "Der Kläger"] plaintiff: User, - #[description = "Der Angeklagte"] accused: User, - #[description = "Der Richter"] judge: User, - #[description = "Der Grund für die Klage"] reason: String, - #[description = "Der Anwalt des Klägers"] plaintiff_lawyer: Option, - #[description = "Der Anwalt des Angeklagten"] accused_lawyer: Option, -) -> Result<()> { - lawsuit_create_impl( - ctx, - plaintiff, - accused, - judge, - reason, - plaintiff_lawyer, - accused_lawyer, - ) - .await - .wrap_err("lawsuit_create") -} - -/// Die Rolle für Gefangene setzen -#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] -async fn lawsuit_set_category( - ctx: crate::Context<'_>, - #[description = "Die Kategorie"] category: Channel, -) -> Result<()> { - lawsuit_set_category_impl(ctx, category) - .await - .wrap_err("lawsuit_set_category") -} - -/// Den Gerichtsprozess abschliessen und ein Urteil fällen -#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] -async fn lawsuit_close( - ctx: crate::Context<'_>, - #[description = "Das Urteil"] verdict: String, -) -> Result<()> { - lawsuit_close_impl(ctx, verdict) - .await - .wrap_err("lawsuit_close") -} - -/// Alle Rechtsprozessdaten löschen -#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] -async fn lawsuit_clear(ctx: crate::Context<'_>) -> Result<()> { - lawsuit_clear_impl(ctx).await.wrap_err("lawsuit_clear") -} - -#[poise::command( - slash_command, - subcommands("prison_set_role", "prison_arrest", "prison_release") -)] -pub async fn prison(_: crate::Context<'_>) -> Result<()> { - unreachable!() -} - -/// Die Rolle für Gefangene setzen -#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] -async fn prison_set_role( - ctx: crate::Context<'_>, - #[description = "Die Rolle"] role: Role, -) -> Result<()> { - prison_set_role_impl(ctx, role) - .await - .wrap_err("prison_set_role") -} - -/// Jemanden einsperren -#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] -async fn prison_arrest( - ctx: crate::Context<'_>, - #[description = "Die Person zum einsperren"] user: User, -) -> Result<()> { - prison_arrest_impl(ctx, user) - .await - .wrap_err("prison_arrest") -} - -/// Einen Gefangenen freilassen -#[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] -async fn prison_release( - ctx: crate::Context<'_>, - #[description = "Die Person zum freilassen"] user: User, -) -> Result<()> { - prison_release_impl(ctx, user) - .await - .wrap_err("prison_release") -} - -async fn lawsuit_create_impl( - ctx: crate::Context<'_>, - plaintiff: User, - accused: User, - judge: User, - reason: String, - plaintiff_lawyer: Option, - accused_lawyer: Option, -) -> Result<()> { - let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; - - let lawsuit = Lawsuit { - id: Uuid::new(), - plaintiff: plaintiff.id.into(), - accused: accused.id.into(), - judge: judge.id.into(), - plaintiff_lawyer: plaintiff_lawyer.map(|user| user.id.into()), - accused_lawyer: accused_lawyer.map(|user| user.id.into()), - reason: reason.to_owned(), - verdict: None, - court_room: SnowflakeId(0), - }; - - let lawsuit_ctx = LawsuitCtx { - lawsuit, - mongo_client: ctx.data().mongo.clone(), - http: ctx.discord().http.clone(), - guild_id, - }; - - let response = lawsuit_ctx - .initialize() - .await - .wrap_err("initialize lawsuit")?; - - ctx.say(response.to_string()).await?; - - Ok(()) -} - -async fn lawsuit_set_category_impl(ctx: crate::Context<'_>, category: Channel) -> Result<()> { - let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; - - //let channel = channel - // .id - // .to_channel(&ctx.http) - // .await - // .wrap_err("fetch category for set_category")?; - match category.category() { - Some(category) => { - let id = category.id; - ctx.data() - .mongo - .set_court_category(guild_id.into(), id.into()) - .await?; - ctx.say("isch gsetzt").await?; - } - None => { - ctx.say("Das ist keine Kategorie!").await?; - } + #[poise::command( + slash_command, + subcommands( + "create", + "set_category", + "close", + "clear" + ) + )] + pub async fn lawsuit(_: crate::Context<'_>) -> Result<()> { + unreachable!() } - Ok(()) -} - -async fn lawsuit_close_impl(ctx: crate::Context<'_>, verdict: String) -> Result<()> { - let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; - - let member = ctx.author_member().await.wrap_err("member not found")?; - let permission_override = member - .permissions - .wrap_err("permissions not found")? - .contains(Permissions::MANAGE_GUILD); - - let room_id = ctx.channel_id(); - let mongo_client = &ctx.data().mongo; - - let state = mongo_client - .find_or_insert_state(guild_id.into()) - .await - .wrap_err("find guild for verdict")?; - - let lawsuit = state - .lawsuits - .iter() - .find(|l| l.court_room == room_id.into() && l.verdict.is_none()); - - let lawsuit = match lawsuit { - Some(lawsuit) => lawsuit.clone(), - None => { - ctx.say("i dem channel lauft kein aktive prozess!").await?; - return Ok(()); - } - }; - - let room = state - .court_rooms - .iter() - .find(|r| r.channel_id == room_id.into()); - let room = match room { - Some(room) => room.clone(), - None => { - ctx.say("i dem channel lauft kein aktive prozess!").await?; - return Ok(()); - } - }; - - let mut lawsuit_ctx = LawsuitCtx { - lawsuit, - mongo_client: mongo_client.clone(), - http: ctx.discord().http.clone(), - guild_id, - }; - - let response = lawsuit_ctx - .rule_verdict( - permission_override, - member.user.id, - verdict.to_string(), - room, + /// Einen neuen Gerichtsprozess erstellen + #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] + async fn create( + ctx: crate::Context<'_>, + #[description = "Der Kläger"] plaintiff: User, + #[description = "Der Angeklagte"] accused: User, + #[description = "Der Richter"] judge: User, + #[description = "Der Grund für die Klage"] reason: String, + #[description = "Der Anwalt des Klägers"] plaintiff_lawyer: Option, + #[description = "Der Anwalt des Angeklagten"] accused_lawyer: Option, + ) -> Result<()> { + lawsuit_create_impl( + ctx, + plaintiff, + accused, + judge, + reason, + plaintiff_lawyer, + accused_lawyer, ) - .await?; + .await + .wrap_err("lawsuit_create") + } + + /// Die Rolle für Gefangene setzen + #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] + async fn set_category( + ctx: crate::Context<'_>, + #[description = "Die Kategorie"] category: Channel, + ) -> Result<()> { + lawsuit_set_category_impl(ctx, category) + .await + .wrap_err("lawsuit_set_category") + } + + /// Den Gerichtsprozess abschliessen und ein Urteil fällen + #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] + async fn close( + ctx: crate::Context<'_>, + #[description = "Das Urteil"] verdict: String, + ) -> Result<()> { + lawsuit_close_impl(ctx, verdict) + .await + .wrap_err("lawsuit_close") + } + + /// Alle Rechtsprozessdaten löschen + #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] + async fn clear(ctx: crate::Context<'_>) -> Result<()> { + lawsuit_clear_impl(ctx).await.wrap_err("lawsuit_clear") + } + + async fn lawsuit_create_impl( + ctx: crate::Context<'_>, + plaintiff: User, + accused: User, + judge: User, + reason: String, + plaintiff_lawyer: Option, + accused_lawyer: Option, + ) -> Result<()> { + let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; + + let lawsuit = Lawsuit { + id: Uuid::new(), + plaintiff: plaintiff.id.into(), + accused: accused.id.into(), + judge: judge.id.into(), + plaintiff_lawyer: plaintiff_lawyer.map(|user| user.id.into()), + accused_lawyer: accused_lawyer.map(|user| user.id.into()), + reason: reason.to_owned(), + verdict: None, + court_room: SnowflakeId(0), + }; + + let lawsuit_ctx = LawsuitCtx { + lawsuit, + mongo_client: ctx.data().mongo.clone(), + http: ctx.discord().http.clone(), + guild_id, + }; + + let response = lawsuit_ctx + .initialize() + .await + .wrap_err("initialize lawsuit")?; - if let Err(response) = response { ctx.say(response.to_string()).await?; - return Ok(()); + + Ok(()) } - ctx.say("ich han en dir abschlosse").await?; + async fn lawsuit_set_category_impl(ctx: crate::Context<'_>, category: Channel) -> Result<()> { + let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; - Ok(()) -} + //let channel = channel + // .id + // .to_channel(&ctx.http) + // .await + // .wrap_err("fetch category for set_category")?; + match category.category() { + Some(category) => { + let id = category.id; + ctx.data() + .mongo + .set_court_category(guild_id.into(), id.into()) + .await?; + ctx.say("isch gsetzt").await?; + } + None => { + ctx.say("Das ist keine Kategorie!").await?; + } + } -async fn lawsuit_clear_impl(ctx: crate::Context<'_>) -> Result<()> { - let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; + Ok(()) + } - ctx.data().mongo.delete_guild(guild_id.into()).await?; - ctx.say("alles weg").await?; - Ok(()) -} + async fn lawsuit_close_impl(ctx: crate::Context<'_>, verdict: String) -> Result<()> { + let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; -async fn prison_set_role_impl(ctx: crate::Context<'_>, role: Role) -> Result<()> { - ctx.data() - .mongo - .set_prison_role( - ctx.guild_id().wrap_err("guild_id not found")?.into(), - role.id.into(), - ) - .await?; + let member = ctx.author_member().await.wrap_err("member not found")?; + let permission_override = member + .permissions + .wrap_err("permissions not found")? + .contains(Permissions::MANAGE_GUILD); - ctx.say("isch gsetzt").await.wrap_err("reply")?; + let room_id = ctx.channel_id(); + let mongo_client = &ctx.data().mongo; - Ok(()) -} + let state = mongo_client + .find_or_insert_state(guild_id.into()) + .await + .wrap_err("find guild for verdict")?; -async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> Result<()> { - let mongo_client = &ctx.data().mongo; - let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; - let http = &ctx.discord().http; + let lawsuit = state + .lawsuits + .iter() + .find(|l| l.court_room == room_id.into() && l.verdict.is_none()); - let state = mongo_client.find_or_insert_state(guild_id.into()).await?; - let role = state.prison_role; + let lawsuit = match lawsuit { + Some(lawsuit) => lawsuit.clone(), + None => { + ctx.say("i dem channel lauft kein aktive prozess!").await?; + return Ok(()); + } + }; - let role = match role { - Some(role) => role, - None => { - ctx.say("du mosch zerst e rolle setze mit /prison set_role") - .await?; + let room = state + .court_rooms + .iter() + .find(|r| r.channel_id == room_id.into()); + let room = match room { + Some(room) => room.clone(), + None => { + ctx.say("i dem channel lauft kein aktive prozess!").await?; + return Ok(()); + } + }; + + let mut lawsuit_ctx = LawsuitCtx { + lawsuit, + mongo_client: mongo_client.clone(), + http: ctx.discord().http.clone(), + guild_id, + }; + + let response = lawsuit_ctx + .rule_verdict( + permission_override, + member.user.id, + verdict.to_string(), + room, + ) + .await?; + + if let Err(response) = response { + ctx.say(response.to_string()).await?; return Ok(()); } - }; - mongo_client - .add_to_prison(guild_id.into(), user.id.into()) - .await?; + ctx.say("ich han en dir abschlosse").await?; - guild_id - .member(http, user.id) - .await - .wrap_err("fetching guild member")? - .add_role(http, role) - .await - .wrap_err("add guild member role")?; - Ok(()) + Ok(()) + } + + async fn lawsuit_clear_impl(ctx: crate::Context<'_>) -> Result<()> { + let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; + + ctx.data().mongo.delete_guild(guild_id.into()).await?; + ctx.say("alles weg").await?; + Ok(()) + } } -async fn prison_release_impl(ctx: crate::Context<'_>, user: User) -> Result<()> { - let mongo_client = &ctx.data().mongo; - let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; - let http = &ctx.discord().http; +pub mod prison { + use super::*; - let state = mongo_client.find_or_insert_state(guild_id.into()).await?; - let role = state.prison_role; + #[poise::command( + slash_command, + subcommands("set_role", "arrest", "release") + )] + pub async fn prison(_: crate::Context<'_>) -> Result<()> { + unreachable!() + } - let role = match role { - Some(role) => role, - None => { - ctx.say("du mosch zerst e rolle setze mit /prison set_role") - .await?; - return Ok(()); - } - }; + /// Die Rolle für Gefangene setzen + #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] + async fn set_role( + ctx: crate::Context<'_>, + #[description = "Die Rolle"] role: Role, + ) -> Result<()> { + prison_set_role_impl(ctx, role) + .await + .wrap_err("prison_set_role") + } - mongo_client - .remove_from_prison(guild_id.into(), user.id.into()) - .await?; + /// Jemanden einsperren + #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] + async fn arrest( + ctx: crate::Context<'_>, + #[description = "Die Person zum einsperren"] user: User, + ) -> Result<()> { + prison_arrest_impl(ctx, user) + .await + .wrap_err("prison_arrest") + } - guild_id - .member(http, user.id) - .await - .wrap_err("fetching guild member")? - .remove_role(http, role) - .await - .wrap_err("remove guild member role")?; + /// Einen Gefangenen freilassen + #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] + async fn release( + ctx: crate::Context<'_>, + #[description = "Die Person zum freilassen"] user: User, + ) -> Result<()> { + prison_release_impl(ctx, user) + .await + .wrap_err("prison_release") + } - ctx.say("d'freiheit wartet").await?; + async fn prison_set_role_impl(ctx: crate::Context<'_>, role: Role) -> Result<()> { + ctx.data() + .mongo + .set_prison_role( + ctx.guild_id().wrap_err("guild_id not found")?.into(), + role.id.into(), + ) + .await?; - Ok(()) + ctx.say("isch gsetzt").await.wrap_err("reply")?; + + Ok(()) + } + + async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> Result<()> { + let mongo_client = &ctx.data().mongo; + let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; + let http = &ctx.discord().http; + + let state = mongo_client.find_or_insert_state(guild_id.into()).await?; + let role = state.prison_role; + + let role = match role { + Some(role) => role, + None => { + ctx.say("du mosch zerst e rolle setze mit /prison set_role") + .await?; + return Ok(()); + } + }; + + mongo_client + .add_to_prison(guild_id.into(), user.id.into()) + .await?; + + guild_id + .member(http, user.id) + .await + .wrap_err("fetching guild member")? + .add_role(http, role) + .await + .wrap_err("add guild member role")?; + Ok(()) + } + + async fn prison_release_impl(ctx: crate::Context<'_>, user: User) -> Result<()> { + let mongo_client = &ctx.data().mongo; + let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; + let http = &ctx.discord().http; + + let state = mongo_client.find_or_insert_state(guild_id.into()).await?; + let role = state.prison_role; + + let role = match role { + Some(role) => role, + None => { + ctx.say("du mosch zerst e rolle setze mit /prison set_role") + .await?; + return Ok(()); + } + }; + + mongo_client + .remove_from_prison(guild_id.into(), user.id.into()) + .await?; + + guild_id + .member(http, user.id) + .await + .wrap_err("fetching guild member")? + .remove_role(http, role) + .await + .wrap_err("remove guild member role")?; + + ctx.say("d'freiheit wartet").await?; + + Ok(()) + } } pub async fn listener( diff --git a/src/main.rs b/src/main.rs index d4768f8..a87066f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,7 +44,7 @@ async fn main() -> Result<()> { let token = env::var("DISCORD_TOKEN").wrap_err("DISCORD_TOKEN not found in environment")?; let dev_guild_id = if env::var("DEV").is_ok() { - Some(serenity::GuildId( + Some(GuildId( env::var("GUILD_ID") .wrap_err("GUILD_ID not found in environment, must be set when DEV is set")? .parse() @@ -106,7 +106,7 @@ async fn main() -> Result<()> { }) }) .options(poise::FrameworkOptions { - commands: vec![handler::lawsuit(), handler::prison(), hello()], + commands: vec![handler::lawsuit::lawsuit(), handler::prison::prison(), hello()], on_error: |err| Box::pin(async { handler::error_handler(err).await }), listener: |ctx, event, ctx2, data| { Box::pin(async move { handler::listener(ctx, event, ctx2, data).await }) From d91ee43933afa6241574963e6683c5c2e343ea6d Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 19 Jun 2022 20:37:56 +0200 Subject: [PATCH 7/8] pwetty tracing owo --- Cargo.lock | 25 +++++++++++++++++++++++++ Cargo.toml | 1 + README.md | 1 + src/handler.rs | 22 +++++++++------------- src/lawsuit.rs | 6 ++++-- src/main.rs | 34 +++++++++++++++++++++++++++++----- src/model.rs | 12 ++++++++++++ 7 files changed, 81 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6df0ff2..25bd04b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,6 +64,17 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -209,6 +220,7 @@ dependencies = [ "tokio", "tracing", "tracing-subscriber", + "tracing-tree", ] [[package]] @@ -1743,6 +1755,19 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "tracing-tree" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07e90b329c621ade432823988574e820212648aa40e7a2497777d58de0fb453" +dependencies = [ + "ansi_term", + "atty", + "tracing-core", + "tracing-log", + "tracing-subscriber", +] + [[package]] name = "trust-dns-proto" version = "0.21.2" diff --git a/Cargo.toml b/Cargo.toml index 704074f..c1ae4fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ tracing-subscriber = { version = "0.3.11", features = ["env-filter"] } serde = { version = "1.0.137", features = ["derive"] } serde_json = "1.0.81" poise = "0.2.2" +tracing-tree = "0.2.1" diff --git a/README.md b/README.md index 83fa392..aab6825 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ MONGO_INITDB_ROOT_USERNAME=root MONGO_INITDB_ROOT_PASSWORD=uwu DEV= # SET_GLOBAL= +PRETTY= ``` run mongodb diff --git a/src/handler.rs b/src/handler.rs index 264aa7a..4fafa6b 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -75,15 +75,7 @@ impl Handler { pub mod lawsuit { use super::*; - #[poise::command( - slash_command, - subcommands( - "create", - "set_category", - "close", - "clear" - ) - )] + #[poise::command(slash_command, subcommands("create", "set_category", "close", "clear"))] pub async fn lawsuit(_: crate::Context<'_>) -> Result<()> { unreachable!() } @@ -140,6 +132,7 @@ pub mod lawsuit { lawsuit_clear_impl(ctx).await.wrap_err("lawsuit_clear") } + #[tracing::instrument(skip(ctx))] async fn lawsuit_create_impl( ctx: crate::Context<'_>, plaintiff: User, @@ -180,6 +173,7 @@ pub mod lawsuit { Ok(()) } + #[tracing::instrument(skip(ctx))] async fn lawsuit_set_category_impl(ctx: crate::Context<'_>, category: Channel) -> Result<()> { let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; @@ -205,6 +199,7 @@ pub mod lawsuit { Ok(()) } + #[tracing::instrument(skip(ctx))] async fn lawsuit_close_impl(ctx: crate::Context<'_>, verdict: String) -> Result<()> { let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; @@ -273,6 +268,7 @@ pub mod lawsuit { Ok(()) } + #[tracing::instrument(skip(ctx))] async fn lawsuit_clear_impl(ctx: crate::Context<'_>) -> Result<()> { let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; @@ -285,10 +281,7 @@ pub mod lawsuit { pub mod prison { use super::*; - #[poise::command( - slash_command, - subcommands("set_role", "arrest", "release") - )] + #[poise::command(slash_command, subcommands("set_role", "arrest", "release"))] pub async fn prison(_: crate::Context<'_>) -> Result<()> { unreachable!() } @@ -326,6 +319,7 @@ pub mod prison { .wrap_err("prison_release") } + #[tracing::instrument(skip(ctx))] async fn prison_set_role_impl(ctx: crate::Context<'_>, role: Role) -> Result<()> { ctx.data() .mongo @@ -340,6 +334,7 @@ pub mod prison { Ok(()) } + #[tracing::instrument(skip(ctx))] async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> Result<()> { let mongo_client = &ctx.data().mongo; let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; @@ -371,6 +366,7 @@ pub mod prison { Ok(()) } + #[tracing::instrument(skip(ctx))] async fn prison_release_impl(ctx: crate::Context<'_>, user: User) -> Result<()> { let mongo_client = &ctx.data().mongo; let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; diff --git a/src/lawsuit.rs b/src/lawsuit.rs index ce3369e..d7035db 100644 --- a/src/lawsuit.rs +++ b/src/lawsuit.rs @@ -2,8 +2,10 @@ use std::sync::Arc; use color_eyre::Result; use mongodb::bson::{doc, Uuid}; -use poise::{serenity::model::prelude::*, serenity_prelude::Http}; -use poise::serenity_prelude::CreateMessage; +use poise::{ + serenity::model::prelude::*, + serenity_prelude::{CreateMessage, Http}, +}; use serde::{Deserialize, Serialize}; use tracing::{error, info}; diff --git a/src/main.rs b/src/main.rs index a87066f..d9a11ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use poise::{ serenity_prelude::{Activity, GatewayIntents, GuildId}, }; use tracing::{error, info}; -use tracing_subscriber::EnvFilter; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry}; use crate::{handler::Handler, model::Mongo}; @@ -24,9 +24,9 @@ async fn main() -> Result<()> { let _ = dotenv::dotenv(); - tracing_subscriber::fmt() - .with_env_filter(EnvFilter::from_default_env()) - .init(); + let pretty = env::var("PRETTY").is_ok(); + + setup_tracing(pretty); info!("Starting up..."); @@ -106,7 +106,11 @@ async fn main() -> Result<()> { }) }) .options(poise::FrameworkOptions { - commands: vec![handler::lawsuit::lawsuit(), handler::prison::prison(), hello()], + commands: vec![ + handler::lawsuit::lawsuit(), + handler::prison::prison(), + hello(), + ], on_error: |err| Box::pin(async { handler::error_handler(err).await }), listener: |ctx, event, ctx2, data| { Box::pin(async move { handler::listener(ctx, event, ctx2, data).await }) @@ -148,3 +152,23 @@ async fn hello(ctx: Context<'_>) -> Result<()> { ctx.say("hoi!").await?; Ok(()) } + +fn setup_tracing(pretty: bool) { + let registry = Registry::default().with(EnvFilter::from_default_env()); + + if pretty { + let tree_layer = tracing_tree::HierarchicalLayer::new(2) + .with_targets(true) + .with_bracketed_fields(true); + + registry.with(tree_layer).init(); + } else { + let fmt_layer = tracing_subscriber::fmt::layer() + .with_level(true) + .with_timer(tracing_subscriber::fmt::time::time()) + .with_ansi(true) + .with_thread_names(true); + + registry.with(fmt_layer).init(); + }; +} diff --git a/src/model.rs b/src/model.rs index 0a7d1d1..d3a9585 100644 --- a/src/model.rs +++ b/src/model.rs @@ -137,6 +137,7 @@ impl Mongo { Ok(Self { db }) } + #[tracing::instrument(skip(self))] pub async fn find_or_insert_state(&self, guild_id: SnowflakeId) -> Result { let coll = self.state_coll(); let state = coll @@ -155,6 +156,7 @@ impl Mongo { Ok(state) } + #[tracing::instrument(skip(self))] pub async fn new_state(&self, guild_id: SnowflakeId) -> Result { let state = State { guild_id, @@ -171,6 +173,7 @@ impl Mongo { Ok(state) } + #[tracing::instrument(skip(self))] pub async fn set_court_category( &self, guild_id: SnowflakeId, @@ -188,6 +191,7 @@ impl Mongo { Ok(()) } + #[tracing::instrument(skip(self))] pub async fn set_prison_role( &self, guild_id: SnowflakeId, @@ -205,6 +209,7 @@ impl Mongo { Ok(()) } + #[tracing::instrument(skip(self))] pub async fn add_court_room(&self, guild_id: SnowflakeId, room: &CourtRoom) -> Result<()> { let _ = self.find_or_insert_state(guild_id).await?; let coll = self.state_coll(); @@ -218,6 +223,7 @@ impl Mongo { Ok(()) } + #[tracing::instrument(skip(self))] pub async fn add_lawsuit(&self, guild_id: SnowflakeId, lawsuit: &Lawsuit) -> Result<()> { let _ = self.find_or_insert_state(guild_id).await?; let coll = self.state_coll(); @@ -233,6 +239,7 @@ impl Mongo { Ok(()) } + #[tracing::instrument(skip(self, value))] pub async fn set_court_room( &self, guild_id: SnowflakeId, @@ -252,6 +259,7 @@ impl Mongo { Ok(()) } + #[tracing::instrument(skip(self, value))] pub async fn set_lawsuit( &self, guild_id: SnowflakeId, @@ -271,6 +279,7 @@ impl Mongo { Ok(()) } + #[tracing::instrument(skip(self))] pub async fn delete_guild(&self, guild_id: SnowflakeId) -> Result<()> { let coll = self.state_coll(); @@ -280,6 +289,7 @@ impl Mongo { Ok(()) } + #[tracing::instrument(skip(self))] pub async fn add_to_prison(&self, guild_id: SnowflakeId, user_id: SnowflakeId) -> Result<()> { let coll = self.prison_coll(); @@ -298,6 +308,7 @@ impl Mongo { Ok(()) } + #[tracing::instrument(skip(self))] pub async fn remove_from_prison( &self, guild_id: SnowflakeId, @@ -312,6 +323,7 @@ impl Mongo { Ok(()) } + #[tracing::instrument(skip(self))] pub async fn find_prison_entry( &self, guild_id: SnowflakeId, From aa6e57b2fa47563e957c29774208f2aa9a8f1a6c Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 19 Jun 2022 21:14:35 +0200 Subject: [PATCH 8/8] fix author perms --- Cargo.lock | 1 + Cargo.toml | 1 + README.md | 1 - src/handler.rs | 92 ++++++++++++++++++++++++++++---------------------- src/main.rs | 4 ++- src/model.rs | 34 +++++++++++++++++-- 6 files changed, 87 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 25bd04b..635d2c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,6 +219,7 @@ dependencies = [ "serde_json", "tokio", "tracing", + "tracing-error", "tracing-subscriber", "tracing-tree", ] diff --git a/Cargo.toml b/Cargo.toml index c1ae4fa..148d9b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,4 @@ serde = { version = "1.0.137", features = ["derive"] } serde_json = "1.0.81" poise = "0.2.2" tracing-tree = "0.2.1" +tracing-error = "0.2.0" diff --git a/README.md b/README.md index aab6825..e106a4f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ a very funny discord bot .env ``` DISCORD_TOKEN=token -APPLICATION_ID=uwu RUST_LOG=DEBUG MONGO_URI=mongodb://localhost:27017 DB_NAME=court_bot diff --git a/src/handler.rs b/src/handler.rs index 4fafa6b..c639a1a 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -8,7 +8,7 @@ use tracing::{debug, error, info}; use crate::{ lawsuit::{Lawsuit, LawsuitCtx}, model::SnowflakeId, - Mongo, Report, WrapErr, + Context, Mongo, Report, WrapErr, }; pub struct Handler { @@ -73,17 +73,23 @@ impl Handler { } pub mod lawsuit { + use color_eyre::eyre::eyre; + use super::*; - #[poise::command(slash_command, subcommands("create", "set_category", "close", "clear"))] - pub async fn lawsuit(_: crate::Context<'_>) -> Result<()> { + #[poise::command( + slash_command, + guild_only, + subcommands("create", "set_category", "close", "clear") + )] + pub async fn lawsuit(_: Context<'_>) -> Result<()> { unreachable!() } /// Einen neuen Gerichtsprozess erstellen - #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] + #[poise::command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")] async fn create( - ctx: crate::Context<'_>, + ctx: Context<'_>, #[description = "Der Kläger"] plaintiff: User, #[description = "Der Angeklagte"] accused: User, #[description = "Der Richter"] judge: User, @@ -105,9 +111,9 @@ pub mod lawsuit { } /// Die Rolle für Gefangene setzen - #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] + #[poise::command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")] async fn set_category( - ctx: crate::Context<'_>, + ctx: Context<'_>, #[description = "Die Kategorie"] category: Channel, ) -> Result<()> { lawsuit_set_category_impl(ctx, category) @@ -116,25 +122,22 @@ pub mod lawsuit { } /// Den Gerichtsprozess abschliessen und ein Urteil fällen - #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] - async fn close( - ctx: crate::Context<'_>, - #[description = "Das Urteil"] verdict: String, - ) -> Result<()> { + #[poise::command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")] + async fn close(ctx: Context<'_>, #[description = "Das Urteil"] verdict: String) -> Result<()> { lawsuit_close_impl(ctx, verdict) .await .wrap_err("lawsuit_close") } /// Alle Rechtsprozessdaten löschen - #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] - async fn clear(ctx: crate::Context<'_>) -> Result<()> { + #[poise::command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")] + async fn clear(ctx: Context<'_>) -> Result<()> { lawsuit_clear_impl(ctx).await.wrap_err("lawsuit_clear") } #[tracing::instrument(skip(ctx))] async fn lawsuit_create_impl( - ctx: crate::Context<'_>, + ctx: Context<'_>, plaintiff: User, accused: User, judge: User, @@ -174,14 +177,9 @@ pub mod lawsuit { } #[tracing::instrument(skip(ctx))] - async fn lawsuit_set_category_impl(ctx: crate::Context<'_>, category: Channel) -> Result<()> { + async fn lawsuit_set_category_impl(ctx: Context<'_>, category: Channel) -> Result<()> { let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; - //let channel = channel - // .id - // .to_channel(&ctx.http) - // .await - // .wrap_err("fetch category for set_category")?; match category.category() { Some(category) => { let id = category.id; @@ -200,14 +198,23 @@ pub mod lawsuit { } #[tracing::instrument(skip(ctx))] - async fn lawsuit_close_impl(ctx: crate::Context<'_>, verdict: String) -> Result<()> { + async fn lawsuit_close_impl(ctx: Context<'_>, verdict: String) -> Result<()> { let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; - let member = ctx.author_member().await.wrap_err("member not found")?; + let application_context = match ctx { + Context::Application(ctx) => ctx, + Context::Prefix(_) => return Err(eyre!("wrong context, cannot happen!")), + }; + + let member = application_context + .interaction + .member() + .wrap_err("member not found")?; + let permission_override = member .permissions - .wrap_err("permissions not found")? - .contains(Permissions::MANAGE_GUILD); + .map(|p| p.contains(Permissions::MANAGE_GUILD)) + .unwrap_or(false); let room_id = ctx.channel_id(); let mongo_client = &ctx.data().mongo; @@ -269,7 +276,7 @@ pub mod lawsuit { } #[tracing::instrument(skip(ctx))] - async fn lawsuit_clear_impl(ctx: crate::Context<'_>) -> Result<()> { + async fn lawsuit_clear_impl(ctx: Context<'_>) -> Result<()> { let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; ctx.data().mongo.delete_guild(guild_id.into()).await?; @@ -280,27 +287,27 @@ pub mod lawsuit { pub mod prison { use super::*; - - #[poise::command(slash_command, subcommands("set_role", "arrest", "release"))] - pub async fn prison(_: crate::Context<'_>) -> Result<()> { + #[poise::command( + slash_command, + guild_only, + subcommands("set_role", "arrest", "release") + )] + pub async fn prison(_: Context<'_>) -> Result<()> { unreachable!() } /// Die Rolle für Gefangene setzen - #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] - async fn set_role( - ctx: crate::Context<'_>, - #[description = "Die Rolle"] role: Role, - ) -> Result<()> { + #[poise::command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")] + async fn set_role(ctx: Context<'_>, #[description = "Die Rolle"] role: Role) -> Result<()> { prison_set_role_impl(ctx, role) .await .wrap_err("prison_set_role") } /// Jemanden einsperren - #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] + #[poise::command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")] async fn arrest( - ctx: crate::Context<'_>, + ctx: Context<'_>, #[description = "Die Person zum einsperren"] user: User, ) -> Result<()> { prison_arrest_impl(ctx, user) @@ -309,9 +316,9 @@ pub mod prison { } /// Einen Gefangenen freilassen - #[poise::command(slash_command, required_permissions = "MANAGE_GUILD")] + #[poise::command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")] async fn release( - ctx: crate::Context<'_>, + ctx: Context<'_>, #[description = "Die Person zum freilassen"] user: User, ) -> Result<()> { prison_release_impl(ctx, user) @@ -320,7 +327,7 @@ pub mod prison { } #[tracing::instrument(skip(ctx))] - async fn prison_set_role_impl(ctx: crate::Context<'_>, role: Role) -> Result<()> { + async fn prison_set_role_impl(ctx: Context<'_>, role: Role) -> Result<()> { ctx.data() .mongo .set_prison_role( @@ -335,7 +342,7 @@ pub mod prison { } #[tracing::instrument(skip(ctx))] - async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> Result<()> { + async fn prison_arrest_impl(ctx: Context<'_>, user: User) -> Result<()> { let mongo_client = &ctx.data().mongo; let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; let http = &ctx.discord().http; @@ -363,11 +370,14 @@ pub mod prison { .add_role(http, role) .await .wrap_err("add guild member role")?; + + ctx.say("isch igsperrt").await?; + Ok(()) } #[tracing::instrument(skip(ctx))] - async fn prison_release_impl(ctx: crate::Context<'_>, user: User) -> Result<()> { + async fn prison_release_impl(ctx: Context<'_>, user: User) -> Result<()> { let mongo_client = &ctx.data().mongo; let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; let http = &ctx.discord().http; diff --git a/src/main.rs b/src/main.rs index d9a11ff..d6199aa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -154,7 +154,9 @@ async fn hello(ctx: Context<'_>) -> Result<()> { } fn setup_tracing(pretty: bool) { - let registry = Registry::default().with(EnvFilter::from_default_env()); + let registry = Registry::default() + .with(EnvFilter::from_default_env()) + .with(tracing_error::ErrorLayer::default()); if pretty { let tree_layer = tracing_tree::HierarchicalLayer::new(2) diff --git a/src/model.rs b/src/model.rs index d3a9585..a8727b1 100644 --- a/src/model.rs +++ b/src/model.rs @@ -8,8 +8,8 @@ use color_eyre::Result; use mongodb::{ bson, bson::{doc, Bson, Uuid}, - options::{ClientOptions, Credential, UpdateOptions}, - Client, Collection, Database, + options::{ClientOptions, Credential, IndexOptions, UpdateOptions}, + Client, Collection, Database, IndexModel, }; use poise::serenity::model::id::{ChannelId, GuildId, RoleId, UserId}; use serde::{Deserialize, Serialize}; @@ -114,6 +114,7 @@ pub struct Mongo { } impl Mongo { + #[tracing::instrument(skip(password))] pub async fn connect( uri: &str, db_name: &str, @@ -133,8 +134,35 @@ impl Mongo { let client = Client::with_options(client_options).wrap_err("failed to create client")?; let db = client.database(db_name); + let mongo = Self { db }; - Ok(Self { db }) + info!("Creating indexes"); + + mongo + .state_coll() + .create_index( + IndexModel::builder() + .keys(doc! { "guild_id": 1 }) + .options(IndexOptions::builder().name("state.guild_id".to_string()).build()) + .build(), + None, + ) + .await + .wrap_err("create state index")?; + + mongo + .prison_coll() + .create_index( + IndexModel::builder() + .keys(doc! { "guild_id": 1, "user_id": 1 }) + .options(IndexOptions::builder().name("prison.guild_id_user_id".to_string()).build()) + .build(), + None, + ) + .await + .wrap_err("create state index")?; + + Ok(mongo) } #[tracing::instrument(skip(self))]