removed all guild data related code
This commit is contained in:
parent
44debf93c5
commit
e36e718f28
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1201,7 +1201,6 @@ dependencies = [
|
|||||||
"base64",
|
"base64",
|
||||||
"chrono",
|
"chrono",
|
||||||
"chrono-tz",
|
"chrono-tz",
|
||||||
"dashmap",
|
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"humantime",
|
"humantime",
|
||||||
|
@ -5,7 +5,6 @@ authors = ["jellywx <judesouthworth@pm.me>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dashmap = "4.0"
|
|
||||||
dotenv = "0.15"
|
dotenv = "0.15"
|
||||||
humantime = "2.1"
|
humantime = "2.1"
|
||||||
tokio = { version = "1", features = ["process", "full"] }
|
tokio = { version = "1", features = ["process", "full"] }
|
||||||
|
@ -3,7 +3,6 @@ use regex_command_attr::command;
|
|||||||
use serenity::{builder::CreateEmbedFooter, client::Context};
|
use serenity::{builder::CreateEmbedFooter, client::Context};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
consts::DEFAULT_PREFIX,
|
|
||||||
framework::{CommandInvoke, CreateGenericResponse},
|
framework::{CommandInvoke, CreateGenericResponse},
|
||||||
models::CtxData,
|
models::CtxData,
|
||||||
THEME_COLOR,
|
THEME_COLOR,
|
||||||
@ -28,8 +27,6 @@ fn footer(ctx: &Context) -> impl FnOnce(&mut CreateEmbedFooter) -> &mut CreateEm
|
|||||||
#[description("Get information about the bot")]
|
#[description("Get information about the bot")]
|
||||||
#[group("Info")]
|
#[group("Info")]
|
||||||
async fn info(ctx: &Context, invoke: &mut CommandInvoke) {
|
async fn info(ctx: &Context, invoke: &mut CommandInvoke) {
|
||||||
let prefix = ctx.prefix(invoke.guild_id()).await;
|
|
||||||
let current_user = ctx.cache.current_user();
|
|
||||||
let footer = footer(ctx);
|
let footer = footer(ctx);
|
||||||
|
|
||||||
let _ = invoke
|
let _ = invoke
|
||||||
@ -38,18 +35,15 @@ async fn info(ctx: &Context, invoke: &mut CommandInvoke) {
|
|||||||
CreateGenericResponse::new().embed(|e| {
|
CreateGenericResponse::new().embed(|e| {
|
||||||
e.title("Info")
|
e.title("Info")
|
||||||
.description(format!(
|
.description(format!(
|
||||||
"Default prefix: `{default_prefix}`
|
"Help: `/help`
|
||||||
Reset prefix: `@{user} prefix {default_prefix}`
|
|
||||||
Help: `{prefix}help`**Welcome to Reminder Bot!**
|
**Welcome to Reminder Bot!**
|
||||||
Developer: <@203532103185465344>
|
Developer: <@203532103185465344>
|
||||||
Icon: <@253202252821430272>
|
Icon: <@253202252821430272>
|
||||||
Find me on https://discord.jellywx.com and on https://github.com/JellyWX :)
|
Find me on https://discord.jellywx.com and on https://github.com/JellyWX :)
|
||||||
|
|
||||||
Invite the bot: https://invite.reminder-bot.com/
|
Invite the bot: https://invite.reminder-bot.com/
|
||||||
Use our dashboard: https://reminder-bot.com/",
|
Use our dashboard: https://reminder-bot.com/",
|
||||||
default_prefix = *DEFAULT_PREFIX,
|
|
||||||
user = current_user.name,
|
|
||||||
prefix = prefix
|
|
||||||
))
|
))
|
||||||
.footer(footer)
|
.footer(footer)
|
||||||
.color(*THEME_COLOR)
|
.color(*THEME_COLOR)
|
||||||
|
@ -12,7 +12,7 @@ use crate::{
|
|||||||
consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR},
|
consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR},
|
||||||
framework::{CommandInvoke, CommandOptions, CreateGenericResponse, OptionValue},
|
framework::{CommandInvoke, CommandOptions, CreateGenericResponse, OptionValue},
|
||||||
hooks::{CHECK_GUILD_PERMISSIONS_HOOK, CHECK_MANAGED_PERMISSIONS_HOOK},
|
hooks::{CHECK_GUILD_PERMISSIONS_HOOK, CHECK_MANAGED_PERMISSIONS_HOOK},
|
||||||
models::{channel_data::ChannelData, command_macro::CommandMacro, CtxData},
|
models::{command_macro::CommandMacro, CtxData},
|
||||||
PopularTimezones, RecordingMacros, RegexFramework, SQLPool,
|
PopularTimezones, RecordingMacros, RegexFramework, SQLPool,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ use regex_command_attr::command;
|
|||||||
use serenity::{builder::CreateEmbed, client::Context, model::channel::Channel};
|
use serenity::{builder::CreateEmbed, client::Context, model::channel::Channel};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
check_subscription_on_message,
|
|
||||||
component_models::{
|
component_models::{
|
||||||
pager::{DelPager, LookPager, Pager},
|
pager::{DelPager, LookPager, Pager},
|
||||||
ComponentDataModel, DelSelector,
|
ComponentDataModel, DelSelector,
|
||||||
|
@ -10,42 +10,22 @@ const THEME_COLOR_FALLBACK: u32 = 0x8fb677;
|
|||||||
|
|
||||||
use std::{collections::HashSet, env, iter::FromIterator};
|
use std::{collections::HashSet, env, iter::FromIterator};
|
||||||
|
|
||||||
use regex::{Regex, RegexBuilder};
|
use regex::Regex;
|
||||||
use serenity::http::AttachmentType;
|
use serenity::http::AttachmentType;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref DEFAULT_AVATAR: AttachmentType<'static> = (
|
pub static ref DEFAULT_AVATAR: AttachmentType<'static> = (
|
||||||
include_bytes!(concat!(
|
include_bytes!(concat!(
|
||||||
env!("CARGO_MANIFEST_DIR"),
|
env!("CARGO_MANIFEST_DIR"),
|
||||||
"/assets/",
|
"/assets/",
|
||||||
env!("WEBHOOK_AVATAR", "WEBHOOK_AVATAR not provided for compilation")
|
env!("WEBHOOK_AVATAR", "WEBHOOK_AVATAR not provided for compilation")
|
||||||
)) as &[u8],
|
)) as &[u8],
|
||||||
env!("WEBHOOK_AVATAR"),
|
env!("WEBHOOK_AVATAR"),
|
||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
pub static ref REGEX_CHANNEL: Regex = Regex::new(r#"^\s*<#(\d+)>\s*$"#).unwrap();
|
pub static ref REGEX_CHANNEL: Regex = Regex::new(r#"^\s*<#(\d+)>\s*$"#).unwrap();
|
||||||
|
|
||||||
pub static ref REGEX_ROLE: Regex = Regex::new(r#"<@&(\d+)>"#).unwrap();
|
pub static ref REGEX_ROLE: Regex = Regex::new(r#"<@&(\d+)>"#).unwrap();
|
||||||
|
|
||||||
pub static ref REGEX_CONTENT_SUBSTITUTION: Regex = Regex::new(r#"<<((?P<user>\d+)|(?P<role>.{1,100}))>>"#).unwrap();
|
|
||||||
|
|
||||||
pub static ref REGEX_CHANNEL_USER: Regex = Regex::new(r#"\s*<(#|@)(?:!)?(\d+)>\s*"#).unwrap();
|
pub static ref REGEX_CHANNEL_USER: Regex = Regex::new(r#"\s*<(#|@)(?:!)?(\d+)>\s*"#).unwrap();
|
||||||
|
|
||||||
pub static ref REGEX_NATURAL_COMMAND_1: Regex = RegexBuilder::new(
|
|
||||||
r#"(?P<time>.*?)(?:\s+)(?:send|say)(?:\s+)(?P<msg>.*?)(?:(?:\s+)to(?:\s+)(?P<mentions>((?:<@\d+>)|(?:<@!\d+>)|(?:<#\d+>)|(?:\s+))+))?$"#
|
|
||||||
)
|
|
||||||
.dot_matches_new_line(true)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
pub static ref REGEX_NATURAL_COMMAND_2: Regex = RegexBuilder::new(
|
|
||||||
r#"(?P<msg>.*)(?:\s+)every(?:\s+)(?P<interval>.*?)(?:(?:\s+)(?:until|for)(?:\s+)(?P<expires>.*?))?$"#
|
|
||||||
)
|
|
||||||
.dot_matches_new_line(true)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
pub static ref SUBSCRIPTION_ROLES: HashSet<u64> = HashSet::from_iter(
|
pub static ref SUBSCRIPTION_ROLES: HashSet<u64> = HashSet::from_iter(
|
||||||
env::var("SUBSCRIPTION_ROLES")
|
env::var("SUBSCRIPTION_ROLES")
|
||||||
.map(|var| var
|
.map(|var| var
|
||||||
@ -54,35 +34,23 @@ lazy_static! {
|
|||||||
.collect::<Vec<u64>>())
|
.collect::<Vec<u64>>())
|
||||||
.unwrap_or_else(|_| Vec::new())
|
.unwrap_or_else(|_| Vec::new())
|
||||||
);
|
);
|
||||||
|
pub static ref CNC_GUILD: Option<u64> =
|
||||||
pub static ref CNC_GUILD: Option<u64> = env::var("CNC_GUILD")
|
env::var("CNC_GUILD").map(|var| var.parse::<u64>().ok()).ok().flatten();
|
||||||
.map(|var| var.parse::<u64>().ok())
|
|
||||||
.ok()
|
|
||||||
.flatten();
|
|
||||||
|
|
||||||
pub static ref MIN_INTERVAL: i64 = env::var("MIN_INTERVAL")
|
pub static ref MIN_INTERVAL: i64 = env::var("MIN_INTERVAL")
|
||||||
.ok()
|
.ok()
|
||||||
.map(|inner| inner.parse::<i64>().ok())
|
.map(|inner| inner.parse::<i64>().ok())
|
||||||
.flatten()
|
.flatten()
|
||||||
.unwrap_or(600);
|
.unwrap_or(600);
|
||||||
|
|
||||||
pub static ref MAX_TIME: i64 = env::var("MAX_TIME")
|
pub static ref MAX_TIME: i64 = env::var("MAX_TIME")
|
||||||
.ok()
|
.ok()
|
||||||
.map(|inner| inner.parse::<i64>().ok())
|
.map(|inner| inner.parse::<i64>().ok())
|
||||||
.flatten()
|
.flatten()
|
||||||
.unwrap_or(60 * 60 * 24 * 365 * 50);
|
.unwrap_or(60 * 60 * 24 * 365 * 50);
|
||||||
|
|
||||||
pub static ref LOCAL_TIMEZONE: String =
|
pub static ref LOCAL_TIMEZONE: String =
|
||||||
env::var("LOCAL_TIMEZONE").unwrap_or_else(|_| "UTC".to_string());
|
env::var("LOCAL_TIMEZONE").unwrap_or_else(|_| "UTC".to_string());
|
||||||
|
pub static ref THEME_COLOR: u32 = env::var("THEME_COLOR")
|
||||||
pub static ref DEFAULT_PREFIX: String =
|
.map_or(THEME_COLOR_FALLBACK, |inner| u32::from_str_radix(&inner, 16)
|
||||||
env::var("DEFAULT_PREFIX").unwrap_or_else(|_| "$".to_string());
|
.unwrap_or(THEME_COLOR_FALLBACK));
|
||||||
|
|
||||||
pub static ref THEME_COLOR: u32 = env::var("THEME_COLOR").map_or(
|
|
||||||
THEME_COLOR_FALLBACK,
|
|
||||||
|inner| u32::from_str_radix(&inner, 16).unwrap_or(THEME_COLOR_FALLBACK)
|
|
||||||
);
|
|
||||||
|
|
||||||
pub static ref PYTHON_LOCATION: String =
|
pub static ref PYTHON_LOCATION: String =
|
||||||
env::var("PYTHON_LOCATION").unwrap_or_else(|_| "venv/bin/python3".to_string());
|
env::var("PYTHON_LOCATION").unwrap_or_else(|_| "venv/bin/python3".to_string());
|
||||||
}
|
}
|
||||||
|
189
src/framework.rs
189
src/framework.rs
@ -7,7 +7,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use regex::{Match, Regex, RegexBuilder};
|
use regex::{Regex, RegexBuilder};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serenity::{
|
use serenity::{
|
||||||
async_trait,
|
async_trait,
|
||||||
@ -16,11 +16,11 @@ use serenity::{
|
|||||||
client::Context,
|
client::Context,
|
||||||
framework::Framework,
|
framework::Framework,
|
||||||
futures::prelude::future::BoxFuture,
|
futures::prelude::future::BoxFuture,
|
||||||
http::{CacheHttp, Http},
|
http::Http,
|
||||||
model::{
|
model::{
|
||||||
channel::Message,
|
channel::Message,
|
||||||
guild::{Guild, Member},
|
guild::{Guild, Member},
|
||||||
id::{ChannelId, GuildId, MessageId, RoleId, UserId},
|
id::{ChannelId, GuildId, RoleId, UserId},
|
||||||
interactions::{
|
interactions::{
|
||||||
application_command::{
|
application_command::{
|
||||||
ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType,
|
ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType,
|
||||||
@ -34,7 +34,7 @@ use serenity::{
|
|||||||
Result as SerenityResult,
|
Result as SerenityResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{models::CtxData, LimitExecutors};
|
use crate::LimitExecutors;
|
||||||
|
|
||||||
pub struct CreateGenericResponse {
|
pub struct CreateGenericResponse {
|
||||||
content: String,
|
content: String,
|
||||||
@ -89,7 +89,6 @@ impl CreateGenericResponse {
|
|||||||
enum InvokeModel {
|
enum InvokeModel {
|
||||||
Slash(ApplicationCommandInteraction),
|
Slash(ApplicationCommandInteraction),
|
||||||
Component(MessageComponentInteraction),
|
Component(MessageComponentInteraction),
|
||||||
Text(Message),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -108,10 +107,6 @@ impl CommandInvoke {
|
|||||||
Self { model: InvokeModel::Slash(interaction), already_responded: false, deferred: false }
|
Self { model: InvokeModel::Slash(interaction), already_responded: false, deferred: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn msg(msg: Message) -> Self {
|
|
||||||
Self { model: InvokeModel::Text(msg), already_responded: false, deferred: false }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn defer(&mut self, http: impl AsRef<Http>) {
|
pub async fn defer(&mut self, http: impl AsRef<Http>) {
|
||||||
if !self.deferred {
|
if !self.deferred {
|
||||||
match &self.model {
|
match &self.model {
|
||||||
@ -133,7 +128,6 @@ impl CommandInvoke {
|
|||||||
|
|
||||||
self.deferred = true;
|
self.deferred = true;
|
||||||
}
|
}
|
||||||
InvokeModel::Text(_) => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,7 +136,6 @@ impl CommandInvoke {
|
|||||||
match &self.model {
|
match &self.model {
|
||||||
InvokeModel::Slash(i) => i.channel_id,
|
InvokeModel::Slash(i) => i.channel_id,
|
||||||
InvokeModel::Component(i) => i.channel_id,
|
InvokeModel::Component(i) => i.channel_id,
|
||||||
InvokeModel::Text(m) => m.channel_id,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +143,6 @@ impl CommandInvoke {
|
|||||||
match &self.model {
|
match &self.model {
|
||||||
InvokeModel::Slash(i) => i.guild_id,
|
InvokeModel::Slash(i) => i.guild_id,
|
||||||
InvokeModel::Component(i) => i.guild_id,
|
InvokeModel::Component(i) => i.guild_id,
|
||||||
InvokeModel::Text(m) => m.guild_id,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,15 +154,13 @@ impl CommandInvoke {
|
|||||||
match &self.model {
|
match &self.model {
|
||||||
InvokeModel::Slash(i) => i.user.id,
|
InvokeModel::Slash(i) => i.user.id,
|
||||||
InvokeModel::Component(i) => i.user.id,
|
InvokeModel::Component(i) => i.user.id,
|
||||||
InvokeModel::Text(m) => m.author.id,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn member(&self, cache_http: impl CacheHttp) -> Option<Member> {
|
pub fn member(&self) -> Option<Member> {
|
||||||
match &self.model {
|
match &self.model {
|
||||||
InvokeModel::Slash(i) => i.member.clone(),
|
InvokeModel::Slash(i) => i.member.clone(),
|
||||||
InvokeModel::Component(i) => i.member.clone(),
|
InvokeModel::Component(i) => i.member.clone(),
|
||||||
InvokeModel::Text(m) => m.member(cache_http).await.ok(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,26 +254,6 @@ impl CommandInvoke {
|
|||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.map(|_| ()),
|
.map(|_| ()),
|
||||||
InvokeModel::Text(m) => m
|
|
||||||
.channel_id
|
|
||||||
.send_message(http, |m| {
|
|
||||||
m.content(generic_response.content);
|
|
||||||
|
|
||||||
if let Some(embed) = generic_response.embed {
|
|
||||||
m.set_embed(embed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(components) = generic_response.components {
|
|
||||||
m.components(|c| {
|
|
||||||
*c = components;
|
|
||||||
c
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
m
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.map(|_| ()),
|
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
self.already_responded = true;
|
self.already_responded = true;
|
||||||
@ -484,9 +454,6 @@ pub enum HookResult {
|
|||||||
type SlashCommandFn =
|
type SlashCommandFn =
|
||||||
for<'fut> fn(&'fut Context, &'fut mut CommandInvoke, CommandOptions) -> BoxFuture<'fut, ()>;
|
for<'fut> fn(&'fut Context, &'fut mut CommandInvoke, CommandOptions) -> BoxFuture<'fut, ()>;
|
||||||
|
|
||||||
type TextCommandFn =
|
|
||||||
for<'fut> fn(&'fut Context, &'fut mut CommandInvoke, String) -> BoxFuture<'fut, ()>;
|
|
||||||
|
|
||||||
type MultiCommandFn = for<'fut> fn(&'fut Context, &'fut mut CommandInvoke) -> BoxFuture<'fut, ()>;
|
type MultiCommandFn = for<'fut> fn(&'fut Context, &'fut mut CommandInvoke) -> BoxFuture<'fut, ()>;
|
||||||
|
|
||||||
pub type HookFn = for<'fut> fn(
|
pub type HookFn = for<'fut> fn(
|
||||||
@ -497,16 +464,9 @@ pub type HookFn = for<'fut> fn(
|
|||||||
|
|
||||||
pub enum CommandFnType {
|
pub enum CommandFnType {
|
||||||
Slash(SlashCommandFn),
|
Slash(SlashCommandFn),
|
||||||
Text(TextCommandFn),
|
|
||||||
Multi(MultiCommandFn),
|
Multi(MultiCommandFn),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandFnType {
|
|
||||||
pub fn is_slash(&self) -> bool {
|
|
||||||
!matches!(self, CommandFnType::Text(_))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Hook {
|
pub struct Hook {
|
||||||
pub fun: HookFn,
|
pub fun: HookFn,
|
||||||
pub uuid: u128,
|
pub uuid: u128,
|
||||||
@ -697,44 +657,42 @@ impl RegexFramework {
|
|||||||
commands: &'a mut CreateApplicationCommands,
|
commands: &'a mut CreateApplicationCommands,
|
||||||
) -> &'a mut CreateApplicationCommands {
|
) -> &'a mut CreateApplicationCommands {
|
||||||
for command in &self.commands {
|
for command in &self.commands {
|
||||||
if command.fun.is_slash() {
|
commands.create_application_command(|c| {
|
||||||
commands.create_application_command(|c| {
|
c.name(command.names[0]).description(command.desc);
|
||||||
c.name(command.names[0]).description(command.desc);
|
|
||||||
|
|
||||||
for arg in command.args {
|
for arg in command.args {
|
||||||
c.create_option(|o| {
|
c.create_option(|o| {
|
||||||
o.name(arg.name)
|
o.name(arg.name)
|
||||||
.description(arg.description)
|
.description(arg.description)
|
||||||
.kind(arg.kind)
|
.kind(arg.kind)
|
||||||
.required(arg.required);
|
.required(arg.required);
|
||||||
|
|
||||||
for option in arg.options {
|
for option in arg.options {
|
||||||
o.create_sub_option(|s| {
|
o.create_sub_option(|s| {
|
||||||
s.name(option.name)
|
s.name(option.name)
|
||||||
.description(option.description)
|
.description(option.description)
|
||||||
.kind(option.kind)
|
.kind(option.kind)
|
||||||
.required(option.required);
|
.required(option.required);
|
||||||
|
|
||||||
for sub_option in option.options {
|
for sub_option in option.options {
|
||||||
s.create_sub_option(|ss| {
|
s.create_sub_option(|ss| {
|
||||||
ss.name(sub_option.name)
|
ss.name(sub_option.name)
|
||||||
.description(sub_option.description)
|
.description(sub_option.description)
|
||||||
.kind(sub_option.kind)
|
.kind(sub_option.kind)
|
||||||
.required(sub_option.required)
|
.required(sub_option.required)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
s
|
s
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
o
|
o
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
c
|
c
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
commands
|
commands
|
||||||
@ -798,7 +756,6 @@ impl RegexFramework {
|
|||||||
match command.fun {
|
match command.fun {
|
||||||
CommandFnType::Slash(t) => t(&ctx, &mut command_invoke, args).await,
|
CommandFnType::Slash(t) => t(&ctx, &mut command_invoke, args).await,
|
||||||
CommandFnType::Multi(m) => m(&ctx, &mut command_invoke).await,
|
CommandFnType::Multi(m) => m(&ctx, &mut command_invoke).await,
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.drop_executing(user_id).await;
|
ctx.drop_executing(user_id).await;
|
||||||
@ -820,85 +777,11 @@ impl RegexFramework {
|
|||||||
match command.fun {
|
match command.fun {
|
||||||
CommandFnType::Slash(t) => t(&ctx, command_invoke, command_options).await,
|
CommandFnType::Slash(t) => t(&ctx, command_invoke, command_options).await,
|
||||||
CommandFnType::Multi(m) => m(&ctx, command_invoke).await,
|
CommandFnType::Multi(m) => m(&ctx, command_invoke).await,
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Framework for RegexFramework {
|
impl Framework for RegexFramework {
|
||||||
async fn dispatch(&self, ctx: Context, msg: Message) {
|
async fn dispatch(&self, _ctx: Context, _msg: Message) {}
|
||||||
async fn check_prefix(ctx: &Context, guild: &Guild, prefix_opt: Option<Match<'_>>) -> bool {
|
|
||||||
if let Some(prefix) = prefix_opt {
|
|
||||||
let guild_prefix = ctx.prefix(Some(guild.id)).await;
|
|
||||||
|
|
||||||
guild_prefix.as_str() == prefix.as_str()
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// gate to prevent analysing messages unnecessarily
|
|
||||||
if (msg.author.bot && self.ignore_bots) || msg.content.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let user_id = msg.author.id;
|
|
||||||
let mut invoke = CommandInvoke::msg(msg.clone());
|
|
||||||
|
|
||||||
// Guild Command
|
|
||||||
if let Some(guild) = msg.guild(&ctx) {
|
|
||||||
if let Some(full_match) = self.command_matcher.captures(&msg.content) {
|
|
||||||
if check_prefix(&ctx, &guild, full_match.name("prefix")).await {
|
|
||||||
let command = self
|
|
||||||
.commands_map
|
|
||||||
.get(&full_match.name("cmd").unwrap().as_str().to_lowercase())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let channel_data = ctx.channel_data(invoke.channel_id()).await.unwrap();
|
|
||||||
|
|
||||||
if !command.can_blacklist || !channel_data.blacklisted {
|
|
||||||
let args =
|
|
||||||
full_match.name("args").map(|m| m.as_str()).unwrap_or("").to_string();
|
|
||||||
|
|
||||||
if msg.id == MessageId(0) || !ctx.check_executing(user_id).await {
|
|
||||||
ctx.set_executing(user_id).await;
|
|
||||||
|
|
||||||
match command.fun {
|
|
||||||
CommandFnType::Text(t) => t(&ctx, &mut invoke, args).await,
|
|
||||||
CommandFnType::Multi(m) => m(&ctx, &mut invoke).await,
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
ctx.drop_executing(user_id).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// DM Command
|
|
||||||
else if self.dm_enabled {
|
|
||||||
if let Some(full_match) = self.dm_regex_matcher.captures(&msg.content[..]) {
|
|
||||||
let command = self
|
|
||||||
.commands_map
|
|
||||||
.get(&full_match.name("cmd").unwrap().as_str().to_lowercase())
|
|
||||||
.unwrap();
|
|
||||||
let args = full_match.name("args").map(|m| m.as_str()).unwrap_or("").to_string();
|
|
||||||
|
|
||||||
let user_id = invoke.author_id();
|
|
||||||
|
|
||||||
if msg.id == MessageId(0) || !ctx.check_executing(user_id).await {
|
|
||||||
ctx.set_executing(user_id).await;
|
|
||||||
|
|
||||||
match command.fun {
|
|
||||||
CommandFnType::Text(t) => t(&ctx, &mut invoke, args).await,
|
|
||||||
CommandFnType::Multi(m) => m(&ctx, &mut invoke).await,
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
ctx.drop_executing(user_id).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ pub async fn check_managed_permissions(
|
|||||||
return HookResult::Continue;
|
return HookResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let member = invoke.member(&ctx).await.unwrap();
|
let member = invoke.member().unwrap();
|
||||||
|
|
||||||
let pool = ctx
|
let pool = ctx
|
||||||
.data
|
.data
|
||||||
|
75
src/main.rs
75
src/main.rs
@ -13,19 +13,17 @@ mod time_parser;
|
|||||||
use std::{collections::HashMap, env, sync::Arc, time::Instant};
|
use std::{collections::HashMap, env, sync::Arc, time::Instant};
|
||||||
|
|
||||||
use chrono_tz::Tz;
|
use chrono_tz::Tz;
|
||||||
use dashmap::DashMap;
|
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
use log::info;
|
use log::info;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
async_trait,
|
async_trait,
|
||||||
cache::Cache,
|
|
||||||
client::{bridge::gateway::GatewayIntents, Client},
|
client::{bridge::gateway::GatewayIntents, Client},
|
||||||
futures::TryFutureExt,
|
futures::TryFutureExt,
|
||||||
http::{client::Http, CacheHttp},
|
http::{client::Http, CacheHttp},
|
||||||
model::{
|
model::{
|
||||||
channel::{GuildChannel, Message},
|
channel::GuildChannel,
|
||||||
gateway::{Activity, Ready},
|
gateway::{Activity, Ready},
|
||||||
guild::{Guild, GuildUnavailable},
|
guild::Guild,
|
||||||
id::{GuildId, UserId},
|
id::{GuildId, UserId},
|
||||||
interactions::Interaction,
|
interactions::Interaction,
|
||||||
},
|
},
|
||||||
@ -38,17 +36,11 @@ use tokio::sync::RwLock;
|
|||||||
use crate::{
|
use crate::{
|
||||||
commands::{info_cmds, moderation_cmds, reminder_cmds, todo_cmds},
|
commands::{info_cmds, moderation_cmds, reminder_cmds, todo_cmds},
|
||||||
component_models::ComponentDataModel,
|
component_models::ComponentDataModel,
|
||||||
consts::{CNC_GUILD, DEFAULT_PREFIX, SUBSCRIPTION_ROLES, THEME_COLOR},
|
consts::{CNC_GUILD, SUBSCRIPTION_ROLES, THEME_COLOR},
|
||||||
framework::RegexFramework,
|
framework::RegexFramework,
|
||||||
models::{command_macro::CommandMacro, guild_data::GuildData},
|
models::command_macro::CommandMacro,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GuildDataCache;
|
|
||||||
|
|
||||||
impl TypeMapKey for GuildDataCache {
|
|
||||||
type Value = Arc<DashMap<GuildId, Arc<RwLock<GuildData>>>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SQLPool;
|
struct SQLPool;
|
||||||
|
|
||||||
impl TypeMapKey for SQLPool {
|
impl TypeMapKey for SQLPool {
|
||||||
@ -156,20 +148,6 @@ DELETE FROM channels WHERE channel = ?
|
|||||||
if is_new {
|
if is_new {
|
||||||
let guild_id = guild.id.as_u64().to_owned();
|
let guild_id = guild.id.as_u64().to_owned();
|
||||||
|
|
||||||
{
|
|
||||||
let pool = ctx
|
|
||||||
.data
|
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
.get::<SQLPool>()
|
|
||||||
.cloned()
|
|
||||||
.expect("Could not get SQLPool from data");
|
|
||||||
|
|
||||||
GuildData::from_guild(guild, &pool).await.unwrap_or_else(|_| {
|
|
||||||
panic!("Failed to create new guild object for {}", guild_id)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(token) = env::var("DISCORDBOTS_TOKEN") {
|
if let Ok(token) = env::var("DISCORDBOTS_TOKEN") {
|
||||||
let shard_count = ctx.cache.shard_count();
|
let shard_count = ctx.cache.shard_count();
|
||||||
let current_shard_id = shard_id(guild_id, shard_count);
|
let current_shard_id = shard_id(guild_id, shard_count);
|
||||||
@ -214,34 +192,6 @@ DELETE FROM channels WHERE channel = ?
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn guild_delete(
|
|
||||||
&self,
|
|
||||||
ctx: Context,
|
|
||||||
deleted_guild: GuildUnavailable,
|
|
||||||
_guild: Option<Guild>,
|
|
||||||
) {
|
|
||||||
let pool = ctx
|
|
||||||
.data
|
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
.get::<SQLPool>()
|
|
||||||
.cloned()
|
|
||||||
.expect("Could not get SQLPool from data");
|
|
||||||
|
|
||||||
let guild_data_cache = ctx.data.read().await.get::<GuildDataCache>().cloned().unwrap();
|
|
||||||
guild_data_cache.remove(&deleted_guild.id);
|
|
||||||
|
|
||||||
sqlx::query!(
|
|
||||||
"
|
|
||||||
DELETE FROM guilds WHERE guild = ?
|
|
||||||
",
|
|
||||||
deleted_guild.id.as_u64()
|
|
||||||
)
|
|
||||||
.execute(&pool)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn ready(&self, ctx: Context, _: Ready) {
|
async fn ready(&self, ctx: Context, _: Ready) {
|
||||||
ctx.set_activity(Activity::watching("for /remind")).await;
|
ctx.set_activity(Activity::watching("for /remind")).await;
|
||||||
}
|
}
|
||||||
@ -288,7 +238,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
let dm_enabled = env::var("DM_ENABLED").map_or(true, |var| var == "1");
|
let dm_enabled = env::var("DM_ENABLED").map_or(true, |var| var == "1");
|
||||||
|
|
||||||
let framework = RegexFramework::new(logged_in_id)
|
let framework = RegexFramework::new(logged_in_id)
|
||||||
.default_prefix(DEFAULT_PREFIX.clone())
|
.default_prefix("")
|
||||||
.case_insensitive(env::var("CASE_INSENSITIVE").map_or(true, |var| var == "1"))
|
.case_insensitive(env::var("CASE_INSENSITIVE").map_or(true, |var| var == "1"))
|
||||||
.ignore_bots(env::var("IGNORE_BOTS").map_or(true, |var| var == "1"))
|
.ignore_bots(env::var("IGNORE_BOTS").map_or(true, |var| var == "1"))
|
||||||
.debug_guild(env::var("DEBUG_GUILD").map_or(None, |g| {
|
.debug_guild(env::var("DEBUG_GUILD").map_or(None, |g| {
|
||||||
@ -337,8 +287,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
.expect("Error occurred creating client");
|
.expect("Error occurred creating client");
|
||||||
|
|
||||||
{
|
{
|
||||||
let guild_data_cache = dashmap::DashMap::new();
|
|
||||||
|
|
||||||
let pool = MySqlPool::connect(
|
let pool = MySqlPool::connect(
|
||||||
&env::var("DATABASE_URL").expect("Missing DATABASE_URL from environment"),
|
&env::var("DATABASE_URL").expect("Missing DATABASE_URL from environment"),
|
||||||
)
|
)
|
||||||
@ -357,7 +305,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
|
|
||||||
let mut data = client.data.write().await;
|
let mut data = client.data.write().await;
|
||||||
|
|
||||||
data.insert::<GuildDataCache>(Arc::new(guild_data_cache));
|
|
||||||
data.insert::<CurrentlyExecuting>(Arc::new(RwLock::new(HashMap::new())));
|
data.insert::<CurrentlyExecuting>(Arc::new(RwLock::new(HashMap::new())));
|
||||||
data.insert::<SQLPool>(pool);
|
data.insert::<SQLPool>(pool);
|
||||||
data.insert::<PopularTimezones>(Arc::new(popular_timezones));
|
data.insert::<PopularTimezones>(Arc::new(popular_timezones));
|
||||||
@ -415,15 +362,3 @@ pub async fn check_subscription(cache_http: impl CacheHttp, user_id: impl Into<U
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn check_subscription_on_message(
|
|
||||||
cache_http: impl CacheHttp + AsRef<Cache>,
|
|
||||||
msg: &Message,
|
|
||||||
) -> bool {
|
|
||||||
check_subscription(&cache_http, &msg.author).await
|
|
||||||
|| if let Some(guild) = msg.guild(&cache_http) {
|
|
||||||
check_subscription(&cache_http, guild.owner_id).await
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
use log::error;
|
|
||||||
use serenity::model::guild::Guild;
|
|
||||||
use sqlx::MySqlPool;
|
|
||||||
|
|
||||||
use crate::consts::DEFAULT_PREFIX;
|
|
||||||
|
|
||||||
pub struct GuildData {
|
|
||||||
pub id: u32,
|
|
||||||
pub name: Option<String>,
|
|
||||||
pub prefix: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GuildData {
|
|
||||||
pub async fn from_guild(guild: Guild, pool: &MySqlPool) -> Result<Self, sqlx::Error> {
|
|
||||||
let guild_id = guild.id.as_u64().to_owned();
|
|
||||||
|
|
||||||
match sqlx::query_as!(
|
|
||||||
Self,
|
|
||||||
"
|
|
||||||
SELECT id, name, prefix FROM guilds WHERE guild = ?
|
|
||||||
",
|
|
||||||
guild_id
|
|
||||||
)
|
|
||||||
.fetch_one(pool)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(mut g) => {
|
|
||||||
g.name = Some(guild.name);
|
|
||||||
|
|
||||||
Ok(g)
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(sqlx::Error::RowNotFound) => {
|
|
||||||
sqlx::query!(
|
|
||||||
"
|
|
||||||
INSERT INTO guilds (guild, name, prefix) VALUES (?, ?, ?)
|
|
||||||
",
|
|
||||||
guild_id,
|
|
||||||
guild.name,
|
|
||||||
*DEFAULT_PREFIX
|
|
||||||
)
|
|
||||||
.execute(&pool.clone())
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(sqlx::query_as!(
|
|
||||||
Self,
|
|
||||||
"
|
|
||||||
SELECT id, name, prefix FROM guilds WHERE guild = ?
|
|
||||||
",
|
|
||||||
guild_id
|
|
||||||
)
|
|
||||||
.fetch_one(pool)
|
|
||||||
.await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(e) => {
|
|
||||||
error!("Unexpected error in guild query: {:?}", e);
|
|
||||||
|
|
||||||
Err(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn commit_changes(&self, pool: &MySqlPool) {
|
|
||||||
sqlx::query!(
|
|
||||||
"
|
|
||||||
UPDATE guilds SET name = ?, prefix = ? WHERE id = ?
|
|
||||||
",
|
|
||||||
self.name,
|
|
||||||
self.prefix,
|
|
||||||
self.id
|
|
||||||
)
|
|
||||||
.execute(pool)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +1,23 @@
|
|||||||
pub mod channel_data;
|
pub mod channel_data;
|
||||||
pub mod command_macro;
|
pub mod command_macro;
|
||||||
pub mod guild_data;
|
|
||||||
pub mod reminder;
|
pub mod reminder;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod user_data;
|
pub mod user_data;
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use chrono_tz::Tz;
|
use chrono_tz::Tz;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
async_trait,
|
async_trait,
|
||||||
model::id::{ChannelId, GuildId, UserId},
|
model::id::{ChannelId, UserId},
|
||||||
prelude::Context,
|
prelude::Context,
|
||||||
};
|
};
|
||||||
use tokio::sync::RwLock;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
consts::DEFAULT_PREFIX,
|
models::{channel_data::ChannelData, user_data::UserData},
|
||||||
models::{channel_data::ChannelData, guild_data::GuildData, user_data::UserData},
|
SQLPool,
|
||||||
GuildDataCache, SQLPool,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait CtxData {
|
pub trait CtxData {
|
||||||
async fn guild_data<G: Into<GuildId> + Send + Sync>(
|
|
||||||
&self,
|
|
||||||
guild_id: G,
|
|
||||||
) -> Result<Arc<RwLock<GuildData>>, sqlx::Error>;
|
|
||||||
|
|
||||||
async fn prefix<G: Into<GuildId> + Send + Sync>(&self, guild_id: Option<G>) -> String;
|
|
||||||
|
|
||||||
async fn user_data<U: Into<UserId> + Send + Sync>(
|
async fn user_data<U: Into<UserId> + Send + Sync>(
|
||||||
&self,
|
&self,
|
||||||
user_id: U,
|
user_id: U,
|
||||||
@ -45,45 +33,6 @@ pub trait CtxData {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl CtxData for Context {
|
impl CtxData for Context {
|
||||||
async fn guild_data<G: Into<GuildId> + Send + Sync>(
|
|
||||||
&self,
|
|
||||||
guild_id: G,
|
|
||||||
) -> Result<Arc<RwLock<GuildData>>, sqlx::Error> {
|
|
||||||
let guild_id = guild_id.into();
|
|
||||||
|
|
||||||
let guild = guild_id.to_guild_cached(&self.cache).unwrap();
|
|
||||||
|
|
||||||
let guild_cache = self.data.read().await.get::<GuildDataCache>().cloned().unwrap();
|
|
||||||
|
|
||||||
let x = if let Some(guild_data) = guild_cache.get(&guild_id) {
|
|
||||||
Ok(guild_data.clone())
|
|
||||||
} else {
|
|
||||||
let pool = self.data.read().await.get::<SQLPool>().cloned().unwrap();
|
|
||||||
|
|
||||||
match GuildData::from_guild(guild, &pool).await {
|
|
||||||
Ok(d) => {
|
|
||||||
let lock = Arc::new(RwLock::new(d));
|
|
||||||
|
|
||||||
guild_cache.insert(guild_id, lock.clone());
|
|
||||||
|
|
||||||
Ok(lock)
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
x
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn prefix<G: Into<GuildId> + Send + Sync>(&self, guild_id: Option<G>) -> String {
|
|
||||||
if let Some(guild_id) = guild_id {
|
|
||||||
self.guild_data(guild_id).await.unwrap().read().await.prefix.clone()
|
|
||||||
} else {
|
|
||||||
DEFAULT_PREFIX.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn user_data<U: Into<UserId> + Send + Sync>(
|
async fn user_data<U: Into<UserId> + Send + Sync>(
|
||||||
&self,
|
&self,
|
||||||
user_id: U,
|
user_id: U,
|
||||||
|
Loading…
Reference in New Issue
Block a user