Move all commands to their own files

This commit is contained in:
jude
2024-02-17 18:55:16 +00:00
parent eb92eacb90
commit 4823754955
51 changed files with 1757 additions and 1699 deletions

View File

@ -0,0 +1,38 @@
use crate::{models::CtxData, Context, Error};
/// Add an item to the channel todo list
#[poise::command(
slash_command,
rename = "add",
guild_only = true,
identifying_name = "todo_channel_add",
default_member_permissions = "MANAGE_GUILD"
)]
pub async fn add(
ctx: Context<'_>,
#[description = "The task to add to the todo list"] task: String,
) -> Result<(), Error> {
// ensure channel is cached
let _ = ctx.channel_data().await;
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().get(),
ctx.channel_id().get(),
task
)
.execute(&ctx.data().database)
.await
.unwrap();
ctx.say("Item added to todo list").await?;
Ok(())
}

View File

@ -0,0 +1,16 @@
pub mod add;
pub mod view;
use crate::{Context, Error};
/// Manage the channel todo list
#[poise::command(
slash_command,
rename = "channel",
guild_only = true,
identifying_name = "todo_channel_base",
default_member_permissions = "MANAGE_GUILD"
)]
pub async fn channel(_ctx: Context<'_>) -> Result<(), Error> {
Ok(())
}

View File

@ -0,0 +1,38 @@
use crate::{commands::todo::show_todo_page, Context, Error};
/// View and remove from the channel todo list
#[poise::command(
slash_command,
rename = "view",
guild_only = true,
identifying_name = "todo_channel_view",
default_member_permissions = "MANAGE_GUILD"
)]
pub async fn view(ctx: Context<'_>) -> Result<(), Error> {
let values = sqlx::query!(
"
SELECT todos.id, value FROM todos
INNER JOIN channels ON todos.channel_id = channels.id
WHERE channels.channel = ?
",
ctx.channel_id().get(),
)
.fetch_all(&ctx.data().database)
.await
.unwrap()
.iter()
.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().get()),
ctx.guild_id().map(|g| g.get()),
);
ctx.send(resp).await?;
Ok(())
}

View File

@ -0,0 +1,31 @@
use crate::{Context, Error};
/// Add an item to the server todo list
#[poise::command(
slash_command,
rename = "add",
guild_only = true,
identifying_name = "todo_guild_add",
default_member_permissions = "MANAGE_GUILD"
)]
pub async fn add(
ctx: Context<'_>,
#[description = "The task to add to the todo list"] task: String,
) -> Result<(), Error> {
sqlx::query!(
"
INSERT INTO todos (guild_id, value)
VALUES (
(SELECT id FROM guilds WHERE guild = ?), ?
)",
ctx.guild_id().unwrap().get(),
task
)
.execute(&ctx.data().database)
.await
.unwrap();
ctx.say("Item added to todo list").await?;
Ok(())
}

View File

@ -0,0 +1,15 @@
pub mod add;
pub mod view;
use crate::{Context, Error};
/// Manage the server todo list
#[poise::command(
slash_command,
rename = "server",
guild_only = true,
default_member_permissions = "MANAGE_GUILD"
)]
pub async fn guild(_ctx: Context<'_>) -> Result<(), Error> {
Ok(())
}

View File

@ -0,0 +1,32 @@
use crate::{commands::todo::show_todo_page, Context, Error};
/// View and remove from the server todo list
#[poise::command(
slash_command,
rename = "view",
guild_only = true,
identifying_name = "todo_guild_view",
default_member_permissions = "MANAGE_GUILD"
)]
pub async fn view(ctx: Context<'_>) -> Result<(), Error> {
let values = sqlx::query!(
"
SELECT todos.id, value FROM todos
INNER JOIN guilds ON todos.guild_id = guilds.id
WHERE guilds.guild = ?
",
ctx.guild_id().unwrap().get(),
)
.fetch_all(&ctx.data().database)
.await
.unwrap()
.iter()
.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.get()));
ctx.send(resp).await?;
Ok(())
}

157
src/commands/todo/mod.rs Normal file
View File

@ -0,0 +1,157 @@
use poise::{
serenity_prelude::{
CreateActionRow, CreateEmbed, CreateEmbedFooter, CreateSelectMenu, CreateSelectMenuKind,
CreateSelectMenuOption,
},
CreateReply,
};
use crate::{
component_models::{
pager::{Pager, TodoPager},
ComponentDataModel, TodoSelector,
},
consts::{EMBED_DESCRIPTION_MAX_LENGTH, SELECT_MAX_ENTRIES, THEME_COLOR},
Context, Error,
};
pub mod channel;
pub mod guild;
pub mod user;
/// Manage todo lists
#[poise::command(slash_command, default_member_permissions = "MANAGE_GUILD")]
pub async fn todo(_ctx: Context<'_>) -> Result<(), Error> {
Ok(())
}
pub fn max_todo_page(todo_values: &[(usize, String)]) -> usize {
let mut rows = 0;
let mut char_count = 0;
todo_values.iter().enumerate().map(|(c, (_, v))| format!("{}: {}", c, v)).fold(
1,
|mut pages, text| {
rows += 1;
char_count += text.len();
if char_count > EMBED_DESCRIPTION_MAX_LENGTH || rows > SELECT_MAX_ENTRIES {
rows = 1;
char_count = text.len();
pages += 1;
}
pages
},
)
}
pub fn show_todo_page(
todo_values: &[(usize, String)],
page: usize,
user_id: Option<u64>,
channel_id: Option<u64>,
guild_id: Option<u64>,
) -> CreateReply {
let pager = TodoPager::new(page, user_id, channel_id, guild_id);
let pages = max_todo_page(todo_values);
let mut page = page;
if page >= pages {
page = pages - 1;
}
let mut 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 (todo_ids, display_vec): (Vec<usize>, Vec<String>) = todo_values
.iter()
.enumerate()
.map(|(c, (i, v))| (i, format!("`{}`: {}", c + 1, v)))
.skip_while(|(_, p)| {
first_num += 1;
skipped_rows += 1;
skipped_char_count += p.len();
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 && rows <= SELECT_MAX_ENTRIES
})
.unzip();
let display = display_vec.join("\n");
let title = if user_id.is_some() {
"Your"
} else if channel_id.is_some() {
"Channel"
} else {
"Server"
};
if todo_ids.is_empty() {
CreateReply::default().embed(
CreateEmbed::new()
.title(format!("{} Todo List", title))
.description("Todo List Empty!")
.color(*THEME_COLOR)
.footer(CreateEmbedFooter::new(format!("Page {} of {}", page + 1, pages))),
)
} else {
let todo_selector =
ComponentDataModel::TodoSelector(TodoSelector { page, user_id, channel_id, guild_id });
CreateReply::default()
.embed(
CreateEmbed::new()
.title(format!("{} Todo List", title))
.description(display)
.color(*THEME_COLOR)
.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()
};
CreateSelectMenuOption::new(
format!("Mark {} complete", count + first_num),
id.to_string(),
)
.description(description)
})
.collect(),
},
)),
])
}
}

View File

@ -0,0 +1,27 @@
use crate::{Context, Error};
/// Add an item to your personal todo list
#[poise::command(slash_command, rename = "add", identifying_name = "todo_user_add")]
pub async fn add(
ctx: Context<'_>,
#[description = "The task to add to the todo list"] task: String,
) -> Result<(), Error> {
sqlx::query!(
"
INSERT INTO todos (user_id, value)
VALUES (
(SELECT id FROM users WHERE user = ?),
?
)
",
ctx.author().id.get(),
task
)
.execute(&ctx.data().database)
.await
.unwrap();
ctx.say("Item added to todo list").await?;
Ok(())
}

View File

@ -0,0 +1,10 @@
pub mod add;
pub mod view;
use crate::{Context, Error};
/// Manage your personal todo list
#[poise::command(slash_command, rename = "user", identifying_name = "todo_user_base")]
pub async fn user(_ctx: Context<'_>) -> Result<(), Error> {
Ok(())
}

View File

@ -0,0 +1,26 @@
use crate::{commands::todo::show_todo_page, Context, Error};
/// View and remove from your personal todo list
#[poise::command(slash_command, rename = "view", identifying_name = "todo_user_view")]
pub async fn view(ctx: Context<'_>) -> Result<(), Error> {
let values = sqlx::query!(
"
SELECT todos.id, value FROM todos
INNER JOIN users ON todos.user_id = users.id
WHERE users.user = ?
",
ctx.author().id.get(),
)
.fetch_all(&ctx.data().database)
.await
.unwrap()
.iter()
.map(|row| (row.id as usize, row.value.clone()))
.collect::<Vec<(usize, String)>>();
let resp = show_todo_page(&values, 0, Some(ctx.author().id.get()), None, None);
ctx.send(resp).await?;
Ok(())
}