fixed del pager. todo stuff

This commit is contained in:
jellywx 2021-09-27 17:34:13 +01:00
parent 379e488f7a
commit 6b5d6ae288
7 changed files with 126 additions and 168 deletions

View File

@ -416,132 +416,12 @@ Any commands ran as part of recording will be inconsequential")
}
}
/*
#[command("alias")]
#[supports_dm(false)]
#[permission_level(Managed)]
async fn alias(ctx: &Context, msg: &Message, args: String) {
let (pool, lm) = get_ctx_data(&ctx).await;
let language = UserData::language_of(&msg.author, &pool).await;
let guild_id = msg.guild_id.unwrap().as_u64().to_owned();
let matches_opt = REGEX_ALIAS.captures(&args);
if let Some(matches) = matches_opt {
let name = matches.name("name").unwrap().as_str();
let command_opt = matches.name("cmd").map(|m| m.as_str());
match name {
"list" => {
let aliases = sqlx::query!(
"
SELECT name, command FROM command_aliases WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?)
",
guild_id
)
.fetch_all(&pool)
.await
.unwrap();
let content = iter::once("Aliases:".to_string()).chain(
aliases
.iter()
.map(|row| format!("**{}**: `{}`", row.name, row.command)),
);
let _ = msg.channel_id.say_lines(&ctx, content).await;
}
"remove" => {
if let Some(command) = command_opt {
let deleted_count = sqlx::query!(
"
SELECT COUNT(1) AS count FROM command_aliases WHERE name = ? AND guild_id = (SELECT id FROM guilds WHERE guild = ?)
", command, guild_id)
.fetch_one(&pool)
.await
.unwrap();
sqlx::query!(
"
DELETE FROM command_aliases WHERE name = ? AND guild_id = (SELECT id FROM guilds WHERE guild = ?)
",
command,
guild_id
)
.execute(&pool)
.await
.unwrap();
let content = lm
.get(&language, "alias/removed")
.replace("{count}", &deleted_count.count.to_string());
let _ = msg.channel_id.say(&ctx, content).await;
} else {
let _ = msg
.channel_id
.say(&ctx, lm.get(&language, "alias/help"))
.await;
}
}
name => {
if let Some(command) = command_opt {
let res = sqlx::query!(
"
INSERT INTO command_aliases (guild_id, name, command) VALUES ((SELECT id FROM guilds WHERE guild = ?), ?, ?)
", guild_id, name, command)
.execute(&pool)
.await;
if res.is_err() {
sqlx::query!(
"
UPDATE command_aliases SET command = ? WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND name = ?
", command, guild_id, name)
.execute(&pool)
.await
.unwrap();
}
let content = lm.get(&language, "alias/created").replace("{name}", name);
let _ = msg.channel_id.say(&ctx, content).await;
} else {
match sqlx::query!(
"
SELECT command FROM command_aliases WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND name = ?
", guild_id, name)
.fetch_one(&pool)
.await {
Ok(row) => {
let framework = ctx.data.read().await
.get::<FrameworkCtx>().cloned().expect("Could not get FrameworkCtx from data");
let mut new_msg = msg.clone();
new_msg.content = format!("<@{}> {}", &ctx.cache.current_user_id(), row.command);
new_msg.id = MessageId(0);
framework.dispatch(ctx.clone(), new_msg).await;
},
Err(_) => {
let content = lm.get(&language, "alias/not_found").replace("{name}", name);
let _ = msg.channel_id.say(&ctx, content).await;
},
}
}
}
}
} else {
let prefix = ctx.prefix(msg.guild_id).await;
command_help(ctx, msg, lm, &prefix, &language, "alias").await;
}
}
*/
#[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) {}

View File

@ -22,7 +22,7 @@ use crate::{
},
consts::{
EMBED_DESCRIPTION_MAX_LENGTH, REGEX_CHANNEL_USER, REGEX_NATURAL_COMMAND_1,
REGEX_NATURAL_COMMAND_2, THEME_COLOR,
REGEX_NATURAL_COMMAND_2, SELECT_MAX_ENTRIES, THEME_COLOR,
},
framework::{CommandInvoke, CommandOptions, CreateGenericResponse, OptionValue},
hooks::{CHECK_GUILD_PERMISSIONS_HOOK, CHECK_MANAGED_PERMISSIONS_HOOK},
@ -290,7 +290,7 @@ async fn look(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
let channel_id = if let Some(Channel::Guild(channel)) = channel_opt {
if Some(channel.guild_id) == invoke.guild_id() {
flags.channel_id.unwrap_or(invoke.channel_id())
flags.channel_id.unwrap_or_else(|| invoke.channel_id())
} else {
invoke.channel_id()
}
@ -374,45 +374,57 @@ async fn delete(ctx: &Context, invoke: CommandInvoke, _args: CommandOptions) {
let _ = interaction
.create_interaction_response(&ctx, |r| {
*r = resp;
r
r.kind(InteractionResponseType::ChannelMessageWithSource)
})
.await;
.await
.unwrap();
}
pub fn max_delete_page(reminders: &Vec<Reminder>, timezone: &Tz) -> usize {
pub fn max_delete_page(reminders: &[Reminder], timezone: &Tz) -> usize {
let mut rows = 0;
let mut char_count = 0;
reminders
.iter()
.enumerate()
.map(|(count, reminder)| reminder.display_del(count, timezone))
.fold(0, |t, r| t + r.len())
.div_ceil(EMBED_DESCRIPTION_MAX_LENGTH)
.fold(1, |mut pages, reminder| {
rows += 1;
char_count += reminder.len();
if char_count > EMBED_DESCRIPTION_MAX_LENGTH || rows > SELECT_MAX_ENTRIES {
rows = 1;
char_count = reminder.len();
pages += 1;
}
pages
})
}
pub async fn show_delete_page(
reminders: &Vec<Reminder>,
reminders: &[Reminder],
page: usize,
timezone: Tz,
) -> CreateInteractionResponse {
let pager = DelPager::new(timezone);
let pager = DelPager::new(page, timezone);
if reminders.is_empty() {
let mut embed = CreateEmbed::default();
embed.title("Delete Reminders").description("No Reminders").color(*THEME_COLOR);
let mut response = CreateInteractionResponse::default();
response.kind(InteractionResponseType::UpdateMessage).interaction_response_data(
|response| {
response.embeds(vec![embed]).components(|comp| {
pager.create_button_row(0, comp);
comp
})
},
);
response.interaction_response_data(|response| {
response.embeds(vec![embed]).components(|comp| {
pager.create_button_row(0, comp);
comp
})
});
return response;
}
let pages = max_delete_page(&reminders, &timezone);
let pages = max_delete_page(reminders, &timezone);
let mut page = page;
if page >= pages {
@ -420,23 +432,37 @@ pub async fn show_delete_page(
}
let mut char_count = 0;
let mut skip_char_count = 0;
let mut rows = 0;
let mut skipped_rows = 0;
let mut skipped_char_count = 0;
let mut first_num = 0;
let mut skipped_pages = 0;
let (shown_reminders, display_vec): (Vec<&Reminder>, Vec<String>) = reminders
.iter()
.enumerate()
.map(|(count, reminder)| (reminder, reminder.display_del(count, &timezone)))
.skip_while(|(_, p)| {
first_num += 1;
skip_char_count += p.len();
skipped_rows += 1;
skipped_char_count += p.len();
skip_char_count < EMBED_DESCRIPTION_MAX_LENGTH * page
if skipped_char_count > EMBED_DESCRIPTION_MAX_LENGTH
|| skipped_rows > SELECT_MAX_ENTRIES
{
skipped_rows = 1;
skipped_char_count = p.len();
skipped_pages += 1;
}
skipped_pages < page
})
.take_while(|(_, p)| {
rows += 1;
char_count += p.len();
char_count < EMBED_DESCRIPTION_MAX_LENGTH
char_count < EMBED_DESCRIPTION_MAX_LENGTH && rows <= SELECT_MAX_ENTRIES
})
.unzip();
@ -452,7 +478,7 @@ pub async fn show_delete_page(
.color(*THEME_COLOR);
let mut response = CreateInteractionResponse::default();
response.kind(InteractionResponseType::UpdateMessage).interaction_response_data(|d| {
response.interaction_response_data(|d| {
d.embeds(vec![embed]).components(|comp| {
pager.create_button_row(pages, comp);
@ -596,7 +622,7 @@ DELETE FROM timers WHERE owner = ? AND name = ?
"list" => {
let timers = Timer::from_owner(owner, &pool).await;
if timers.len() > 0 {
if !timers.is_empty() {
let _ = invoke
.respond(
ctx.http.clone(),
@ -699,7 +725,7 @@ async fn remind(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
let list = args
.get("channels")
.map(|arg| parse_mention_list(&arg.to_string()))
.unwrap_or(vec![]);
.unwrap_or_default();
if list.is_empty() {
vec![ReminderScope::Channel(interaction.channel_id.0)]

View File

@ -1,7 +1,10 @@
use regex_command_attr::command;
use serenity::client::Context;
use crate::framework::{CommandInvoke, CommandOptions};
use crate::{
framework::{CommandInvoke, CommandOptions, CreateGenericResponse},
SQLPool,
};
#[command]
#[description("Manage todo lists")]
@ -41,4 +44,55 @@ use crate::framework::{CommandInvoke, CommandOptions};
)]
#[subcommand("view")]
#[description("View and remove from your personal todo list")]
async fn todo(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {}
async fn todo(ctx: &Context, invoke: CommandInvoke, args: CommandOptions) {
if invoke.guild_id().is_none() && args.subcommand_group != Some("user".to_string()) {
let _ = invoke
.respond(
&ctx,
CreateGenericResponse::new().content("Please use `/todo user` in direct messages"),
)
.await;
} else {
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
let keys = match args.subcommand_group.as_ref().unwrap().as_str() {
"server" => (None, None, invoke.guild_id().map(|g| g.0)),
"channel" => (None, Some(invoke.channel_id().0), invoke.guild_id().map(|g| g.0)),
_ => (Some(invoke.author_id().0), None, None),
};
match args.get("task") {
Some(task) => {
let task = task.to_string();
sqlx::query!(
"INSERT INTO todos (user_id, channel_id, guild_id, value) VALUES (?, ?, ?, ?)",
keys.0,
keys.1,
keys.2,
task
)
.execute(&pool)
.await
.unwrap();
let _ = invoke
.respond(&ctx, CreateGenericResponse::new().content("Item added to todo list"))
.await;
}
None => {
let values = sqlx::query!(
"SELECT value FROM todos WHERE user_id = ? AND channel_id = ? AND guild_id = ?",
keys.0,
keys.1,
keys.2,
)
.fetch_all(&pool)
.await
.unwrap()
.iter()
.map(|row| &row.value);
}
}
}
}

View File

@ -174,7 +174,7 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
let _ = component
.create_interaction_response(&ctx, move |r| {
*r = resp;
r
r.kind(InteractionResponseType::UpdateMessage)
})
.await;
}
@ -195,7 +195,7 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id
let _ = component
.create_interaction_response(&ctx, move |r| {
*r = resp;
r
r.kind(InteractionResponseType::UpdateMessage)
})
.await;
}

View File

@ -186,8 +186,8 @@ impl Pager for DelPager {
}
impl DelPager {
pub fn new(timezone: Tz) -> Self {
Self { page: 0, action: PageAction::First, timezone }
pub fn new(page: usize, timezone: Tz) -> Self {
Self { page, action: PageAction::Refresh, timezone }
}
pub fn buttons(

View File

@ -2,6 +2,7 @@ pub const DAY: u64 = 86_400;
pub const HOUR: u64 = 3_600;
pub const MINUTE: u64 = 60;
pub const EMBED_DESCRIPTION_MAX_LENGTH: usize = 4000;
pub const SELECT_MAX_ENTRIES: usize = 25;
pub const CHARACTERS: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";

View File

@ -144,7 +144,7 @@ impl CommandInvoke {
d.content(generic_response.content);
if let Some(embed) = generic_response.embed {
d.add_embed(embed.clone());
d.add_embed(embed);
}
if let Some(components) = generic_response.components {
@ -164,7 +164,7 @@ impl CommandInvoke {
d.content(generic_response.content);
if let Some(embed) = generic_response.embed {
d.add_embed(embed.clone());
d.add_embed(embed);
}
if let Some(components) = generic_response.components {
@ -186,7 +186,7 @@ impl CommandInvoke {
m.content(generic_response.content);
if let Some(embed) = generic_response.embed {
m.set_embed(embed.clone());
m.set_embed(embed);
}
if let Some(components) = generic_response.components {
@ -308,7 +308,7 @@ impl CommandOptions {
ApplicationCommandOptionType::String => {
cmd_opts.options.insert(
option.name,
OptionValue::String(option.value.unwrap().to_string()),
OptionValue::String(option.value.unwrap().as_str().unwrap().to_string()),
);
}
ApplicationCommandOptionType::Integer => {
@ -404,10 +404,7 @@ pub enum CommandFnType {
impl CommandFnType {
pub fn is_slash(&self) -> bool {
match self {
CommandFnType::Text(_) => false,
_ => true,
}
!matches!(self, CommandFnType::Text(_))
}
}