mirror of
https://github.com/Noratrieb/discord-court-bot.git
synced 2026-01-17 03:15:01 +01:00
commit
e851bd7449
7 changed files with 632 additions and 655 deletions
147
Cargo.lock
generated
147
Cargo.lock
generated
|
|
@ -64,6 +64,17 @@ dependencies = [
|
||||||
"webpki-roots",
|
"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]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -164,6 +175,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"serde",
|
||||||
"time 0.1.44",
|
"time 0.1.44",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
@ -202,13 +214,14 @@ dependencies = [
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"mongodb",
|
"mongodb",
|
||||||
"nougat",
|
"poise",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serenity",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"tracing-error",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
"tracing-tree",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -239,14 +252,38 @@ dependencies = [
|
||||||
"typenum",
|
"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]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.13.4"
|
version = "0.13.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
|
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core 0.13.4",
|
||||||
"darling_macro",
|
"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]]
|
[[package]]
|
||||||
|
|
@ -263,13 +300,24 @@ dependencies = [
|
||||||
"syn",
|
"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]]
|
[[package]]
|
||||||
name = "darling_macro"
|
name = "darling_macro"
|
||||||
version = "0.13.4"
|
version = "0.13.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
|
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core 0.13.4",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
@ -748,22 +796,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"
|
||||||
|
|
@ -883,27 +915,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"
|
||||||
|
|
@ -1005,12 +1016,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"
|
||||||
|
|
@ -1038,6 +1043,36 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
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]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
|
|
@ -1368,7 +1403,7 @@ version = "1.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
|
checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling 0.13.4",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
|
|
@ -1386,6 +1421,7 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bytes",
|
"bytes",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"chrono",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"flate2",
|
"flate2",
|
||||||
"futures",
|
"futures",
|
||||||
|
|
@ -1720,6 +1756,19 @@ dependencies = [
|
||||||
"tracing-log",
|
"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]]
|
[[package]]
|
||||||
name = "trust-dns-proto"
|
name = "trust-dns-proto"
|
||||||
version = "0.21.2"
|
version = "0.21.2"
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,7 @@ tokio = { version = "1.19.2", features = ["full"] }
|
||||||
tracing = "0.1.35"
|
tracing = "0.1.35"
|
||||||
tracing-subscriber = { version = "0.3.11", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.11", features = ["env-filter"] }
|
||||||
serde = { version = "1.0.137", features = ["derive"] }
|
serde = { version = "1.0.137", features = ["derive"] }
|
||||||
nougat = "0.1.0"
|
|
||||||
serde_json = "1.0.81"
|
serde_json = "1.0.81"
|
||||||
|
poise = "0.2.2"
|
||||||
[dependencies.serenity]
|
tracing-tree = "0.2.1"
|
||||||
version = "0.11.2"
|
tracing-error = "0.2.0"
|
||||||
default-features = false
|
|
||||||
features = ["builder", "cache", "client", "gateway", "collector", "http", "rustls_backend", "tokio", "typemap_rev", "utils"]
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ a very funny discord bot
|
||||||
.env
|
.env
|
||||||
```
|
```
|
||||||
DISCORD_TOKEN=token
|
DISCORD_TOKEN=token
|
||||||
APPLICATION_ID=uwu
|
|
||||||
RUST_LOG=DEBUG
|
RUST_LOG=DEBUG
|
||||||
MONGO_URI=mongodb://localhost:27017
|
MONGO_URI=mongodb://localhost:27017
|
||||||
DB_NAME=court_bot
|
DB_NAME=court_bot
|
||||||
|
|
@ -13,6 +12,7 @@ MONGO_INITDB_ROOT_USERNAME=root
|
||||||
MONGO_INITDB_ROOT_PASSWORD=uwu
|
MONGO_INITDB_ROOT_PASSWORD=uwu
|
||||||
DEV=
|
DEV=
|
||||||
# SET_GLOBAL=
|
# SET_GLOBAL=
|
||||||
|
PRETTY=
|
||||||
```
|
```
|
||||||
|
|
||||||
run mongodb
|
run mongodb
|
||||||
|
|
|
||||||
697
src/handler.rs
697
src/handler.rs
|
|
@ -1,240 +1,50 @@
|
||||||
use color_eyre::eyre::{eyre, ContextCompat};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
|
|
||||||
|
use color_eyre::{eyre::ContextCompat, Result};
|
||||||
use mongodb::bson::Uuid;
|
use mongodb::bson::Uuid;
|
||||||
use serenity::{
|
use poise::{serenity::model::prelude::*, serenity_prelude as serenity, Event};
|
||||||
async_trait,
|
|
||||||
builder::CreateApplicationCommands,
|
|
||||||
model::{
|
|
||||||
interactions::application_command::ApplicationCommandOptionType,
|
|
||||||
prelude::{application_command::*, *},
|
|
||||||
},
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
lawsuit::{Lawsuit, LawsuitCtx},
|
lawsuit::{Lawsuit, LawsuitCtx},
|
||||||
model::SnowflakeId,
|
model::SnowflakeId,
|
||||||
Mongo, WrapErr,
|
Context, 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("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)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Handler {
|
pub struct Handler {
|
||||||
pub dev_guild_id: Option<GuildId>,
|
pub dev_guild_id: Option<GuildId>,
|
||||||
pub set_global_commands: bool,
|
pub set_global_commands: bool,
|
||||||
pub mongo: Mongo,
|
pub mongo: Mongo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for Handler {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str("HandlerData")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum Response {
|
pub enum Response {
|
||||||
EphemeralStr(&'static str),
|
EphemeralStr(&'static str),
|
||||||
Ephemeral(String),
|
Ephemeral(String),
|
||||||
NoPermissions,
|
NoPermissions,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl Display for Response {
|
||||||
impl EventHandler for Handler {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
async fn guild_member_addition(&self, ctx: Context, new_member: Member) {
|
match self {
|
||||||
if let Err(err) = self.handle_guild_member_join(ctx, new_member).await {
|
Self::EphemeralStr(str) => f.write_str(str),
|
||||||
error!(?err, "An error occurred in guild_member_addition handler");
|
Self::Ephemeral(str) => f.write_str(str),
|
||||||
}
|
Self::NoPermissions => f.write_str("du häsch kei recht für da!"),
|
||||||
}
|
|
||||||
|
|
||||||
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"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|
||||||
"prison" => prison_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: &serenity::Context,
|
||||||
mut member: Member,
|
member: &Member,
|
||||||
) -> color_eyre::Result<()> {
|
) -> Result<()> {
|
||||||
let guild_id = member.guild_id;
|
let guild_id = member.guild_id;
|
||||||
let user_id = member.user.id;
|
let user_id = member.user.id;
|
||||||
let state = self.mongo.find_or_insert_state(guild_id.into()).await?;
|
let state = self.mongo.find_or_insert_state(guild_id.into()).await?;
|
||||||
|
|
@ -251,6 +61,7 @@ impl Handler {
|
||||||
info!("New member was in prison, giving them the prison role");
|
info!("New member was in prison, giving them the prison role");
|
||||||
|
|
||||||
member
|
member
|
||||||
|
.clone()
|
||||||
.add_role(&ctx.http, role_id)
|
.add_role(&ctx.http, role_id)
|
||||||
.await
|
.await
|
||||||
.wrap_err("add role to member in prison")?;
|
.wrap_err("add role to member in prison")?;
|
||||||
|
|
@ -259,82 +70,90 @@ impl Handler {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn send_response(
|
pub mod lawsuit {
|
||||||
&self,
|
use color_eyre::eyre::eyre;
|
||||||
ctx: Context,
|
|
||||||
command: ApplicationCommandInteraction,
|
use super::*;
|
||||||
response: Response,
|
|
||||||
) -> color_eyre::Result<()> {
|
#[poise::command(
|
||||||
command
|
slash_command,
|
||||||
.create_interaction_response(&ctx.http, |res| match response {
|
guild_only,
|
||||||
Response::EphemeralStr(content) => res
|
subcommands("create", "set_category", "close", "clear")
|
||||||
.kind(InteractionResponseType::ChannelMessageWithSource)
|
)]
|
||||||
.interaction_response_data(|message| {
|
pub async fn lawsuit(_: Context<'_>) -> Result<()> {
|
||||||
message
|
unreachable!()
|
||||||
.content(content)
|
}
|
||||||
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
|
|
||||||
}),
|
/// Einen neuen Gerichtsprozess erstellen
|
||||||
Response::Ephemeral(content) => res
|
#[poise::command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")]
|
||||||
.kind(InteractionResponseType::ChannelMessageWithSource)
|
async fn create(
|
||||||
.interaction_response_data(|message| {
|
ctx: Context<'_>,
|
||||||
message
|
#[description = "Der Kläger"] plaintiff: User,
|
||||||
.content(content)
|
#[description = "Der Angeklagte"] accused: User,
|
||||||
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
|
#[description = "Der Richter"] judge: User,
|
||||||
}),
|
#[description = "Der Grund für die Klage"] reason: String,
|
||||||
Response::NoPermissions => res
|
#[description = "Der Anwalt des Klägers"] plaintiff_lawyer: Option<User>,
|
||||||
.kind(InteractionResponseType::ChannelMessageWithSource)
|
#[description = "Der Anwalt des Angeklagten"] accused_lawyer: Option<User>,
|
||||||
.interaction_response_data(|message| {
|
) -> Result<()> {
|
||||||
message
|
lawsuit_create_impl(
|
||||||
.content("du häsch kei recht für da!")
|
ctx,
|
||||||
.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
|
plaintiff,
|
||||||
}),
|
accused,
|
||||||
})
|
judge,
|
||||||
|
reason,
|
||||||
|
plaintiff_lawyer,
|
||||||
|
accused_lawyer,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.wrap_err("sending response")?;
|
.wrap_err("lawsuit_create")
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn lawsuit_command_handler(
|
/// Die Rolle für Gefangene setzen
|
||||||
command: &ApplicationCommandInteraction,
|
#[poise::command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")]
|
||||||
ctx: &Context,
|
async fn set_category(
|
||||||
mongo_client: &Mongo,
|
ctx: Context<'_>,
|
||||||
) -> color_eyre::Result<Response> {
|
#[description = "Die Kategorie"] category: Channel,
|
||||||
let options = &command.data.options;
|
) -> Result<()> {
|
||||||
let subcommand = options.get(0).wrap_err("needs subcommand")?;
|
lawsuit_set_category_impl(ctx, category)
|
||||||
|
.await
|
||||||
let options = &subcommand.options;
|
.wrap_err("lawsuit_set_category")
|
||||||
let guild_id = command.guild_id.wrap_err("guild_id not found")?;
|
|
||||||
|
|
||||||
let member = command
|
|
||||||
.member
|
|
||||||
.as_ref()
|
|
||||||
.wrap_err("command must be used my member")?;
|
|
||||||
let permissions = member.permissions.wrap_err("must be in interaction")?;
|
|
||||||
|
|
||||||
match subcommand.name.as_str() {
|
|
||||||
"create" => {
|
|
||||||
if !permissions.contains(Permissions::MANAGE_GUILD) {
|
|
||||||
return Ok(Response::NoPermissions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let plaintiff = UserOption::get(options.get(0)).wrap_err("plaintiff")?;
|
/// Den Gerichtsprozess abschliessen und ein Urteil fällen
|
||||||
let accused = UserOption::get(options.get(1)).wrap_err("accused")?;
|
#[poise::command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")]
|
||||||
let judge = UserOption::get(options.get(2)).wrap_err("judge")?;
|
async fn close(ctx: Context<'_>, #[description = "Das Urteil"] verdict: String) -> Result<()> {
|
||||||
let reason = StringOption::get(options.get(3)).wrap_err("reason")?;
|
lawsuit_close_impl(ctx, verdict)
|
||||||
let plaintiff_layer =
|
.await
|
||||||
UserOption::get_optional(options.get(4)).wrap_err("plaintiff_layer")?;
|
.wrap_err("lawsuit_close")
|
||||||
let accused_layer =
|
}
|
||||||
UserOption::get_optional(options.get(5)).wrap_err("accused_layer")?;
|
|
||||||
|
/// Alle Rechtsprozessdaten löschen
|
||||||
|
#[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: Context<'_>,
|
||||||
|
plaintiff: User,
|
||||||
|
accused: User,
|
||||||
|
judge: User,
|
||||||
|
reason: String,
|
||||||
|
plaintiff_lawyer: Option<User>,
|
||||||
|
accused_lawyer: Option<User>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let guild_id = ctx.guild_id().wrap_err("guild_id not found")?;
|
||||||
|
|
||||||
let lawsuit = Lawsuit {
|
let lawsuit = Lawsuit {
|
||||||
id: Uuid::new(),
|
id: Uuid::new(),
|
||||||
plaintiff: plaintiff.0.id.into(),
|
plaintiff: plaintiff.id.into(),
|
||||||
accused: accused.0.id.into(),
|
accused: accused.id.into(),
|
||||||
judge: judge.0.id.into(),
|
judge: judge.id.into(),
|
||||||
plaintiff_lawyer: plaintiff_layer.map(|user| user.0.id.into()),
|
plaintiff_lawyer: plaintiff_lawyer.map(|user| user.id.into()),
|
||||||
accused_lawyer: accused_layer.map(|user| user.0.id.into()),
|
accused_lawyer: accused_lawyer.map(|user| user.id.into()),
|
||||||
reason: reason.to_owned(),
|
reason: reason.to_owned(),
|
||||||
verdict: None,
|
verdict: None,
|
||||||
court_room: SnowflakeId(0),
|
court_room: SnowflakeId(0),
|
||||||
|
|
@ -342,8 +161,8 @@ async fn lawsuit_command_handler(
|
||||||
|
|
||||||
let lawsuit_ctx = LawsuitCtx {
|
let lawsuit_ctx = LawsuitCtx {
|
||||||
lawsuit,
|
lawsuit,
|
||||||
mongo_client: mongo_client.clone(),
|
mongo_client: ctx.data().mongo.clone(),
|
||||||
http: ctx.http.clone(),
|
http: ctx.discord().http.clone(),
|
||||||
guild_id,
|
guild_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -352,38 +171,53 @@ async fn lawsuit_command_handler(
|
||||||
.await
|
.await
|
||||||
.wrap_err("initialize lawsuit")?;
|
.wrap_err("initialize lawsuit")?;
|
||||||
|
|
||||||
Ok(response)
|
ctx.say(response.to_string()).await?;
|
||||||
}
|
|
||||||
"set_category" => {
|
Ok(())
|
||||||
if !permissions.contains(Permissions::MANAGE_GUILD) {
|
|
||||||
return Ok(Response::NoPermissions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let channel = ChannelOption::get(options.get(0))?;
|
#[tracing::instrument(skip(ctx))]
|
||||||
|
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
|
match category.category() {
|
||||||
.id
|
|
||||||
.to_channel(&ctx.http)
|
|
||||||
.await
|
|
||||||
.wrap_err("fetch category for set_category")?;
|
|
||||||
match channel.category() {
|
|
||||||
Some(category) => {
|
Some(category) => {
|
||||||
let id = category.id;
|
let id = category.id;
|
||||||
mongo_client
|
ctx.data()
|
||||||
|
.mongo
|
||||||
.set_court_category(guild_id.into(), id.into())
|
.set_court_category(guild_id.into(), id.into())
|
||||||
.await?;
|
.await?;
|
||||||
|
ctx.say("isch gsetzt").await?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
ctx.say("Das ist keine Kategorie!").await?;
|
||||||
}
|
}
|
||||||
None => return Ok(Response::EphemeralStr("Das ist keine Kategorie!")),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Response::EphemeralStr("isch gsetzt"))
|
Ok(())
|
||||||
}
|
}
|
||||||
"close" => {
|
|
||||||
let permission_override = permissions.contains(Permissions::MANAGE_GUILD);
|
|
||||||
|
|
||||||
let verdict = StringOption::get(options.get(0))?;
|
#[tracing::instrument(skip(ctx))]
|
||||||
|
async fn lawsuit_close_impl(ctx: Context<'_>, verdict: String) -> Result<()> {
|
||||||
|
let guild_id = ctx.guild_id().wrap_err("guild_id not found")?;
|
||||||
|
|
||||||
let room_id = command.channel_id;
|
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
|
||||||
|
.map(|p| p.contains(Permissions::MANAGE_GUILD))
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
let room_id = ctx.channel_id();
|
||||||
|
let mongo_client = &ctx.data().mongo;
|
||||||
|
|
||||||
let state = mongo_client
|
let state = mongo_client
|
||||||
.find_or_insert_state(guild_id.into())
|
.find_or_insert_state(guild_id.into())
|
||||||
|
|
@ -398,9 +232,8 @@ async fn lawsuit_command_handler(
|
||||||
let lawsuit = match lawsuit {
|
let lawsuit = match lawsuit {
|
||||||
Some(lawsuit) => lawsuit.clone(),
|
Some(lawsuit) => lawsuit.clone(),
|
||||||
None => {
|
None => {
|
||||||
return Ok(Response::EphemeralStr(
|
ctx.say("i dem channel lauft kein aktive prozess!").await?;
|
||||||
"i dem channel lauft kein aktive prozess!",
|
return Ok(());
|
||||||
))
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -411,16 +244,15 @@ async fn lawsuit_command_handler(
|
||||||
let room = match room {
|
let room = match room {
|
||||||
Some(room) => room.clone(),
|
Some(room) => room.clone(),
|
||||||
None => {
|
None => {
|
||||||
return Ok(Response::EphemeralStr(
|
ctx.say("i dem channel lauft kein aktive prozess!").await?;
|
||||||
"i dem channel lauft kein aktive prozess!",
|
return Ok(());
|
||||||
))
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut lawsuit_ctx = LawsuitCtx {
|
let mut lawsuit_ctx = LawsuitCtx {
|
||||||
lawsuit,
|
lawsuit,
|
||||||
mongo_client: mongo_client.clone(),
|
mongo_client: mongo_client.clone(),
|
||||||
http: ctx.http.clone(),
|
http: ctx.discord().http.clone(),
|
||||||
guild_id,
|
guild_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -434,60 +266,86 @@ async fn lawsuit_command_handler(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Err(response) = response {
|
if let Err(response) = response {
|
||||||
return Ok(response);
|
ctx.say(response.to_string()).await?;
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Response::EphemeralStr("ich han en dir abschlosse"))
|
ctx.say("ich han en dir abschlosse").await?;
|
||||||
}
|
|
||||||
"clear" => {
|
Ok(())
|
||||||
if !permissions.contains(Permissions::MANAGE_GUILD) {
|
|
||||||
return Ok(Response::NoPermissions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mongo_client.delete_guild(guild_id.into()).await?;
|
#[tracing::instrument(skip(ctx))]
|
||||||
Ok(Response::EphemeralStr("alles weg"))
|
async fn lawsuit_clear_impl(ctx: Context<'_>) -> Result<()> {
|
||||||
}
|
let guild_id = ctx.guild_id().wrap_err("guild_id not found")?;
|
||||||
_ => Err(eyre!("Unknown subcommand")),
|
|
||||||
|
ctx.data().mongo.delete_guild(guild_id.into()).await?;
|
||||||
|
ctx.say("alles weg").await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn prison_command_handler(
|
pub mod prison {
|
||||||
command: &ApplicationCommandInteraction,
|
use super::*;
|
||||||
ctx: &Context,
|
#[poise::command(
|
||||||
mongo_client: &Mongo,
|
slash_command,
|
||||||
) -> color_eyre::Result<Response> {
|
guild_only,
|
||||||
let options = &command.data.options;
|
subcommands("set_role", "arrest", "release")
|
||||||
let subcommand = options.get(0).wrap_err("needs subcommand")?;
|
)]
|
||||||
|
pub async fn prison(_: Context<'_>) -> Result<()> {
|
||||||
let options = &subcommand.options;
|
unreachable!()
|
||||||
let guild_id = command.guild_id.wrap_err("guild_id not found")?;
|
|
||||||
|
|
||||||
let member = command
|
|
||||||
.member
|
|
||||||
.as_ref()
|
|
||||||
.wrap_err("command must be used my member")?;
|
|
||||||
let permissions = member.permissions.wrap_err("must be in interaction")?;
|
|
||||||
|
|
||||||
match subcommand.name.as_str() {
|
|
||||||
"set_role" => {
|
|
||||||
if !permissions.contains(Permissions::MANAGE_GUILD) {
|
|
||||||
return Ok(Response::NoPermissions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let role = RoleOption::get(options.get(0))?;
|
/// Die Rolle für Gefangene setzen
|
||||||
|
#[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")
|
||||||
|
}
|
||||||
|
|
||||||
mongo_client
|
/// Jemanden einsperren
|
||||||
.set_prison_role(guild_id.into(), role.id.into())
|
#[poise::command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")]
|
||||||
|
async fn arrest(
|
||||||
|
ctx: 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, guild_only, required_permissions = "MANAGE_GUILD")]
|
||||||
|
async fn release(
|
||||||
|
ctx: Context<'_>,
|
||||||
|
#[description = "Die Person zum freilassen"] user: User,
|
||||||
|
) -> Result<()> {
|
||||||
|
prison_release_impl(ctx, user)
|
||||||
|
.await
|
||||||
|
.wrap_err("prison_release")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(ctx))]
|
||||||
|
async fn prison_set_role_impl(ctx: Context<'_>, role: Role) -> Result<()> {
|
||||||
|
ctx.data()
|
||||||
|
.mongo
|
||||||
|
.set_prison_role(
|
||||||
|
ctx.guild_id().wrap_err("guild_id not found")?.into(),
|
||||||
|
role.id.into(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(Response::EphemeralStr("isch gsetzt"))
|
ctx.say("isch gsetzt").await.wrap_err("reply")?;
|
||||||
}
|
|
||||||
"arrest" => {
|
Ok(())
|
||||||
if !permissions.contains(Permissions::MANAGE_GUILD) {
|
|
||||||
return Ok(Response::NoPermissions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (user, _) = UserOption::get(options.get(0))?;
|
#[tracing::instrument(skip(ctx))]
|
||||||
|
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;
|
||||||
|
|
||||||
let state = mongo_client.find_or_insert_state(guild_id.into()).await?;
|
let state = mongo_client.find_or_insert_state(guild_id.into()).await?;
|
||||||
let role = state.prison_role;
|
let role = state.prison_role;
|
||||||
|
|
@ -495,9 +353,9 @@ async fn prison_command_handler(
|
||||||
let role = match role {
|
let role = match role {
|
||||||
Some(role) => role,
|
Some(role) => role,
|
||||||
None => {
|
None => {
|
||||||
return Ok(Response::EphemeralStr(
|
ctx.say("du mosch zerst e rolle setze mit /prison set_role")
|
||||||
"du mosch zerst e rolle setze mit /prison set_role",
|
.await?;
|
||||||
))
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -506,21 +364,23 @@ async fn prison_command_handler(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
guild_id
|
guild_id
|
||||||
.member(&ctx.http, user.id)
|
.member(http, user.id)
|
||||||
.await
|
.await
|
||||||
.wrap_err("fetching guild member")?
|
.wrap_err("fetching guild member")?
|
||||||
.add_role(&ctx.http, role)
|
.add_role(http, role)
|
||||||
.await
|
.await
|
||||||
.wrap_err("add guild member role")?;
|
.wrap_err("add guild member role")?;
|
||||||
|
|
||||||
Ok(Response::EphemeralStr("hani igsperrt"))
|
ctx.say("isch igsperrt").await?;
|
||||||
}
|
|
||||||
"release" => {
|
Ok(())
|
||||||
if !permissions.contains(Permissions::MANAGE_GUILD) {
|
|
||||||
return Ok(Response::NoPermissions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (user, _) = UserOption::get(options.get(0))?;
|
#[tracing::instrument(skip(ctx))]
|
||||||
|
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;
|
||||||
|
|
||||||
let state = mongo_client.find_or_insert_state(guild_id.into()).await?;
|
let state = mongo_client.find_or_insert_state(guild_id.into()).await?;
|
||||||
let role = state.prison_role;
|
let role = state.prison_role;
|
||||||
|
|
@ -528,9 +388,9 @@ async fn prison_command_handler(
|
||||||
let role = match role {
|
let role = match role {
|
||||||
Some(role) => role,
|
Some(role) => role,
|
||||||
None => {
|
None => {
|
||||||
return Ok(Response::EphemeralStr(
|
ctx.say("du mosch zerst e rolle setze mit /prison set_role")
|
||||||
"du mosch zerst e rolle setze mit /prison set_role",
|
.await?;
|
||||||
))
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -539,116 +399,37 @@ async fn prison_command_handler(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
guild_id
|
guild_id
|
||||||
.member(&ctx.http, user.id)
|
.member(http, user.id)
|
||||||
.await
|
.await
|
||||||
.wrap_err("fetching guild member")?
|
.wrap_err("fetching guild member")?
|
||||||
.remove_role(&ctx.http, role)
|
.remove_role(http, role)
|
||||||
.await
|
.await
|
||||||
.wrap_err("remove guild member role")?;
|
.wrap_err("remove guild member role")?;
|
||||||
|
|
||||||
Ok(Response::EphemeralStr("d'freiheit wartet"))
|
ctx.say("d'freiheit wartet").await?;
|
||||||
}
|
|
||||||
_ => Err(eyre!("Unknown subcommand")),
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[nougat::gat]
|
pub async fn listener(
|
||||||
trait GetOption {
|
ctx: &serenity::Context,
|
||||||
type Get<'a>;
|
event: &Event<'_>,
|
||||||
|
_: poise::FrameworkContext<'_, Handler, Report>,
|
||||||
fn extract(
|
data: &Handler,
|
||||||
command: &ApplicationCommandInteractionDataOptionValue,
|
) -> Result<()> {
|
||||||
) -> color_eyre::Result<Self::Get<'_>>;
|
#[allow(clippy::single_match)]
|
||||||
|
match event {
|
||||||
fn get(
|
Event::GuildMemberAddition { new_member } => {
|
||||||
option: Option<&ApplicationCommandInteractionDataOption>,
|
if let Err(err) = data.handle_guild_member_join(ctx, new_member).await {
|
||||||
) -> color_eyre::Result<Self::Get<'_>> {
|
error!(?err, "An error occurred in guild_member_addition handler");
|
||||||
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<Option<Self::Get<'_>>> {
|
|
||||||
if let Some(option) = option {
|
|
||||||
if let Some(command) = option.resolved.as_ref() {
|
|
||||||
Self::extract(command).map(Some)
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UserOption;
|
pub async fn error_handler(error: poise::FrameworkError<'_, Handler, Report>) {
|
||||||
|
error!(?error, "Error during command execution");
|
||||||
#[nougat::gat]
|
|
||||||
impl GetOption for UserOption {
|
|
||||||
type Get<'a> = (&'a User, &'a Option<PartialMember>);
|
|
||||||
|
|
||||||
fn extract(
|
|
||||||
command: &ApplicationCommandInteractionDataOptionValue,
|
|
||||||
) -> crate::Result<Self::Get<'_>> {
|
|
||||||
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<Self::Get<'_>> {
|
|
||||||
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<Self::Get<'_>> {
|
|
||||||
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<Self::Get<'_>> {
|
|
||||||
if let ApplicationCommandInteractionDataOptionValue::Role(role) = command {
|
|
||||||
Ok(role)
|
|
||||||
} else {
|
|
||||||
Err(eyre!("Expected string!"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,11 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use mongodb::bson::{doc, Uuid};
|
use mongodb::bson::{doc, Uuid};
|
||||||
use serde::{Deserialize, Serialize};
|
use poise::{
|
||||||
use serenity::{
|
serenity::model::prelude::*,
|
||||||
builder::CreateMessage,
|
serenity_prelude::{CreateMessage, Http},
|
||||||
http::Http,
|
|
||||||
model::{channel::PermissionOverwriteType, prelude::*, Permissions},
|
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
|
||||||
135
src/main.rs
135
src/main.rs
|
|
@ -6,22 +6,27 @@ mod model;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use color_eyre::{eyre::WrapErr, Result};
|
use color_eyre::{eyre::WrapErr, Report, Result};
|
||||||
use serenity::{model::prelude::*, prelude::*};
|
use poise::{
|
||||||
use tracing::info;
|
serenity_prelude as serenity,
|
||||||
use tracing_subscriber::EnvFilter;
|
serenity_prelude::{Activity, GatewayIntents, GuildId},
|
||||||
|
};
|
||||||
|
use tracing::{error, info};
|
||||||
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry};
|
||||||
|
|
||||||
use crate::{handler::Handler, model::Mongo};
|
use crate::{handler::Handler, model::Mongo};
|
||||||
|
|
||||||
|
type Context<'a> = poise::Context<'a, Handler, Report>;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
color_eyre::install()?;
|
color_eyre::install()?;
|
||||||
|
|
||||||
let _ = dotenv::dotenv();
|
let _ = dotenv::dotenv();
|
||||||
|
|
||||||
tracing_subscriber::fmt()
|
let pretty = env::var("PRETTY").is_ok();
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
|
||||||
.init();
|
setup_tracing(pretty);
|
||||||
|
|
||||||
info!("Starting up...");
|
info!("Starting up...");
|
||||||
|
|
||||||
|
|
@ -51,15 +56,121 @@ async fn main() -> Result<()> {
|
||||||
|
|
||||||
let set_global_commands = env::var("SET_GLOBAL").is_ok();
|
let set_global_commands = env::var("SET_GLOBAL").is_ok();
|
||||||
|
|
||||||
let mut client = Client::builder(token, GatewayIntents::empty())
|
poise::Framework::build()
|
||||||
.event_handler(Handler {
|
.token(token)
|
||||||
|
.user_data_setup(move |ctx, ready, framework| {
|
||||||
|
Box::pin(async move {
|
||||||
|
let data = Handler {
|
||||||
dev_guild_id,
|
dev_guild_id,
|
||||||
set_global_commands,
|
set_global_commands,
|
||||||
mongo,
|
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
|
||||||
})
|
})
|
||||||
.intents(GatewayIntents::GUILD_MEMBERS)
|
.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::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 })
|
||||||
|
},
|
||||||
|
pre_command: |ctx| {
|
||||||
|
Box::pin(async move {
|
||||||
|
let channel_name = ctx
|
||||||
|
.channel_id()
|
||||||
|
.name(&ctx.discord())
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|| "<unknown>".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(GatewayIntents::non_privileged() | GatewayIntents::GUILD_MEMBERS)
|
||||||
|
.run()
|
||||||
.await
|
.await
|
||||||
.wrap_err("failed to create discord client")?;
|
.wrap_err("failed to create discord client")?;
|
||||||
|
Ok(())
|
||||||
client.start().await.wrap_err("running client")
|
}
|
||||||
|
|
||||||
|
/// Sag Karin hallo.
|
||||||
|
#[poise::command(slash_command)]
|
||||||
|
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())
|
||||||
|
.with(tracing_error::ErrorLayer::default());
|
||||||
|
|
||||||
|
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();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
48
src/model.rs
48
src/model.rs
|
|
@ -8,11 +8,11 @@ use color_eyre::Result;
|
||||||
use mongodb::{
|
use mongodb::{
|
||||||
bson,
|
bson,
|
||||||
bson::{doc, Bson, Uuid},
|
bson::{doc, Bson, Uuid},
|
||||||
options::{ClientOptions, Credential, UpdateOptions},
|
options::{ClientOptions, Credential, IndexOptions, UpdateOptions},
|
||||||
Client, Collection, Database,
|
Client, Collection, Database, IndexModel,
|
||||||
};
|
};
|
||||||
|
use poise::serenity::model::id::{ChannelId, GuildId, RoleId, UserId};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serenity::model::id::{ChannelId, GuildId, RoleId, UserId};
|
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use crate::{lawsuit::Lawsuit, WrapErr};
|
use crate::{lawsuit::Lawsuit, WrapErr};
|
||||||
|
|
@ -114,6 +114,7 @@ pub struct Mongo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mongo {
|
impl Mongo {
|
||||||
|
#[tracing::instrument(skip(password))]
|
||||||
pub async fn connect(
|
pub async fn connect(
|
||||||
uri: &str,
|
uri: &str,
|
||||||
db_name: &str,
|
db_name: &str,
|
||||||
|
|
@ -133,10 +134,38 @@ impl Mongo {
|
||||||
let client = Client::with_options(client_options).wrap_err("failed to create client")?;
|
let client = Client::with_options(client_options).wrap_err("failed to create client")?;
|
||||||
|
|
||||||
let db = client.database(db_name);
|
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))]
|
||||||
pub async fn find_or_insert_state(&self, guild_id: SnowflakeId) -> Result<State> {
|
pub async fn find_or_insert_state(&self, guild_id: SnowflakeId) -> Result<State> {
|
||||||
let coll = self.state_coll();
|
let coll = self.state_coll();
|
||||||
let state = coll
|
let state = coll
|
||||||
|
|
@ -155,6 +184,7 @@ impl Mongo {
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
pub async fn new_state(&self, guild_id: SnowflakeId) -> Result<State> {
|
pub async fn new_state(&self, guild_id: SnowflakeId) -> Result<State> {
|
||||||
let state = State {
|
let state = State {
|
||||||
guild_id,
|
guild_id,
|
||||||
|
|
@ -171,6 +201,7 @@ impl Mongo {
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
pub async fn set_court_category(
|
pub async fn set_court_category(
|
||||||
&self,
|
&self,
|
||||||
guild_id: SnowflakeId,
|
guild_id: SnowflakeId,
|
||||||
|
|
@ -188,6 +219,7 @@ impl Mongo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
pub async fn set_prison_role(
|
pub async fn set_prison_role(
|
||||||
&self,
|
&self,
|
||||||
guild_id: SnowflakeId,
|
guild_id: SnowflakeId,
|
||||||
|
|
@ -205,6 +237,7 @@ impl Mongo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
pub async fn add_court_room(&self, guild_id: SnowflakeId, room: &CourtRoom) -> Result<()> {
|
pub async fn add_court_room(&self, guild_id: SnowflakeId, room: &CourtRoom) -> Result<()> {
|
||||||
let _ = self.find_or_insert_state(guild_id).await?;
|
let _ = self.find_or_insert_state(guild_id).await?;
|
||||||
let coll = self.state_coll();
|
let coll = self.state_coll();
|
||||||
|
|
@ -218,6 +251,7 @@ impl Mongo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
pub async fn add_lawsuit(&self, guild_id: SnowflakeId, lawsuit: &Lawsuit) -> Result<()> {
|
pub async fn add_lawsuit(&self, guild_id: SnowflakeId, lawsuit: &Lawsuit) -> Result<()> {
|
||||||
let _ = self.find_or_insert_state(guild_id).await?;
|
let _ = self.find_or_insert_state(guild_id).await?;
|
||||||
let coll = self.state_coll();
|
let coll = self.state_coll();
|
||||||
|
|
@ -233,6 +267,7 @@ impl Mongo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self, value))]
|
||||||
pub async fn set_court_room(
|
pub async fn set_court_room(
|
||||||
&self,
|
&self,
|
||||||
guild_id: SnowflakeId,
|
guild_id: SnowflakeId,
|
||||||
|
|
@ -252,6 +287,7 @@ impl Mongo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self, value))]
|
||||||
pub async fn set_lawsuit(
|
pub async fn set_lawsuit(
|
||||||
&self,
|
&self,
|
||||||
guild_id: SnowflakeId,
|
guild_id: SnowflakeId,
|
||||||
|
|
@ -271,6 +307,7 @@ impl Mongo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
pub async fn delete_guild(&self, guild_id: SnowflakeId) -> Result<()> {
|
pub async fn delete_guild(&self, guild_id: SnowflakeId) -> Result<()> {
|
||||||
let coll = self.state_coll();
|
let coll = self.state_coll();
|
||||||
|
|
||||||
|
|
@ -280,6 +317,7 @@ impl Mongo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
pub async fn add_to_prison(&self, guild_id: SnowflakeId, user_id: SnowflakeId) -> Result<()> {
|
pub async fn add_to_prison(&self, guild_id: SnowflakeId, user_id: SnowflakeId) -> Result<()> {
|
||||||
let coll = self.prison_coll();
|
let coll = self.prison_coll();
|
||||||
|
|
||||||
|
|
@ -298,6 +336,7 @@ impl Mongo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
pub async fn remove_from_prison(
|
pub async fn remove_from_prison(
|
||||||
&self,
|
&self,
|
||||||
guild_id: SnowflakeId,
|
guild_id: SnowflakeId,
|
||||||
|
|
@ -312,6 +351,7 @@ impl Mongo {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
pub async fn find_prison_entry(
|
pub async fn find_prison_entry(
|
||||||
&self,
|
&self,
|
||||||
guild_id: SnowflakeId,
|
guild_id: SnowflakeId,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue