diff --git a/src/handler.rs b/src/handler.rs index 87e883b..cd1e309 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -39,6 +39,13 @@ fn slash_commands(commands: &mut CreateApplicationCommands) -> &mut CreateApplic .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") @@ -182,17 +189,19 @@ async fn lawsuit_command_handler( "create" => { let plaintiff = UserOption::get(options.get(0)).wrap_err("plaintiff")?; let accused = UserOption::get(options.get(1)).wrap_err("accused")?; - let reason = StringOption::get(options.get(2)).wrap_err("reason")?; + 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(3)).wrap_err("plaintiff_layer")?; + UserOption::get_optional(options.get(4)).wrap_err("plaintiff_layer")?; let accused_layer = - UserOption::get_optional(options.get(4)).wrap_err("accused_layer")?; + UserOption::get_optional(options.get(5)).wrap_err("accused_layer")?; let mut lawsuit = Lawsuit { - plaintiff: plaintiff.0.id, - accused: accused.0.id, - plaintiff_layer: plaintiff_layer.map(|l| l.0.id), - accused_layer: accused_layer.map(|l| l.0.id), + plaintiff: plaintiff.0.id.to_string(), + accused: accused.0.id.to_string(), + judge: judge.0.id.to_string(), + plaintiff_layer: plaintiff_layer.map(|l| l.0.id.to_string()), + accused_layer: accused_layer.map(|l| l.0.id.to_string()), reason: reason.to_owned(), state: LawsuitState::Initial, court_room: None, diff --git a/src/lawsuit.rs b/src/lawsuit.rs index 4dcc263..c7a143e 100644 --- a/src/lawsuit.rs +++ b/src/lawsuit.rs @@ -4,12 +4,7 @@ use color_eyre::Result; use serde::{Deserialize, Serialize}; use serenity::{ http::Http, - model::{ - channel::PermissionOverwriteType, - id::{ChannelId, UserId}, - prelude::{GuildId, PermissionOverwrite}, - Permissions, - }, + model::{channel::PermissionOverwriteType, id::ChannelId, prelude::*, Permissions}, }; use tracing::info; @@ -24,13 +19,14 @@ pub enum LawsuitState { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Lawsuit { - pub plaintiff: UserId, - pub accused: UserId, - pub plaintiff_layer: Option, - pub accused_layer: Option, + pub plaintiff: String, + pub accused: String, + pub plaintiff_layer: Option, + pub accused_layer: Option, + pub judge: String, pub reason: String, pub state: LawsuitState, - pub court_room: Option, + pub court_room: Option, } impl Lawsuit { @@ -44,14 +40,18 @@ impl Lawsuit { .find_or_insert_state(&guild_id.to_string()) .await?; - let free_room = state.court_rooms.iter().find(|r| !r.ongoing_lawsuit); + let free_room = state + .court_rooms + .iter() + .find(|r| !r.ongoing_lawsuit) + .cloned(); - match (free_room, &state.court_category) { - (Some(_room), _) => Ok(Response::Simple("a free room? rip".to_owned())), + let room = match (free_room, &state.court_category) { + (Some(room), _) => room, (None, Some(category)) => { // create room - create_room( + let result = create_room( http, guild_id, state.court_rooms.len(), @@ -61,13 +61,93 @@ impl Lawsuit { .await .wrap_err("create new room")?; - Ok(Response::Simple("no free room? rip".to_owned())) + match result { + Err(res) => return Ok(res), + Ok(room) => room, + } } - (None, None) => Ok(Response::Simple( + (None, None) => return Ok(Response::Simple( "Zuerst eine Kategorie für die Gerichtsräume festlegen mit `/lawsuit set_category`" .to_owned(), )), + }; + + self.court_room = Some(room.channel_id.clone()); + + let result = self + .send_process_open_message(http, guild_id, &room) + .await + .wrap_err("send process open message")?; + + if let Err(response) = result { + return Ok(response); } + + // TODO: now give the people their roles + + Ok(Response::Simple(format!( + "ha eine ufgmacht im channel <#{}>", + room.channel_id + ))) + } + + async fn send_process_open_message( + &self, + http: &Http, + guild_id: GuildId, + room: &CourtRoom, + ) -> Result> { + let channels = guild_id + .to_partial_guild(http) + .await + .wrap_err("fetch partial guild")? + .channels(http) + .await + .wrap_err("fetch channels")?; + let channel = channels.get(&ChannelId::from_str(&room.channel_id).expect("oh god")); + + match channel { + Some(channel) => { + channel + .id + .send_message(http, |msg| { + msg.embed(|embed| { + embed + .title("Prozess") + .field("Grund", &self.reason, false) + .field("Kläger", format!("<@{}>", self.plaintiff), false) + .field( + "Anwalt des Klägers", + match &self.plaintiff_layer { + Some(lawyer) => format!("<@{}>", lawyer), + None => "TBD".to_string(), + }, + false, + ) + .field("Angeklagter", format!("<@{}>", self.accused), false) + .field( + "Anwalt des Angeklagten", + match &self.accused_layer { + Some(lawyer) => format!("<@{}>", lawyer), + None => "TBD".to_string(), + }, + false, + ) + .field("Richter", format!("<@{}>", self.judge), false) + }) + }) + .await + .wrap_err("send message")?; + } + None => { + // todo: remove the court room from the db + return Ok(Err(Response::Simple( + "i ha de channel zum de prozess öffne nöd gfunde".to_string(), + ))); + } + } + + Ok(Ok(())) } } @@ -77,7 +157,7 @@ async fn create_room( room_len: usize, category_id: ChannelId, mongo_client: &Mongo, -) -> Result<()> { +) -> Result> { let room_number = room_len + 1; let room_name = format!("gerichtsraum-{room_number}"); let role_name = format!("Gerichtsprozess {room_number}"); @@ -87,39 +167,60 @@ async fn create_room( .await .wrap_err("fetch partial guild")?; - let court_role = guild - .create_role(http, |role| { - role.name(role_name).permissions(Permissions::empty()) - }) - .await - .wrap_err("create role")?; + let role_id = match guild.role_by_name(&role_name) { + Some(role) => role.id, + None => { + guild + .create_role(http, |role| { + role.name(role_name).permissions(Permissions::empty()) + }) + .await + .wrap_err("create role")? + .id + } + }; - let channel = guild - .create_channel(http, |channel| { - channel - .name(room_name) - .category(category_id) - .permissions(vec![PermissionOverwrite { - allow: Permissions::SEND_MESSAGES, - deny: Permissions::empty(), - kind: PermissionOverwriteType::Role(court_role.id), - }]) - }) - .await - .wrap_err("create channel")?; + let channels = guild.channels(http).await.wrap_err("fetching channels")?; + + let channel_id = match channels.values().find(|c| c.name() == room_name) { + Some(channel) => { + if channel.parent_id != Some(category_id) { + return Ok(Err(Response::Simple(format!( + "de channel {room_name} isch i de falsche kategorie, man eh" + )))); + } + channel.id + } + None => { + guild + .create_channel(http, |channel| { + channel + .name(room_name) + .category(category_id) + .permissions(vec![PermissionOverwrite { + allow: Permissions::SEND_MESSAGES, + deny: Permissions::empty(), + kind: PermissionOverwriteType::Role(role_id), + }]) + }) + .await + .wrap_err("create channel")? + .id + } + }; let room = CourtRoom { - channel_id: channel.id.to_string(), + channel_id: channel_id.to_string(), ongoing_lawsuit: false, - role_id: court_role.id.to_string(), + role_id: role_id.to_string(), }; mongo_client - .add_court_room(&guild_id.to_string(), room) + .add_court_room(&guild_id.to_string(), &room) .await .wrap_err("add court room to database")?; - info!(guild_id = %guild_id, channel_id = %channel.id, "Created new court room"); + info!(guild_id = %guild_id, channel_id = %channel_id, "Created new court room"); - Ok(()) + Ok(Ok(room)) } diff --git a/src/model.rs b/src/model.rs index a2b3b7e..d39f50f 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,5 +1,6 @@ use color_eyre::Result; use mongodb::{ + bson, bson::doc, options::{ClientOptions, Credential}, Client, Collection, Database, @@ -98,12 +99,12 @@ impl Mongo { Ok(()) } - pub async fn add_court_room(&self, guild_id: &str, room: CourtRoom) -> Result<()> { + pub async fn add_court_room(&self, guild_id: &str, room: &CourtRoom) -> Result<()> { let _ = self.find_or_insert_state(guild_id).await?; let coll = self.state_coll(); coll.update_one( doc! {"guild_id": &guild_id }, - doc! {"$push": { "court_rooms": &serde_json::to_string(&room).unwrap() }}, + doc! {"$push": { "court_rooms": bson::to_bson(room).wrap_err("invalid bson for room")? }}, None, ) .await