migrate lawsuit commands to poise

This commit is contained in:
nora 2022-06-19 18:19:48 +02:00
parent d4cae5b572
commit ccdc51f826
2 changed files with 258 additions and 417 deletions

44
Cargo.lock generated
View file

@ -203,7 +203,6 @@ dependencies = [
"color-eyre", "color-eyre",
"dotenv", "dotenv",
"mongodb", "mongodb",
"nougat",
"poise", "poise",
"serde", "serde",
"serde_json", "serde_json",
@ -785,22 +784,6 @@ dependencies = [
"linked-hash-map", "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]] [[package]]
name = "match_cfg" name = "match_cfg"
version = "0.1.0" version = "0.1.0"
@ -920,27 +903,6 @@ dependencies = [
"webpki-roots", "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]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.45" version = "0.1.45"
@ -1042,12 +1004,6 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "paste"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
[[package]] [[package]]
name = "pbkdf2" name = "pbkdf2"
version = "0.10.1" version = "0.10.1"

View file

@ -1,4 +1,4 @@
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Display, Formatter};
use color_eyre::eyre::{eyre, ContextCompat}; use color_eyre::eyre::{eyre, ContextCompat};
use mongodb::bson::Uuid; use mongodb::bson::Uuid;
@ -20,136 +20,17 @@ use crate::{
}; };
fn slash_commands(commands: &mut CreateApplicationCommands) -> &mut CreateApplicationCommands { fn slash_commands(commands: &mut CreateApplicationCommands) -> &mut CreateApplicationCommands {
commands commands.create_application_command(|command| {
.create_application_command(|command| { command
command .name("lawsuit")
.name("lawsuit") .description("Einen Gerichtsprozess starten")
.description("Einen Gerichtsprozess starten") .create_option(|option| {
.create_option(|option| { option
option .name("clear")
.name("create") .description("Alle Rechtsprozessdaten löschen")
.description("Einen neuen Gerichtsprozess anfangen") .kind(ApplicationCommandOptionType::SubCommand)
.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)
})
})
})
} }
pub struct Handler { pub struct Handler {
@ -170,6 +51,16 @@ pub enum Response {
NoPermissions, 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] #[async_trait]
impl EventHandler for Handler { impl EventHandler for Handler {
async fn guild_member_addition(&self, ctx: Context, new_member: Member) { 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 { 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( async fn handle_guild_member_join(
&self, &self,
ctx: Context, ctx: Context,
@ -266,196 +124,78 @@ impl Handler {
Ok(()) 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( #[poise::command(
command: &ApplicationCommandInteraction, slash_command,
ctx: &Context, subcommands("prison_set_role", "prison_arrest", "prison_release")
mongo_client: &Mongo, )]
) -> color_eyre::Result<Response> { async fn lawsuit(_: crate::Context<'_>) -> color_eyre::Result<()> {
let options = &command.data.options; unreachable!()
let subcommand = options.get(0).wrap_err("needs subcommand")?; }
let options = &subcommand.options; /// Einen neuen Gerichtsprozess erstellen
let guild_id = command.guild_id.wrap_err("guild_id not found")?; #[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<User>,
#[description = "Der Anwalt des Angeklagten"] accused_lawyer: Option<User>,
) -> color_eyre::Result<()> {
lawsuit_create_impl(
ctx,
plaintiff,
accused,
judge,
reason,
plaintiff_lawyer,
accused_lawyer,
)
.await
.wrap_err("lawsuit_create")
}
let member = command /// Die Rolle für Gefangene setzen
.member #[poise::command(
.as_ref() slash_command,
.wrap_err("command must be used my member")?; required_permissions = "MANAGE_GUILD",
let permissions = member.permissions.wrap_err("must be in interaction")?; 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() { /// Den Gerichtsprozess abschliessen und ein Urteil fällen
"create" => { #[poise::command(
if !permissions.contains(Permissions::MANAGE_GUILD) { slash_command,
return Ok(Response::NoPermissions); 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")?; /// Alle Rechtsprozessdaten löschen
let accused = UserOption::get(options.get(1)).wrap_err("accused")?; #[poise::command(
let judge = UserOption::get(options.get(2)).wrap_err("judge")?; slash_command,
let reason = StringOption::get(options.get(3)).wrap_err("reason")?; required_permissions = "MANAGE_GUILD",
let plaintiff_layer = on_error = "error_handler"
UserOption::get_optional(options.get(4)).wrap_err("plaintiff_layer")?; )]
let accused_layer = async fn lawsuit_clear(ctx: crate::Context<'_>) -> color_eyre::Result<()> {
UserOption::get_optional(options.get(5)).wrap_err("accused_layer")?; lawsuit_clear_impl(ctx).await.wrap_err("lawsuit_clear")
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")),
}
} }
#[poise::command( #[poise::command(
@ -474,13 +214,179 @@ async fn prison(_: crate::Context<'_>) -> color_eyre::Result<()> {
)] )]
async fn prison_set_role( async fn prison_set_role(
ctx: crate::Context<'_>, ctx: crate::Context<'_>,
#[description = "Die rolle"] role: Role, #[description = "Die Rolle"] role: Role,
) -> color_eyre::Result<()> { ) -> color_eyre::Result<()> {
prison_set_role_impl(ctx, role) prison_set_role_impl(ctx, role)
.await .await
.wrap_err("prison_set_role") .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<User>,
accused_lawyer: Option<User>,
) -> 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<()> { async fn prison_set_role_impl(ctx: crate::Context<'_>, role: Role) -> color_eyre::Result<()> {
ctx.data() ctx.data()
.mongo .mongo
@ -495,17 +401,6 @@ async fn prison_set_role_impl(ctx: crate::Context<'_>, role: Role) -> color_eyre
Ok(()) 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<()> { async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> color_eyre::Result<()> {
let mongo_client = &ctx.data().mongo; let mongo_client = &ctx.data().mongo;
let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; 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 { let role = match role {
Some(role) => role, Some(role) => role,
None => { 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(()); return Ok(());
} }
}; };
@ -536,17 +432,6 @@ async fn prison_arrest_impl(ctx: crate::Context<'_>, user: User) -> color_eyre::
Ok(()) 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<()> { async fn prison_release_impl(ctx: crate::Context<'_>, user: User) -> color_eyre::Result<()> {
let mongo_client = &ctx.data().mongo; let mongo_client = &ctx.data().mongo;
let guild_id = ctx.guild_id().wrap_err("guild_id not found")?; let guild_id = ctx.guild_id().wrap_err("guild_id not found")?;