Add option types for top-level commands
This commit is contained in:
		@@ -1,11 +1,13 @@
 | 
			
		||||
use chrono::Utc;
 | 
			
		||||
use poise::CreateReply;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{models::CtxData, Context, Error};
 | 
			
		||||
use crate::{models::CtxData, utils::Extract, Context, Error};
 | 
			
		||||
 | 
			
		||||
/// View the current time in your selected timezone
 | 
			
		||||
#[poise::command(slash_command)]
 | 
			
		||||
pub async fn clock(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
#[derive(Serialize, Deserialize, Extract)]
 | 
			
		||||
pub struct Options;
 | 
			
		||||
 | 
			
		||||
pub async fn clock(ctx: Context<'_>, _options: Options) -> Result<(), Error> {
 | 
			
		||||
    ctx.defer_ephemeral().await?;
 | 
			
		||||
 | 
			
		||||
    let tz = ctx.timezone().await;
 | 
			
		||||
@@ -20,3 +22,9 @@ pub async fn clock(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// View the current time in your selected timezone
 | 
			
		||||
#[poise::command(slash_command, rename = "clock")]
 | 
			
		||||
pub async fn command(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
    clock(ctx, Options {}).await
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,16 @@
 | 
			
		||||
use poise::{serenity_prelude::CreateEmbed, CreateReply};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{consts::THEME_COLOR, utils::footer, Context, Error};
 | 
			
		||||
use crate::{
 | 
			
		||||
    consts::THEME_COLOR,
 | 
			
		||||
    utils::{footer, Extract},
 | 
			
		||||
    Context, Error,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Get the link to the online dashboard
 | 
			
		||||
#[poise::command(slash_command)]
 | 
			
		||||
pub async fn dashboard(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
#[derive(Serialize, Deserialize, Extract)]
 | 
			
		||||
pub struct Options;
 | 
			
		||||
 | 
			
		||||
pub async fn dashboard(ctx: Context<'_>, _options: Options) -> Result<(), Error> {
 | 
			
		||||
    let footer = footer(ctx);
 | 
			
		||||
 | 
			
		||||
    ctx.send(
 | 
			
		||||
@@ -20,3 +26,9 @@ pub async fn dashboard(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get the link to the web dashboard
 | 
			
		||||
#[poise::command(slash_command, rename = "dashboard")]
 | 
			
		||||
pub async fn command(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
    dashboard(ctx, Options {}).await
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ use poise::{
 | 
			
		||||
    },
 | 
			
		||||
    CreateReply,
 | 
			
		||||
};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    component_models::{
 | 
			
		||||
@@ -14,29 +15,10 @@ use crate::{
 | 
			
		||||
    },
 | 
			
		||||
    consts::{EMBED_DESCRIPTION_MAX_LENGTH, SELECT_MAX_ENTRIES, THEME_COLOR},
 | 
			
		||||
    models::{reminder::Reminder, CtxData},
 | 
			
		||||
    utils::Extract,
 | 
			
		||||
    Context, Error,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Delete reminders
 | 
			
		||||
#[poise::command(
 | 
			
		||||
    slash_command,
 | 
			
		||||
    rename = "del",
 | 
			
		||||
    identifying_name = "delete",
 | 
			
		||||
    default_member_permissions = "MANAGE_GUILD"
 | 
			
		||||
)]
 | 
			
		||||
pub async fn delete(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
    let timezone = ctx.timezone().await;
 | 
			
		||||
 | 
			
		||||
    let reminders =
 | 
			
		||||
        Reminder::from_guild(&ctx, &ctx.data().database, ctx.guild_id(), ctx.author().id).await;
 | 
			
		||||
 | 
			
		||||
    let resp = show_delete_page(&reminders, 0, timezone);
 | 
			
		||||
 | 
			
		||||
    ctx.send(resp).await?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn max_delete_page(reminders: &[Reminder], timezone: &Tz) -> usize {
 | 
			
		||||
    let mut rows = 0;
 | 
			
		||||
    let mut char_count = 0;
 | 
			
		||||
@@ -154,3 +136,25 @@ pub fn show_delete_page(reminders: &[Reminder], page: usize, timezone: Tz) -> Cr
 | 
			
		||||
        .embed(embed)
 | 
			
		||||
        .components(vec![pager.create_button_row(pages), CreateActionRow::SelectMenu(select_menu)])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Deserialize, Extract)]
 | 
			
		||||
pub struct Options;
 | 
			
		||||
 | 
			
		||||
pub async fn delete(ctx: Context<'_>, _options: Options) -> Result<(), Error> {
 | 
			
		||||
    let timezone = ctx.timezone().await;
 | 
			
		||||
 | 
			
		||||
    let reminders =
 | 
			
		||||
        Reminder::from_guild(&ctx, &ctx.data().database, ctx.guild_id(), ctx.author().id).await;
 | 
			
		||||
 | 
			
		||||
    let resp = show_delete_page(&reminders, 0, timezone);
 | 
			
		||||
 | 
			
		||||
    ctx.send(resp).await?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete reminders
 | 
			
		||||
#[poise::command(slash_command, rename = "del", default_member_permissions = "MANAGE_GUILD")]
 | 
			
		||||
pub async fn command(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
    delete(ctx, Options {}).await
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,16 @@
 | 
			
		||||
use poise::{serenity_prelude::CreateEmbed, CreateReply};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{consts::THEME_COLOR, utils::footer, Context, Error};
 | 
			
		||||
use crate::{
 | 
			
		||||
    consts::THEME_COLOR,
 | 
			
		||||
    utils::{footer, Extract},
 | 
			
		||||
    Context, Error,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Details on supporting the bot and Patreon benefits
 | 
			
		||||
#[poise::command(slash_command)]
 | 
			
		||||
pub async fn donate(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
#[derive(Serialize, Deserialize, Extract)]
 | 
			
		||||
pub struct Options;
 | 
			
		||||
 | 
			
		||||
pub async fn donate(ctx: Context<'_>, _options: Options) -> Result<(), Error> {
 | 
			
		||||
    let footer = footer(ctx);
 | 
			
		||||
 | 
			
		||||
    ctx.send(CreateReply::default().embed(CreateEmbed::new().title("Donate")
 | 
			
		||||
@@ -32,3 +38,9 @@ Just $2 USD/month!
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Details on supporting the bot and Patreon benefits
 | 
			
		||||
#[poise::command(slash_command, rename = "patreon")]
 | 
			
		||||
pub async fn command(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
    donate(ctx, Options {}).await
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,16 @@
 | 
			
		||||
use poise::{serenity_prelude::CreateEmbed, CreateReply};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{consts::THEME_COLOR, utils::footer, Context, Error};
 | 
			
		||||
use crate::{
 | 
			
		||||
    consts::THEME_COLOR,
 | 
			
		||||
    utils::{footer, Extract},
 | 
			
		||||
    Context, Error,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Get an overview of bot commands
 | 
			
		||||
#[poise::command(slash_command)]
 | 
			
		||||
pub async fn help(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
#[derive(Serialize, Deserialize, Extract)]
 | 
			
		||||
pub struct Options;
 | 
			
		||||
 | 
			
		||||
pub async fn help(ctx: Context<'_>, _options: Options) -> Result<(), Error> {
 | 
			
		||||
    let footer = footer(ctx);
 | 
			
		||||
 | 
			
		||||
    ctx.send(
 | 
			
		||||
@@ -46,3 +52,9 @@ __Advanced Commands__
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get an overview of bot commands
 | 
			
		||||
#[poise::command(slash_command, rename = "help")]
 | 
			
		||||
pub async fn command(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
    help(ctx, Options {}).await
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,19 +1,24 @@
 | 
			
		||||
use poise::{serenity_prelude::CreateEmbed, CreateReply};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{consts::THEME_COLOR, utils::footer, Context, Error};
 | 
			
		||||
use crate::{
 | 
			
		||||
    consts::THEME_COLOR,
 | 
			
		||||
    utils::{footer, Extract},
 | 
			
		||||
    Context, Error,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Get information about the bot
 | 
			
		||||
#[poise::command(slash_command)]
 | 
			
		||||
pub async fn info(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
#[derive(Serialize, Deserialize, Extract)]
 | 
			
		||||
pub struct Options;
 | 
			
		||||
 | 
			
		||||
pub async fn info(ctx: Context<'_>, _options: Options) -> Result<(), Error> {
 | 
			
		||||
    let footer = footer(ctx);
 | 
			
		||||
 | 
			
		||||
    let _ = ctx
 | 
			
		||||
        .send(
 | 
			
		||||
            CreateReply::default().ephemeral(true).embed(
 | 
			
		||||
                CreateEmbed::new()
 | 
			
		||||
                    .title("Info")
 | 
			
		||||
                    .description(
 | 
			
		||||
                        "Help: `/help`
 | 
			
		||||
    ctx.send(
 | 
			
		||||
        CreateReply::default().ephemeral(true).embed(
 | 
			
		||||
            CreateEmbed::new()
 | 
			
		||||
                .title("Info")
 | 
			
		||||
                .description(
 | 
			
		||||
                    "Help: `/help`
 | 
			
		||||
 | 
			
		||||
**Welcome to Reminder Bot!**
 | 
			
		||||
Developer: <@203532103185465344>
 | 
			
		||||
@@ -22,12 +27,18 @@ Find me on https://discord.jellywx.com and on https://github.com/JellyWX :)
 | 
			
		||||
 | 
			
		||||
Invite the bot: https://invite.reminder-bot.com/
 | 
			
		||||
Use our dashboard: https://reminder-bot.com/",
 | 
			
		||||
                    )
 | 
			
		||||
                    .footer(footer)
 | 
			
		||||
                    .color(*THEME_COLOR),
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
        .await;
 | 
			
		||||
                )
 | 
			
		||||
                .footer(footer)
 | 
			
		||||
                .color(*THEME_COLOR),
 | 
			
		||||
        ),
 | 
			
		||||
    )
 | 
			
		||||
    .await?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get information about the bot
 | 
			
		||||
#[poise::command(slash_command, rename = "info")]
 | 
			
		||||
pub async fn command(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
    info(ctx, Options {}).await
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
use poise::{
 | 
			
		||||
    serenity_prelude::{model::id::ChannelId, Channel, CreateEmbed, CreateEmbedFooter},
 | 
			
		||||
    serenity_prelude::{model::id::ChannelId, CreateEmbed, CreateEmbedFooter, PartialChannel},
 | 
			
		||||
    CreateReply,
 | 
			
		||||
};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
@@ -9,17 +9,18 @@ use crate::{
 | 
			
		||||
    component_models::pager::{LookPager, Pager},
 | 
			
		||||
    consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR},
 | 
			
		||||
    models::{reminder::Reminder, CtxData},
 | 
			
		||||
    utils::Extract,
 | 
			
		||||
    Context, Error,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize_repr, Deserialize_repr, Copy, Clone, Debug)]
 | 
			
		||||
#[derive(Serialize_repr, Deserialize_repr, Copy, Clone)]
 | 
			
		||||
#[repr(u8)]
 | 
			
		||||
pub enum TimeDisplayType {
 | 
			
		||||
    Absolute = 0,
 | 
			
		||||
    Relative = 1,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
 | 
			
		||||
#[derive(Serialize, Deserialize, Copy, Clone)]
 | 
			
		||||
pub struct LookFlags {
 | 
			
		||||
    pub show_disabled: bool,
 | 
			
		||||
    pub channel_id: Option<ChannelId>,
 | 
			
		||||
@@ -32,24 +33,20 @@ impl Default for LookFlags {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// View reminders on a specific channel
 | 
			
		||||
#[poise::command(
 | 
			
		||||
    slash_command,
 | 
			
		||||
    identifying_name = "look",
 | 
			
		||||
    default_member_permissions = "MANAGE_GUILD"
 | 
			
		||||
)]
 | 
			
		||||
pub async fn look(
 | 
			
		||||
    ctx: Context<'_>,
 | 
			
		||||
    #[description = "Channel to view reminders on"] channel: Option<Channel>,
 | 
			
		||||
    #[description = "Whether to show disabled reminders or not"] disabled: Option<bool>,
 | 
			
		||||
    #[description = "Whether to display times as relative or exact times"] relative: Option<bool>,
 | 
			
		||||
) -> Result<(), Error> {
 | 
			
		||||
#[derive(Serialize, Deserialize, Extract)]
 | 
			
		||||
pub struct Options {
 | 
			
		||||
    channel: Option<PartialChannel>,
 | 
			
		||||
    disabled: Option<bool>,
 | 
			
		||||
    relative: Option<bool>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn look(ctx: Context<'_>, options: Options) -> Result<(), Error> {
 | 
			
		||||
    let timezone = ctx.timezone().await;
 | 
			
		||||
 | 
			
		||||
    let flags = LookFlags {
 | 
			
		||||
        show_disabled: disabled.unwrap_or(true),
 | 
			
		||||
        channel_id: channel.map(|c| c.id()),
 | 
			
		||||
        time_display: relative.map_or(TimeDisplayType::Relative, |b| {
 | 
			
		||||
        show_disabled: options.disabled.unwrap_or(true),
 | 
			
		||||
        channel_id: options.channel.map(|c| c.id),
 | 
			
		||||
        time_display: options.relative.map_or(TimeDisplayType::Relative, |b| {
 | 
			
		||||
            if b {
 | 
			
		||||
                TimeDisplayType::Relative
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -117,3 +114,14 @@ pub async fn look(
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// View reminders on a specific channel
 | 
			
		||||
#[poise::command(slash_command, rename = "look", default_member_permissions = "MANAGE_GUILD")]
 | 
			
		||||
pub async fn command(
 | 
			
		||||
    ctx: Context<'_>,
 | 
			
		||||
    #[description = "Channel to view reminders on"] channel: Option<PartialChannel>,
 | 
			
		||||
    #[description = "Whether to show disabled reminders or not"] disabled: Option<bool>,
 | 
			
		||||
    #[description = "Whether to display times as relative or exact times"] relative: Option<bool>,
 | 
			
		||||
) -> Result<(), Error> {
 | 
			
		||||
    look(ctx, Options { channel, disabled, relative }).await
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,13 @@
 | 
			
		||||
use chrono_tz::Tz;
 | 
			
		||||
use log::warn;
 | 
			
		||||
use poise::{CreateReply, Modal};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    commands::autocomplete::{time_hint_autocomplete, timezone_autocomplete},
 | 
			
		||||
    models::reminder::create_reminder,
 | 
			
		||||
    ApplicationContext, Context, Error,
 | 
			
		||||
    utils::Extract,
 | 
			
		||||
    Context, Error,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(poise::Modal)]
 | 
			
		||||
@@ -18,14 +20,61 @@ struct ContentModal {
 | 
			
		||||
    content: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Deserialize, Extract)]
 | 
			
		||||
pub struct Options {
 | 
			
		||||
    time: String,
 | 
			
		||||
    channels: Option<String>,
 | 
			
		||||
    interval: Option<String>,
 | 
			
		||||
    expires: Option<String>,
 | 
			
		||||
    tts: Option<bool>,
 | 
			
		||||
    timezone: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn multiline(ctx: Context<'_>, options: Options) -> Result<(), Error> {
 | 
			
		||||
    match ctx {
 | 
			
		||||
        Context::Application(app_ctx) => {
 | 
			
		||||
            let tz = options.timezone.map(|t| t.parse::<Tz>().ok()).flatten();
 | 
			
		||||
            let data_opt = ContentModal::execute(app_ctx).await?;
 | 
			
		||||
 | 
			
		||||
            match data_opt {
 | 
			
		||||
                Some(data) => {
 | 
			
		||||
                    create_reminder(
 | 
			
		||||
                        ctx,
 | 
			
		||||
                        options.time,
 | 
			
		||||
                        data.content,
 | 
			
		||||
                        options.channels,
 | 
			
		||||
                        options.interval,
 | 
			
		||||
                        options.expires,
 | 
			
		||||
                        options.tts,
 | 
			
		||||
                        tz,
 | 
			
		||||
                    )
 | 
			
		||||
                    .await
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                None => {
 | 
			
		||||
                    warn!("Unexpected None encountered in /multiline");
 | 
			
		||||
                    Ok(ctx
 | 
			
		||||
                        .send(CreateReply::default().content("Unexpected error.").ephemeral(true))
 | 
			
		||||
                        .await
 | 
			
		||||
                        .map(|_| ())?)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        _ => {
 | 
			
		||||
            warn!("Shouldn't be here");
 | 
			
		||||
            Ok(ctx
 | 
			
		||||
                .send(CreateReply::default().content("Unexpected error.").ephemeral(true))
 | 
			
		||||
                .await
 | 
			
		||||
                .map(|_| ())?)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create a reminder with multi-line content. Press "+4 more" for other options.
 | 
			
		||||
#[poise::command(
 | 
			
		||||
    slash_command,
 | 
			
		||||
    identifying_name = "multiline",
 | 
			
		||||
    default_member_permissions = "MANAGE_GUILD"
 | 
			
		||||
)]
 | 
			
		||||
pub async fn multiline(
 | 
			
		||||
    ctx: ApplicationContext<'_>,
 | 
			
		||||
#[poise::command(slash_command, rename = "multiline", default_member_permissions = "MANAGE_GUILD")]
 | 
			
		||||
pub async fn command(
 | 
			
		||||
    ctx: Context<'_>,
 | 
			
		||||
    #[description = "A description of the time to set the reminder for"]
 | 
			
		||||
    #[autocomplete = "time_hint_autocomplete"]
 | 
			
		||||
    time: String,
 | 
			
		||||
@@ -40,30 +89,5 @@ pub async fn multiline(
 | 
			
		||||
    #[autocomplete = "timezone_autocomplete"]
 | 
			
		||||
    timezone: Option<String>,
 | 
			
		||||
) -> Result<(), Error> {
 | 
			
		||||
    let tz = timezone.map(|t| t.parse::<Tz>().ok()).flatten();
 | 
			
		||||
    let data_opt = ContentModal::execute(ctx).await?;
 | 
			
		||||
 | 
			
		||||
    match data_opt {
 | 
			
		||||
        Some(data) => {
 | 
			
		||||
            create_reminder(
 | 
			
		||||
                Context::Application(ctx),
 | 
			
		||||
                time,
 | 
			
		||||
                data.content,
 | 
			
		||||
                channels,
 | 
			
		||||
                interval,
 | 
			
		||||
                expires,
 | 
			
		||||
                tts,
 | 
			
		||||
                tz,
 | 
			
		||||
            )
 | 
			
		||||
            .await
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        None => {
 | 
			
		||||
            warn!("Unexpected None encountered in /multiline");
 | 
			
		||||
            Ok(Context::Application(ctx)
 | 
			
		||||
                .send(CreateReply::default().content("Unexpected error.").ephemeral(true))
 | 
			
		||||
                .await
 | 
			
		||||
                .map(|_| ())?)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    multiline(ctx, Options { time, channels, interval, expires, tts, timezone }).await
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,18 @@
 | 
			
		||||
use crate::{consts::MINUTE, models::CtxData, Context, Error};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{consts::MINUTE, models::CtxData, utils::Extract, Context, Error};
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Deserialize, Extract)]
 | 
			
		||||
pub struct Options {
 | 
			
		||||
    minutes: Option<isize>,
 | 
			
		||||
    seconds: Option<isize>,
 | 
			
		||||
    minutes: Option<i64>,
 | 
			
		||||
    seconds: Option<i64>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
        options.minutes.map_or(0, |m| m * MINUTE as i64) + options.seconds.map_or(0, |s| s);
 | 
			
		||||
 | 
			
		||||
    if combined_time < i16::MIN as isize || combined_time > i16::MAX as isize {
 | 
			
		||||
    if combined_time < i16::MIN as i64 || combined_time > i16::MAX as i64 {
 | 
			
		||||
        ctx.say("Nudge times must be less than 500 minutes").await?;
 | 
			
		||||
    } else {
 | 
			
		||||
        let mut channel_data = ctx.channel_data().await.unwrap();
 | 
			
		||||
@@ -24,15 +27,11 @@ pub async fn nudge(ctx: Context<'_>, options: Options) -> Result<(), 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"
 | 
			
		||||
)]
 | 
			
		||||
#[poise::command(slash_command, rename = "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>,
 | 
			
		||||
    #[description = "Number of minutes to nudge new reminders by"] minutes: Option<i64>,
 | 
			
		||||
    #[description = "Number of seconds to nudge new reminders by"] seconds: Option<i64>,
 | 
			
		||||
) -> Result<(), Error> {
 | 
			
		||||
    nudge(ctx, Options { minutes, seconds }).await
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,21 +2,22 @@ use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    consts::{HOUR, MINUTE},
 | 
			
		||||
    utils::Extract,
 | 
			
		||||
    Context, Error,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Deserialize, Default)]
 | 
			
		||||
#[derive(Serialize, Deserialize, Extract)]
 | 
			
		||||
pub struct Options {
 | 
			
		||||
    hours: Option<isize>,
 | 
			
		||||
    minutes: Option<isize>,
 | 
			
		||||
    seconds: Option<isize>,
 | 
			
		||||
    hours: Option<i64>,
 | 
			
		||||
    minutes: Option<i64>,
 | 
			
		||||
    seconds: Option<i64>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async fn offset(ctx: Context<'_>, options: Options) -> Result<(), Error> {
 | 
			
		||||
    ctx.defer().await?;
 | 
			
		||||
 | 
			
		||||
    let combined_time = options.hours.map_or(0, |h| h * HOUR as isize)
 | 
			
		||||
        + options.minutes.map_or(0, |m| m * MINUTE as isize)
 | 
			
		||||
    let combined_time = options.hours.map_or(0, |h| h * HOUR as i64)
 | 
			
		||||
        + options.minutes.map_or(0, |m| m * MINUTE as i64)
 | 
			
		||||
        + options.seconds.map_or(0, |s| s);
 | 
			
		||||
 | 
			
		||||
    if combined_time == 0 {
 | 
			
		||||
@@ -69,16 +70,12 @@ async fn offset(ctx: Context<'_>, options: Options) -> Result<(), 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"
 | 
			
		||||
)]
 | 
			
		||||
#[poise::command(slash_command, rename = "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>,
 | 
			
		||||
    #[description = "Number of hours to offset by"] hours: Option<i64>,
 | 
			
		||||
    #[description = "Number of minutes to offset by"] minutes: Option<i64>,
 | 
			
		||||
    #[description = "Number of seconds to offset by"] seconds: Option<i64>,
 | 
			
		||||
) -> Result<(), Error> {
 | 
			
		||||
    offset(ctx, Options { hours, minutes, seconds }).await
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,13 @@
 | 
			
		||||
use chrono::NaiveDateTime;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    models::CtxData, time_parser::natural_parser, utils::Extract, ApplicationContext, Context,
 | 
			
		||||
    Error,
 | 
			
		||||
};
 | 
			
		||||
use crate::{models::CtxData, time_parser::natural_parser, utils::Extract, Context, 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;
 | 
			
		||||
 | 
			
		||||
@@ -73,11 +64,7 @@ pub async fn pause(ctx: Context<'_>, options: Options) -> Result<(), 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"
 | 
			
		||||
)]
 | 
			
		||||
#[poise::command(slash_command, rename = "pause", default_member_permissions = "MANAGE_GUILD")]
 | 
			
		||||
pub async fn command(
 | 
			
		||||
    ctx: Context<'_>,
 | 
			
		||||
    #[description = "When to pause until"] until: Option<String>,
 | 
			
		||||
 
 | 
			
		||||
@@ -4,11 +4,11 @@ use serde::{Deserialize, Serialize};
 | 
			
		||||
use crate::{
 | 
			
		||||
    commands::autocomplete::{time_hint_autocomplete, timezone_autocomplete},
 | 
			
		||||
    models::reminder::create_reminder,
 | 
			
		||||
    utils::{extract_arg, Extract},
 | 
			
		||||
    ApplicationContext, Context, Error,
 | 
			
		||||
    utils::Extract,
 | 
			
		||||
    Context, Error,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Deserialize)]
 | 
			
		||||
#[derive(Serialize, Deserialize, Extract)]
 | 
			
		||||
pub struct Options {
 | 
			
		||||
    time: String,
 | 
			
		||||
    content: String,
 | 
			
		||||
@@ -19,20 +19,6 @@ pub struct Options {
 | 
			
		||||
    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();
 | 
			
		||||
 | 
			
		||||
@@ -50,11 +36,7 @@ pub async fn remind(ctx: Context<'_>, options: Options) -> Result<(), Error> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create a reminder. Press "+4 more" for other options. Use "/multiline" for multiline content.
 | 
			
		||||
#[poise::command(
 | 
			
		||||
    slash_command,
 | 
			
		||||
    identifying_name = "remind",
 | 
			
		||||
    default_member_permissions = "MANAGE_GUILD"
 | 
			
		||||
)]
 | 
			
		||||
#[poise::command(slash_command, rename = "remind", default_member_permissions = "MANAGE_GUILD")]
 | 
			
		||||
pub async fn command(
 | 
			
		||||
    ctx: Context<'_>,
 | 
			
		||||
    #[description = "The time (and optionally date) to set the reminder for"]
 | 
			
		||||
 
 | 
			
		||||
@@ -8,11 +8,11 @@ use poise::{
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    commands::autocomplete::timezone_autocomplete, consts::THEME_COLOR, models::CtxData, Context,
 | 
			
		||||
    Error,
 | 
			
		||||
    commands::autocomplete::timezone_autocomplete, consts::THEME_COLOR, models::CtxData,
 | 
			
		||||
    utils::Extract, Context, Error,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Deserialize)]
 | 
			
		||||
#[derive(Serialize, Deserialize, Extract)]
 | 
			
		||||
pub struct Options {
 | 
			
		||||
    pub timezone: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
@@ -116,7 +116,7 @@ You may want to use one of the popular timezones below, otherwise click [here](h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Select your timezone
 | 
			
		||||
#[poise::command(slash_command, identifying_name = "timezone")]
 | 
			
		||||
#[poise::command(slash_command, rename = "timezone")]
 | 
			
		||||
pub async fn command(
 | 
			
		||||
    ctx: Context<'_>,
 | 
			
		||||
    #[description = "Timezone to use from this list: https://gist.github.com/JellyWX/913dfc8b63d45192ad6cb54c829324ee"]
 | 
			
		||||
 
 | 
			
		||||
@@ -2,17 +2,11 @@ use log::warn;
 | 
			
		||||
use poise::CreateReply;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{models::CtxData, utils::Extract, ApplicationContext, Context, Error};
 | 
			
		||||
use crate::{models::CtxData, utils::Extract, Context, Error};
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Deserialize)]
 | 
			
		||||
#[derive(Serialize, Deserialize, Extract)]
 | 
			
		||||
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) => {
 | 
			
		||||
@@ -40,11 +34,7 @@ Do not share it!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// View the webhook being used to send reminders to this channel
 | 
			
		||||
#[poise::command(
 | 
			
		||||
    slash_command,
 | 
			
		||||
    identifying_name = "webhook_url",
 | 
			
		||||
    required_permissions = "ADMINISTRATOR"
 | 
			
		||||
)]
 | 
			
		||||
#[poise::command(slash_command, rename = "webhook", required_permissions = "ADMINISTRATOR")]
 | 
			
		||||
pub async fn command(ctx: Context<'_>) -> Result<(), Error> {
 | 
			
		||||
    webhook(ctx, Options {}).await
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user