Goodbye moderation
We'll probably keep zeppelin / move back to Lily -- however the reminders seem to currently be broken :/
This commit is contained in:
parent
e0fea8d23e
commit
f2979d4cde
7 changed files with 1 additions and 559 deletions
|
@ -4,7 +4,6 @@ use color_eyre::eyre::Report;
|
||||||
use poise::Command;
|
use poise::Command;
|
||||||
|
|
||||||
mod general;
|
mod general;
|
||||||
pub mod moderation;
|
|
||||||
|
|
||||||
pub fn to_global_commands() -> Vec<Command<Data, Report>> {
|
pub fn to_global_commands() -> Vec<Command<Data, Report>> {
|
||||||
vec![
|
vec![
|
||||||
|
@ -15,8 +14,5 @@ pub fn to_global_commands() -> Vec<Command<Data, Report>> {
|
||||||
general::say(),
|
general::say(),
|
||||||
general::stars(),
|
general::stars(),
|
||||||
general::tag(),
|
general::tag(),
|
||||||
moderation::ban_user(),
|
|
||||||
moderation::mass_ban(),
|
|
||||||
moderation::kick_user(),
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,238 +0,0 @@
|
||||||
use crate::{consts::COLORS, Context};
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use color_eyre::eyre::{eyre, Context as _, Result};
|
|
||||||
use log::*;
|
|
||||||
use poise::serenity_prelude::{CacheHttp, GuildId, Http, Timestamp, User};
|
|
||||||
|
|
||||||
type Fields<'a> = Vec<(&'a str, String, bool)>;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait ModActionInfo {
|
|
||||||
fn to_fields(&self) -> Option<Fields>;
|
|
||||||
fn description(&self) -> String;
|
|
||||||
async fn run_action(
|
|
||||||
&self,
|
|
||||||
http: impl CacheHttp + AsRef<Http>,
|
|
||||||
user: &User,
|
|
||||||
guild_id: &GuildId,
|
|
||||||
reason: String,
|
|
||||||
) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ModAction<T>
|
|
||||||
where
|
|
||||||
T: ModActionInfo,
|
|
||||||
{
|
|
||||||
pub reason: Option<String>,
|
|
||||||
pub data: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ModActionInfo> ModAction<T> {
|
|
||||||
fn get_all_fields(&self) -> Fields {
|
|
||||||
let mut fields = vec![];
|
|
||||||
|
|
||||||
if let Some(reason) = self.reason.clone() {
|
|
||||||
fields.push(("Reason:", reason, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(mut action_fields) = self.data.to_fields() {
|
|
||||||
fields.append(&mut action_fields);
|
|
||||||
}
|
|
||||||
|
|
||||||
fields
|
|
||||||
}
|
|
||||||
|
|
||||||
/// internal mod logging
|
|
||||||
pub async fn log_action(&self, ctx: &Context<'_>) -> Result<()> {
|
|
||||||
let channel_id = ctx
|
|
||||||
.data()
|
|
||||||
.config
|
|
||||||
.discord
|
|
||||||
.channels
|
|
||||||
.say_log_channel_id
|
|
||||||
.ok_or_else(|| eyre!("Couldn't find say_log_channel_id! Unable to log mod action"))?;
|
|
||||||
|
|
||||||
let channel = ctx
|
|
||||||
.http()
|
|
||||||
.get_channel(channel_id.into())
|
|
||||||
.await
|
|
||||||
.wrap_err_with(|| "Couldn't resolve say_log_channel_id as a Channel! Are you sure you sure you used the right one?")?;
|
|
||||||
|
|
||||||
let channel = channel
|
|
||||||
.guild()
|
|
||||||
.ok_or_else(|| eyre!("Couldn't resolve say_log_channel_id as a GuildChannel! Are you sure you used the right one?"))?;
|
|
||||||
|
|
||||||
let fields = self.get_all_fields();
|
|
||||||
let title = format!("{} user!", self.data.description());
|
|
||||||
|
|
||||||
channel
|
|
||||||
.send_message(ctx, |m| {
|
|
||||||
m.embed(|e| e.title(title).fields(fields).color(COLORS["red"]))
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// public facing message
|
|
||||||
pub async fn reply(&self, ctx: &Context<'_>, user: &User, dm_user: Option<bool>) -> Result<()> {
|
|
||||||
let mut resp = format!("{} {}!", self.data.description(), user.name);
|
|
||||||
|
|
||||||
if dm_user.unwrap_or_default() {
|
|
||||||
resp = format!("{resp} (user notified with direct message)");
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.reply(resp).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn dm_user(&self, ctx: &Context<'_>, user: &User, guild_id: &GuildId) -> Result<()> {
|
|
||||||
let guild = ctx.http().get_guild(*guild_id.as_u64()).await?;
|
|
||||||
let title = format!("{} from {}!", self.data.description(), guild.name);
|
|
||||||
|
|
||||||
user.dm(ctx, |m| {
|
|
||||||
m.embed(|e| {
|
|
||||||
e.title(title).color(COLORS["red"]);
|
|
||||||
|
|
||||||
if let Some(reason) = &self.reason {
|
|
||||||
e.description(format!("Reason: {}", reason));
|
|
||||||
}
|
|
||||||
|
|
||||||
e
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle(
|
|
||||||
&self,
|
|
||||||
ctx: &Context<'_>,
|
|
||||||
user: &User,
|
|
||||||
quiet: Option<bool>,
|
|
||||||
dm_user: Option<bool>,
|
|
||||||
handle_reply: bool,
|
|
||||||
) -> Result<()> {
|
|
||||||
if quiet.unwrap_or_default() {
|
|
||||||
ctx.defer_ephemeral().await?;
|
|
||||||
} else {
|
|
||||||
ctx.defer().await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let guild_id = ctx
|
|
||||||
.guild_id()
|
|
||||||
.ok_or_else(|| eyre!("Couldn't get GuildId for context!"))?;
|
|
||||||
let actual_reason = self.reason.clone().unwrap_or("".to_string());
|
|
||||||
|
|
||||||
if dm_user.unwrap_or_default() {
|
|
||||||
self.dm_user(ctx, user, &guild_id).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.data
|
|
||||||
.run_action(ctx, user, &guild_id, actual_reason)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
self.log_action(ctx).await?;
|
|
||||||
|
|
||||||
if handle_reply {
|
|
||||||
self.reply(ctx, user, dm_user).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Ban {
|
|
||||||
pub purge_messages_days: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl ModActionInfo for Ban {
|
|
||||||
fn to_fields(&self) -> Option<Fields> {
|
|
||||||
let fields = vec![(
|
|
||||||
"Purged messages:",
|
|
||||||
format!("Last {} day(s)", self.purge_messages_days),
|
|
||||||
false,
|
|
||||||
)];
|
|
||||||
|
|
||||||
Some(fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn description(&self) -> String {
|
|
||||||
"Banned".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run_action(
|
|
||||||
&self,
|
|
||||||
http: impl CacheHttp + AsRef<Http>,
|
|
||||||
user: &User,
|
|
||||||
guild_id: &GuildId,
|
|
||||||
reason: String,
|
|
||||||
) -> Result<()> {
|
|
||||||
debug!("Banning user {user} with reason: \"{reason}\"");
|
|
||||||
|
|
||||||
guild_id
|
|
||||||
.ban_with_reason(http, user, self.purge_messages_days, reason)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Timeout {
|
|
||||||
pub time_until: Timestamp,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl ModActionInfo for Timeout {
|
|
||||||
fn to_fields(&self) -> Option<Fields> {
|
|
||||||
let fields = vec![("Timed out until:", self.time_until.to_string(), false)];
|
|
||||||
|
|
||||||
Some(fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn description(&self) -> String {
|
|
||||||
"Timed out".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
|
||||||
async fn run_action(
|
|
||||||
&self,
|
|
||||||
http: impl CacheHttp + AsRef<Http>,
|
|
||||||
user: &User,
|
|
||||||
guild_id: &GuildId,
|
|
||||||
reason: String,
|
|
||||||
) -> Result<()> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Kick {}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl ModActionInfo for Kick {
|
|
||||||
fn to_fields(&self) -> Option<Fields> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn description(&self) -> String {
|
|
||||||
"Kicked".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run_action(
|
|
||||||
&self,
|
|
||||||
http: impl CacheHttp + AsRef<Http>,
|
|
||||||
user: &User,
|
|
||||||
guild_id: &GuildId,
|
|
||||||
reason: String,
|
|
||||||
) -> Result<()> {
|
|
||||||
debug!("Kicked user {user} with reason: \"{reason}\"");
|
|
||||||
|
|
||||||
guild_id.kick_with_reason(http, user, &reason).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,166 +0,0 @@
|
||||||
use crate::Context;
|
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
use color_eyre::eyre::{eyre, Result};
|
|
||||||
use poise::serenity_prelude::{ArgumentConvert, ChannelId, GuildId, User};
|
|
||||||
|
|
||||||
pub mod actions;
|
|
||||||
use actions::{Ban, Kick, ModAction};
|
|
||||||
|
|
||||||
async fn split_argument<T>(
|
|
||||||
ctx: &Context<'_>,
|
|
||||||
guild_id: Option<GuildId>,
|
|
||||||
channel_id: Option<ChannelId>,
|
|
||||||
list: String,
|
|
||||||
) -> Result<Vec<T>>
|
|
||||||
where
|
|
||||||
T: ArgumentConvert,
|
|
||||||
T::Err: Error + Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
// yes i should be using something like `filter_map()` here. async closures
|
|
||||||
// are unstable though so woooooo
|
|
||||||
let mut res: Vec<T> = vec![];
|
|
||||||
for item in list.split(',') {
|
|
||||||
let item = T::convert(ctx.serenity_context(), guild_id, channel_id, item.trim()).await?;
|
|
||||||
|
|
||||||
res.push(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ban a user
|
|
||||||
#[poise::command(
|
|
||||||
slash_command,
|
|
||||||
prefix_command,
|
|
||||||
guild_only,
|
|
||||||
default_member_permissions = "BAN_MEMBERS",
|
|
||||||
required_permissions = "BAN_MEMBERS",
|
|
||||||
aliases("ban")
|
|
||||||
)]
|
|
||||||
pub async fn ban_user(
|
|
||||||
ctx: Context<'_>,
|
|
||||||
#[description = "User to ban"] user: User,
|
|
||||||
#[description = "Reason to ban"] reason: Option<String>,
|
|
||||||
#[description = "Number of days to purge their messages from (defaults to 0)"]
|
|
||||||
purge_messages_days: Option<u8>,
|
|
||||||
#[description = "If true, the reply from the bot will be ephemeral"] quiet: Option<bool>,
|
|
||||||
#[description = "If true, the affected user will be sent a DM"] dm_user: Option<bool>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let dmd = purge_messages_days.unwrap_or(0);
|
|
||||||
|
|
||||||
let action = ModAction {
|
|
||||||
reason,
|
|
||||||
data: Ban {
|
|
||||||
purge_messages_days: dmd,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
action.handle(&ctx, &user, quiet, dm_user, true).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ban multiple users
|
|
||||||
#[poise::command(
|
|
||||||
slash_command,
|
|
||||||
prefix_command,
|
|
||||||
guild_only,
|
|
||||||
default_member_permissions = "BAN_MEMBERS",
|
|
||||||
required_permissions = "BAN_MEMBERS",
|
|
||||||
aliases("ban_multi")
|
|
||||||
)]
|
|
||||||
pub async fn mass_ban(
|
|
||||||
ctx: Context<'_>,
|
|
||||||
#[description = "Comma separated list of users to ban"] users: String,
|
|
||||||
#[description = "Reason to ban"] reason: Option<String>,
|
|
||||||
#[description = "Number of days to purge their messages from (defaults to 0)"]
|
|
||||||
purge_messages_days: Option<u8>,
|
|
||||||
#[description = "If true, the reply from the bot will be ephemeral"] quiet: Option<bool>,
|
|
||||||
#[description = "If true, the affected user will be sent a DM"] dm_user: Option<bool>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let gid = ctx
|
|
||||||
.guild_id()
|
|
||||||
.ok_or_else(|| eyre!("Couldn't get GuildId!"))?;
|
|
||||||
|
|
||||||
let dmd = purge_messages_days.unwrap_or(0);
|
|
||||||
let users: Vec<User> = split_argument(&ctx, Some(gid), None, users).await?;
|
|
||||||
|
|
||||||
for user in &users {
|
|
||||||
let action = ModAction {
|
|
||||||
reason: reason.clone(),
|
|
||||||
data: Ban {
|
|
||||||
purge_messages_days: dmd,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
action.handle(&ctx, user, quiet, dm_user, false).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let resp = format!("{} users banned!", users.len());
|
|
||||||
ctx.reply(resp).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Kick a user
|
|
||||||
#[poise::command(
|
|
||||||
slash_command,
|
|
||||||
prefix_command,
|
|
||||||
guild_only,
|
|
||||||
default_member_permissions = "KICK_MEMBERS",
|
|
||||||
required_permissions = "KICK_MEMBERS",
|
|
||||||
aliases("kick")
|
|
||||||
)]
|
|
||||||
pub async fn kick_user(
|
|
||||||
ctx: Context<'_>,
|
|
||||||
#[description = "User to kick"] user: User,
|
|
||||||
#[description = "Reason to kick"] reason: Option<String>,
|
|
||||||
#[description = "If true, the reply from the bot will be ephemeral"] quiet: Option<bool>,
|
|
||||||
#[description = "If true, the affected user will be sent a DM"] dm_user: Option<bool>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let action = ModAction {
|
|
||||||
reason,
|
|
||||||
data: Kick {},
|
|
||||||
};
|
|
||||||
|
|
||||||
action.handle(&ctx, &user, quiet, dm_user, true).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Kick multiple users
|
|
||||||
#[poise::command(
|
|
||||||
slash_command,
|
|
||||||
prefix_command,
|
|
||||||
guild_only,
|
|
||||||
default_member_permissions = "KICK_MEMBERS",
|
|
||||||
required_permissions = "KICK_MEMBERS",
|
|
||||||
aliases("multi_kick")
|
|
||||||
)]
|
|
||||||
pub async fn mass_kick(
|
|
||||||
ctx: Context<'_>,
|
|
||||||
#[description = "Comma separated list of users to kick"] users: String,
|
|
||||||
#[description = "Reason to kick"] reason: Option<String>,
|
|
||||||
#[description = "If true, the reply from the bot will be ephemeral"] quiet: Option<bool>,
|
|
||||||
#[description = "If true, the affected user will be sent a DM"] dm_user: Option<bool>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let gid = ctx
|
|
||||||
.guild_id()
|
|
||||||
.ok_or_else(|| eyre!("Couldn't get GuildId!"))?;
|
|
||||||
let users: Vec<User> = split_argument(&ctx, Some(gid), None, users).await?;
|
|
||||||
|
|
||||||
for user in &users {
|
|
||||||
let action = ModAction {
|
|
||||||
reason: reason.clone(),
|
|
||||||
data: Kick {},
|
|
||||||
};
|
|
||||||
|
|
||||||
action.handle(&ctx, user, quiet, dm_user, false).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let resp = format!("{} users kicked!", users.len());
|
|
||||||
ctx.reply(resp).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
use crate::consts::COLORS;
|
|
||||||
use crate::Data;
|
|
||||||
|
|
||||||
use color_eyre::eyre::{eyre, Result};
|
|
||||||
use log::debug;
|
|
||||||
use poise::serenity_prelude::{
|
|
||||||
ChannelId, Colour, Http, Message, MessageId, MessageUpdateEvent, User,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
|
||||||
pub async fn log_msg<T>(user: &User, content: String, color: T) -> Result<()>
|
|
||||||
where
|
|
||||||
T: Into<Colour>,
|
|
||||||
{
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_create(data: &Data, msg: &Message) -> Result<()> {
|
|
||||||
let channel_id = msg.channel_id;
|
|
||||||
let message_id = msg.id;
|
|
||||||
let content = &msg.content;
|
|
||||||
let author_id = msg.author.id;
|
|
||||||
|
|
||||||
debug!("Logging message {message_id}");
|
|
||||||
data.storage
|
|
||||||
.store_message(&channel_id, &message_id, content.to_string(), author_id)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_update(data: &Data, event: &MessageUpdateEvent) -> Result<()> {
|
|
||||||
let stored = data
|
|
||||||
.storage
|
|
||||||
.get_message(&event.channel_id, &event.id)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let new_content = event.content.as_ref().ok_or_else(|| {
|
|
||||||
eyre!("Couldn't get content from event! Is the MESSAGE_CONTENT intent enabled?")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let author = event
|
|
||||||
.author
|
|
||||||
.as_ref()
|
|
||||||
.ok_or_else(|| eyre!("Couldn't get author from message!"))?;
|
|
||||||
|
|
||||||
if new_content != &stored.content {
|
|
||||||
log_msg(author, new_content.to_string(), COLORS["yellow"]).await?;
|
|
||||||
|
|
||||||
debug!("Updating message {}", event.id);
|
|
||||||
data.storage
|
|
||||||
.store_message(
|
|
||||||
&event.channel_id,
|
|
||||||
&event.id,
|
|
||||||
new_content.to_string(),
|
|
||||||
author.id,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_delete(
|
|
||||||
http: impl AsRef<Http>,
|
|
||||||
data: &Data,
|
|
||||||
channel_id: &ChannelId,
|
|
||||||
message_id: &MessageId,
|
|
||||||
) -> Result<()> {
|
|
||||||
let stored = data.storage.get_message(channel_id, message_id).await?;
|
|
||||||
let user = http.as_ref().get_user(*stored.author.as_u64()).await?;
|
|
||||||
|
|
||||||
log_msg(&user, stored.content, COLORS["red"]).await?;
|
|
||||||
|
|
||||||
debug!("Deleting message {message_id}");
|
|
||||||
data.storage.delete_message(channel_id, message_id).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -9,7 +9,6 @@ mod analyze_logs;
|
||||||
mod delete_on_reaction;
|
mod delete_on_reaction;
|
||||||
mod eta;
|
mod eta;
|
||||||
mod expand_link;
|
mod expand_link;
|
||||||
mod message_logger;
|
|
||||||
pub mod pluralkit;
|
pub mod pluralkit;
|
||||||
mod support_onboard;
|
mod support_onboard;
|
||||||
|
|
||||||
|
@ -48,28 +47,11 @@ pub async fn handle(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// store all new messages to monitor edits and deletes
|
|
||||||
message_logger::handle_create(data, new_message).await?;
|
|
||||||
|
|
||||||
eta::handle(ctx, new_message).await?;
|
eta::handle(ctx, new_message).await?;
|
||||||
expand_link::handle(ctx, new_message).await?;
|
expand_link::handle(ctx, new_message).await?;
|
||||||
analyze_logs::handle(ctx, new_message, data).await?;
|
analyze_logs::handle(ctx, new_message, data).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::MessageDelete {
|
|
||||||
channel_id,
|
|
||||||
deleted_message_id,
|
|
||||||
guild_id: _,
|
|
||||||
} => message_logger::handle_delete(ctx, data, channel_id, deleted_message_id).await?,
|
|
||||||
|
|
||||||
Event::MessageUpdate {
|
|
||||||
old_if_available: _,
|
|
||||||
new: _,
|
|
||||||
event,
|
|
||||||
} => {
|
|
||||||
message_logger::handle_update(data, event).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Event::ReactionAdd { add_reaction } => {
|
Event::ReactionAdd { add_reaction } => {
|
||||||
delete_on_reaction::handle(ctx, add_reaction).await?
|
delete_on_reaction::handle(ctx, add_reaction).await?
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
use poise::serenity_prelude::UserId;
|
|
||||||
use redis_macros::{FromRedisValue, ToRedisArgs};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
pub const MSG_LOG_KEY: &str = "message-log-v1";
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize, FromRedisValue, ToRedisArgs)]
|
|
||||||
pub struct MessageLog {
|
|
||||||
pub author: UserId,
|
|
||||||
pub content: String,
|
|
||||||
}
|
|
|
@ -2,12 +2,9 @@ use std::fmt::Debug;
|
||||||
|
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use log::*;
|
use log::*;
|
||||||
use poise::serenity_prelude::{ChannelId, MessageId, UserId};
|
use poise::serenity_prelude::UserId;
|
||||||
use redis::{AsyncCommands as _, Client, FromRedisValue, ToRedisArgs};
|
use redis::{AsyncCommands as _, Client, FromRedisValue, ToRedisArgs};
|
||||||
|
|
||||||
pub mod message_logger;
|
|
||||||
use message_logger::*;
|
|
||||||
|
|
||||||
const PK_KEY: &str = "pluralkit-v1";
|
const PK_KEY: &str = "pluralkit-v1";
|
||||||
const LAUNCHER_VERSION_KEY: &str = "launcher-version-v1";
|
const LAUNCHER_VERSION_KEY: &str = "launcher-version-v1";
|
||||||
|
|
||||||
|
@ -97,45 +94,6 @@ impl Storage {
|
||||||
self.key_exists(&key).await
|
self.key_exists(&key).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn store_message(
|
|
||||||
&self,
|
|
||||||
channel_id: &ChannelId,
|
|
||||||
message_id: &MessageId,
|
|
||||||
content: String,
|
|
||||||
author: UserId,
|
|
||||||
) -> Result<()> {
|
|
||||||
let key = format!("{MSG_LOG_KEY}:{channel_id}:{message_id}");
|
|
||||||
|
|
||||||
let val = MessageLog { author, content };
|
|
||||||
|
|
||||||
self.set_key(&key, val).await?;
|
|
||||||
self.expire_key(&key, 30 * 24 * 60 * 60).await?; // only store for 30 days
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_message(
|
|
||||||
&self,
|
|
||||||
channel_id: &ChannelId,
|
|
||||||
message_id: &MessageId,
|
|
||||||
) -> Result<MessageLog> {
|
|
||||||
let key = format!("{MSG_LOG_KEY}:{channel_id}:{message_id}");
|
|
||||||
let res = self.get_key(&key).await?;
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn delete_message(
|
|
||||||
&self,
|
|
||||||
channel_id: &ChannelId,
|
|
||||||
message_id: &MessageId,
|
|
||||||
) -> Result<()> {
|
|
||||||
let key = format!("{MSG_LOG_KEY}:{channel_id}:{message_id}");
|
|
||||||
self.delete_key(&key).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn cache_launcher_version(&self, version: &str) -> Result<()> {
|
pub async fn cache_launcher_version(&self, version: &str) -> Result<()> {
|
||||||
self.set_key(LAUNCHER_VERSION_KEY, version).await?;
|
self.set_key(LAUNCHER_VERSION_KEY, version).await?;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue