changed a bunch of types so the macro run command works nicely
This commit is contained in:
parent
903daf65e6
commit
a362a24cfc
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -177,7 +177,6 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "command_attr"
|
name = "command_attr"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
source = "git+https://github.com/serenity-rs/serenity?branch=next#40f3247f0012b0aa944dcf0132cc763f557707d4"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1453,7 +1452,6 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "serenity"
|
name = "serenity"
|
||||||
version = "0.10.9"
|
version = "0.10.9"
|
||||||
source = "git+https://github.com/serenity-rs/serenity?branch=next#40f3247f0012b0aa944dcf0132cc763f557707d4"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"async-tungstenite",
|
"async-tungstenite",
|
||||||
|
@ -23,7 +23,8 @@ serde_repr = "0.1"
|
|||||||
rmp-serde = "0.15"
|
rmp-serde = "0.15"
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
levenshtein = "1.0"
|
levenshtein = "1.0"
|
||||||
serenity = { git = "https://github.com/serenity-rs/serenity", branch = "next", features = ["collector", "unstable_discord_api"] }
|
serenity = { path = "/home/jude/serenity", features = ["collector", "unstable_discord_api"] }
|
||||||
|
# serenity = { git = "https://github.com/serenity-rs/serenity", branch = "next", features = ["collector", "unstable_discord_api"] }
|
||||||
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal", "chrono"]}
|
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal", "chrono"]}
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
CREATE TABLE macro (
|
CREATE TABLE macro (
|
||||||
id INT UNSIGNED AUTO_INCREMENT,
|
id INT UNSIGNED AUTO_INCREMENT,
|
||||||
guild_id INT UNSIGNED NOT NULL,
|
guild_id BIGINT UNSIGNED NOT NULL,
|
||||||
|
|
||||||
name VARCHAR(100) NOT NULL,
|
name VARCHAR(100) NOT NULL,
|
||||||
description VARCHAR(100),
|
description VARCHAR(100),
|
||||||
commands TEXT,
|
commands TEXT NOT NULL,
|
||||||
|
|
||||||
FOREIGN KEY (guild_id) REFERENCES guilds(id),
|
FOREIGN KEY (guild_id) REFERENCES guilds(guild) ON DELETE CASCADE,
|
||||||
PRIMARY KEY (id)
|
PRIMARY KEY (id)
|
||||||
);
|
);
|
||||||
|
@ -27,7 +27,7 @@ fn footer(ctx: &Context) -> impl FnOnce(&mut CreateEmbedFooter) -> &mut CreateEm
|
|||||||
#[aliases("invite")]
|
#[aliases("invite")]
|
||||||
#[description("Get information about the bot")]
|
#[description("Get information about the bot")]
|
||||||
#[group("Info")]
|
#[group("Info")]
|
||||||
async fn info(ctx: &Context, invoke: CommandInvoke) {
|
async fn info(ctx: &Context, invoke: &mut CommandInvoke) {
|
||||||
let prefix = ctx.prefix(invoke.guild_id()).await;
|
let prefix = ctx.prefix(invoke.guild_id()).await;
|
||||||
let current_user = ctx.cache.current_user();
|
let current_user = ctx.cache.current_user();
|
||||||
let footer = footer(ctx);
|
let footer = footer(ctx);
|
||||||
@ -61,7 +61,7 @@ Use our dashboard: https://reminder-bot.com/",
|
|||||||
#[command]
|
#[command]
|
||||||
#[description("Details on supporting the bot and Patreon benefits")]
|
#[description("Details on supporting the bot and Patreon benefits")]
|
||||||
#[group("Info")]
|
#[group("Info")]
|
||||||
async fn donate(ctx: &Context, invoke: CommandInvoke) {
|
async fn donate(ctx: &Context, invoke: &mut CommandInvoke) {
|
||||||
let footer = footer(ctx);
|
let footer = footer(ctx);
|
||||||
|
|
||||||
let _ = invoke
|
let _ = invoke
|
||||||
@ -94,7 +94,7 @@ Just $2 USD/month!
|
|||||||
#[command]
|
#[command]
|
||||||
#[description("Get the link to the online dashboard")]
|
#[description("Get the link to the online dashboard")]
|
||||||
#[group("Info")]
|
#[group("Info")]
|
||||||
async fn dashboard(ctx: &Context, invoke: CommandInvoke) {
|
async fn dashboard(ctx: &Context, invoke: &mut CommandInvoke) {
|
||||||
let footer = footer(ctx);
|
let footer = footer(ctx);
|
||||||
|
|
||||||
let _ = invoke
|
let _ = invoke
|
||||||
@ -113,7 +113,7 @@ async fn dashboard(ctx: &Context, invoke: CommandInvoke) {
|
|||||||
#[command]
|
#[command]
|
||||||
#[description("View the current time in your selected timezone")]
|
#[description("View the current time in your selected timezone")]
|
||||||
#[group("Info")]
|
#[group("Info")]
|
||||||
async fn clock(ctx: &Context, invoke: CommandInvoke) {
|
async fn clock(ctx: &Context, invoke: &mut CommandInvoke) {
|
||||||
let ud = ctx.user_data(&invoke.author_id()).await.unwrap();
|
let ud = ctx.user_data(&invoke.author_id()).await.unwrap();
|
||||||
let now = Utc::now().with_timezone(&ud.timezone());
|
let now = Utc::now().with_timezone(&ud.timezone());
|
||||||
|
|
||||||
|
@ -2,18 +2,10 @@ use chrono::offset::Utc;
|
|||||||
use chrono_tz::{Tz, TZ_VARIANTS};
|
use chrono_tz::{Tz, TZ_VARIANTS};
|
||||||
use levenshtein::levenshtein;
|
use levenshtein::levenshtein;
|
||||||
use regex_command_attr::command;
|
use regex_command_attr::command;
|
||||||
use serenity::{
|
use serenity::{client::Context, model::misc::Mentionable};
|
||||||
client::Context,
|
|
||||||
http::AttachmentType,
|
|
||||||
model::{
|
|
||||||
interactions::InteractionResponseType, misc::Mentionable,
|
|
||||||
prelude::InteractionApplicationCommandCallbackDataFlags,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
component_models::{ComponentDataModel, Restrict},
|
component_models::{ComponentDataModel, Restrict},
|
||||||
consts,
|
|
||||||
consts::THEME_COLOR,
|
consts::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},
|
||||||
@ -32,7 +24,7 @@ use crate::{
|
|||||||
#[supports_dm(false)]
|
#[supports_dm(false)]
|
||||||
#[hook(CHECK_GUILD_PERMISSIONS_HOOK)]
|
#[hook(CHECK_GUILD_PERMISSIONS_HOOK)]
|
||||||
#[can_blacklist(false)]
|
#[can_blacklist(false)]
|
||||||
async fn blacklist(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
async fn blacklist(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptions) {
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
||||||
|
|
||||||
let channel = match args.get("channel") {
|
let channel = match args.get("channel") {
|
||||||
@ -75,7 +67,7 @@ async fn blacklist(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
kind = "String",
|
kind = "String",
|
||||||
required = false
|
required = false
|
||||||
)]
|
)]
|
||||||
async fn timezone(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
async fn timezone(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptions) {
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
||||||
let mut user_data = ctx.user_data(invoke.author_id()).await.unwrap();
|
let mut user_data = ctx.user_data(invoke.author_id()).await.unwrap();
|
||||||
|
|
||||||
@ -182,7 +174,7 @@ You may want to use one of the popular timezones below, otherwise click [here](h
|
|||||||
#[description("Configure a prefix for text-based commands (deprecated)")]
|
#[description("Configure a prefix for text-based commands (deprecated)")]
|
||||||
#[supports_dm(false)]
|
#[supports_dm(false)]
|
||||||
#[hook(CHECK_GUILD_PERMISSIONS_HOOK)]
|
#[hook(CHECK_GUILD_PERMISSIONS_HOOK)]
|
||||||
async fn prefix(ctx: &Context, invoke: CommandInvoke, args: String) {
|
async fn prefix(ctx: &Context, invoke: &mut CommandInvoke, args: String) {
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
||||||
|
|
||||||
let guild_data = ctx.guild_data(invoke.guild_id().unwrap()).await.unwrap();
|
let guild_data = ctx.guild_data(invoke.guild_id().unwrap()).await.unwrap();
|
||||||
@ -226,7 +218,7 @@ async fn prefix(ctx: &Context, invoke: CommandInvoke, args: String) {
|
|||||||
)]
|
)]
|
||||||
#[supports_dm(false)]
|
#[supports_dm(false)]
|
||||||
#[hook(CHECK_GUILD_PERMISSIONS_HOOK)]
|
#[hook(CHECK_GUILD_PERMISSIONS_HOOK)]
|
||||||
async fn restrict(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
async fn restrict(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptions) {
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
||||||
let framework = ctx.data.read().await.get::<RegexFramework>().cloned().unwrap();
|
let framework = ctx.data.read().await.get::<RegexFramework>().cloned().unwrap();
|
||||||
|
|
||||||
@ -310,10 +302,13 @@ async fn restrict(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
#[subcommand("run")]
|
#[subcommand("run")]
|
||||||
#[description("Run a recorded macro")]
|
#[description("Run a recorded macro")]
|
||||||
#[arg(name = "name", description = "Name of the macro to run", kind = "String", required = true)]
|
#[arg(name = "name", description = "Name of the macro to run", kind = "String", required = true)]
|
||||||
|
#[subcommand("delete")]
|
||||||
|
#[description("Delete a recorded macro")]
|
||||||
|
#[arg(name = "name", description = "Name of the macro to delete", kind = "String", required = true)]
|
||||||
#[supports_dm(false)]
|
#[supports_dm(false)]
|
||||||
#[hook(CHECK_MANAGED_PERMISSIONS_HOOK)]
|
#[hook(CHECK_MANAGED_PERMISSIONS_HOOK)]
|
||||||
async fn macro_cmd(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
async fn macro_cmd(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptions) {
|
||||||
let interaction = invoke.interaction().unwrap();
|
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
||||||
|
|
||||||
match args.subcommand.clone().unwrap().as_str() {
|
match args.subcommand.clone().unwrap().as_str() {
|
||||||
"record" => {
|
"record" => {
|
||||||
@ -322,10 +317,10 @@ async fn macro_cmd(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
{
|
{
|
||||||
let mut lock = macro_buffer.write().await;
|
let mut lock = macro_buffer.write().await;
|
||||||
|
|
||||||
let guild_id = interaction.guild_id.unwrap();
|
let guild_id = invoke.guild_id().unwrap();
|
||||||
|
|
||||||
lock.insert(
|
lock.insert(
|
||||||
(guild_id, interaction.user.id),
|
(guild_id, invoke.author_id()),
|
||||||
CommandMacro {
|
CommandMacro {
|
||||||
guild_id,
|
guild_id,
|
||||||
name: args.get("name").unwrap().to_string(),
|
name: args.get("name").unwrap().to_string(),
|
||||||
@ -335,25 +330,22 @@ async fn macro_cmd(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = interaction
|
let _ = invoke
|
||||||
.create_interaction_response(&ctx, |r| {
|
.respond(
|
||||||
r.kind(InteractionResponseType::ChannelMessageWithSource)
|
&ctx,
|
||||||
.interaction_response_data(|d| {
|
CreateGenericResponse::new().ephemeral().embed(|e| {
|
||||||
d.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
|
|
||||||
.create_embed(|e| {
|
|
||||||
e
|
e
|
||||||
.title("Macro Recording Started")
|
.title("Macro Recording Started")
|
||||||
.description(
|
.description(
|
||||||
"Run up to 5 commands, or type `/macro finish` to stop at any point.
|
"Run up to 5 commands, or type `/macro finish` to stop at any point.
|
||||||
Any commands ran as part of recording will be inconsequential")
|
Any commands ran as part of recording will be inconsequential")
|
||||||
.color(*THEME_COLOR)
|
.color(*THEME_COLOR)
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
})
|
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
"finish" => {
|
"finish" => {
|
||||||
let key = (interaction.guild_id.unwrap(), interaction.user.id);
|
let key = (invoke.guild_id().unwrap(), invoke.author_id());
|
||||||
let macro_buffer = ctx.data.read().await.get::<RecordingMacros>().cloned().unwrap();
|
let macro_buffer = ctx.data.read().await.get::<RecordingMacros>().cloned().unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -361,28 +353,22 @@ Any commands ran as part of recording will be inconsequential")
|
|||||||
let contained = lock.get(&key);
|
let contained = lock.get(&key);
|
||||||
|
|
||||||
if contained.map_or(true, |cmacro| cmacro.commands.is_empty()) {
|
if contained.map_or(true, |cmacro| cmacro.commands.is_empty()) {
|
||||||
let _ = interaction
|
let _ = invoke
|
||||||
.create_interaction_response(&ctx, |r| {
|
.respond(
|
||||||
r.kind(InteractionResponseType::ChannelMessageWithSource)
|
&ctx,
|
||||||
.interaction_response_data(|d| {
|
CreateGenericResponse::new().embed(|e| {
|
||||||
d.create_embed(|e| {
|
|
||||||
e.title("No Macro Recorded")
|
e.title("No Macro Recorded")
|
||||||
.description(
|
.description("Use `/macro record` to start recording a macro")
|
||||||
"Use `/macro record` to start recording a macro",
|
|
||||||
)
|
|
||||||
.color(*THEME_COLOR)
|
.color(*THEME_COLOR)
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
})
|
|
||||||
.await;
|
.await;
|
||||||
} else {
|
} else {
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
|
||||||
|
|
||||||
let command_macro = contained.unwrap();
|
let command_macro = contained.unwrap();
|
||||||
let json = serde_json::to_string(&command_macro.commands).unwrap();
|
let json = serde_json::to_string(&command_macro.commands).unwrap();
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"INSERT INTO macro (guild_id, name, description, commands) VALUES ((SELECT id FROM guilds WHERE guild = ?), ?, ?, ?)",
|
"INSERT INTO macro (guild_id, name, description, commands) VALUES (?, ?, ?, ?)",
|
||||||
command_macro.guild_id.0,
|
command_macro.guild_id.0,
|
||||||
command_macro.name,
|
command_macro.name,
|
||||||
command_macro.description,
|
command_macro.description,
|
||||||
@ -392,17 +378,15 @@ Any commands ran as part of recording will be inconsequential")
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let _ = interaction
|
let _ = invoke
|
||||||
.create_interaction_response(&ctx, |r| {
|
.respond(
|
||||||
r.kind(InteractionResponseType::ChannelMessageWithSource)
|
&ctx,
|
||||||
.interaction_response_data(|d| {
|
CreateGenericResponse::new().embed(|e| {
|
||||||
d.create_embed(|e| {
|
|
||||||
e.title("Macro Recorded")
|
e.title("Macro Recorded")
|
||||||
.description("Use `/macro run` to execute the macro")
|
.description("Use `/macro run` to execute the macro")
|
||||||
.color(*THEME_COLOR)
|
.color(*THEME_COLOR)
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
})
|
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -413,54 +397,45 @@ Any commands ran as part of recording will be inconsequential")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"list" => {}
|
"list" => {}
|
||||||
"run" => {}
|
"run" => {
|
||||||
|
let macro_name = args.get("name").unwrap().to_string();
|
||||||
|
|
||||||
|
match sqlx::query!(
|
||||||
|
"SELECT commands FROM macro WHERE guild_id = ? AND name = ?",
|
||||||
|
invoke.guild_id().unwrap().0,
|
||||||
|
macro_name
|
||||||
|
)
|
||||||
|
.fetch_one(&pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(row) => {
|
||||||
|
invoke.defer(&ctx).await;
|
||||||
|
|
||||||
|
let commands: Vec<CommandOptions> =
|
||||||
|
serde_json::from_str(&row.commands).unwrap();
|
||||||
|
let framework = ctx.data.read().await.get::<RegexFramework>().cloned().unwrap();
|
||||||
|
|
||||||
|
for command in commands {
|
||||||
|
framework.run_command_from_options(ctx, invoke, command).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(sqlx::Error::RowNotFound) => {
|
||||||
|
let _ = invoke
|
||||||
|
.respond(
|
||||||
|
&ctx,
|
||||||
|
CreateGenericResponse::new()
|
||||||
|
.content(format!("Macro \"{}\" not found", macro_name)),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(e) => {
|
||||||
|
panic!("{}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"delete" => {}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command("webhook")]
|
|
||||||
#[description("Modify this channel's webhooks")]
|
|
||||||
#[subcommand("username")]
|
|
||||||
#[description("Change the webhook username")]
|
|
||||||
#[arg(name = "username", description = "The username to use", kind = "String", required = true)]
|
|
||||||
#[subcommand("avatar")]
|
|
||||||
#[description("Change the webhook avatar")]
|
|
||||||
#[arg(name = "url", description = "The URL of the image to use", kind = "String", required = true)]
|
|
||||||
async fn configure_webhook(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
|
||||||
let mut channel_data = ctx.channel_data(invoke.channel_id()).await.unwrap();
|
|
||||||
|
|
||||||
let (username, avatar) = (
|
|
||||||
args.get("username").map_or("Reminder".to_string(), |i| i.to_string()),
|
|
||||||
args.get("url").map_or(consts::DEFAULT_AVATAR, |i| AttachmentType::Image(&i.to_string())),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let (Some(id), Some(token)) = (channel_data.webhook_id, channel_data.webhook_token) {
|
|
||||||
match ctx.http.get_webhook_with_token(id, &token).await {
|
|
||||||
Ok(mut webhook) => {
|
|
||||||
webhook.edit(&ctx, Some(username), Some(avatar)).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(_) => {
|
|
||||||
let webhook = invoke
|
|
||||||
.channel_id()
|
|
||||||
.create_webhook_with_avatar(&ctx, username, avatar)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
channel_data.webhook_token = webhook.token;
|
|
||||||
channel_data.webhook_id = Some(webhook.id.0);
|
|
||||||
|
|
||||||
channel_data.commit_changes(&pool).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let webhook =
|
|
||||||
invoke.channel_id().create_webhook_with_avatar(&ctx, username, avatar).await.unwrap();
|
|
||||||
|
|
||||||
channel_data.webhook_token = webhook.token;
|
|
||||||
channel_data.webhook_id = Some(webhook.id.0);
|
|
||||||
|
|
||||||
channel_data.commit_changes(&pool).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -8,11 +8,7 @@ use chrono::NaiveDateTime;
|
|||||||
use chrono_tz::Tz;
|
use chrono_tz::Tz;
|
||||||
use num_integer::Integer;
|
use num_integer::Integer;
|
||||||
use regex_command_attr::command;
|
use regex_command_attr::command;
|
||||||
use serenity::{
|
use serenity::{builder::CreateEmbed, client::Context, model::channel::Channel};
|
||||||
builder::{CreateEmbed, CreateInteractionResponse},
|
|
||||||
client::Context,
|
|
||||||
model::{channel::Channel, interactions::InteractionResponseType},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
check_subscription_on_message,
|
check_subscription_on_message,
|
||||||
@ -54,7 +50,7 @@ use crate::{
|
|||||||
)]
|
)]
|
||||||
#[supports_dm(false)]
|
#[supports_dm(false)]
|
||||||
#[hook(CHECK_GUILD_PERMISSIONS_HOOK)]
|
#[hook(CHECK_GUILD_PERMISSIONS_HOOK)]
|
||||||
async fn pause(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
async fn pause(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptions) {
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
||||||
|
|
||||||
let timezone = UserData::timezone_of(&invoke.author_id(), &pool).await;
|
let timezone = UserData::timezone_of(&invoke.author_id(), &pool).await;
|
||||||
@ -140,7 +136,7 @@ async fn pause(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
required = false
|
required = false
|
||||||
)]
|
)]
|
||||||
#[hook(CHECK_GUILD_PERMISSIONS_HOOK)]
|
#[hook(CHECK_GUILD_PERMISSIONS_HOOK)]
|
||||||
async fn offset(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
async fn offset(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptions) {
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
||||||
|
|
||||||
let combined_time = args.get("hours").map_or(0, |h| h.as_i64().unwrap() * 3600)
|
let combined_time = args.get("hours").map_or(0, |h| h.as_i64().unwrap() * 3600)
|
||||||
@ -217,7 +213,7 @@ WHERE FIND_IN_SET(channels.`channel`, ?)",
|
|||||||
required = false
|
required = false
|
||||||
)]
|
)]
|
||||||
#[hook(CHECK_GUILD_PERMISSIONS_HOOK)]
|
#[hook(CHECK_GUILD_PERMISSIONS_HOOK)]
|
||||||
async fn nudge(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
async fn nudge(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptions) {
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
||||||
|
|
||||||
let combined_time = args.get("minutes").map_or(0, |m| m.as_i64().unwrap() * 60)
|
let combined_time = args.get("minutes").map_or(0, |m| m.as_i64().unwrap() * 60)
|
||||||
@ -269,7 +265,7 @@ async fn nudge(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
required = false
|
required = false
|
||||||
)]
|
)]
|
||||||
#[hook(CHECK_MANAGED_PERMISSIONS_HOOK)]
|
#[hook(CHECK_MANAGED_PERMISSIONS_HOOK)]
|
||||||
async fn look(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
async fn look(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptions) {
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
||||||
|
|
||||||
let timezone = UserData::timezone_of(&invoke.author_id(), &pool).await;
|
let timezone = UserData::timezone_of(&invoke.author_id(), &pool).await;
|
||||||
@ -362,22 +358,14 @@ async fn look(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
#[command("del")]
|
#[command("del")]
|
||||||
#[description("Delete reminders")]
|
#[description("Delete reminders")]
|
||||||
#[hook(CHECK_MANAGED_PERMISSIONS_HOOK)]
|
#[hook(CHECK_MANAGED_PERMISSIONS_HOOK)]
|
||||||
async fn delete(ctx: &Context, invoke: CommandInvoke, _args: CommandOptions) {
|
async fn delete(ctx: &Context, invoke: &mut CommandInvoke, _args: CommandOptions) {
|
||||||
let interaction = invoke.interaction().unwrap();
|
let timezone = ctx.timezone(invoke.author_id()).await;
|
||||||
|
|
||||||
let timezone = ctx.timezone(interaction.user.id).await;
|
let reminders = Reminder::from_guild(ctx, invoke.guild_id(), invoke.author_id()).await;
|
||||||
|
|
||||||
let reminders = Reminder::from_guild(ctx, interaction.guild_id, interaction.user.id).await;
|
|
||||||
|
|
||||||
let resp = show_delete_page(&reminders, 0, timezone);
|
let resp = show_delete_page(&reminders, 0, timezone);
|
||||||
|
|
||||||
let _ = interaction
|
let _ = invoke.respond(&ctx, resp).await;
|
||||||
.create_interaction_response(&ctx, |r| {
|
|
||||||
*r = resp;
|
|
||||||
r.kind(InteractionResponseType::ChannelMessageWithSource)
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_delete_page(reminders: &[Reminder], timezone: &Tz) -> usize {
|
pub fn max_delete_page(reminders: &[Reminder], timezone: &Tz) -> usize {
|
||||||
@ -406,22 +394,16 @@ pub fn show_delete_page(
|
|||||||
reminders: &[Reminder],
|
reminders: &[Reminder],
|
||||||
page: usize,
|
page: usize,
|
||||||
timezone: Tz,
|
timezone: Tz,
|
||||||
) -> CreateInteractionResponse {
|
) -> CreateGenericResponse {
|
||||||
let pager = DelPager::new(page, timezone);
|
let pager = DelPager::new(page, timezone);
|
||||||
|
|
||||||
if reminders.is_empty() {
|
if reminders.is_empty() {
|
||||||
let mut embed = CreateEmbed::default();
|
return CreateGenericResponse::new()
|
||||||
embed.title("Delete Reminders").description("No Reminders").color(*THEME_COLOR);
|
.embed(|e| e.title("Delete Reminders").description("No Reminders").color(*THEME_COLOR))
|
||||||
|
.components(|comp| {
|
||||||
let mut response = CreateInteractionResponse::default();
|
|
||||||
response.interaction_response_data(|response| {
|
|
||||||
response.embeds(vec![embed]).components(|comp| {
|
|
||||||
pager.create_button_row(0, comp);
|
pager.create_button_row(0, comp);
|
||||||
comp
|
comp
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let pages = max_delete_page(reminders, &timezone);
|
let pages = max_delete_page(reminders, &timezone);
|
||||||
@ -470,16 +452,14 @@ pub fn show_delete_page(
|
|||||||
|
|
||||||
let del_selector = ComponentDataModel::DelSelector(DelSelector { page, timezone });
|
let del_selector = ComponentDataModel::DelSelector(DelSelector { page, timezone });
|
||||||
|
|
||||||
let mut embed = CreateEmbed::default();
|
CreateGenericResponse::new()
|
||||||
embed
|
.embed(|e| {
|
||||||
.title("Delete Reminders")
|
e.title("Delete Reminders")
|
||||||
.description(display)
|
.description(display)
|
||||||
.footer(|f| f.text(format!("Page {} of {}", page + 1, pages)))
|
.footer(|f| f.text(format!("Page {} of {}", page + 1, pages)))
|
||||||
.color(*THEME_COLOR);
|
.color(*THEME_COLOR)
|
||||||
|
})
|
||||||
let mut response = CreateInteractionResponse::default();
|
.components(|comp| {
|
||||||
response.interaction_response_data(|d| {
|
|
||||||
d.embeds(vec![embed]).components(|comp| {
|
|
||||||
pager.create_button_row(pages, comp);
|
pager.create_button_row(pages, comp);
|
||||||
|
|
||||||
comp.create_action_row(|row| {
|
comp.create_action_row(|row| {
|
||||||
@ -511,8 +491,6 @@ pub fn show_delete_page(
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
|
||||||
response
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command("timer")]
|
#[command("timer")]
|
||||||
@ -526,7 +504,7 @@ pub fn show_delete_page(
|
|||||||
#[description("Delete a timer")]
|
#[description("Delete a timer")]
|
||||||
#[arg(name = "name", description = "Name of the timer to delete", kind = "String", required = true)]
|
#[arg(name = "name", description = "Name of the timer to delete", kind = "String", required = true)]
|
||||||
#[hook(CHECK_MANAGED_PERMISSIONS_HOOK)]
|
#[hook(CHECK_MANAGED_PERMISSIONS_HOOK)]
|
||||||
async fn timer(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
async fn timer(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptions) {
|
||||||
fn time_difference(start_time: NaiveDateTime) -> String {
|
fn time_difference(start_time: NaiveDateTime) -> String {
|
||||||
let unix_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64;
|
let unix_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64;
|
||||||
let now = NaiveDateTime::from_timestamp(unix_time, 0);
|
let now = NaiveDateTime::from_timestamp(unix_time, 0);
|
||||||
@ -692,18 +670,10 @@ DELETE FROM timers WHERE owner = ? AND name = ?
|
|||||||
required = false
|
required = false
|
||||||
)]
|
)]
|
||||||
#[hook(CHECK_MANAGED_PERMISSIONS_HOOK)]
|
#[hook(CHECK_MANAGED_PERMISSIONS_HOOK)]
|
||||||
async fn remind(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
async fn remind(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptions) {
|
||||||
let interaction = invoke.interaction().unwrap();
|
invoke.defer(&ctx).await;
|
||||||
|
|
||||||
// defer response since processing times can take some time
|
let user_data = ctx.user_data(invoke.author_id()).await.unwrap();
|
||||||
interaction
|
|
||||||
.create_interaction_response(&ctx, |r| {
|
|
||||||
r.kind(InteractionResponseType::DeferredChannelMessageWithSource)
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let user_data = ctx.user_data(interaction.user.id).await.unwrap();
|
|
||||||
let timezone = user_data.timezone();
|
let timezone = user_data.timezone();
|
||||||
|
|
||||||
let time = {
|
let time = {
|
||||||
@ -728,7 +698,7 @@ async fn remind(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
if list.is_empty() {
|
if list.is_empty() {
|
||||||
vec![ReminderScope::Channel(interaction.channel_id.0)]
|
vec![ReminderScope::Channel(invoke.channel_id().0)]
|
||||||
} else {
|
} else {
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
@ -751,7 +721,7 @@ async fn remind(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut builder = MultiReminderBuilder::new(ctx, interaction.guild_id)
|
let mut builder = MultiReminderBuilder::new(ctx, invoke.guild_id())
|
||||||
.author(user_data)
|
.author(user_data)
|
||||||
.content(content)
|
.content(content)
|
||||||
.time(time)
|
.time(time)
|
||||||
@ -764,16 +734,19 @@ async fn remind(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
|
|
||||||
let embed = create_response(successes, errors, time);
|
let embed = create_response(successes, errors, time);
|
||||||
|
|
||||||
interaction
|
let _ = invoke
|
||||||
.edit_original_interaction_response(&ctx, |r| r.add_embed(embed))
|
.respond(
|
||||||
.await
|
&ctx,
|
||||||
.unwrap();
|
CreateGenericResponse::new().embed(|c| {
|
||||||
|
*c = embed;
|
||||||
|
c
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let _ = interaction
|
let _ = invoke
|
||||||
.edit_original_interaction_response(&ctx, |r| {
|
.respond(&ctx, CreateGenericResponse::new().content("Time could not be processed"))
|
||||||
r.content("Time could not be processed.")
|
|
||||||
})
|
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
use regex_command_attr::command;
|
use regex_command_attr::command;
|
||||||
use serenity::{
|
use serenity::client::Context;
|
||||||
builder::{CreateEmbed, CreateInteractionResponse},
|
|
||||||
client::Context,
|
|
||||||
model::interactions::InteractionResponseType,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
component_models::{
|
component_models::{
|
||||||
@ -53,7 +49,7 @@ use crate::{
|
|||||||
)]
|
)]
|
||||||
#[subcommand("view")]
|
#[subcommand("view")]
|
||||||
#[description("View and remove from your personal todo list")]
|
#[description("View and remove from your personal todo list")]
|
||||||
async fn todo(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
async fn todo(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptions) {
|
||||||
if invoke.guild_id().is_none() && args.subcommand_group != Some("user".to_string()) {
|
if invoke.guild_id().is_none() && args.subcommand_group != Some("user".to_string()) {
|
||||||
let _ = invoke
|
let _ = invoke
|
||||||
.respond(
|
.respond(
|
||||||
@ -106,15 +102,7 @@ async fn todo(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
|
|||||||
|
|
||||||
let resp = show_todo_page(&values, 0, keys.0, keys.1, keys.2);
|
let resp = show_todo_page(&values, 0, keys.0, keys.1, keys.2);
|
||||||
|
|
||||||
let interaction = invoke.interaction().unwrap();
|
let _ = invoke.respond(&ctx, resp).await;
|
||||||
|
|
||||||
let _ = interaction
|
|
||||||
.create_interaction_response(&ctx, |r| {
|
|
||||||
*r = resp;
|
|
||||||
r.kind(InteractionResponseType::ChannelMessageWithSource)
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,7 +135,7 @@ pub fn show_todo_page(
|
|||||||
user_id: Option<u64>,
|
user_id: Option<u64>,
|
||||||
channel_id: Option<u64>,
|
channel_id: Option<u64>,
|
||||||
guild_id: Option<u64>,
|
guild_id: Option<u64>,
|
||||||
) -> CreateInteractionResponse {
|
) -> CreateGenericResponse {
|
||||||
let pager = TodoPager::new(page, user_id, channel_id, guild_id);
|
let pager = TodoPager::new(page, user_id, channel_id, guild_id);
|
||||||
|
|
||||||
let pages = max_todo_page(todo_values);
|
let pages = max_todo_page(todo_values);
|
||||||
@ -204,16 +192,14 @@ pub fn show_todo_page(
|
|||||||
let todo_selector =
|
let todo_selector =
|
||||||
ComponentDataModel::TodoSelector(TodoSelector { page, user_id, channel_id, guild_id });
|
ComponentDataModel::TodoSelector(TodoSelector { page, user_id, channel_id, guild_id });
|
||||||
|
|
||||||
let mut embed = CreateEmbed::default();
|
CreateGenericResponse::new()
|
||||||
embed
|
.embed(|e| {
|
||||||
.title(format!("{} Todo List", title))
|
e.title(format!("{} Todo List", title))
|
||||||
.description(display)
|
.description(display)
|
||||||
.footer(|f| f.text(format!("Page {} of {}", page + 1, pages)))
|
.footer(|f| f.text(format!("Page {} of {}", page + 1, pages)))
|
||||||
.color(*THEME_COLOR);
|
.color(*THEME_COLOR)
|
||||||
|
})
|
||||||
let mut response = CreateInteractionResponse::default();
|
.components(|comp| {
|
||||||
response.interaction_response_data(|d| {
|
|
||||||
d.embeds(vec![embed]).components(|comp| {
|
|
||||||
pager.create_button_row(pages, comp);
|
pager.create_button_row(pages, comp);
|
||||||
|
|
||||||
comp.create_action_row(|row| {
|
comp.create_action_row(|row| {
|
||||||
@ -232,7 +218,4 @@ pub fn show_todo_page(
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
|
||||||
|
|
||||||
response
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
component_models::pager::{DelPager, LookPager, Pager, TodoPager},
|
component_models::pager::{DelPager, LookPager, Pager, TodoPager},
|
||||||
consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR},
|
consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR},
|
||||||
|
framework::CommandInvoke,
|
||||||
models::reminder::Reminder,
|
models::reminder::Reminder,
|
||||||
SQLPool,
|
SQLPool,
|
||||||
};
|
};
|
||||||
@ -175,12 +176,8 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
|
|||||||
|
|
||||||
let resp = show_delete_page(&reminders, pager.next_page(max_pages), pager.timezone);
|
let resp = show_delete_page(&reminders, pager.next_page(max_pages), pager.timezone);
|
||||||
|
|
||||||
let _ = component
|
let mut invoke = CommandInvoke::component(component);
|
||||||
.create_interaction_response(&ctx, move |r| {
|
let _ = invoke.respond(&ctx, resp).await;
|
||||||
*r = resp;
|
|
||||||
r.kind(InteractionResponseType::UpdateMessage)
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
ComponentDataModel::DelSelector(selector) => {
|
ComponentDataModel::DelSelector(selector) => {
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
||||||
@ -196,12 +193,8 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
|
|||||||
|
|
||||||
let resp = show_delete_page(&reminders, selector.page, selector.timezone);
|
let resp = show_delete_page(&reminders, selector.page, selector.timezone);
|
||||||
|
|
||||||
let _ = component
|
let mut invoke = CommandInvoke::component(component);
|
||||||
.create_interaction_response(&ctx, move |r| {
|
let _ = invoke.respond(&ctx, resp).await;
|
||||||
*r = resp;
|
|
||||||
r.kind(InteractionResponseType::UpdateMessage)
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
ComponentDataModel::TodoPager(pager) => {
|
ComponentDataModel::TodoPager(pager) => {
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
||||||
@ -230,12 +223,8 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
|
|||||||
pager.guild_id,
|
pager.guild_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
let _ = component
|
let mut invoke = CommandInvoke::component(component);
|
||||||
.create_interaction_response(&ctx, move |r| {
|
let _ = invoke.respond(&ctx, resp).await;
|
||||||
*r = resp;
|
|
||||||
r.kind(InteractionResponseType::UpdateMessage)
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
ComponentDataModel::TodoSelector(selector) => {
|
ComponentDataModel::TodoSelector(selector) => {
|
||||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
||||||
@ -260,8 +249,6 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
|
|||||||
.map(|row| (row.id as usize, row.value.clone()))
|
.map(|row| (row.id as usize, row.value.clone()))
|
||||||
.collect::<Vec<(usize, String)>>();
|
.collect::<Vec<(usize, String)>>();
|
||||||
|
|
||||||
let max_pages = max_todo_page(&values);
|
|
||||||
|
|
||||||
let resp = show_todo_page(
|
let resp = show_todo_page(
|
||||||
&values,
|
&values,
|
||||||
selector.page,
|
selector.page,
|
||||||
@ -270,12 +257,8 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
|
|||||||
selector.guild_id,
|
selector.guild_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
let _ = component
|
let mut invoke = CommandInvoke::component(component);
|
||||||
.create_interaction_response(&ctx, move |r| {
|
let _ = invoke.respond(&ctx, resp).await;
|
||||||
*r = resp;
|
|
||||||
r.kind(InteractionResponseType::UpdateMessage)
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,7 @@
|
|||||||
use chrono_tz::Tz;
|
use chrono_tz::Tz;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_repr::*;
|
use serde_repr::*;
|
||||||
use serenity::{
|
use serenity::{builder::CreateComponents, model::interactions::message_component::ButtonStyle};
|
||||||
builder::CreateComponents,
|
|
||||||
model::{
|
|
||||||
id::{ChannelId, GuildId, UserId},
|
|
||||||
interactions::message_component::ButtonStyle,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{component_models::ComponentDataModel, models::reminder::look_flags::LookFlags};
|
use crate::{component_models::ComponentDataModel, models::reminder::look_flags::LookFlags};
|
||||||
|
|
||||||
|
@ -8,7 +8,13 @@ pub const CHARACTERS: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX
|
|||||||
|
|
||||||
const THEME_COLOR_FALLBACK: u32 = 0x8fb677;
|
const THEME_COLOR_FALLBACK: u32 = 0x8fb677;
|
||||||
|
|
||||||
pub const DEFAULT_AVATAR: AttachmentType = (
|
use std::{collections::HashSet, env, iter::FromIterator};
|
||||||
|
|
||||||
|
use regex::{Regex, RegexBuilder};
|
||||||
|
use serenity::http::AttachmentType;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref DEFAULT_AVATAR: AttachmentType<'static> = (
|
||||||
include_bytes!(concat!(
|
include_bytes!(concat!(
|
||||||
env!("CARGO_MANIFEST_DIR"),
|
env!("CARGO_MANIFEST_DIR"),
|
||||||
"/assets/",
|
"/assets/",
|
||||||
@ -18,32 +24,14 @@ pub const DEFAULT_AVATAR: AttachmentType = (
|
|||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
use std::{collections::HashSet, env, iter::FromIterator};
|
|
||||||
|
|
||||||
use regex::{Regex, RegexBuilder};
|
|
||||||
use serenity::http::AttachmentType;
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
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_COMMANDS: Regex = Regex::new(r#"([a-z]+)"#).unwrap();
|
|
||||||
|
|
||||||
pub static ref REGEX_ALIAS: Regex =
|
|
||||||
Regex::new(r#"(?P<name>[\S]{1,12})(?:(?: (?P<cmd>.*)$)|$)"#).unwrap();
|
|
||||||
|
|
||||||
pub static ref REGEX_CONTENT_SUBSTITUTION: Regex = Regex::new(r#"<<((?P<user>\d+)|(?P<role>.{1,100}))>>"#).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_REMIND_COMMAND: Regex = RegexBuilder::new(
|
|
||||||
r#"(?P<mentions>(?:<@\d+>\s+|<@!\d+>\s+|<#\d+>\s+)*)(?P<time>(?:(?:\d+)(?:s|m|h|d|:|/|-|))+)(?:\s+(?P<interval>(?:(?:\d+)(?:s|m|h|d|))+))?(?:\s+(?P<expires>(?:(?:\d+)(?:s|m|h|d|:|/|-|))+))?\s+(?P<content>.*)"#
|
|
||||||
)
|
|
||||||
.dot_matches_new_line(true)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
pub static ref REGEX_NATURAL_COMMAND_1: Regex = RegexBuilder::new(
|
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+))+))?$"#
|
r#"(?P<time>.*?)(?:\s+)(?:send|say)(?:\s+)(?P<msg>.*?)(?:(?:\s+)to(?:\s+)(?P<mentions>((?:<@\d+>)|(?:<@!\d+>)|(?:<#\d+>)|(?:\s+))+))?$"#
|
||||||
)
|
)
|
||||||
|
206
src/framework.rs
206
src/framework.rs
@ -25,7 +25,8 @@ use serenity::{
|
|||||||
application_command::{
|
application_command::{
|
||||||
ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType,
|
ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType,
|
||||||
},
|
},
|
||||||
InteractionResponseType,
|
message_component::MessageComponentInteraction,
|
||||||
|
InteractionApplicationCommandCallbackDataFlags, InteractionResponseType,
|
||||||
},
|
},
|
||||||
prelude::application_command::ApplicationCommandInteractionDataOption,
|
prelude::application_command::ApplicationCommandInteractionDataOption,
|
||||||
},
|
},
|
||||||
@ -39,11 +40,23 @@ pub struct CreateGenericResponse {
|
|||||||
content: String,
|
content: String,
|
||||||
embed: Option<CreateEmbed>,
|
embed: Option<CreateEmbed>,
|
||||||
components: Option<CreateComponents>,
|
components: Option<CreateComponents>,
|
||||||
|
flags: InteractionApplicationCommandCallbackDataFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CreateGenericResponse {
|
impl CreateGenericResponse {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { content: "".to_string(), embed: None, components: None }
|
Self {
|
||||||
|
content: "".to_string(),
|
||||||
|
embed: None,
|
||||||
|
components: None,
|
||||||
|
flags: InteractionApplicationCommandCallbackDataFlags::empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ephemeral(mut self) -> Self {
|
||||||
|
self.flags.insert(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL);
|
||||||
|
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn content<D: ToString>(mut self, content: D) -> Self {
|
pub fn content<D: ToString>(mut self, content: D) -> Self {
|
||||||
@ -72,35 +85,63 @@ impl CreateGenericResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
enum InvokeModel {
|
enum InvokeModel {
|
||||||
Slash(ApplicationCommandInteraction),
|
Slash(ApplicationCommandInteraction),
|
||||||
|
Component(MessageComponentInteraction),
|
||||||
Text(Message),
|
Text(Message),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct CommandInvoke {
|
pub struct CommandInvoke {
|
||||||
model: InvokeModel,
|
model: InvokeModel,
|
||||||
already_responded: bool,
|
already_responded: bool,
|
||||||
|
deferred: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandInvoke {
|
impl CommandInvoke {
|
||||||
|
pub fn component(component: MessageComponentInteraction) -> Self {
|
||||||
|
Self { model: InvokeModel::Component(component), already_responded: false, deferred: false }
|
||||||
|
}
|
||||||
|
|
||||||
fn slash(interaction: ApplicationCommandInteraction) -> Self {
|
fn slash(interaction: ApplicationCommandInteraction) -> Self {
|
||||||
Self { model: InvokeModel::Slash(interaction), already_responded: false }
|
Self { model: InvokeModel::Slash(interaction), already_responded: false, deferred: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn msg(msg: Message) -> Self {
|
fn msg(msg: Message) -> Self {
|
||||||
Self { model: InvokeModel::Text(msg), already_responded: false }
|
Self { model: InvokeModel::Text(msg), already_responded: false, deferred: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interaction(self) -> Option<ApplicationCommandInteraction> {
|
pub async fn defer(&mut self, http: impl AsRef<Http>) {
|
||||||
match self.model {
|
if !self.deferred {
|
||||||
InvokeModel::Slash(i) => Some(i),
|
match &self.model {
|
||||||
InvokeModel::Text(_) => None,
|
InvokeModel::Slash(i) => {
|
||||||
|
i.create_interaction_response(http, |r| {
|
||||||
|
r.kind(InteractionResponseType::DeferredChannelMessageWithSource)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
self.deferred = true;
|
||||||
|
}
|
||||||
|
InvokeModel::Component(i) => {
|
||||||
|
i.create_interaction_response(http, |r| {
|
||||||
|
r.kind(InteractionResponseType::DeferredChannelMessageWithSource)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
self.deferred = true;
|
||||||
|
}
|
||||||
|
InvokeModel::Text(_) => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn channel_id(&self) -> ChannelId {
|
pub fn channel_id(&self) -> ChannelId {
|
||||||
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::Text(m) => m.channel_id,
|
InvokeModel::Text(m) => m.channel_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,6 +149,7 @@ impl CommandInvoke {
|
|||||||
pub fn guild_id(&self) -> Option<GuildId> {
|
pub fn guild_id(&self) -> Option<GuildId> {
|
||||||
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::Text(m) => m.guild_id,
|
InvokeModel::Text(m) => m.guild_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,6 +161,7 @@ impl CommandInvoke {
|
|||||||
pub fn author_id(&self) -> UserId {
|
pub fn author_id(&self) -> UserId {
|
||||||
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::Text(m) => m.author.id,
|
InvokeModel::Text(m) => m.author.id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,18 +169,57 @@ impl CommandInvoke {
|
|||||||
pub async fn member(&self, cache_http: impl CacheHttp) -> Option<Member> {
|
pub async fn member(&self, cache_http: impl CacheHttp) -> 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::Text(m) => m.member(cache_http).await.ok(),
|
InvokeModel::Text(m) => m.member(cache_http).await.ok(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn respond(
|
pub async fn respond(
|
||||||
&self,
|
&mut self,
|
||||||
http: impl AsRef<Http>,
|
http: impl AsRef<Http>,
|
||||||
generic_response: CreateGenericResponse,
|
generic_response: CreateGenericResponse,
|
||||||
) -> SerenityResult<()> {
|
) -> SerenityResult<()> {
|
||||||
match &self.model {
|
match &self.model {
|
||||||
InvokeModel::Slash(i) => {
|
InvokeModel::Slash(i) => {
|
||||||
if !self.already_responded {
|
if self.already_responded {
|
||||||
|
i.create_followup_message(http, |d| {
|
||||||
|
d.content(generic_response.content);
|
||||||
|
|
||||||
|
if let Some(embed) = generic_response.embed {
|
||||||
|
d.add_embed(embed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(components) = generic_response.components {
|
||||||
|
d.components(|c| {
|
||||||
|
*c = components;
|
||||||
|
c
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
d
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
|
} else if self.deferred {
|
||||||
|
i.edit_original_interaction_response(http, |d| {
|
||||||
|
d.content(generic_response.content);
|
||||||
|
|
||||||
|
if let Some(embed) = generic_response.embed {
|
||||||
|
d.add_embed(embed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(components) = generic_response.components {
|
||||||
|
d.components(|c| {
|
||||||
|
*c = components;
|
||||||
|
c
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
d
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
|
} else {
|
||||||
i.create_interaction_response(http, |r| {
|
i.create_interaction_response(http, |r| {
|
||||||
r.kind(InteractionResponseType::ChannelMessageWithSource)
|
r.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||||
.interaction_response_data(|d| {
|
.interaction_response_data(|d| {
|
||||||
@ -159,7 +241,10 @@ impl CommandInvoke {
|
|||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
} else {
|
}
|
||||||
|
}
|
||||||
|
InvokeModel::Component(i) => {
|
||||||
|
if self.already_responded {
|
||||||
i.create_followup_message(http, |d| {
|
i.create_followup_message(http, |d| {
|
||||||
d.content(generic_response.content);
|
d.content(generic_response.content);
|
||||||
|
|
||||||
@ -178,6 +263,47 @@ impl CommandInvoke {
|
|||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
|
} else if self.deferred {
|
||||||
|
i.edit_original_interaction_response(http, |d| {
|
||||||
|
d.content(generic_response.content);
|
||||||
|
|
||||||
|
if let Some(embed) = generic_response.embed {
|
||||||
|
d.add_embed(embed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(components) = generic_response.components {
|
||||||
|
d.components(|c| {
|
||||||
|
*c = components;
|
||||||
|
c
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
d
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
|
} else {
|
||||||
|
i.create_interaction_response(http, |r| {
|
||||||
|
r.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||||
|
.interaction_response_data(|d| {
|
||||||
|
d.content(generic_response.content);
|
||||||
|
|
||||||
|
if let Some(embed) = generic_response.embed {
|
||||||
|
d.add_embed(embed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(components) = generic_response.components {
|
||||||
|
d.components(|c| {
|
||||||
|
*c = components;
|
||||||
|
c
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
d
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InvokeModel::Text(m) => m
|
InvokeModel::Text(m) => m
|
||||||
@ -200,7 +326,11 @@ impl CommandInvoke {
|
|||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.map(|_| ()),
|
.map(|_| ()),
|
||||||
}
|
}?;
|
||||||
|
|
||||||
|
self.already_responded = true;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +393,7 @@ impl OptionValue {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct CommandOptions {
|
pub struct CommandOptions {
|
||||||
pub command: &'static str,
|
pub command: String,
|
||||||
pub subcommand: Option<String>,
|
pub subcommand: Option<String>,
|
||||||
pub subcommand_group: Option<String>,
|
pub subcommand_group: Option<String>,
|
||||||
pub options: HashMap<String, OptionValue>,
|
pub options: HashMap<String, OptionValue>,
|
||||||
@ -278,7 +408,7 @@ impl CommandOptions {
|
|||||||
impl CommandOptions {
|
impl CommandOptions {
|
||||||
fn new(command: &'static Command) -> Self {
|
fn new(command: &'static Command) -> Self {
|
||||||
Self {
|
Self {
|
||||||
command: command.names[0],
|
command: command.names[0].to_string(),
|
||||||
subcommand: None,
|
subcommand: None,
|
||||||
subcommand_group: None,
|
subcommand_group: None,
|
||||||
options: Default::default(),
|
options: Default::default(),
|
||||||
@ -384,15 +514,16 @@ pub enum HookResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SlashCommandFn =
|
type SlashCommandFn =
|
||||||
for<'fut> fn(&'fut Context, CommandInvoke, CommandOptions) -> BoxFuture<'fut, ()>;
|
for<'fut> fn(&'fut Context, &'fut mut CommandInvoke, CommandOptions) -> BoxFuture<'fut, ()>;
|
||||||
|
|
||||||
type TextCommandFn = for<'fut> fn(&'fut Context, CommandInvoke, String) -> BoxFuture<'fut, ()>;
|
type TextCommandFn =
|
||||||
|
for<'fut> fn(&'fut Context, &'fut mut CommandInvoke, String) -> BoxFuture<'fut, ()>;
|
||||||
|
|
||||||
type MultiCommandFn = for<'fut> fn(&'fut Context, 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(
|
||||||
&'fut Context,
|
&'fut Context,
|
||||||
&'fut CommandInvoke,
|
&'fut mut CommandInvoke,
|
||||||
&'fut CommandOptions,
|
&'fut CommandOptions,
|
||||||
) -> BoxFuture<'fut, HookResult>;
|
) -> BoxFuture<'fut, HookResult>;
|
||||||
|
|
||||||
@ -671,10 +802,10 @@ impl RegexFramework {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let args = CommandOptions::new(command).populate(&interaction);
|
let args = CommandOptions::new(command).populate(&interaction);
|
||||||
let command_invoke = CommandInvoke::slash(interaction);
|
let mut command_invoke = CommandInvoke::slash(interaction);
|
||||||
|
|
||||||
for hook in command.hooks {
|
for hook in command.hooks {
|
||||||
match (hook.fun)(&ctx, &command_invoke, &args).await {
|
match (hook.fun)(&ctx, &mut command_invoke, &args).await {
|
||||||
HookResult::Continue => {}
|
HookResult::Continue => {}
|
||||||
HookResult::Halt => {
|
HookResult::Halt => {
|
||||||
return;
|
return;
|
||||||
@ -683,7 +814,7 @@ impl RegexFramework {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for hook in &self.hooks {
|
for hook in &self.hooks {
|
||||||
match (hook.fun)(&ctx, &command_invoke, &args).await {
|
match (hook.fun)(&ctx, &mut command_invoke, &args).await {
|
||||||
HookResult::Continue => {}
|
HookResult::Continue => {}
|
||||||
HookResult::Halt => {
|
HookResult::Halt => {
|
||||||
return;
|
return;
|
||||||
@ -697,14 +828,33 @@ impl RegexFramework {
|
|||||||
ctx.set_executing(user_id).await;
|
ctx.set_executing(user_id).await;
|
||||||
|
|
||||||
match command.fun {
|
match command.fun {
|
||||||
CommandFnType::Slash(t) => t(&ctx, command_invoke, args).await,
|
CommandFnType::Slash(t) => t(&ctx, &mut command_invoke, args).await,
|
||||||
CommandFnType::Multi(m) => m(&ctx, command_invoke).await,
|
CommandFnType::Multi(m) => m(&ctx, &mut command_invoke).await,
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.drop_executing(user_id).await;
|
ctx.drop_executing(user_id).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn run_command_from_options(
|
||||||
|
&self,
|
||||||
|
ctx: &Context,
|
||||||
|
command_invoke: &mut CommandInvoke,
|
||||||
|
command_options: CommandOptions,
|
||||||
|
) {
|
||||||
|
let command = {
|
||||||
|
self.commands_map
|
||||||
|
.get(&command_options.command)
|
||||||
|
.expect(&format!("Received invalid command: {}", command_options.command))
|
||||||
|
};
|
||||||
|
|
||||||
|
match command.fun {
|
||||||
|
CommandFnType::Slash(t) => t(&ctx, command_invoke, command_options).await,
|
||||||
|
CommandFnType::Multi(m) => m(&ctx, command_invoke).await,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -726,7 +876,7 @@ impl Framework for RegexFramework {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let user_id = msg.author.id;
|
let user_id = msg.author.id;
|
||||||
let invoke = CommandInvoke::msg(msg.clone());
|
let mut invoke = CommandInvoke::msg(msg.clone());
|
||||||
|
|
||||||
// Guild Command
|
// Guild Command
|
||||||
if let Some(guild) = msg.guild(&ctx) {
|
if let Some(guild) = msg.guild(&ctx) {
|
||||||
@ -747,8 +897,8 @@ impl Framework for RegexFramework {
|
|||||||
ctx.set_executing(user_id).await;
|
ctx.set_executing(user_id).await;
|
||||||
|
|
||||||
match command.fun {
|
match command.fun {
|
||||||
CommandFnType::Text(t) => t(&ctx, invoke, args).await,
|
CommandFnType::Text(t) => t(&ctx, &mut invoke, args).await,
|
||||||
CommandFnType::Multi(m) => m(&ctx, invoke).await,
|
CommandFnType::Multi(m) => m(&ctx, &mut invoke).await,
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -773,8 +923,8 @@ impl Framework for RegexFramework {
|
|||||||
ctx.set_executing(user_id).await;
|
ctx.set_executing(user_id).await;
|
||||||
|
|
||||||
match command.fun {
|
match command.fun {
|
||||||
CommandFnType::Text(t) => t(&ctx, invoke, args).await,
|
CommandFnType::Text(t) => t(&ctx, &mut invoke, args).await,
|
||||||
CommandFnType::Multi(m) => m(&ctx, invoke).await,
|
CommandFnType::Multi(m) => m(&ctx, &mut invoke).await,
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ use crate::{
|
|||||||
#[check]
|
#[check]
|
||||||
pub async fn macro_check(
|
pub async fn macro_check(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
invoke: &CommandInvoke,
|
invoke: &mut CommandInvoke,
|
||||||
args: &CommandOptions,
|
args: &CommandOptions,
|
||||||
) -> HookResult {
|
) -> HookResult {
|
||||||
if let Some(guild_id) = invoke.guild_id() {
|
if let Some(guild_id) = invoke.guild_id() {
|
||||||
@ -44,7 +44,7 @@ pub async fn macro_check(
|
|||||||
#[check]
|
#[check]
|
||||||
pub async fn check_self_permissions(
|
pub async fn check_self_permissions(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
invoke: &CommandInvoke,
|
invoke: &mut CommandInvoke,
|
||||||
_args: &CommandOptions,
|
_args: &CommandOptions,
|
||||||
) -> HookResult {
|
) -> HookResult {
|
||||||
if let Some(guild) = invoke.guild(&ctx) {
|
if let Some(guild) = invoke.guild(&ctx) {
|
||||||
@ -97,7 +97,7 @@ pub async fn check_self_permissions(
|
|||||||
#[check]
|
#[check]
|
||||||
pub async fn check_managed_permissions(
|
pub async fn check_managed_permissions(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
invoke: &CommandInvoke,
|
invoke: &mut CommandInvoke,
|
||||||
args: &CommandOptions,
|
args: &CommandOptions,
|
||||||
) -> HookResult {
|
) -> HookResult {
|
||||||
if let Some(guild) = invoke.guild(&ctx) {
|
if let Some(guild) = invoke.guild(&ctx) {
|
||||||
@ -191,7 +191,7 @@ Please talk to your server admin, and ask them to use the `/restrict` command to
|
|||||||
#[check]
|
#[check]
|
||||||
pub async fn check_guild_permissions(
|
pub async fn check_guild_permissions(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
invoke: &CommandInvoke,
|
invoke: &mut CommandInvoke,
|
||||||
_args: &CommandOptions,
|
_args: &CommandOptions,
|
||||||
) -> HookResult {
|
) -> HookResult {
|
||||||
if let Some(guild) = invoke.guild(&ctx) {
|
if let Some(guild) = invoke.guild(&ctx) {
|
||||||
|
@ -30,7 +30,7 @@ async fn create_webhook(
|
|||||||
channel: GuildChannel,
|
channel: GuildChannel,
|
||||||
name: impl Display,
|
name: impl Display,
|
||||||
) -> SerenityResult<Webhook> {
|
) -> SerenityResult<Webhook> {
|
||||||
channel.create_webhook_with_avatar(ctx.http(), name, consts::DEFAULT_AVATAR).await
|
channel.create_webhook_with_avatar(ctx.http(), name, consts::DEFAULT_AVATAR.clone()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Hash, PartialEq, Eq)]
|
#[derive(Hash, PartialEq, Eq)]
|
||||||
|
Loading…
Reference in New Issue
Block a user