Wip commit

This commit is contained in:
jude
2024-01-06 19:48:17 +00:00
parent cce0de7c75
commit e4e9af2bb4
37 changed files with 1051 additions and 1366 deletions

View File

@ -26,7 +26,7 @@ FROM macro
WHERE
guild_id = (SELECT id FROM guilds WHERE guild = ?)
AND name LIKE CONCAT(?, '%')",
ctx.guild_id().unwrap().0,
ctx.guild_id().unwrap().get(),
partial,
)
.fetch_all(&ctx.data().database)

View File

@ -18,7 +18,7 @@ pub async fn delete_macro(
match sqlx::query!(
"
SELECT id FROM macro WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND name = ?",
ctx.guild_id().unwrap().0,
ctx.guild_id().unwrap().get(),
name
)
.fetch_one(&ctx.data().database)

View File

@ -1,4 +1,7 @@
use poise::CreateReply;
use poise::{
serenity_prelude::{CreateEmbed, CreateEmbedFooter},
CreateReply,
};
use crate::{
component_models::pager::{MacroPager, Pager},
@ -20,11 +23,7 @@ pub async fn list_macro(ctx: Context<'_>) -> Result<(), Error> {
let resp = show_macro_page(&macros, 0);
ctx.send(|m| {
*m = resp;
m
})
.await?;
ctx.send(resp).await?;
Ok(())
}
@ -37,15 +36,12 @@ pub fn show_macro_page<U, E>(macros: &[CommandMacro<U, E>], page: usize) -> Crea
let pager = MacroPager::new(page);
if macros.is_empty() {
let mut reply = CreateReply::default();
reply.embed(|e| {
e.title("Macros")
return CreateReply::default().embed(
CreateEmbed::new()
.title("Macros")
.description("No Macros Set Up. Use `/macro record` to get started.")
.color(*THEME_COLOR)
});
return reply;
.color(*THEME_COLOR),
);
}
let pages = max_macro_page(macros);
@ -70,20 +66,13 @@ pub fn show_macro_page<U, E>(macros: &[CommandMacro<U, E>], page: usize) -> Crea
}
});
let mut reply = CreateReply::default();
reply
.embed(|e| {
e.title("Macros")
CreateReply::default()
.embed(
CreateEmbed::new()
.title("Macros")
.fields(fields)
.footer(|f| f.text(format!("Page {} of {}", page + 1, pages)))
.color(*THEME_COLOR)
})
.components(|comp| {
pager.create_button_row(pages, comp);
comp
});
reply
.footer(CreateEmbedFooter::new(format!("Page {} of {}", page + 1, pages))),
)
.components(vec![pager.create_button_row(pages)])
}

View File

@ -1,5 +1,5 @@
use lazy_regex::regex;
use poise::serenity_prelude::CommandOptionType;
use poise::{serenity_prelude::CommandOptionType, CreateReply};
use regex::Captures;
use serde_json::{json, Value};
@ -25,7 +25,7 @@ pub async fn migrate_macro(ctx: Context<'_>) -> Result<(), Error> {
let aliases = sqlx::query_as!(
Alias,
"SELECT name, command FROM command_aliases WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?)",
guild_id.0
guild_id.get()
)
.fetch_all(&mut *transaction)
.await?;
@ -37,7 +37,7 @@ pub async fn migrate_macro(ctx: Context<'_>) -> Result<(), Error> {
Some(cmd_macro) => {
sqlx::query!(
"INSERT INTO macro (guild_id, name, description, commands) VALUES ((SELECT id FROM guilds WHERE guild = ?), ?, ?, ?)",
cmd_macro.guild_id.0,
cmd_macro.guild_id.get(),
cmd_macro.name,
cmd_macro.description,
cmd_macro.commands
@ -54,7 +54,7 @@ pub async fn migrate_macro(ctx: Context<'_>) -> Result<(), Error> {
transaction.commit().await?;
ctx.send(|b| b.content(format!("Added {} macros.", added_aliases))).await?;
ctx.send(CreateReply::default().content(format!("Added {} macros.", added_aliases))).await?;
Ok(())
}

View File

@ -1,5 +1,7 @@
use std::collections::hash_map::Entry;
use poise::{serenity_prelude::CreateEmbed, CreateReply};
use crate::{consts::THEME_COLOR, models::command_macro::CommandMacro, Context, Error};
/// Start recording up to 5 commands to replay
@ -32,23 +34,24 @@ pub async fn record_macro(
let row = sqlx::query!(
"
SELECT 1 as _e FROM macro WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND name = ?",
guild_id.0,
guild_id.get(),
name
)
.fetch_one(&ctx.data().database)
.await;
if row.is_ok() {
ctx.send(|m| {
m.ephemeral(true).embed(|e| {
e.title("Unique Name Required")
ctx.send(
CreateReply::default().ephemeral(true).embed(
CreateEmbed::new()
.title("Unique Name Required")
.description(
"A macro already exists under this name.
Please select a unique name for your macro.",
)
.color(*THEME_COLOR)
})
})
.color(*THEME_COLOR),
),
)
.await?;
} else {
let okay = {
@ -63,28 +66,30 @@ Please select a unique name for your macro.",
};
if okay {
ctx.send(|m| {
m.ephemeral(true).embed(|e| {
e.title("Macro Recording Started")
ctx.send(
CreateReply::default().ephemeral(true).embed(
CreateEmbed::new()
.title("Macro Recording Started")
.description(
"Run up to 5 commands, or type `/macro finish` to stop at any point.
Any commands ran as part of recording will be inconsequential",
)
.color(*THEME_COLOR)
})
})
.color(*THEME_COLOR),
),
)
.await?;
} else {
ctx.send(|m| {
m.ephemeral(true).embed(|e| {
e.title("Macro Already Recording")
ctx.send(
CreateReply::default().ephemeral(true).embed(
CreateEmbed::new()
.title("Macro Already Recording")
.description(
"You are already recording a macro in this server.
Please use `/macro finish` to end this recording before starting another.",
)
.color(*THEME_COLOR)
})
})
.color(*THEME_COLOR),
),
)
.await?;
}
}
@ -108,13 +113,14 @@ pub async fn finish_macro(ctx: Context<'_>) -> Result<(), Error> {
let contained = lock.get(&key);
if contained.map_or(true, |cmacro| cmacro.commands.is_empty()) {
ctx.send(|m| {
m.embed(|e| {
e.title("No Macro Recorded")
ctx.send(
CreateReply::default().embed(
CreateEmbed::new()
.title("No Macro Recorded")
.description("Use `/macro record` to start recording a macro")
.color(*THEME_COLOR)
})
})
.color(*THEME_COLOR),
),
)
.await?;
} else {
let command_macro = contained.unwrap();
@ -122,7 +128,7 @@ pub async fn finish_macro(ctx: Context<'_>) -> Result<(), Error> {
sqlx::query!(
"INSERT INTO macro (guild_id, name, description, commands) VALUES ((SELECT id FROM guilds WHERE guild = ?), ?, ?, ?)",
command_macro.guild_id.0,
command_macro.guild_id.get(),
command_macro.name,
command_macro.description,
json
@ -131,13 +137,14 @@ pub async fn finish_macro(ctx: Context<'_>) -> Result<(), Error> {
.await
.unwrap();
ctx.send(|m| {
m.embed(|e| {
e.title("Macro Recorded")
ctx.send(
CreateReply::default().embed(
CreateEmbed::new()
.title("Macro Recorded")
.description("Use `/macro run` to execute the macro")
.color(*THEME_COLOR)
})
})
.color(*THEME_COLOR),
),
)
.await?;
}
}

View File

@ -1,3 +1,8 @@
use poise::{
serenity_prelude::{CommandOption, CreateEmbed},
CreateReply,
};
use super::super::autocomplete::macro_name_autocomplete;
use crate::{models::command_macro::guild_command_macro, Context, Data, Error, THEME_COLOR};
@ -18,15 +23,15 @@ pub async fn run_macro(
match guild_command_macro(&Context::Application(ctx), &name).await {
Some(command_macro) => {
Context::Application(ctx)
.send(|b| {
b.embed(|e| {
e.title("Running Macro").color(*THEME_COLOR).description(format!(
.send(CreateReply::default().embed(
CreateEmbed::new().title("Running Macro").color(*THEME_COLOR).description(
format!(
"Running macro {} ({} commands)",
command_macro.name,
command_macro.commands.len()
))
})
})
),
),
))
.await?;
for command in command_macro.commands {

View File

@ -1,22 +1,22 @@
use chrono::offset::Utc;
use poise::{serenity_prelude as serenity, serenity_prelude::Mentionable};
use poise::{
serenity_prelude as serenity,
serenity_prelude::{CreateEmbed, CreateEmbedFooter, Mentionable},
CreateReply,
};
use crate::{models::CtxData, Context, Error, THEME_COLOR};
fn footer(
ctx: Context<'_>,
) -> impl FnOnce(&mut serenity::CreateEmbedFooter) -> &mut serenity::CreateEmbedFooter {
fn footer(ctx: Context<'_>) -> CreateEmbedFooter {
let shard_count = ctx.serenity_context().cache.shard_count();
let shard = ctx.serenity_context().shard_id;
move |f| {
f.text(format!(
"{}\nshard {} of {}",
concat!(env!("CARGO_PKG_NAME"), " ver ", env!("CARGO_PKG_VERSION")),
shard,
shard_count,
))
}
CreateEmbedFooter::new(format!(
"{}\nshard {} of {}",
concat!(env!("CARGO_PKG_NAME"), " ver ", env!("CARGO_PKG_VERSION")),
shard,
shard_count,
))
}
/// Get an overview of bot commands
@ -24,9 +24,10 @@ fn footer(
pub async fn help(ctx: Context<'_>) -> Result<(), Error> {
let footer = footer(ctx);
ctx.send(|m| {
m.ephemeral(true).embed(|e| {
e.title("Help")
ctx.send(
CreateReply::default().ephemeral(true).embed(
CreateEmbed::new()
.title("Help")
.color(*THEME_COLOR)
.description(
"__Info Commands__
@ -55,9 +56,9 @@ __Advanced Commands__
`/macro` - Record and replay command sequences
",
)
.footer(footer)
})
})
.footer(footer),
),
)
.await?;
Ok(())
@ -69,9 +70,10 @@ pub async fn info(ctx: Context<'_>) -> Result<(), Error> {
let footer = footer(ctx);
let _ = ctx
.send(|m| {
m.ephemeral(true).embed(|e| {
e.title("Info")
.send(
CreateReply::default().ephemeral(true).embed(
CreateEmbed::new()
.title("Info")
.description(
"Help: `/help`
@ -84,9 +86,9 @@ Invite the bot: https://invite.reminder-bot.com/
Use our dashboard: https://reminder-bot.com/",
)
.footer(footer)
.color(*THEME_COLOR)
})
})
.color(*THEME_COLOR),
),
)
.await;
Ok(())
@ -97,8 +99,7 @@ Use our dashboard: https://reminder-bot.com/",
pub async fn donate(ctx: Context<'_>) -> Result<(), Error> {
let footer = footer(ctx);
ctx.send(|m| m.embed(|e| {
e.title("Donate")
ctx.send(CreateReply::default().embed(CreateEmbed::new().title("Donate")
.description("Thinking of adding a monthly contribution?
Click below for my Patreon and official bot server :)
@ -117,7 +118,7 @@ Just $2 USD/month!
*Please note, you must be in the JellyWX Discord server to receive Patreon features*")
.footer(footer)
.color(*THEME_COLOR)
}),
),
)
.await?;
@ -129,14 +130,15 @@ Just $2 USD/month!
pub async fn dashboard(ctx: Context<'_>) -> Result<(), Error> {
let footer = footer(ctx);
ctx.send(|m| {
m.ephemeral(true).embed(|e| {
e.title("Dashboard")
ctx.send(
CreateReply::default().ephemeral(true).embed(
CreateEmbed::new()
.title("Dashboard")
.description("**https://reminder-bot.com/dashboard**")
.footer(footer)
.color(*THEME_COLOR)
})
})
.color(*THEME_COLOR),
),
)
.await?;
Ok(())
@ -150,9 +152,11 @@ pub async fn clock(ctx: Context<'_>) -> Result<(), Error> {
let tz = ctx.timezone().await;
let now = Utc::now().with_timezone(&tz);
ctx.send(|m| {
m.ephemeral(true).content(format!("Time in **{}**: `{}`", tz, now.format("%H:%M")))
})
ctx.send(CreateReply::default().ephemeral(true).content(format!(
"Time in **{}**: `{}`",
tz,
now.format("%H:%M")
)))
.await?;
Ok(())
@ -168,13 +172,11 @@ pub async fn clock_context_menu(ctx: Context<'_>, user: serenity::User) -> Resul
let now = Utc::now().with_timezone(&tz);
ctx.send(|m| {
m.ephemeral(true).content(format!(
"Time in {}'s timezone: `{}`",
user.mention(),
now.format("%H:%M")
))
})
ctx.send(CreateReply::default().ephemeral(true).content(format!(
"Time in {}'s timezone: `{}`",
user.mention(),
now.format("%H:%M")
)))
.await?;
Ok(())

View File

@ -2,6 +2,10 @@ use chrono::offset::Utc;
use chrono_tz::{Tz, TZ_VARIANTS};
use levenshtein::levenshtein;
use log::warn;
use poise::{
serenity_prelude::{CreateEmbed, CreateEmbedFooter},
CreateReply,
};
use super::autocomplete::timezone_autocomplete;
use crate::{consts::THEME_COLOR, models::CtxData, Context, Error};
@ -26,17 +30,18 @@ pub async fn timezone(
let now = Utc::now().with_timezone(&tz);
ctx.send(|m| {
m.embed(|e| {
e.title("Timezone Set")
ctx.send(
CreateReply::default().embed(
CreateEmbed::new()
.title("Timezone Set")
.description(format!(
"Timezone has been set to **{}**. Your current time should be `{}`",
timezone,
now.format("%H:%M")
))
.color(*THEME_COLOR)
})
})
.color(*THEME_COLOR),
),
)
.await?;
}
@ -60,16 +65,15 @@ pub async fn timezone(
)
});
ctx.send(|m| {
m.embed(|e| {
e.title("Timezone Not Recognized")
ctx.send(CreateReply::default().embed(CreateEmbed::new()
.title("Timezone Not Recognized")
.description("Possibly you meant one of the following timezones, otherwise click [here](https://gist.github.com/JellyWX/913dfc8b63d45192ad6cb54c829324ee):")
.color(*THEME_COLOR)
.fields(fields)
.footer(|f| f.text(footer_text))
.footer(CreateEmbedFooter::new(footer_text))
.url("https://gist.github.com/JellyWX/913dfc8b63d45192ad6cb54c829324ee")
})
})
)
)
.await?;
}
}
@ -78,9 +82,10 @@ pub async fn timezone(
(t.to_string(), format!("🕗 `{}`", Utc::now().with_timezone(t).format("%H:%M")), true)
});
ctx.send(|m| {
m.embed(|e| {
e.title("Timezone Usage")
ctx.send(
CreateReply::default().embed(
CreateEmbed::new()
.title("Timezone Usage")
.description(
"**Usage:**
`/timezone Name`
@ -92,10 +97,10 @@ You may want to use one of the popular timezones below, otherwise click [here](h
)
.color(*THEME_COLOR)
.fields(popular_timezones_iter)
.footer(|f| f.text(footer_text))
.url("https://gist.github.com/JellyWX/913dfc8b63d45192ad6cb54c829324ee")
})
})
.footer(CreateEmbedFooter::new(footer_text))
.url("https://gist.github.com/JellyWX/913dfc8b63d45192ad6cb54c829324ee"),
),
)
.await?;
}
@ -136,13 +141,11 @@ pub async fn set_ephemeral_confirmations(ctx: Context<'_>) -> Result<(), Error>
guild_data.ephemeral_confirmations = true;
guild_data.commit_changes(&ctx.data().database).await;
ctx.send(|r| {
r.ephemeral(true).embed(|e| {
e.title("Confirmations ephemeral")
ctx.send(CreateReply::default().ephemeral(true).embed(CreateEmbed::new().title("Confirmations ephemeral")
.description("Reminder confirmations will be sent privately, and removed when your client restarts.")
.color(*THEME_COLOR)
})
})
)
)
.await?;
Ok(())
@ -160,15 +163,13 @@ pub async fn unset_ephemeral_confirmations(ctx: Context<'_>) -> Result<(), Error
guild_data.ephemeral_confirmations = false;
guild_data.commit_changes(&ctx.data().database).await;
ctx.send(|r| {
r.ephemeral(true).embed(|e| {
e.title("Confirmations public")
ctx.send(CreateReply::default().ephemeral(true).embed(CreateEmbed::new().title("Confirmations public")
.description(
"Reminder confirmations will be sent as regular messages, and won't be removed automatically.",
)
.color(*THEME_COLOR)
})
})
)
)
.await?;
Ok(())
@ -187,13 +188,14 @@ pub async fn set_allowed_dm(ctx: Context<'_>) -> Result<(), Error> {
user_data.allowed_dm = true;
user_data.commit_changes(&ctx.data().database).await;
ctx.send(|r| {
r.ephemeral(true).embed(|e| {
e.title("DMs permitted")
ctx.send(
CreateReply::default().ephemeral(true).embed(
CreateEmbed::new()
.title("DMs permitted")
.description("You will receive a message if a user sets a DM reminder for you.")
.color(*THEME_COLOR)
})
})
.color(*THEME_COLOR),
),
)
.await?;
Ok(())
@ -206,15 +208,16 @@ pub async fn unset_allowed_dm(ctx: Context<'_>) -> Result<(), Error> {
user_data.allowed_dm = false;
user_data.commit_changes(&ctx.data().database).await;
ctx.send(|r| {
r.ephemeral(true).embed(|e| {
e.title("DMs blocked")
ctx.send(
CreateReply::default().ephemeral(true).embed(
CreateEmbed::new()
.title("DMs blocked")
.description(
"You can still set DM reminders for yourself or for users with DMs enabled.",
)
.color(*THEME_COLOR)
})
})
.color(*THEME_COLOR),
),
)
.await?;
Ok(())
@ -230,15 +233,13 @@ pub async fn webhook(ctx: Context<'_>) -> Result<(), Error> {
match ctx.channel_data().await {
Ok(data) => {
if let (Some(id), Some(token)) = (data.webhook_id, data.webhook_token) {
ctx.send(|b| {
b.ephemeral(true).content(format!(
"**Warning!**
ctx.send(CreateReply::default().ephemeral(true).content(format!(
"**Warning!**
This link can be used by users to anonymously send messages, with or without permissions.
Do not share it!
|| https://discord.com/api/webhooks/{}/{} ||",
id, token,
))
})
id, token,
)))
.await?;
} else {
ctx.say("No webhook configured on this channel.").await?;

View File

@ -5,7 +5,11 @@ use chrono_tz::Tz;
use log::warn;
use num_integer::Integer;
use poise::{
serenity_prelude::{builder::CreateEmbed, model::channel::Channel, ButtonStyle, ReactionType},
serenity_prelude::{
builder::CreateEmbed, model::channel::Channel, ButtonStyle, CreateActionRow, CreateButton,
CreateEmbedFooter, CreateSelectMenu, CreateSelectMenuKind, CreateSelectMenuOption,
ReactionType,
},
CreateReply, Modal,
};
@ -125,21 +129,19 @@ pub async fn offset(
let channels = guild
.channels
.iter()
.filter(|(_, channel)| match channel {
Channel::Guild(guild_channel) => guild_channel.is_text_based(),
_ => false,
})
.map(|(id, _)| id.0.to_string())
.filter(|(_, channel)| channel.is_text_based())
.map(|(id, _)| id.get().to_string())
.collect::<Vec<String>>()
.join(",");
sqlx::query!(
"
UPDATE reminders
INNER JOIN
`channels` ON `channels`.id = reminders.channel_id
SET reminders.`utc_time` = DATE_ADD(reminders.`utc_time`, INTERVAL ? SECOND)
WHERE FIND_IN_SET(channels.`channel`, ?)",
UPDATE reminders
INNER JOIN `channels`
ON `channels`.id = reminders.channel_id
SET reminders.`utc_time` = DATE_ADD(reminders.`utc_time`, INTERVAL ? SECOND)
WHERE FIND_IN_SET(channels.`channel`, ?)
",
combined_time as i64,
channels
)
@ -148,9 +150,15 @@ WHERE FIND_IN_SET(channels.`channel`, ?)",
.unwrap();
} else {
sqlx::query!(
"UPDATE reminders INNER JOIN `channels` ON `channels`.id = reminders.channel_id SET reminders.`utc_time` = reminders.`utc_time` + ? WHERE channels.`channel` = ?",
"
UPDATE reminders
INNER JOIN `channels`
ON `channels`.id = reminders.channel_id
SET reminders.`utc_time` = reminders.`utc_time` + ?
WHERE channels.`channel` = ?
",
combined_time as i64,
ctx.channel_id().0
ctx.channel_id().get()
)
.execute(&ctx.data().database)
.await
@ -216,9 +224,9 @@ pub async fn look(
}),
};
let channel_opt = ctx.channel_id().to_channel_cached(&ctx);
let channel_opt = ctx.channel_id().to_channel_cached(&ctx.cache());
let channel_id = if let Some(Channel::Guild(channel)) = channel_opt {
let channel_id = if let Some(channel) = channel_opt {
if Some(channel.guild_id) == ctx.guild_id() {
flags.channel_id.unwrap_or_else(|| ctx.channel_id())
} else {
@ -228,11 +236,8 @@ pub async fn look(
ctx.channel_id()
};
let channel_name = if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx) {
Some(channel.name)
} else {
None
};
let channel_name =
channel_id.to_channel_cached(&ctx.cache()).map(|channel| channel.name.clone());
let reminders = Reminder::from_channel(&ctx.data().database, channel_id, &flags).await;
@ -260,23 +265,21 @@ pub async fn look(
let pager = LookPager::new(flags, timezone);
ctx.send(|r| {
r.ephemeral(true)
.embed(|e| {
e.title(format!(
"Reminders{}",
channel_name.map_or(String::new(), |n| format!(" on #{}", n))
))
.description(display)
.footer(|f| f.text(format!("Page {} of {}", 1, pages)))
.color(*THEME_COLOR)
})
.components(|comp| {
pager.create_button_row(pages, comp);
comp
})
})
ctx.send(
CreateReply::default()
.ephemeral(true)
.embed(
CreateEmbed::new()
.title(format!(
"Reminders{}",
channel_name.map_or(String::new(), |n| format!(" on #{}", n))
))
.description(display)
.footer(CreateEmbedFooter::new(format!("Page {} of {}", 1, pages)))
.color(*THEME_COLOR),
)
.components(vec![pager.create_button_row(pages)]),
)
.await?;
}
@ -298,11 +301,7 @@ pub async fn delete(ctx: Context<'_>) -> Result<(), Error> {
let resp = show_delete_page(&reminders, 0, timezone);
ctx.send(|r| {
*r = resp;
r
})
.await?;
ctx.send(resp).await?;
Ok(())
}
@ -333,16 +332,12 @@ pub fn show_delete_page(reminders: &[Reminder], page: usize, timezone: Tz) -> Cr
let pager = DelPager::new(page, timezone);
if reminders.is_empty() {
let mut reply = CreateReply::default();
let embed = CreateEmbed::new()
.title("Delete Reminders")
.description("No Reminders")
.color(*THEME_COLOR);
reply
.embed(|e| e.title("Delete Reminders").description("No Reminders").color(*THEME_COLOR))
.components(|comp| {
pager.create_button_row(0, comp);
comp
});
return reply;
return CreateReply::default().embed(embed).components(vec![pager.create_button_row(0)]);
}
let pages = max_delete_page(reminders, &timezone);
@ -391,49 +386,42 @@ pub fn show_delete_page(reminders: &[Reminder], page: usize, timezone: Tz) -> Cr
let del_selector = ComponentDataModel::DelSelector(DelSelector { page, timezone });
let mut reply = CreateReply::default();
let embed = CreateEmbed::new()
.title("Delete Reminders")
.description(display)
.footer(CreateEmbedFooter::new(format!("Page {} of {}", page + 1, pages)))
.color(*THEME_COLOR);
reply
.embed(|e| {
e.title("Delete Reminders")
.description(display)
.footer(|f| f.text(format!("Page {} of {}", page + 1, pages)))
.color(*THEME_COLOR)
})
.components(|comp| {
pager.create_button_row(pages, comp);
let select_menu = CreateSelectMenu::new(
del_selector.to_custom_id(),
CreateSelectMenuKind::String {
options: shown_reminders
.iter()
.enumerate()
.map(|(count, reminder)| {
let c = reminder.display_content();
let description = if c.len() > 100 {
format!(
"{}...",
reminder.display_content().chars().take(97).collect::<String>()
)
} else {
c.to_string()
};
comp.create_action_row(|row| {
row.create_select_menu(|menu| {
menu.custom_id(del_selector.to_custom_id()).options(|opt| {
for (count, reminder) in shown_reminders.iter().enumerate() {
opt.create_option(|o| {
o.label(count + first_num).value(reminder.id).description({
let c = reminder.display_content();
if c.len() > 100 {
format!(
"{}...",
reminder
.display_content()
.chars()
.take(97)
.collect::<String>()
)
} else {
c.to_string()
}
})
});
}
opt
})
CreateSelectMenuOption::new(
(count + first_num).to_string(),
reminder.id.to_string(),
)
.description(description)
})
})
});
.collect(),
},
);
reply
CreateReply::default()
.embed(embed)
.components(vec![pager.create_button_row(pages), CreateActionRow::SelectMenu(select_menu)])
}
fn time_difference(start_time: DateTime<Utc>) -> String {
@ -465,19 +453,20 @@ pub async fn timer_base(_ctx: Context<'_>) -> Result<(), Error> {
default_member_permissions = "MANAGE_GUILD"
)]
pub async fn list_timer(ctx: Context<'_>) -> Result<(), Error> {
let owner = ctx.guild_id().map(|g| g.0).unwrap_or_else(|| ctx.author().id.0);
let owner = ctx.guild_id().map(|g| g.get()).unwrap_or_else(|| ctx.author().id.get());
let timers = Timer::from_owner(owner, &ctx.data().database).await;
if !timers.is_empty() {
ctx.send(|m| {
m.embed(|e| {
e.fields(timers.iter().map(|timer| {
(&timer.name, format!("⌚ `{}`", time_difference(timer.start_time)), false)
}))
.color(*THEME_COLOR)
})
})
ctx.send(
CreateReply::default().embed(
CreateEmbed::new()
.fields(timers.iter().map(|timer| {
(&timer.name, format!("⌚ `{}`", time_difference(timer.start_time)), false)
}))
.color(*THEME_COLOR),
),
)
.await?;
} else {
ctx.say("No timers currently. Use `/timer start` to create a new timer").await?;
@ -497,7 +486,7 @@ pub async fn start_timer(
ctx: Context<'_>,
#[description = "Name for the new timer"] name: String,
) -> Result<(), Error> {
let owner = ctx.guild_id().map(|g| g.0).unwrap_or_else(|| ctx.author().id.0);
let owner = ctx.guild_id().map(|g| g.get()).unwrap_or_else(|| ctx.author().id.get());
let count = Timer::count_from_owner(owner, &ctx.data().database).await;
@ -530,7 +519,7 @@ pub async fn delete_timer(
ctx: Context<'_>,
#[description = "Name of timer to delete"] name: String,
) -> Result<(), Error> {
let owner = ctx.guild_id().map(|g| g.0).unwrap_or_else(|| ctx.author().id.0);
let owner = ctx.guild_id().map(|g| g.get()).unwrap_or_else(|| ctx.author().id.get());
let exists =
sqlx::query!("SELECT 1 as _r FROM timers WHERE owner = ? AND name = ?", owner, name)
@ -604,7 +593,7 @@ pub async fn multiline(
None => {
warn!("Unexpected None encountered in /multiline");
Ok(Context::Application(ctx)
.send(|m| m.content("Unexpected error.").ephemeral(true))
.send(CreateReply::default().content("Unexpected error.").ephemeral(true))
.await
.map(|_| ())?)
}
@ -682,9 +671,9 @@ async fn create_reminder(
if list.is_empty() {
if ctx.guild_id().is_some() {
vec![ReminderScope::Channel(ctx.channel_id().0)]
vec![ReminderScope::Channel(ctx.channel_id().get())]
} else {
vec![ReminderScope::User(ctx.author().id.0)]
vec![ReminderScope::User(ctx.author().id.get())]
}
} else {
list
@ -709,10 +698,9 @@ async fn create_reminder(
},
)
} else {
ctx.send(|b| {
b.content(
"`repeat` is only available to Patreon subscribers or self-hosted users")
})
ctx.send(CreateReply::default().content(
"`repeat` is only available to Patreon subscribers or self-hosted users",
))
.await?;
return Ok(());
@ -722,17 +710,16 @@ async fn create_reminder(
};
if processed_interval.is_none() && interval.is_some() {
ctx.send(|b| {
b.content(
"Repeat interval could not be processed. Try similar to `1 hour` or `4 days`")
})
ctx.send(CreateReply::default().content(
"Repeat interval could not be processed. Try similar to `1 hour` or `4 days`",
))
.await?;
} else if processed_expires.is_none() && expires.is_some() {
ctx.send(|b| {
b.ephemeral(true).content(
ctx.send(
CreateReply::default().ephemeral(true).content(
"Expiry time failed to process. Please make it as clear as possible",
)
})
),
)
.await?;
} else {
let mut builder = MultiReminderBuilder::new(&ctx, ctx.guild_id())
@ -756,37 +743,20 @@ async fn create_reminder(
reminder_id: reminder,
});
ctx.send(|m| {
m.embed(|c| {
*c = embed;
c
})
.components(|c| {
c.create_action_row(|r| {
r.create_button(|b| {
b.emoji(ReactionType::Unicode("🔕".to_string()))
.label("Cancel")
.style(ButtonStyle::Danger)
.custom_id(undo_button.to_custom_id())
})
.create_button(|b| {
b.emoji(ReactionType::Unicode("📝".to_string()))
.label("Edit")
.style(ButtonStyle::Link)
.url("https://beta.reminder-bot.com/dashboard")
})
})
})
})
ctx.send(CreateReply::default().embed(embed).components(vec![
CreateActionRow::Buttons(vec![
CreateButton::new(undo_button.to_custom_id())
.emoji(ReactionType::Unicode("🔕".to_string()))
.label("Cancel")
.style(ButtonStyle::Danger),
CreateButton::new_link("https://beta.reminder-bot.com/dashboard")
.emoji(ReactionType::Unicode("📝".to_string()))
.label("Edit"),
]),
]))
.await?;
} else {
ctx.send(|m| {
m.embed(|c| {
*c = embed;
c
})
})
.await?;
ctx.send(CreateReply::default().embed(embed)).await?;
}
}
}

View File

@ -1,4 +1,10 @@
use poise::CreateReply;
use poise::{
serenity_prelude::{
CreateActionRow, CreateEmbed, CreateEmbedFooter, CreateSelectMenu, CreateSelectMenuKind,
CreateSelectMenuOption,
},
CreateReply,
};
use crate::{
component_models::{
@ -48,7 +54,7 @@ pub async fn todo_guild_add(
sqlx::query!(
"INSERT INTO todos (guild_id, value)
VALUES ((SELECT id FROM guilds WHERE guild = ?), ?)",
ctx.guild_id().unwrap().0,
ctx.guild_id().unwrap().get(),
task
)
.execute(&ctx.data().database)
@ -73,7 +79,7 @@ pub async fn todo_guild_view(ctx: Context<'_>) -> Result<(), Error> {
"SELECT todos.id, value FROM todos
INNER JOIN guilds ON todos.guild_id = guilds.id
WHERE guilds.guild = ?",
ctx.guild_id().unwrap().0,
ctx.guild_id().unwrap().get(),
)
.fetch_all(&ctx.data().database)
.await
@ -82,13 +88,9 @@ WHERE guilds.guild = ?",
.map(|row| (row.id as usize, row.value.clone()))
.collect::<Vec<(usize, String)>>();
let resp = show_todo_page(&values, 0, None, None, ctx.guild_id().map(|g| g.0));
let resp = show_todo_page(&values, 0, None, None, ctx.guild_id().map(|g| g.get()));
ctx.send(|r| {
*r = resp;
r
})
.await?;
ctx.send(resp).await?;
Ok(())
}
@ -123,8 +125,8 @@ pub async fn todo_channel_add(
sqlx::query!(
"INSERT INTO todos (guild_id, channel_id, value)
VALUES ((SELECT id FROM guilds WHERE guild = ?), (SELECT id FROM channels WHERE channel = ?), ?)",
ctx.guild_id().unwrap().0,
ctx.channel_id().0,
ctx.guild_id().unwrap().get(),
ctx.channel_id().get(),
task
)
.execute(&ctx.data().database)
@ -149,7 +151,7 @@ pub async fn todo_channel_view(ctx: Context<'_>) -> Result<(), Error> {
"SELECT todos.id, value FROM todos
INNER JOIN channels ON todos.channel_id = channels.id
WHERE channels.channel = ?",
ctx.channel_id().0,
ctx.channel_id().get(),
)
.fetch_all(&ctx.data().database)
.await
@ -158,14 +160,15 @@ WHERE channels.channel = ?",
.map(|row| (row.id as usize, row.value.clone()))
.collect::<Vec<(usize, String)>>();
let resp =
show_todo_page(&values, 0, None, Some(ctx.channel_id().0), ctx.guild_id().map(|g| g.0));
let resp = show_todo_page(
&values,
0,
None,
Some(ctx.channel_id().get()),
ctx.guild_id().map(|g| g.get()),
);
ctx.send(|r| {
*r = resp;
r
})
.await?;
ctx.send(resp).await?;
Ok(())
}
@ -185,7 +188,7 @@ pub async fn todo_user_add(
sqlx::query!(
"INSERT INTO todos (user_id, value)
VALUES ((SELECT id FROM users WHERE user = ?), ?)",
ctx.author().id.0,
ctx.author().id.get(),
task
)
.execute(&ctx.data().database)
@ -204,7 +207,7 @@ pub async fn todo_user_view(ctx: Context<'_>) -> Result<(), Error> {
"SELECT todos.id, value FROM todos
INNER JOIN users ON todos.user_id = users.id
WHERE users.user = ?",
ctx.author().id.0,
ctx.author().id.get(),
)
.fetch_all(&ctx.data().database)
.await
@ -213,13 +216,9 @@ WHERE users.user = ?",
.map(|row| (row.id as usize, row.value.clone()))
.collect::<Vec<(usize, String)>>();
let resp = show_todo_page(&values, 0, Some(ctx.author().id.0), None, None);
let resp = show_todo_page(&values, 0, Some(ctx.author().id.get()), None, None);
ctx.send(|r| {
*r = resp;
r
})
.await?;
ctx.send(resp).await?;
Ok(())
}
@ -306,61 +305,51 @@ pub fn show_todo_page(
};
if todo_ids.is_empty() {
let mut reply = CreateReply::default();
reply.embed(|e| {
e.title(format!("{} Todo List", title))
CreateReply::default().embed(
CreateEmbed::new()
.title(format!("{} Todo List", title))
.description("Todo List Empty!")
.footer(|f| f.text(format!("Page {} of {}", page + 1, pages)))
.color(*THEME_COLOR)
});
reply
.footer(CreateEmbedFooter::new(format!("Page {} of {}", page + 1, pages))),
)
} else {
let todo_selector =
ComponentDataModel::TodoSelector(TodoSelector { page, user_id, channel_id, guild_id });
let mut reply = CreateReply::default();
reply
.embed(|e| {
e.title(format!("{} Todo List", title))
CreateReply::default()
.embed(
CreateEmbed::new()
.title(format!("{} Todo List", title))
.description(display)
.footer(|f| f.text(format!("Page {} of {}", page + 1, pages)))
.color(*THEME_COLOR)
})
.components(|comp| {
pager.create_button_row(pages, comp);
.footer(CreateEmbedFooter::new(format!("Page {} of {}", page + 1, pages))),
)
.components(vec![
pager.create_button_row(pages),
CreateActionRow::SelectMenu(CreateSelectMenu::new(
todo_selector.to_custom_id(),
CreateSelectMenuKind::String {
options: todo_ids
.iter()
.zip(&display_vec)
.enumerate()
.map(|(count, (id, disp))| {
let c = disp.split_once(' ').unwrap_or(("", "")).1;
let description = if c.len() > 100 {
format!("{}...", c.chars().take(97).collect::<String>())
} else {
c.to_string()
};
comp.create_action_row(|row| {
row.create_select_menu(|menu| {
menu.custom_id(todo_selector.to_custom_id()).options(|opt| {
for (count, (id, disp)) in todo_ids.iter().zip(&display_vec).enumerate()
{
opt.create_option(|o| {
o.label(format!("Mark {} complete", count + first_num))
.value(id)
.description({
let c = disp.split_once(' ').unwrap_or(("", "")).1;
if c.len() > 100 {
format!(
"{}...",
c.chars().take(97).collect::<String>()
)
} else {
c.to_string()
}
})
});
}
opt
})
})
})
});
reply
CreateSelectMenuOption::new(
format!("Mark {} complete", count + first_num),
id.to_string(),
)
.description(description)
})
.collect(),
},
)),
])
}
}