Extract trait
This commit is contained in:
parent
4823754955
commit
c1305cfb36
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
/target
|
||||
target
|
||||
.env
|
||||
/venv
|
||||
.cargo
|
||||
|
@ -1,17 +1,13 @@
|
||||
use crate::{consts::MINUTE, models::CtxData, Context, Error};
|
||||
|
||||
/// Nudge all future reminders on this channel by a certain amount (don't use for DST! See `/offset`)
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
identifying_name = "nudge",
|
||||
default_member_permissions = "MANAGE_GUILD"
|
||||
)]
|
||||
pub async fn nudge(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Number of minutes to nudge new reminders by"] minutes: Option<isize>,
|
||||
#[description = "Number of seconds to nudge new reminders by"] seconds: Option<isize>,
|
||||
) -> Result<(), Error> {
|
||||
let combined_time = minutes.map_or(0, |m| m * MINUTE as isize) + seconds.map_or(0, |s| s);
|
||||
pub struct Options {
|
||||
minutes: Option<isize>,
|
||||
seconds: Option<isize>,
|
||||
}
|
||||
|
||||
pub async fn nudge(ctx: Context<'_>, options: Options) -> Result<(), Error> {
|
||||
let combined_time =
|
||||
options.minutes.map_or(0, |m| m * MINUTE as isize) + options.seconds.map_or(0, |s| s);
|
||||
|
||||
if combined_time < i16::MIN as isize || combined_time > i16::MAX as isize {
|
||||
ctx.say("Nudge times must be less than 500 minutes").await?;
|
||||
@ -26,3 +22,17 @@ pub async fn nudge(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Nudge all future reminders on this channel by a certain amount (don't use for DST! See `/offset`)
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
identifying_name = "nudge",
|
||||
default_member_permissions = "MANAGE_GUILD"
|
||||
)]
|
||||
pub async fn command(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Number of minutes to nudge new reminders by"] minutes: Option<isize>,
|
||||
#[description = "Number of seconds to nudge new reminders by"] seconds: Option<isize>,
|
||||
) -> Result<(), Error> {
|
||||
nudge(ctx, Options { minutes, seconds }).await
|
||||
}
|
||||
|
@ -1,25 +1,23 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
consts::{HOUR, MINUTE},
|
||||
Context, Error,
|
||||
};
|
||||
|
||||
/// Move all reminders in the current server by a certain amount of time. Times get added together
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
identifying_name = "offset",
|
||||
default_member_permissions = "MANAGE_GUILD"
|
||||
)]
|
||||
pub async fn offset(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Number of hours to offset by"] hours: Option<isize>,
|
||||
#[description = "Number of minutes to offset by"] minutes: Option<isize>,
|
||||
#[description = "Number of seconds to offset by"] seconds: Option<isize>,
|
||||
) -> Result<(), Error> {
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
pub struct Options {
|
||||
hours: Option<isize>,
|
||||
minutes: Option<isize>,
|
||||
seconds: Option<isize>,
|
||||
}
|
||||
|
||||
async fn offset(ctx: Context<'_>, options: Options) -> Result<(), Error> {
|
||||
ctx.defer().await?;
|
||||
|
||||
let combined_time = hours.map_or(0, |h| h * HOUR as isize)
|
||||
+ minutes.map_or(0, |m| m * MINUTE as isize)
|
||||
+ seconds.map_or(0, |s| s);
|
||||
let combined_time = options.hours.map_or(0, |h| h * HOUR as isize)
|
||||
+ options.minutes.map_or(0, |m| m * MINUTE as isize)
|
||||
+ options.seconds.map_or(0, |s| s);
|
||||
|
||||
if combined_time == 0 {
|
||||
ctx.say("Please specify one of `hours`, `minutes` or `seconds`").await?;
|
||||
@ -69,3 +67,18 @@ pub async fn offset(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Move all reminders in the current server by a certain amount of time. Times get added together
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
identifying_name = "offset",
|
||||
default_member_permissions = "MANAGE_GUILD"
|
||||
)]
|
||||
pub async fn command(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Number of hours to offset by"] hours: Option<isize>,
|
||||
#[description = "Number of minutes to offset by"] minutes: Option<isize>,
|
||||
#[description = "Number of seconds to offset by"] seconds: Option<isize>,
|
||||
) -> Result<(), Error> {
|
||||
offset(ctx, Options { hours, minutes, seconds }).await
|
||||
}
|
||||
|
@ -1,22 +1,28 @@
|
||||
use chrono::NaiveDateTime;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{models::CtxData, time_parser::natural_parser, Context, Error};
|
||||
use crate::{
|
||||
models::CtxData, time_parser::natural_parser, utils::Extract, ApplicationContext, Context,
|
||||
Error,
|
||||
};
|
||||
|
||||
/// Pause all reminders on the current channel until a certain time or indefinitely
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
identifying_name = "pause",
|
||||
default_member_permissions = "MANAGE_GUILD"
|
||||
)]
|
||||
pub async fn pause(
|
||||
ctx: Context<'_>,
|
||||
#[description = "When to pause until"] until: Option<String>,
|
||||
) -> Result<(), Error> {
|
||||
#[derive(Serialize, Deserialize, Extract)]
|
||||
pub struct Options {
|
||||
until: Option<String>,
|
||||
}
|
||||
|
||||
impl Extract for Options {
|
||||
fn extract(ctx: ApplicationContext) -> Self {
|
||||
Self { until: extract_arg!(ctx, "until", Option<String>) }
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn pause(ctx: Context<'_>, options: Options) -> Result<(), Error> {
|
||||
let timezone = ctx.timezone().await;
|
||||
|
||||
let mut channel = ctx.channel_data().await.unwrap();
|
||||
|
||||
match until {
|
||||
match options.until {
|
||||
Some(until) => {
|
||||
let parsed = natural_parser(&until, &timezone.to_string()).await;
|
||||
|
||||
@ -65,3 +71,16 @@ pub async fn pause(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Pause all reminders on the current channel until a certain time or indefinitely
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
identifying_name = "pause",
|
||||
default_member_permissions = "MANAGE_GUILD"
|
||||
)]
|
||||
pub async fn command(
|
||||
ctx: Context<'_>,
|
||||
#[description = "When to pause until"] until: Option<String>,
|
||||
) -> Result<(), Error> {
|
||||
pause(ctx, Options { until }).await
|
||||
}
|
||||
|
@ -4,18 +4,49 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
commands::autocomplete::{time_hint_autocomplete, timezone_autocomplete},
|
||||
models::reminder::create_reminder,
|
||||
utils::{extract_arg, Extract},
|
||||
ApplicationContext, Context, Error,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
pub struct RemindOptions {
|
||||
pub time: String,
|
||||
pub content: String,
|
||||
pub channels: Option<String>,
|
||||
pub interval: Option<String>,
|
||||
pub expires: Option<String>,
|
||||
pub tts: Option<bool>,
|
||||
pub timezone: Option<Tz>,
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Options {
|
||||
time: String,
|
||||
content: String,
|
||||
channels: Option<String>,
|
||||
interval: Option<String>,
|
||||
expires: Option<String>,
|
||||
tts: Option<bool>,
|
||||
timezone: Option<String>,
|
||||
}
|
||||
|
||||
impl Extract for Options {
|
||||
fn extract(ctx: ApplicationContext) -> Self {
|
||||
Self {
|
||||
time: extract_arg!(ctx, "time", String),
|
||||
content: extract_arg!(ctx, "content", String),
|
||||
channels: extract_arg!(ctx, "channels", Option<String>),
|
||||
interval: extract_arg!(ctx, "interval", Option<String>),
|
||||
expires: extract_arg!(ctx, "expires", Option<String>),
|
||||
tts: extract_arg!(ctx, "tts", Option<bool>),
|
||||
timezone: extract_arg!(ctx, "timezone", Option<String>),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn remind(ctx: Context<'_>, options: Options) -> Result<(), Error> {
|
||||
let tz = options.timezone.map(|t| t.parse::<Tz>().ok()).flatten();
|
||||
|
||||
create_reminder(
|
||||
ctx,
|
||||
options.time,
|
||||
options.content,
|
||||
options.channels,
|
||||
options.interval,
|
||||
options.expires,
|
||||
options.tts,
|
||||
tz,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Create a reminder. Press "+4 more" for other options. Use "/multiline" for multiline content.
|
||||
@ -24,8 +55,8 @@ pub struct RemindOptions {
|
||||
identifying_name = "remind",
|
||||
default_member_permissions = "MANAGE_GUILD"
|
||||
)]
|
||||
pub async fn remind(
|
||||
ctx: ApplicationContext<'_>,
|
||||
pub async fn command(
|
||||
ctx: Context<'_>,
|
||||
#[description = "The time (and optionally date) to set the reminder for"]
|
||||
#[autocomplete = "time_hint_autocomplete"]
|
||||
time: String,
|
||||
@ -41,8 +72,5 @@ pub async fn remind(
|
||||
#[autocomplete = "timezone_autocomplete"]
|
||||
timezone: Option<String>,
|
||||
) -> Result<(), Error> {
|
||||
let tz = timezone.map(|t| t.parse::<Tz>().ok()).flatten();
|
||||
|
||||
create_reminder(Context::Application(ctx), time, content, channels, interval, expires, tts, tz)
|
||||
.await
|
||||
remind(ctx, Options { time, content, channels, interval, expires, tts, timezone }).await
|
||||
}
|
||||
|
@ -5,25 +5,24 @@ use poise::{
|
||||
serenity_prelude::{CreateEmbed, CreateEmbedFooter},
|
||||
CreateReply,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::autocomplete::timezone_autocomplete, consts::THEME_COLOR, models::CtxData, Context,
|
||||
Error,
|
||||
};
|
||||
|
||||
/// Select your timezone
|
||||
#[poise::command(slash_command, identifying_name = "timezone")]
|
||||
pub async fn timezone(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Timezone to use from this list: https://gist.github.com/JellyWX/913dfc8b63d45192ad6cb54c829324ee"]
|
||||
#[autocomplete = "timezone_autocomplete"]
|
||||
timezone: Option<String>,
|
||||
) -> Result<(), Error> {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Options {
|
||||
pub timezone: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn timezone_fn(ctx: Context<'_>, options: Options) -> Result<(), Error> {
|
||||
let mut user_data = ctx.author_data().await.unwrap();
|
||||
|
||||
let footer_text = format!("Current timezone: {}", user_data.timezone);
|
||||
|
||||
if let Some(timezone) = timezone {
|
||||
if let Some(timezone) = options.timezone {
|
||||
match timezone.parse::<Tz>() {
|
||||
Ok(tz) => {
|
||||
user_data.timezone = timezone.clone();
|
||||
@ -115,3 +114,14 @@ You may want to use one of the popular timezones below, otherwise click [here](h
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Select your timezone
|
||||
#[poise::command(slash_command, identifying_name = "timezone")]
|
||||
pub async fn command(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Timezone to use from this list: https://gist.github.com/JellyWX/913dfc8b63d45192ad6cb54c829324ee"]
|
||||
#[autocomplete = "timezone_autocomplete"]
|
||||
timezone: Option<String>,
|
||||
) -> Result<(), Error> {
|
||||
timezone_fn(ctx, Options { timezone }).await
|
||||
}
|
||||
|
@ -1,15 +1,19 @@
|
||||
use log::warn;
|
||||
use poise::CreateReply;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{models::CtxData, Context, Error};
|
||||
use crate::{models::CtxData, utils::Extract, ApplicationContext, Context, Error};
|
||||
|
||||
/// View the webhook being used to send reminders to this channel
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
identifying_name = "webhook_url",
|
||||
required_permissions = "ADMINISTRATOR"
|
||||
)]
|
||||
pub async fn webhook(ctx: Context<'_>) -> Result<(), Error> {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Options;
|
||||
|
||||
impl Extract for Options {
|
||||
fn extract(_ctx: ApplicationContext) -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn webhook(ctx: Context<'_>, _options: Options) -> Result<(), Error> {
|
||||
match ctx.channel_data().await {
|
||||
Ok(data) => {
|
||||
if let (Some(id), Some(token)) = (data.webhook_id, data.webhook_token) {
|
||||
@ -34,3 +38,13 @@ Do not share it!
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// View the webhook being used to send reminders to this channel
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
identifying_name = "webhook_url",
|
||||
required_permissions = "ADMINISTRATOR"
|
||||
)]
|
||||
pub async fn command(ctx: Context<'_>) -> Result<(), Error> {
|
||||
webhook(ctx, Options {}).await
|
||||
}
|
||||
|
46
src/extract_macro/Cargo.lock
generated
Normal file
46
src/extract_macro/Cargo.lock
generated
Normal file
@ -0,0 +1,46 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "extract_macro"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
11
src/extract_macro/Cargo.toml
Normal file
11
src/extract_macro/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "extract_macro"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0.35"
|
||||
syn = { version = "2.0.49", features = ["full"] }
|
70
src/extract_macro/src/lib.rs
Normal file
70
src/extract_macro/src/lib.rs
Normal file
@ -0,0 +1,70 @@
|
||||
macro_rules! extract_arg {
|
||||
($ctx:ident, $name:literal, String) => {
|
||||
$ctx.args.iter().find(|opt| opt.name == $name).map(|opt| &opt.value).map_or_else(
|
||||
|| String::new(),
|
||||
|v| match v {
|
||||
poise::serenity_prelude::ResolvedValue::String(s) => s.to_string(),
|
||||
_ => String::new(),
|
||||
},
|
||||
)
|
||||
};
|
||||
($ctx:ident, $name:literal, Option<String>) => {
|
||||
$ctx.args
|
||||
.iter()
|
||||
.find(|opt| opt.name == $name)
|
||||
.map(|opt| &opt.value)
|
||||
.map(|v| match v {
|
||||
poise::serenity_prelude::ResolvedValue::String(s) => Some(s.to_string()),
|
||||
_ => None,
|
||||
})
|
||||
.flatten()
|
||||
};
|
||||
($ctx:ident, $name:literal, bool) => {
|
||||
$ctx.args.iter().find(|opt| opt.name == $name).map(|opt| &opt.value).map_or(false, |v| {
|
||||
match v {
|
||||
poise::serenity_prelude::ResolvedValue::Boolean(b) => b.to_owned(),
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
};
|
||||
($ctx:ident, $name:literal, Option<bool>) => {
|
||||
$ctx.args
|
||||
.iter()
|
||||
.find(|opt| opt.name == $name)
|
||||
.map(|opt| &opt.value)
|
||||
.map(|v| match v {
|
||||
poise::serenity_prelude::ResolvedValue::Boolean(b) => Some(b.to_owned()),
|
||||
_ => None,
|
||||
})
|
||||
.flatten()
|
||||
};
|
||||
}
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use syn::parse::Parser;
|
||||
|
||||
#[proc_macro_derive(Extract)]
|
||||
pub fn extract(input: TokenStream) -> TokenStream {
|
||||
// Construct a string representation of the type definition
|
||||
let s = input.to_string();
|
||||
|
||||
// Parse the string representation
|
||||
let ast = syn::parse_derive_input(&s).unwrap();
|
||||
|
||||
// Build the impl
|
||||
let gen = impl_extract(&ast);
|
||||
|
||||
// Return the generated impl
|
||||
gen.parse().unwrap()
|
||||
}
|
||||
|
||||
fn impl_extract(ast: &syn::DeriveInput) -> TokenStream {
|
||||
let name = &ast.ident;
|
||||
TokenStream::from(quote::quote! {
|
||||
impl Extract for #name {
|
||||
fn extract(ctx: ) -> Self {
|
||||
println!("Hello, World! My name is {}", stringify!(#name));
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
20
src/main.rs
20
src/main.rs
@ -37,7 +37,7 @@ use crate::{
|
||||
commands::{
|
||||
allowed_dm, clock::clock, clock_context_menu::clock_context_menu, command_macro,
|
||||
dashboard::dashboard, delete, donate::donate, help::help, info::info, look, multiline,
|
||||
nudge, offset, pause, remind, settings, timer, timezone::timezone, todo, webhook::webhook,
|
||||
nudge, offset, pause, remind, settings, timer, timezone, todo, webhook,
|
||||
},
|
||||
consts::THEME_COLOR,
|
||||
event_handlers::listener,
|
||||
@ -109,7 +109,7 @@ async fn _main(tx: Sender<()>) -> Result<(), Box<dyn StdError + Send + Sync>> {
|
||||
clock(),
|
||||
clock_context_menu(),
|
||||
dashboard(),
|
||||
timezone(),
|
||||
timezone::command(),
|
||||
poise::Command {
|
||||
subcommands: vec![
|
||||
allowed_dm::set_allowed_dm::set_allowed_dm(),
|
||||
@ -127,7 +127,7 @@ async fn _main(tx: Sender<()>) -> Result<(), Box<dyn StdError + Send + Sync>> {
|
||||
}],
|
||||
..settings::settings()
|
||||
},
|
||||
webhook(),
|
||||
webhook::command(),
|
||||
poise::Command {
|
||||
subcommands: vec![
|
||||
command_macro::delete_macro::delete_macro(),
|
||||
@ -138,9 +138,9 @@ async fn _main(tx: Sender<()>) -> Result<(), Box<dyn StdError + Send + Sync>> {
|
||||
],
|
||||
..command_macro::command_macro()
|
||||
},
|
||||
pause::pause(),
|
||||
offset::offset(),
|
||||
nudge::nudge(),
|
||||
pause::command(),
|
||||
offset::command(),
|
||||
nudge::command(),
|
||||
look::look(),
|
||||
delete::delete(),
|
||||
poise::Command {
|
||||
@ -152,7 +152,7 @@ async fn _main(tx: Sender<()>) -> Result<(), Box<dyn StdError + Send + Sync>> {
|
||||
..timer::timer()
|
||||
},
|
||||
multiline::multiline(),
|
||||
remind::remind(),
|
||||
remind::command(),
|
||||
poise::Command {
|
||||
subcommands: vec![
|
||||
poise::Command {
|
||||
@ -197,12 +197,14 @@ async fn _main(tx: Sender<()>) -> Result<(), Box<dyn StdError + Send + Sync>> {
|
||||
sqlx::migrate!().run(&database).await?;
|
||||
|
||||
let popular_timezones = sqlx::query!(
|
||||
"SELECT IFNULL(timezone, 'UTC') AS timezone
|
||||
"
|
||||
SELECT IFNULL(timezone, 'UTC') AS timezone
|
||||
FROM users
|
||||
WHERE timezone IS NOT NULL
|
||||
GROUP BY timezone
|
||||
ORDER BY COUNT(timezone) DESC
|
||||
LIMIT 21"
|
||||
LIMIT 21
|
||||
"
|
||||
)
|
||||
.fetch_all(&database)
|
||||
.await
|
||||
|
@ -1,84 +1,27 @@
|
||||
use chrono_tz::Tz;
|
||||
use poise::serenity_prelude::{model::id::GuildId, ResolvedValue};
|
||||
use poise::serenity_prelude::model::id::GuildId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
commands::remind::RemindOptions, models::reminder::create_reminder, ApplicationContext,
|
||||
Context, Error,
|
||||
};
|
||||
use crate::{commands::remind, utils::Extract, ApplicationContext, Context, Error};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(tag = "command_name")]
|
||||
pub enum RecordedCommand {
|
||||
Remind(RemindOptions),
|
||||
}
|
||||
|
||||
macro_rules! extract_arg {
|
||||
($ctx:ident, $name:literal, String) => {
|
||||
$ctx.args.iter().find(|opt| opt.name == $name).map(|opt| &opt.value).map_or_else(
|
||||
|| String::new(),
|
||||
|v| match v {
|
||||
ResolvedValue::String(s) => s.to_string(),
|
||||
_ => String::new(),
|
||||
},
|
||||
)
|
||||
};
|
||||
($ctx:ident, $name:literal, Option<String>) => {
|
||||
$ctx.args.iter().find(|opt| opt.name == $name).map(|opt| &opt.value).map(|v| match v {
|
||||
ResolvedValue::String(s) => s.to_string(),
|
||||
_ => String::new(),
|
||||
})
|
||||
};
|
||||
($ctx:ident, $name:literal, bool) => {
|
||||
$ctx.args.iter().find(|opt| opt.name == $name).map(|opt| &opt.value).map(|v| match v {
|
||||
ResolvedValue::Boolean(b) => b.to_owned(),
|
||||
_ => false,
|
||||
})
|
||||
};
|
||||
($ctx:ident, $name:literal, Option<Tz>) => {
|
||||
$ctx.args
|
||||
.iter()
|
||||
.find(|opt| opt.name == $name)
|
||||
.map(|opt| &opt.value)
|
||||
.map(|v| match v {
|
||||
ResolvedValue::String(s) => s.parse::<Tz>().ok(),
|
||||
_ => None,
|
||||
})
|
||||
.flatten()
|
||||
};
|
||||
Remind(remind::Options),
|
||||
}
|
||||
|
||||
impl RecordedCommand {
|
||||
pub fn from_context(ctx: ApplicationContext) -> Option<Self> {
|
||||
match ctx.command().identifying_name.as_str() {
|
||||
"remind" => Some(Self::Remind(RemindOptions {
|
||||
time: extract_arg!(ctx, "time", String),
|
||||
content: extract_arg!(ctx, "content", String),
|
||||
channels: extract_arg!(ctx, "channels", Option<String>),
|
||||
interval: extract_arg!(ctx, "interval", Option<String>),
|
||||
expires: extract_arg!(ctx, "expires", Option<String>),
|
||||
tts: extract_arg!(ctx, "tts", bool),
|
||||
timezone: extract_arg!(ctx, "timezone", Option<Tz>),
|
||||
})),
|
||||
"remind" => Some(Self::Remind(remind::Options::extract(ctx))),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn execute(self, ctx: ApplicationContext<'_>) -> Result<(), Error> {
|
||||
match self {
|
||||
RecordedCommand::Remind(command_options) => {
|
||||
create_reminder(
|
||||
Context::Application(ctx),
|
||||
command_options.time,
|
||||
command_options.content,
|
||||
command_options.channels,
|
||||
command_options.interval,
|
||||
command_options.expires,
|
||||
command_options.tts,
|
||||
command_options.timezone,
|
||||
)
|
||||
.await
|
||||
RecordedCommand::Remind(options) => {
|
||||
remind::remind(Context::Application(ctx), options).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,9 @@ pub struct ReminderBuilder {
|
||||
impl ReminderBuilder {
|
||||
pub async fn build(self) -> Result<Reminder, ReminderError> {
|
||||
let queried_time = sqlx::query!(
|
||||
"SELECT DATE_ADD(?, INTERVAL (SELECT nudge FROM channels WHERE id = ?) SECOND) AS `utc_time`",
|
||||
"
|
||||
SELECT DATE_ADD(?, INTERVAL (SELECT nudge FROM channels WHERE id = ?) SECOND) AS `utc_time`
|
||||
",
|
||||
self.utc_time,
|
||||
self.channel,
|
||||
)
|
||||
@ -84,36 +86,24 @@ impl ReminderBuilder {
|
||||
} else {
|
||||
sqlx::query!(
|
||||
"
|
||||
INSERT INTO reminders (
|
||||
`uid`,
|
||||
`channel_id`,
|
||||
`utc_time`,
|
||||
`timezone`,
|
||||
`interval_seconds`,
|
||||
`interval_days`,
|
||||
`interval_months`,
|
||||
`expires`,
|
||||
`content`,
|
||||
`tts`,
|
||||
`attachment_name`,
|
||||
`attachment`,
|
||||
`set_by`
|
||||
) VALUES (
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?
|
||||
)
|
||||
",
|
||||
INSERT INTO reminders (
|
||||
`uid`,
|
||||
`channel_id`,
|
||||
`utc_time`,
|
||||
`timezone`,
|
||||
`interval_seconds`,
|
||||
`interval_days`,
|
||||
`interval_months`,
|
||||
`expires`,
|
||||
`content`,
|
||||
`tts`,
|
||||
`attachment_name`,
|
||||
`attachment`,
|
||||
`set_by`
|
||||
) VALUES (
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
||||
)
|
||||
",
|
||||
self.uid,
|
||||
self.channel,
|
||||
utc_time,
|
||||
|
@ -9,7 +9,7 @@ use poise::{
|
||||
|
||||
use crate::{
|
||||
consts::{CNC_GUILD, SUBSCRIPTION_ROLES},
|
||||
Context,
|
||||
ApplicationContext, Context,
|
||||
};
|
||||
|
||||
pub async fn check_subscription(cache_http: impl CacheHttp, user_id: impl Into<UserId>) -> bool {
|
||||
@ -64,3 +64,7 @@ pub fn footer(ctx: Context<'_>) -> CreateEmbedFooter {
|
||||
shard_count,
|
||||
))
|
||||
}
|
||||
|
||||
pub trait Extract {
|
||||
fn extract(ctx: ApplicationContext) -> Self;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user