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()?;