summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commands/general/ask.rs (renamed from src/commands/ask.rs)3
-rw-r--r--src/commands/general/bing.rs (renamed from src/commands/bing.rs)1
-rw-r--r--src/commands/general/convert.rs (renamed from src/commands/convert.rs)1
-rw-r--r--src/commands/general/mod.rs11
-rw-r--r--src/commands/general/random.rs (renamed from src/commands/random.rs)1
-rw-r--r--src/commands/general/version.rs (renamed from src/commands/version.rs)1
-rw-r--r--src/commands/mod.rs27
-rw-r--r--src/commands/moderation/config.rs140
-rw-r--r--src/commands/moderation/mod.rs3
-rw-r--r--src/commands/optional/copypasta.rs (renamed from src/commands/copypasta.rs)11
-rw-r--r--src/commands/optional/mod.rs5
-rw-r--r--src/commands/optional/teawiespam.rs (renamed from src/commands/teawiespam.rs)7
-rw-r--r--src/handlers/error.rs6
-rw-r--r--src/handlers/event/guild.rs26
-rw-r--r--src/handlers/event/message.rs35
-rw-r--r--src/handlers/event/mod.rs7
-rw-r--r--src/handlers/event/pinboard.rs22
-rw-r--r--src/handlers/event/reactboard.rs24
-rw-r--r--src/main.rs8
-rw-r--r--src/settings.rs139
-rw-r--r--src/utils.rs11
21 files changed, 340 insertions, 149 deletions
diff --git a/src/commands/ask.rs b/src/commands/general/ask.rs
index 3589484..4bbf82e 100644
--- a/src/commands/ask.rs
+++ b/src/commands/general/ask.rs
@@ -1,5 +1,4 @@
use crate::{consts, utils, Context};
-
use color_eyre::eyre::{Context as _, Result};
/// ask teawie a question!
@@ -11,7 +10,7 @@ pub async fn ask(
_question: String,
) -> Result<()> {
let resp = utils::random_choice(consts::RESPONSES)
- .wrap_err("couldn't choose from random responses!")?;
+ .wrap_err("Couldn't choose from random responses!")?;
ctx.say(resp).await?;
Ok(())
diff --git a/src/commands/bing.rs b/src/commands/general/bing.rs
index b80ebca..fefbaf1 100644
--- a/src/commands/bing.rs
+++ b/src/commands/general/bing.rs
@@ -1,5 +1,4 @@
use crate::Context;
-
use color_eyre::eyre::Result;
/// make sure the wie is alive
diff --git a/src/commands/convert.rs b/src/commands/general/convert.rs
index cbbf8dc..60135c4 100644
--- a/src/commands/convert.rs
+++ b/src/commands/general/convert.rs
@@ -1,5 +1,4 @@
use crate::Context;
-
use bottomify::bottom;
use color_eyre::eyre::Result;
diff --git a/src/commands/general/mod.rs b/src/commands/general/mod.rs
new file mode 100644
index 0000000..ffb4d63
--- /dev/null
+++ b/src/commands/general/mod.rs
@@ -0,0 +1,11 @@
+mod ask;
+mod bing;
+mod convert;
+mod random;
+mod version;
+
+pub use ask::ask;
+pub use bing::bing;
+pub use convert::convert;
+pub use random::random;
+pub use version::version;
diff --git a/src/commands/random.rs b/src/commands/general/random.rs
index 9595d09..9aa282a 100644
--- a/src/commands/random.rs
+++ b/src/commands/general/random.rs
@@ -1,5 +1,4 @@
use crate::{api, consts, utils, Context};
-
use color_eyre::eyre::Result;
#[poise::command(slash_command, subcommands("lore", "teawie", "shiggy"))]
diff --git a/src/commands/version.rs b/src/commands/general/version.rs
index 8d9a1f3..8b8d1f1 100644
--- a/src/commands/version.rs
+++ b/src/commands/general/version.rs
@@ -1,6 +1,5 @@
use crate::colors::Colors;
use crate::Context;
-
use color_eyre::eyre::Result;
/// get version info
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index 5edf0b7..8c265d3 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -1,28 +1,23 @@
-pub mod ask;
-pub mod bing;
-pub mod convert;
-pub mod copypasta;
-pub mod random;
-pub mod teawiespam;
-pub mod version;
-
use crate::Data;
use color_eyre::eyre::Report;
use poise::Command;
+mod general;
+mod moderation;
+mod optional;
+
pub fn to_global_commands() -> Vec<Command<Data, Report>> {
vec![
- ask::ask(),
- bing::bing(),
- convert::convert(),
- random::random(),
- copypasta::copypasta(),
- teawiespam::teawiespam(),
- version::version(),
+ general::ask(),
+ general::bing(),
+ general::convert(),
+ general::random(),
+ general::version(),
+ moderation::config(),
]
}
pub fn to_guild_commands() -> Vec<Command<Data, Report>> {
- vec![copypasta::copypasta(), teawiespam::teawiespam()]
+ vec![optional::copypasta(), optional::teawiespam()]
}
diff --git a/src/commands/moderation/config.rs b/src/commands/moderation/config.rs
new file mode 100644
index 0000000..2d1410c
--- /dev/null
+++ b/src/commands/moderation/config.rs
@@ -0,0 +1,140 @@
+use crate::settings::{Settings, SettingsProperties};
+use crate::Context;
+
+use color_eyre::eyre::{eyre, Context as _, ContextCompat, Result};
+use log::*;
+use poise::serenity_prelude::{GuildChannel, ReactionType};
+
+#[poise::command(
+ slash_command,
+ subcommands("set", "get"),
+ default_member_permissions = "MANAGE_GUILD"
+)]
+pub async fn config(_ctx: Context<'_>) -> Result<()> {
+ Ok(())
+}
+
+#[poise::command(slash_command, ephemeral, guild_only)]
+pub async fn set(
+ ctx: Context<'_>,
+ #[channel_types("Text")]
+ #[description = "Where to redirect pins from channels. If empty (the default), the PinBoard is disabled."]
+ pinboard_channel: Option<GuildChannel>,
+ #[channel_types("Text")]
+ #[description = "A channel that PinBoard will redirect pins from. This will be all channels if empty."]
+ pinboard_watch: Option<GuildChannel>,
+ #[channel_types("Text")]
+ #[description = "Where to post messages that made it to the ReactBoard. If left empty, ReactBoard is disabled."]
+ reactboard_channel: Option<GuildChannel>,
+ #[description = "An emoji that will get messages on the ReactBoard. If empty, ReactBoard is disabled."]
+ reactboard_reaction: Option<String>,
+ #[description = "Minimum number of reactions a message needs to make it to the ReactBoard (defaults to 5)"]
+ reactboard_requirement: Option<u64>,
+ #[description = "Enables 'extra' commands like teawiespam and copypasta. Defaults to false."]
+ optional_commands_enabled: Option<bool>,
+) -> Result<()> {
+ let redis = &ctx.data().redis;
+ let gid = ctx.guild_id().unwrap_or_default();
+ let mut settings = Settings::from_redis(redis, &gid).await?;
+ let previous_settings = settings.clone();
+
+ if let Some(channel) = pinboard_channel {
+ settings.pinboard_channel = Some(channel.id);
+ }
+
+ if let Some(watch) = pinboard_watch {
+ if let Some(mut prev) = settings.pinboard_watch {
+ prev.push(watch.id);
+ settings.pinboard_watch = Some(prev);
+ } else {
+ let new = Vec::from([watch.id]);
+ debug!("Setting pinboard_watch to {new:#?} for {} in Redis", gid);
+
+ settings.pinboard_watch = Some(new);
+ }
+ }
+
+ if let Some(channel) = reactboard_channel {
+ debug!(
+ "Setting reactboard_channel to {channel} for {} in Redis",
+ gid
+ );
+
+ settings.reactboard_channel = Some(channel.id);
+ }
+
+ if let Some(requirement) = reactboard_requirement {
+ debug!(
+ "Setting reactboard_requirement to {requirement} for {} in Redis",
+ gid
+ );
+
+ settings.reactboard_requirement = Some(requirement);
+ }
+
+ if let Some(reaction) = reactboard_reaction {
+ let emoji = reaction
+ .parse::<ReactionType>()
+ .wrap_err_with(|| format!("Couldn't parse {reaction} as string!"))?;
+
+ if let Some(mut prev) = settings.reactboard_reactions {
+ prev.push(emoji);
+ settings.reactboard_reactions = Some(prev);
+ } else {
+ let new = Vec::from([emoji]);
+ debug!("Setting pinboard_watch to {new:#?} for {} in Redis", gid);
+
+ settings.reactboard_reactions = Some(new);
+ }
+ }
+
+ if let Some(enabled) = optional_commands_enabled {
+ debug!(
+ "Setting optional_commands_enabled to {enabled} for {} in Redis",
+ gid
+ );
+
+ settings.optional_commands_enabled = enabled;
+ }
+
+ if previous_settings != settings {
+ settings.save(redis).await?;
+ ctx.reply("Configuration updated!").await?;
+ } else {
+ ctx.reply("No changes made, so i'm not updating anything")
+ .await?;
+ }
+
+ Ok(())
+}
+
+#[poise::command(slash_command, ephemeral, guild_only)]
+pub async fn get(
+ ctx: Context<'_>,
+ #[description = "The setting you want to get"] setting: SettingsProperties,
+) -> Result<()> {
+ let gid = &ctx
+ .guild_id()
+ .wrap_err_with(|| eyre!("Failed to get GuildId from context!"))?;
+
+ let settings = Settings::from_redis(&ctx.data().redis, gid).await?;
+
+ let value = match setting {
+ SettingsProperties::GuildId => settings.guild_id.to_string(),
+ SettingsProperties::PinBoardChannel => format!("{:#?}", settings.pinboard_channel),
+ SettingsProperties::PinBoardWatch => format!("{:#?}", settings.pinboard_watch),
+ SettingsProperties::ReactBoardChannel => format!("{:#?}", settings.reactboard_channel),
+ SettingsProperties::ReactBoardRequirement => {
+ format!("{:?}", settings.reactboard_requirement)
+ }
+ SettingsProperties::ReactBoardReactions => format!("{:?}", settings.reactboard_reactions),
+ SettingsProperties::OptionalCommandsEnabled => {
+ settings.optional_commands_enabled.to_string()
+ }
+ };
+
+ ctx.send(|m| m.embed(|e| e.field(setting, value, false)))
+ .await?;
+
+ Ok(())
+}
diff --git a/src/commands/moderation/mod.rs b/src/commands/moderation/mod.rs
new file mode 100644
index 0000000..d54b3f8
--- /dev/null
+++ b/src/commands/moderation/mod.rs
@@ -0,0 +1,3 @@
+mod config;
+
+pub use config::config;
diff --git a/src/commands/copypasta.rs b/src/commands/optional/copypasta.rs
index 16ac562..ea23f5f 100644
--- a/src/commands/copypasta.rs
+++ b/src/commands/optional/copypasta.rs
@@ -1,4 +1,4 @@
-use crate::Context;
+use crate::{Context, Settings};
use std::collections::HashMap;
@@ -66,12 +66,11 @@ pub async fn copypasta(
ctx: Context<'_>,
#[description = "the copypasta you want to send"] copypasta: Copypastas,
) -> Result<()> {
- let gid = ctx
- .guild_id()
- .ok_or_else(|| eyre!("couldnt get guild from message!"))?;
+ let gid = ctx.guild_id().unwrap_or_default();
+ let settings = Settings::from_redis(&ctx.data().redis, &gid).await?;
- if !ctx.data().settings.is_guild_allowed(gid) {
- info!("not running copypasta command in {gid}");
+ if !settings.optional_commands_enabled {
+ debug!("Not running copypasta command in {gid} since it's disabled");
return Ok(());
}
diff --git a/src/commands/optional/mod.rs b/src/commands/optional/mod.rs
new file mode 100644
index 0000000..451deeb
--- /dev/null
+++ b/src/commands/optional/mod.rs
@@ -0,0 +1,5 @@
+mod copypasta;
+mod teawiespam;
+
+pub use copypasta::copypasta;
+pub use teawiespam::teawiespam;
diff --git a/src/commands/teawiespam.rs b/src/commands/optional/teawiespam.rs
index aeea255..c1b3b29 100644
--- a/src/commands/teawiespam.rs
+++ b/src/commands/optional/teawiespam.rs
@@ -1,4 +1,4 @@
-use crate::Context;
+use crate::{Context, Settings};
use color_eyre::eyre::Result;
use log::*;
@@ -7,9 +7,10 @@ use log::*;
#[poise::command(slash_command, prefix_command)]
pub async fn teawiespam(ctx: Context<'_>) -> Result<()> {
let gid = ctx.guild_id().unwrap_or_default();
+ let settings = Settings::from_redis(&ctx.data().redis, &gid).await?;
- if !ctx.data().settings.is_guild_allowed(gid) {
- info!("not running teawiespam command in {gid}");
+ if !settings.optional_commands_enabled {
+ debug!("Not running teawiespam in {gid} since it's disabled");
return Ok(());
}
diff --git a/src/handlers/error.rs b/src/handlers/error.rs
index e256bcf..b5b259d 100644
--- a/src/handlers/error.rs
+++ b/src/handlers/error.rs
@@ -8,7 +8,7 @@ use poise::FrameworkError;
pub async fn handle(error: poise::FrameworkError<'_, Data, Report>) {
match error {
- FrameworkError::Setup { error, .. } => error!("error setting up client! {error:#?}"),
+ FrameworkError::Setup { error, .. } => error!("Error setting up client!\n{error:#?}"),
FrameworkError::Command { error, ctx } => {
error!("Error in command {}:\n{error:?}", ctx.command().name);
@@ -27,10 +27,10 @@ pub async fn handle(error: poise::FrameworkError<'_, Data, Report>) {
FrameworkError::EventHandler {
error,
ctx: _,
- event: _,
+ event,
framework: _,
} => {
- error!("Error while handling event:\n{error:#?}");
+ error!("Error while handling event {}:\n{error:?}", event.name());
}
error => {
diff --git a/src/handlers/event/guild.rs b/src/handlers/event/guild.rs
new file mode 100644
index 0000000..b7a4028
--- /dev/null
+++ b/src/handlers/event/guild.rs
@@ -0,0 +1,26 @@
+use color_eyre::eyre::Result;
+use log::*;
+use poise::serenity_prelude::{Guild, UnavailableGuild};
+
+use crate::{Data, Settings};
+
+pub async fn handle_create(guild: &Guild, is_new: &bool, data: &Data) -> Result<()> {
+ if !is_new && Settings::from_redis(&data.redis, &guild.id).await.is_ok() {
+ debug!("Not recreating Redis key for {}", guild.id);
+ return Ok(());
+ }
+
+ info!("Creating new Redis key for {}", guild.id);
+ Settings::new_redis(&data.redis, &guild.id).await?;
+ Ok(())
+}
+
+pub async fn handle_delete(guild: &UnavailableGuild, data: &Data) -> Result<()> {
+ let redis = &data.redis;
+
+ info!("Deleting redis key for {}", guild.id);
+ let settings = Settings::from_redis(redis, &guild.id).await?;
+ settings.delete(redis).await?;
+
+ Ok(())
+}
diff --git a/src/handlers/event/message.rs b/src/handlers/event/message.rs
index cf619c5..0004caf 100644
--- a/src/handlers/event/message.rs
+++ b/src/handlers/event/message.rs
@@ -1,8 +1,7 @@
-use crate::Settings;
-use crate::{consts, Data};
+use crate::{consts, Data, Settings};
-use color_eyre::eyre::{Report, Result};
-use log::info;
+use color_eyre::eyre::{eyre, Report, Result};
+use log::*;
use poise::serenity_prelude::{Context, Message};
use poise::FrameworkContext;
@@ -12,35 +11,39 @@ pub async fn handle(
msg: &Message,
data: &Data,
) -> Result<()> {
- if should_echo(framework, msg, &data.settings) {
+ if should_echo(framework, msg, data).await? {
msg.reply(ctx, &msg.content).await?;
}
Ok(())
}
-fn should_echo(
+async fn should_echo(
_framework: FrameworkContext<'_, Data, Report>,
msg: &Message,
- settings: &Settings,
-) -> bool {
- let gid = msg.guild_id.unwrap_or_default();
+ data: &Data,
+) -> Result<bool> {
if msg.author.bot && msg.webhook_id.is_none() {
- info!("Not repeating another bot");
- return false;
+ debug!("Not repeating another bot");
+ return Ok(false);
}
- if !settings.is_guild_allowed(gid) {
- info!("Not echoing in guild {gid}");
- return false;
+ let gid = msg
+ .guild_id
+ .ok_or_else(|| eyre!("Couldn't get GuildId from {}!", msg.id))?;
+ let settings = Settings::from_redis(&data.redis, &gid).await?;
+
+ if !settings.optional_commands_enabled {
+ debug!("Not echoing in guild {gid}");
+ return Ok(false);
}
let content = &msg.content;
- content == "🗿"
+ Ok(content == "🗿"
|| consts::TEAMOJIS.contains(&content.as_str())
|| content.to_ascii_lowercase() == "moyai"
|| content
.to_ascii_lowercase()
- .contains("twitter's recommendation algorithm")
+ .contains("twitter's recommendation algorithm"))
}
diff --git a/src/handlers/event/mod.rs b/src/handlers/event/mod.rs
index a587c77..6dd5fe4 100644
--- a/src/handlers/event/mod.rs
+++ b/src/handlers/event/mod.rs
@@ -4,6 +4,7 @@ use color_eyre::eyre::{Report, Result};
use poise::serenity_prelude as serenity;
use poise::{Event, FrameworkContext};
+mod guild;
mod message;
mod pinboard;
mod reactboard;
@@ -27,6 +28,12 @@ pub async fn handle(
Event::ReactionAdd { add_reaction } => reactboard::handle(ctx, add_reaction, data).await?,
+ Event::GuildCreate { guild, is_new } => guild::handle_create(guild, is_new, data).await?,
+ Event::GuildDelete {
+ incomplete,
+ full: _,
+ } => guild::handle_delete(incomplete, data).await?,
+
_ => {}
}
diff --git a/src/handlers/event/pinboard.rs b/src/handlers/event/pinboard.rs
index 33d2680..21e8170 100644
--- a/src/handlers/event/pinboard.rs
+++ b/src/handlers/event/pinboard.rs
@@ -1,4 +1,4 @@
-use crate::{utils, Data};
+use crate::{utils, Data, Settings};
use color_eyre::eyre::{eyre, Context as _, Result};
use log::*;
@@ -6,9 +6,23 @@ use poise::serenity_prelude::model::prelude::*;
use poise::serenity_prelude::Context;
pub async fn handle(ctx: &Context, pin: &ChannelPinsUpdateEvent, data: &Data) -> Result<()> {
- if let Some(sources) = &data.settings.pinboard_sources {
+ let gid = pin.guild_id.unwrap_or_default();
+ let settings = Settings::from_redis(&data.redis, &gid).await?;
+
+ let target = if let Some(target) = settings.reactboard_channel {
+ target
+ } else {
+ debug!("PinBoard is disabled in {gid}, ignoring");
+ return Ok(());
+ };
+
+ if let Some(sources) = settings.pinboard_watch {
if !sources.contains(&pin.channel_id) {
- warn!("Can't access source of pin!");
+ debug!(
+ "{} not listed in PinBoard settings for {gid}, ignoring",
+ &pin.channel_id
+ );
+
return Ok(());
}
}
@@ -22,7 +36,7 @@ pub async fn handle(ctx: &Context, pin: &ChannelPinsUpdateEvent, data: &Data) ->
for pin in pins {
// We call `take` because it's supposed to be just for the latest message.
- redirect(ctx, &pin, pinner.take(), data.settings.pinboard_target).await?;
+ redirect(ctx, &pin, pinner.take(), target).await?;
pin.unpin(&ctx).await?;
}
diff --git a/src/handlers/event/reactboard.rs b/src/handlers/event/reactboard.rs
index 2a417da..2435976 100644
--- a/src/handlers/event/reactboard.rs
+++ b/src/handlers/event/reactboard.rs
@@ -1,4 +1,4 @@
-use crate::{utils, Data};
+use crate::{utils, Data, Settings};
use color_eyre::eyre::{eyre, Context as _, Result};
use log::*;
@@ -52,14 +52,24 @@ async fn send_to_reactboard(
msg: &Message,
data: &Data,
) -> Result<()> {
+ let gid = msg.guild_id.unwrap_or_default();
+ let settings = Settings::from_redis(&data.redis, &gid).await?;
+
// make sure everything is in order...
- if !data.settings.can_use_reaction(reaction) {
- info!("Reaction {} can't be used!", reaction.reaction_type);
+ let target = if let Some(target) = settings.reactboard_channel {
+ target
+ } else {
+ debug!("Reactboard is disabled in {gid}, ignoring");
+ return Ok(());
+ };
+
+ if !settings.can_use_reaction(&reaction.reaction_type) {
+ debug!("Reaction {} can't be used!", reaction.reaction_type);
return Ok(());
}
- if reaction.count < data.settings.reactboard_requirement.unwrap_or(5) {
- info!(
+ if reaction.count < settings.reactboard_requirement.unwrap_or(5) {
+ debug!(
"Ignoring message {} on reactboard, not enough reactions",
msg.id
);
@@ -137,9 +147,7 @@ async fn send_to_reactboard(
} else {
let embed = utils::resolve_message_to_embed(ctx, msg).await;
- let resp = data
- .settings
- .reactboard_target
+ let resp = target
.send_message(ctx, |m| {
m.allowed_mentions(|am| am.empty_parse())
.content(content)
diff --git a/src/main.rs b/src/main.rs
index 6dc99a1..6921f8a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -19,29 +19,25 @@ type Context<'a> = poise::Context<'a, Data, Report>;
#[derive(Clone)]
pub struct Data {
- settings: Settings,
redis: redis::Client,
}
impl Data {
pub fn new() -> Result<Self> {
- let settings =
- Settings::new().ok_or_else(|| eyre!("Couldn't create new settings object!"))?;
-
let redis_url = std::env::var("REDIS_URL")
.wrap_err_with(|| eyre!("Couldn't find Redis URL in environment!"))?;
let redis = redis::Client::open(redis_url)?;
- Ok(Self { settings, redis })
+ Ok(Self { redis })
}
}
#[tokio::main]
async fn main() -> Result<()> {
+ dotenvy::dotenv().ok();
color_eyre::install()?;
env_logger::init();
- dotenvy::dotenv().ok();
let token =
std::env::var("TOKEN").wrap_err_with(|| eyre!("Couldn't find token in environment!"))?;
diff --git a/src/settings.rs b/src/settings.rs
index 406b990..6c02e5c 100644
--- a/src/settings.rs
+++ b/src/settings.rs
@@ -1,89 +1,88 @@
-use crate::{consts, utils};
-use log::*;
-use poise::serenity_prelude::{ChannelId, EmojiId, GuildId, MessageReaction, ReactionType};
+use color_eyre::eyre::{Context as _, Result};
+use poise::serenity_prelude::{ChannelId, GuildId, ReactionType};
+use redis::{AsyncCommands as _, Client};
+use redis_macros::{FromRedisValue, ToRedisArgs};
+use serde::{Deserialize, Serialize};
-#[derive(Clone)]
+const ROOT_KEY: &str = "settings-v1";
+
+#[derive(poise::ChoiceParameter)]
+pub enum SettingsProperties {
+ GuildId,
+ PinBoardChannel,
+ PinBoardWatch,
+ ReactBoardChannel,
+ ReactBoardRequirement,
+ ReactBoardReactions,
+ OptionalCommandsEnabled,
+}
+
+#[derive(Clone, Default, PartialEq, Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
pub struct Settings {
- pub allowed_guilds: Vec<GuildId>,
- pub pinboard_target: ChannelId,
- pub pinboard_sources: Option<Vec<ChannelId>>,
- pub reactboard_target: ChannelId,
+ pub guild_id: GuildId,
+ pub pinboard_channel: Option<ChannelId>,
+ pub pinboard_watch: Option<Vec<ChannelId>>,
+ pub reactboard_channel: Option<ChannelId>,
pub reactboard_requirement: Option<u64>,
- pub reactboard_custom_reactions: Vec<EmojiId>,
- pub reactboard_unicode_reactions: Vec<String>,
+ pub reactboard_reactions: Option<Vec<ReactionType>>,
+ pub optional_commands_enabled: bool,
}
impl Settings {
- pub fn new() -> Option<Self> {
- let allowed_guilds = utils::parse_snowflakes_from_env("ALLOWED_GUILDS", GuildId)
- .unwrap_or_else(|| vec![consts::TEAWIE_GUILD, GuildId(1091969030694375444)]);
-
- let Some(pinboard_target) = utils::parse_snowflake_from_env("PIN_BOARD_TARGET", ChannelId)
- else {
- return None;
+ pub async fn new_redis(redis: &Client, gid: &GuildId) -> Result<()> {
+ let key = format!("{ROOT_KEY}:{gid}");
+ let settings = Self {
+ guild_id: *gid,
+ optional_commands_enabled: false,
+ ..Default::default()
};
- let pinboard_sources = utils::parse_snowflakes_from_env("PIN_BOARD_SOURCES", ChannelId);
- let Some(reactboard_target) =
- utils::parse_snowflake_from_env("REACT_BOARD_TARGET", ChannelId)
- else {
- return None;
- };
+ let mut con = redis.get_async_connection().await?;
+ con.set(&key, settings)
+ .await
+ .wrap_err_with(|| format!("Couldn't set key {key} in Redis!"))?;
- let reactboard_requirement = utils::parse_snowflake_from_env("REACT_BOARD_MIN", u64::from);
+ Ok(())
+ }
- let reactboard_custom_reactions =
- utils::parse_snowflakes_from_env("REACT_BOARD_CUSTOM_REACTIONS", EmojiId)
- .unwrap_or_default();
+ pub async fn from_redis(redis: &Client, gid: &GuildId) -> Result<Self> {
+ let key = format!("{ROOT_KEY}:{gid}");
+ let mut con = redis.get_async_connection().await?;
- let reactboard_unicode_reactions = std::env::var("REACT_BOARD_UNICODE_REACTIONS")
- .ok()
- .map(|v| {
- v.split(',')
- .map(|vs| vs.to_string())
- .collect::<Vec<String>>()
- })
- .unwrap_or_default();
+ let settings: Settings = con
+ .get(&key)
+ .await
+ .wrap_err_with(|| format!("Couldn't get {key} from Redis!"))?;
- info!("PinBoard target is {}", pinboard_target);
- if let Some(sources) = &pinboard_sources {
- info!("PinBoard sources are {:#?}", sources);
- }
- info!("ReactBoard target is {}", reactboard_target);
- info!(
- "ReactBoard custom reactions are {:#?}",
- reactboard_custom_reactions
- );
- info!(
- "ReactBoard unicode reactions are {:#?}",
- reactboard_unicode_reactions
- );
+ Ok(settings)
+ }
+
+ pub async fn delete(&self, redis: &Client) -> Result<()> {
+ let key = format!("{ROOT_KEY}:{}", self.guild_id);
+ let mut con = redis.get_async_connection().await?;
+
+ con.del(&key)
+ .await
+ .wrap_err_with(|| format!("Couldn't delete {key} from Redis!"))?;
- Some(Self {
- allowed_guilds,
- pinboard_target,
- pinboard_sources,
- reactboard_target,
- reactboard_requirement,
- reactboard_custom_reactions,
- reactboard_unicode_reactions,
- })
+ Ok(())
}
- pub fn can_use_reaction(&self, reaction: &MessageReaction) -> bool {
- match &reaction.reaction_type {
- ReactionType::Custom {
- animated: _,
- id,
- name: _,
- } => self.reactboard_custom_reactions.contains(id),
- ReactionType::Unicode(name) => self.reactboard_unicode_reactions.contains(name),
- // no other types exist yet, so assume we can't use them :p
- _ => false,
- }
+ pub async fn save(&self, redis: &Client) -> Result<()> {
+ let key = format!("{ROOT_KEY}:{}", self.guild_id);
+ let mut con = redis.get_async_connection().await?;
+
+ con.set(&key, self)
+ .await
+ .wrap_err_with(|| format!("Couldn't save {key} in Redis!"))?;
+ Ok(())
}
- pub fn is_guild_allowed(&self, gid: GuildId) -> bool {
- self.allowed_guilds.contains(&gid)
+ pub fn can_use_reaction(&self, reaction: &ReactionType) -> bool {
+ if let Some(reactions) = &self.reactboard_reactions {
+ reactions.iter().any(|r| r == reaction)
+ } else {
+ false
+ }
}
}
diff --git a/src/utils.rs b/src/utils.rs
index 10140f4..e4ac03e 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -6,17 +6,6 @@ use rand::seq::SliceRandom;
use serenity::{CreateEmbed, Message};
use url::Url;
-pub fn parse_snowflake_from_env<T, F: Fn(u64) -> T>(key: &str, f: F) -> Option<T> {
- std::env::var(key).ok().and_then(|v| v.parse().map(&f).ok())
-}
-pub fn parse_snowflakes_from_env<T, F: Fn(u64) -> T>(key: &str, f: F) -> Option<Vec<T>> {
- std::env::var(key).ok().and_then(|gs| {
- gs.split(',')
- .map(|g| g.parse().map(&f))
- .collect::<Result<Vec<_>, _>>()
- .ok()
- })
-}
/*
* chooses a random element from an array
*/