Change macro list to use fields to prevent going over limit

Add length checks for name and description
This commit is contained in:
jude 2022-09-17 12:37:58 +01:00
parent b62d24c024
commit 57336f5c81
4 changed files with 42 additions and 66 deletions

View File

@ -2,7 +2,7 @@ use poise::CreateReply;
use crate::{ use crate::{
component_models::pager::{MacroPager, Pager}, component_models::pager::{MacroPager, Pager},
consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR}, consts::THEME_COLOR,
models::{command_macro::CommandMacro, CtxData}, models::{command_macro::CommandMacro, CtxData},
Context, Error, Context, Error,
}; };
@ -30,27 +30,7 @@ pub async fn list_macro(ctx: Context<'_>) -> Result<(), Error> {
} }
pub fn max_macro_page<U, E>(macros: &[CommandMacro<U, E>]) -> usize { pub fn max_macro_page<U, E>(macros: &[CommandMacro<U, E>]) -> usize {
let mut skipped_char_count = 0; ((macros.len() as f64) / 25.0).ceil() as usize
macros
.iter()
.map(|m| {
if let Some(description) = &m.description {
format!("**{}**\n- *{}*\n- Has {} commands", m.name, description, m.commands.len())
} else {
format!("**{}**\n- Has {} commands", m.name, m.commands.len())
}
})
.fold(1, |mut pages, p| {
skipped_char_count += p.len();
if skipped_char_count > EMBED_DESCRIPTION_MAX_LENGTH {
skipped_char_count = p.len();
pages += 1;
}
pages
})
} }
pub fn show_macro_page<U, E>(macros: &[CommandMacro<U, E>], page: usize) -> CreateReply { pub fn show_macro_page<U, E>(macros: &[CommandMacro<U, E>], page: usize) -> CreateReply {
@ -75,45 +55,27 @@ pub fn show_macro_page<U, E>(macros: &[CommandMacro<U, E>], page: usize) -> Crea
page = pages - 1; page = pages - 1;
} }
let mut char_count = 0; let lower = (page * 25).min(macros.len());
let mut skipped_char_count = 0; let upper = ((page + 1) * 25).min(macros.len());
let mut skipped_pages = 0; let fields = macros[lower..upper].iter().map(|m| {
if let Some(description) = &m.description {
let display_vec: Vec<String> = macros (
.iter() m.name.clone(),
.map(|m| { format!("*{}*\n- Has {} commands", description, m.commands.len()),
if let Some(description) = &m.description { true,
format!("**{}**\n- *{}*\n- Has {} commands", m.name, description, m.commands.len()) )
} else { } else {
format!("**{}**\n- Has {} commands", m.name, m.commands.len()) (m.name.clone(), format!("- Has {} commands", m.commands.len()), true)
} }
}) });
.skip_while(|p| {
skipped_char_count += p.len();
if skipped_char_count > EMBED_DESCRIPTION_MAX_LENGTH {
skipped_char_count = p.len();
skipped_pages += 1;
}
skipped_pages < page
})
.take_while(|p| {
char_count += p.len();
char_count < EMBED_DESCRIPTION_MAX_LENGTH
})
.collect::<Vec<String>>();
let display = display_vec.join("\n");
let mut reply = CreateReply::default(); let mut reply = CreateReply::default();
reply reply
.embed(|e| { .embed(|e| {
e.title("Macros") e.title("Macros")
.description(display) .fields(fields)
.footer(|f| f.text(format!("Page {} of {}", page + 1, pages))) .footer(|f| f.text(format!("Page {} of {}", page + 1, pages)))
.color(*THEME_COLOR) .color(*THEME_COLOR)
}) })

View File

@ -15,6 +15,18 @@ pub async fn record_macro(
#[description = "Name for the new macro"] name: String, #[description = "Name for the new macro"] name: String,
#[description = "Description for the new macro"] description: Option<String>, #[description = "Description for the new macro"] description: Option<String>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if name.len() > 100 {
ctx.say("Name must be less than 100 characters").await?;
return Ok(());
}
if description.as_ref().map_or(0, |d| d.len()) > 100 {
ctx.say("Description must be less than 100 characters").await?;
return Ok(());
}
let guild_id = ctx.guild_id().unwrap(); let guild_id = ctx.guild_id().unwrap();
let row = sqlx::query!( let row = sqlx::query!(

View File

@ -1,6 +1,7 @@
use chrono::offset::Utc; use chrono::offset::Utc;
use chrono_tz::{Tz, TZ_VARIANTS}; use chrono_tz::{Tz, TZ_VARIANTS};
use levenshtein::levenshtein; use levenshtein::levenshtein;
use log::warn;
use super::autocomplete::timezone_autocomplete; use super::autocomplete::timezone_autocomplete;
use crate::{consts::THEME_COLOR, models::CtxData, Context, Error}; use crate::{consts::THEME_COLOR, models::CtxData, Context, Error};
@ -157,23 +158,24 @@ pub async fn webhook(ctx: Context<'_>) -> Result<(), Error> {
match ctx.channel_data().await { match ctx.channel_data().await {
Ok(data) => { Ok(data) => {
if let (Some(id), Some(token)) = (data.webhook_id, data.webhook_token) { if let (Some(id), Some(token)) = (data.webhook_id, data.webhook_token) {
let _ = ctx ctx.send(|b| {
.send(|b| { b.ephemeral(true).content(format!(
b.ephemeral(true).content(format!( "**Warning!**
"**Warning!**
This link can be used by users to anonymously send messages, with or without permissions. This link can be used by users to anonymously send messages, with or without permissions.
Do not share it! Do not share it!
|| https://discord.com/api/webhooks/{}/{} ||", || https://discord.com/api/webhooks/{}/{} ||",
id, token, id, token,
)) ))
}) })
.await; .await?;
} else { } else {
let _ = ctx.say("No webhook configured on this channel.").await; ctx.say("No webhook configured on this channel.").await?;
} }
} }
Err(_) => { Err(e) => {
let _ = ctx.say("No webhook configured on this channel.").await; warn!("Error fetching channel data: {:?}", e);
ctx.say("No webhook configured on this channel.").await?;
} }
} }

View File

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