From f5acab74400ecc364e82cb2a44168a8e0cd70ab9 Mon Sep 17 00:00:00 2001 From: jude Date: Sun, 31 Jul 2022 14:56:38 +0100 Subject: [PATCH] Join sounds per-server --- .idea/dataSources.local.xml | 2 +- Cargo.lock | 128 +++++++++---------- Cargo.toml | 10 +- README.md | 2 +- migrations/20220730-expand-join-sounds.sql | 10 ++ src/cmds/settings.rs | 140 +++++++++++++++++++-- src/event_handlers.rs | 3 +- src/main.rs | 19 ++- src/models/join_sound.rs | 113 +++++++++++------ 9 files changed, 300 insertions(+), 127 deletions(-) create mode 100644 migrations/20220730-expand-join-sounds.sql diff --git a/.idea/dataSources.local.xml b/.idea/dataSources.local.xml index e813ad3..3a1e9e9 100644 --- a/.idea/dataSources.local.xml +++ b/.idea/dataSources.local.xml @@ -1,6 +1,6 @@ - + master_key diff --git a/Cargo.lock b/Cargo.lock index 65830f4..527c2e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,9 +190,9 @@ checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" [[package]] name = "bytemuck" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c53dfa917ec274df8ed3c572698f381a24eef2efba9492d797301b72b6db408a" +checksum = "a5377c8865e74a160d21f29c2d40669f53286db6eab59b88540cbb12ffc8b835" [[package]] name = "byteorder" @@ -202,9 +202,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "cc" @@ -291,9 +291,9 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" dependencies = [ "cfg-if", "crossbeam-utils", @@ -301,9 +301,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ "cfg-if", "once_cell", @@ -365,16 +365,6 @@ dependencies = [ "syn", ] -[[package]] -name = "dashmap" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" -dependencies = [ - "cfg-if", - "num_cpus", -] - [[package]] name = "dashmap" version = "5.3.4" @@ -470,9 +460,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.8.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" dependencies = [ "atty", "humantime", @@ -483,9 +473,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] @@ -502,9 +492,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.10.13" +version = "0.10.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ceeb589a3157cac0ab8cc585feb749bd2cea5cb55a6ee802ad72d9fd38303da" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" dependencies = [ "futures-core", "futures-sink", @@ -896,9 +886,9 @@ checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "js-sys" -version = "0.3.58" +version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" dependencies = [ "wasm-bindgen", ] @@ -920,9 +910,9 @@ checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "libm" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db" +checksum = "da83a57f3f5ba3680950aa3cbc806fc297bc0b289d42e8942ed528ace71b8145" [[package]] name = "lock_api" @@ -1420,9 +1410,9 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" dependencies = [ "unicode-ident", ] @@ -1468,9 +1458,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] @@ -1712,9 +1702,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.139" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" +checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" dependencies = [ "serde_derive", ] @@ -1731,9 +1721,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.139" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" +checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" dependencies = [ "proc-macro2", "quote", @@ -1776,9 +1766,9 @@ dependencies = [ [[package]] name = "serenity" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1a6cef5e72d4e5787c96413ec0a45f9317c59f0099e2ff2038b73cb352fefd" +checksum = "82fd5e7b5858ad96e99d440138f34f5b98e1b959ebcd3a1036203b30e78eb788" dependencies = [ "async-trait", "async-tungstenite", @@ -1787,7 +1777,7 @@ dependencies = [ "bytes", "cfg-if", "chrono", - "dashmap 5.3.4", + "dashmap", "flate2", "futures", "mime", @@ -1809,7 +1799,8 @@ dependencies = [ [[package]] name = "serenity-voice-model" version = "0.1.1" -source = "git+https://github.com/serenity-rs/serenity?branch=next#b6d6ce0de112112bbbe4ecdc49c8c8f521bedef1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be3aec8849ca2fde1e8a5dfbed96fbd68e9b5f4283fbe277d8694ce811d4952" dependencies = [ "bitflags", "enum_primitive", @@ -1900,14 +1891,15 @@ dependencies = [ [[package]] name = "songbird" -version = "0.2.2" -source = "git+https://github.com/serenity-rs/songbird?branch=next#49c33461029f5c3a22e12e3d251319237d73b4a4" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4c965f6625a2653e0733abfe217679562eb8c4787f000f4f13047541a444217" dependencies = [ "async-trait", "async-tungstenite", "audiopus", "byteorder", - "dashmap 5.3.4", + "dashmap", "derivative", "discortp", "flume", @@ -1932,9 +1924,9 @@ dependencies = [ [[package]] name = "soundfx-rs" -version = "1.5.0" +version = "1.5.1" dependencies = [ - "dashmap 4.0.2", + "dashmap", "dotenv", "env_logger", "lazy_static", @@ -2219,9 +2211,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57aec3cfa4c296db7255446efb4928a6be304b431a806216105542a67b6ca82e" +checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" dependencies = [ "autocfg 1.1.0", "bytes", @@ -2313,9 +2305,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" dependencies = [ "cfg-if", "log", @@ -2337,9 +2329,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" dependencies = [ "once_cell", "valuable", @@ -2368,9 +2360,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59" +checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b" dependencies = [ "ansi_term", "matchers", @@ -2551,9 +2543,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2561,13 +2553,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", "syn", @@ -2576,9 +2568,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.31" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" +checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad" dependencies = [ "cfg-if", "js-sys", @@ -2588,9 +2580,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2598,9 +2590,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" dependencies = [ "proc-macro2", "quote", @@ -2611,15 +2603,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" +checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" [[package]] name = "web-sys" -version = "0.3.58" +version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 2733d07..08e4b37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,22 +1,22 @@ [package] name = "soundfx-rs" -version = "1.5.0" +version = "1.5.1" authors = ["jellywx "] edition = "2018" [dependencies] -songbird = { git = "https://github.com/serenity-rs/songbird", branch = "next", features = ["builtin-queue"] } +songbird = { version = "0.3", features = ["builtin-queue"] } poise = "0.2" sqlx = { version = "0.5", default-features = false, features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal"] } dotenv = "0.15" tokio = { version = "1", features = ["fs", "process", "io-util"] } lazy_static = "1.4" reqwest = "0.11" -env_logger = "0.8" +env_logger = "0.9" regex = "1.4" log = "0.4" serde_json = "1.0" -dashmap = "4.0" +dashmap = "5.3" [patch."https://github.com/serenity-rs/serenity"] -serenity = { version = "0.11.4" } +serenity = { version = "0.11.5" } diff --git a/README.md b/README.md index b15a690..343992c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A bot for managing sound effects in Discord. ### Building -`sudo apt install gcc gcc-multilib cmake` +`sudo apt install gcc gcc-multilib cmake ffmpeg` Run the migrations in the `migrations` directory to set up the database. diff --git a/migrations/20220730-expand-join-sounds.sql b/migrations/20220730-expand-join-sounds.sql new file mode 100644 index 0000000..b86e2b1 --- /dev/null +++ b/migrations/20220730-expand-join-sounds.sql @@ -0,0 +1,10 @@ +CREATE TABLE join_sounds ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `user` BIGINT UNSIGNED NOT NULL, + `join_sound_id` INT UNSIGNED NOT NULL, + `guild` BIGINT UNSIGNED, + FOREIGN KEY (`join_sound_id`) REFERENCES sounds(id) ON DELETE CASCADE, + PRIMARY KEY (`id`) +); + +INSERT INTO join_sounds (`user`, `join_sound_id`) SELECT `user`, `join_sound_id` FROM `users` WHERE `join_sound_id` is not null; diff --git a/src/cmds/settings.rs b/src/cmds/settings.rs index c6efc0a..2b8afef 100644 --- a/src/cmds/settings.rs +++ b/src/cmds/settings.rs @@ -1,4 +1,7 @@ +use poise::serenity_prelude::{GuildId, User}; + use crate::{ + cmds::autocomplete_sound, models::{guild_data::CtxGuildData, join_sound::JoinSoundCtx, sound::SoundCtx}, Context, Error, }; @@ -31,18 +34,44 @@ pub async fn change_volume( Ok(()) } -/// Manage greet sounds on this server +/// Manage greet sounds #[poise::command(slash_command, rename = "greet", guild_only = true)] pub async fn greet_sound(_ctx: Context<'_>) -> Result<(), Error> { Ok(()) } -/// Set a join sound +/// Manage greet sounds in this server +#[poise::command(slash_command, rename = "server")] +pub async fn guild_greet_sound(_ctx: Context<'_>) -> Result<(), Error> { + Ok(()) +} + +/// Set a user's guild-specific join sound #[poise::command(slash_command, rename = "set")] -pub async fn set_greet_sound( +pub async fn set_guild_greet_sound( ctx: Context<'_>, - #[description = "Name or ID of sound to set as your join sound"] name: String, + #[description = "Name or ID of sound to set as join sound"] + #[autocomplete = "autocomplete_sound"] + name: String, + #[description = "User to set join sound for"] user: User, ) -> Result<(), Error> { + if user.id != ctx.author().id { + let guild = ctx.guild().unwrap(); + let permissions = guild + .member_permissions(&ctx.discord(), ctx.author().id) + .await; + + if permissions.map_or(true, |p| !p.manage_guild()) { + ctx.send(|b| { + b.ephemeral(true) + .content("Only admins can change other user's greet sounds.") + }) + .await?; + + return Ok(()); + } + } + let sound_vec = ctx .data() .search_for_sound(&name, ctx.guild_id().unwrap(), ctx.author().id, true) @@ -51,7 +80,7 @@ pub async fn set_greet_sound( match sound_vec.first() { Some(sound) => { ctx.data() - .update_join_sound(ctx.author().id, Some(sound.id)) + .update_join_sound(user.id, ctx.guild_id(), Some(sound.id)) .await; ctx.say(format!( @@ -69,18 +98,104 @@ pub async fn set_greet_sound( Ok(()) } -/// Set a join sound +/// Unset your global join sound #[poise::command(slash_command, rename = "unset", guild_only = true)] -pub async fn unset_greet_sound(ctx: Context<'_>) -> Result<(), Error> { - ctx.data().update_join_sound(ctx.author().id, None).await; +pub async fn unset_guild_greet_sound( + ctx: Context<'_>, + #[description = "User to set join sound for"] user: User, +) -> Result<(), Error> { + if user.id != ctx.author().id { + let guild = ctx.guild().unwrap(); + let permissions = guild + .member_permissions(&ctx.discord(), ctx.author().id) + .await; + + if permissions.map_or(true, |p| !p.manage_guild()) { + ctx.send(|b| { + b.ephemeral(true) + .content("Only admins can change other user's greet sounds.") + }) + .await?; + + return Ok(()); + } + } + + ctx.data() + .update_join_sound(user.id, ctx.guild_id(), None) + .await; ctx.say("Greet sound has been unset").await?; Ok(()) } +/// Manage your own greet sound +#[poise::command(slash_command, rename = "user")] +pub async fn user_greet_sound(_ctx: Context<'_>) -> Result<(), Error> { + Ok(()) +} + +/// Set your global join sound +#[poise::command(slash_command, rename = "set")] +pub async fn set_user_greet_sound( + ctx: Context<'_>, + #[description = "Name or ID of sound to set as your join sound"] + #[autocomplete = "autocomplete_sound"] + name: String, +) -> Result<(), Error> { + let sound_vec = ctx + .data() + .search_for_sound(&name, ctx.guild_id().unwrap(), ctx.author().id, true) + .await?; + + match sound_vec.first() { + Some(sound) => { + ctx.data() + .update_join_sound(ctx.author().id, None::, Some(sound.id)) + .await; + + ctx.send(|b| { + b.ephemeral(true).content(format!( + "Greet sound has been set to {} (ID {})", + sound.name, sound.id + )) + }) + .await?; + } + + None => { + ctx.send(|b| { + b.ephemeral(true) + .content("Could not find a sound by that name.") + }) + .await?; + } + } + + Ok(()) +} + +/// Unset your global join sound +#[poise::command(slash_command, rename = "unset", guild_only = true)] +pub async fn unset_user_greet_sound(ctx: Context<'_>) -> Result<(), Error> { + ctx.data() + .update_join_sound(ctx.author().id, None::, None) + .await; + + ctx.send(|b| b.ephemeral(true).content("Greet sound has been unset")) + .await?; + + Ok(()) +} + /// Disable greet sounds on this server -#[poise::command(slash_command, rename = "disable", guild_only = true)] +#[poise::command( + slash_command, + rename = "disable", + guild_only = true, + required_permissions = "MANAGE_GUILD" +)] pub async fn disable_greet_sound(ctx: Context<'_>) -> Result<(), Error> { let guild_data_opt = ctx.guild_data(ctx.guild_id().unwrap()).await; @@ -97,7 +212,12 @@ pub async fn disable_greet_sound(ctx: Context<'_>) -> Result<(), Error> { } /// Enable greet sounds on this server -#[poise::command(slash_command, rename = "enable", guild_only = true)] +#[poise::command( + slash_command, + rename = "enable", + guild_only = true, + required_permissions = "MANAGE_GUILD" +)] pub async fn enable_greet_sound(ctx: Context<'_>) -> Result<(), Error> { let guild_data_opt = ctx.guild_data(ctx.guild_id().unwrap()).await; diff --git a/src/event_handlers.rs b/src/event_handlers.rs index 4e45a1f..a301ca0 100644 --- a/src/event_handlers.rs +++ b/src/event_handlers.rs @@ -92,7 +92,8 @@ pub async fn listener(ctx: &Context, event: &poise::Event<'_>, data: &Data) -> R } if allowed_greets { - if let Some(join_id) = data.join_sound(new.user_id).await { + if let Some(join_id) = data.join_sound(new.user_id, new.guild_id).await + { let mut sound = sqlx::query_as_unchecked!( Sound, " diff --git a/src/main.rs b/src/main.rs index 0dad4a4..f205d0e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,14 +25,13 @@ use tokio::sync::RwLock; use crate::{event_handlers::listener, models::guild_data::GuildData}; -// Which database driver are we using? type Database = MySql; pub struct Data { database: Pool, http: reqwest::Client, guild_data_cache: DashMap>>, - join_sound_cache: DashMap>, + join_sound_cache: DashMap, Option>>, } type Error = Box; @@ -103,10 +102,22 @@ async fn main() -> Result<(), Box> { cmds::settings::change_volume(), poise::Command { subcommands: vec![ + poise::Command { + subcommands: vec![ + cmds::settings::set_guild_greet_sound(), + cmds::settings::unset_guild_greet_sound(), + ], + ..cmds::settings::guild_greet_sound() + }, + poise::Command { + subcommands: vec![ + cmds::settings::set_user_greet_sound(), + cmds::settings::unset_user_greet_sound(), + ], + ..cmds::settings::user_greet_sound() + }, cmds::settings::disable_greet_sound(), cmds::settings::enable_greet_sound(), - cmds::settings::set_greet_sound(), - cmds::settings::unset_greet_sound(), ], ..cmds::settings::greet_sound() }, diff --git a/src/models/join_sound.rs b/src/models/join_sound.rs index 8be1278..5ff5598 100644 --- a/src/models/join_sound.rs +++ b/src/models/join_sound.rs @@ -1,45 +1,69 @@ -use poise::serenity::{async_trait, model::id::UserId}; +use poise::{ + serenity::{async_trait, model::id::UserId}, + serenity_prelude::GuildId, +}; use crate::Data; #[async_trait] pub trait JoinSoundCtx { - async fn join_sound + Send + Sync>(&self, user_id: U) -> Option; - async fn update_join_sound + Send + Sync>( + async fn join_sound + Send + Sync, G: Into + Send + Sync>( &self, user_id: U, + guild_id: Option, + ) -> Option; + async fn update_join_sound + Send + Sync, G: Into + Send + Sync>( + &self, + user_id: U, + guild_id: Option, join_id: Option, - ); + ) -> Result<(), sqlx::Error>; } #[async_trait] impl JoinSoundCtx for Data { - async fn join_sound + Send + Sync>(&self, user_id: U) -> Option { + async fn join_sound + Send + Sync, G: Into + Send + Sync>( + &self, + user_id: U, + guild_id: Option, + ) -> Option { let user_id = user_id.into(); + let guild_id = guild_id.map(|g| g.into()); - let x = if let Some(join_sound_id) = self.join_sound_cache.get(&user_id) { - join_sound_id.value().clone() + let cached_join_id = self + .join_sound_cache + .get(&user_id) + .map(|d| d.get(&guild_id).map(|i| i.value().clone())) + .flatten(); + + let x = if let Some(join_sound_id) = cached_join_id { + join_sound_id } else { let join_sound_id = { let join_id_res = sqlx::query!( " SELECT join_sound_id - FROM users + FROM join_sounds WHERE user = ? + AND (guild IS NULL OR guild = ?) + ORDER BY guild IS NULL ", - user_id.as_u64() + user_id.as_u64(), + guild_id.map(|g| g.0) ) .fetch_one(&self.database) .await; if let Ok(row) = join_id_res { - row.join_sound_id + Some(row.join_sound_id) } else { None } }; - self.join_sound_cache.insert(user_id, join_sound_id); + self.join_sound_cache.entry(user_id).and_modify(|d| { + d.insert(guild_id, join_sound_id); + }); join_sound_id }; @@ -47,39 +71,54 @@ SELECT join_sound_id x } - async fn update_join_sound + Send + Sync>( + async fn update_join_sound + Send + Sync, G: Into + Send + Sync>( &self, user_id: U, + guild_id: Option, join_id: Option, - ) { + ) -> Result<(), sqlx::Error> { let user_id = user_id.into(); + let guild_id = guild_id.map(|g| g.into()); - self.join_sound_cache.insert(user_id, join_id); + self.join_sound_cache.entry(user_id).and_modify(|d| { + d.insert(guild_id, join_id); + }); - let pool = self.database.clone(); + let mut transaction = self.database.begin().await?; - let _ = sqlx::query!( - " -INSERT IGNORE INTO users (user) - VALUES (?) - ", - user_id.as_u64() - ) - .execute(&pool) - .await; + match join_id { + Some(join_id) => { + sqlx::query!( + "DELETE FROM join_sounds WHERE user = ? AND guild <=> ?", + user_id.0, + guild_id.map(|g| g.0) + ) + .execute(&mut transaction) + .await?; - let _ = sqlx::query!( - " -UPDATE users -SET - join_sound_id = ? -WHERE - user = ? - ", - join_id, - user_id.as_u64() - ) - .execute(&pool) - .await; + sqlx::query!( + "INSERT INTO join_sounds (user, join_sound_id, guild) VALUES (?, ?, ?)", + user_id.0, + join_id, + guild_id.map(|g| g.0) + ) + .execute(&mut transaction) + .await?; + } + + None => { + sqlx::query!( + "DELETE FROM join_sounds WHERE user = ? AND guild <=> ?", + user_id.0, + guild_id.map(|g| g.0) + ) + .execute(&mut transaction) + .await?; + } + } + + transaction.commit().await?; + + Ok(()) } }