diff --git a/Cargo.lock b/Cargo.lock index df41718..6fcab73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -204,6 +204,7 @@ dependencies = [ "mongodb", "nougat", "serde", + "serde_json", "serenity", "tokio", "tracing", diff --git a/Cargo.toml b/Cargo.toml index 090ca94..13fdd38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ 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" [dependencies.serenity] version = "0.11.2" diff --git a/src/handler.rs b/src/handler.rs index 98ba3c1..87e883b 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -83,7 +83,7 @@ pub struct Handler { pub mongo: Mongo, } -enum Response { +pub enum Response { Simple(String), } @@ -176,7 +176,7 @@ async fn lawsuit_command_handler( let subcommand = options.get(0).wrap_err("needs subcommand")?; let options = &subcommand.options; - let guild_id = command.guild_id.wrap_err("guild_id not found")?.to_string(); + let guild_id = command.guild_id.wrap_err("guild_id not found")?; match subcommand.name.as_str() { "create" => { @@ -198,14 +198,14 @@ async fn lawsuit_command_handler( court_room: None, }; - lawsuit - .initialize(&guild_id, mongo_client) + let response = lawsuit + .initialize(&ctx.http, guild_id, mongo_client) .await .wrap_err("initialize lawsuit")?; info!(?lawsuit, "Created lawsuit"); - Ok(Response::Simple("hani erstellt, keis problem".to_owned())) + Ok(response) } "set_category" => { let channel = ChannelOption::get(options.get(0))?; @@ -219,7 +219,7 @@ async fn lawsuit_command_handler( Some(category) => { let id = category.id; mongo_client - .set_court_category(&guild_id, &id.to_string()) + .set_court_category(&guild_id.to_string(), &id.to_string()) .await?; } None => return Ok(Response::Simple("Das ist keine Kategorie!".to_owned())), diff --git a/src/lawsuit.rs b/src/lawsuit.rs index c99dd98..4dcc263 100644 --- a/src/lawsuit.rs +++ b/src/lawsuit.rs @@ -1,8 +1,19 @@ +use std::str::FromStr; + use color_eyre::Result; use serde::{Deserialize, Serialize}; -use serenity::model::id::{ChannelId, UserId}; +use serenity::{ + http::Http, + model::{ + channel::PermissionOverwriteType, + id::{ChannelId, UserId}, + prelude::{GuildId, PermissionOverwrite}, + Permissions, + }, +}; +use tracing::info; -use crate::Mongo; +use crate::{handler::Response, model::CourtRoom, Mongo, WrapErr}; #[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub enum LawsuitState { @@ -23,9 +34,92 @@ pub struct Lawsuit { } impl Lawsuit { - pub async fn initialize(&mut self, guild_id: &str, mongo_client: &Mongo) -> Result<()> { - let _state = mongo_client.find_or_insert_state(&guild_id).await?; + pub async fn initialize( + &mut self, + http: &Http, + guild_id: GuildId, + mongo_client: &Mongo, + ) -> Result { + let state = mongo_client + .find_or_insert_state(&guild_id.to_string()) + .await?; - Ok(()) + let free_room = state.court_rooms.iter().find(|r| !r.ongoing_lawsuit); + + match (free_room, &state.court_category) { + (Some(_room), _) => Ok(Response::Simple("a free room? rip".to_owned())), + (None, Some(category)) => { + // create room + + create_room( + http, + guild_id, + state.court_rooms.len(), + ChannelId::from_str(category).wrap_err("invalid channel_id stored")?, + mongo_client, + ) + .await + .wrap_err("create new room")?; + + Ok(Response::Simple("no free room? rip".to_owned())) + } + (None, None) => Ok(Response::Simple( + "Zuerst eine Kategorie für die Gerichtsräume festlegen mit `/lawsuit set_category`" + .to_owned(), + )), + } } } + +async fn create_room( + http: &Http, + guild_id: GuildId, + room_len: usize, + category_id: ChannelId, + mongo_client: &Mongo, +) -> Result<()> { + let room_number = room_len + 1; + let room_name = format!("gerichtsraum-{room_number}"); + let role_name = format!("Gerichtsprozess {room_number}"); + + let guild = guild_id + .to_partial_guild(http) + .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 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 room = CourtRoom { + channel_id: channel.id.to_string(), + ongoing_lawsuit: false, + role_id: court_role.id.to_string(), + }; + + mongo_client + .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"); + + Ok(()) +} diff --git a/src/model.rs b/src/model.rs index 2b97cd5..a2b3b7e 100644 --- a/src/model.rs +++ b/src/model.rs @@ -21,6 +21,7 @@ pub struct State { pub struct CourtRoom { pub channel_id: String, pub ongoing_lawsuit: bool, + pub role_id: String, } pub struct Mongo { @@ -97,6 +98,19 @@ impl Mongo { Ok(()) } + 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() }}, + None, + ) + .await + .wrap_err("push court room")?; + Ok(()) + } + fn state_coll(&self) -> Collection { self.db.collection("state") }