2022-02-19 18:21:11 +00:00
|
|
|
use poise::CreateReply;
|
2021-09-24 11:55:35 +00:00
|
|
|
|
2021-09-27 16:34:13 +00:00
|
|
|
use crate::{
|
2021-10-11 20:19:08 +00:00
|
|
|
component_models::{
|
2021-10-26 19:11:19 +00:00
|
|
|
pager::{Pager, TodoPager},
|
2021-10-11 20:19:08 +00:00
|
|
|
ComponentDataModel, TodoSelector,
|
|
|
|
},
|
2021-10-02 21:54:34 +00:00
|
|
|
consts::{EMBED_DESCRIPTION_MAX_LENGTH, SELECT_MAX_ENTRIES, THEME_COLOR},
|
2022-02-19 22:11:21 +00:00
|
|
|
hooks::guild_only,
|
2022-02-19 18:21:11 +00:00
|
|
|
Context, Error,
|
2021-09-27 16:34:13 +00:00
|
|
|
};
|
2021-09-24 11:55:35 +00:00
|
|
|
|
2022-02-19 18:21:11 +00:00
|
|
|
/// Manage todo lists
|
2022-02-20 12:19:39 +00:00
|
|
|
#[poise::command(slash_command, rename = "todo", identifying_name = "todo_base")]
|
2022-02-19 18:21:11 +00:00
|
|
|
pub async fn todo_base(_ctx: Context<'_>) -> Result<(), Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Manage the server todo list
|
2022-02-20 12:19:39 +00:00
|
|
|
#[poise::command(
|
|
|
|
slash_command,
|
|
|
|
rename = "server",
|
|
|
|
check = "guild_only",
|
|
|
|
identifying_name = "todo_guild_base"
|
|
|
|
)]
|
2022-02-19 18:21:11 +00:00
|
|
|
pub async fn todo_guild_base(_ctx: Context<'_>) -> Result<(), Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Add an item to the server todo list
|
2022-02-20 12:19:39 +00:00
|
|
|
#[poise::command(
|
|
|
|
slash_command,
|
|
|
|
rename = "add",
|
|
|
|
check = "guild_only",
|
|
|
|
identifying_name = "todo_guild_add"
|
|
|
|
)]
|
2022-02-19 18:21:11 +00:00
|
|
|
pub async fn todo_guild_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().0,
|
|
|
|
task
|
|
|
|
)
|
|
|
|
.execute(&ctx.data().database)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
ctx.say("Item added to todo list").await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// View and remove from the server todo list
|
2022-02-20 12:19:39 +00:00
|
|
|
#[poise::command(
|
|
|
|
slash_command,
|
|
|
|
rename = "view",
|
|
|
|
check = "guild_only",
|
|
|
|
identifying_name = "todo_guild_view"
|
|
|
|
)]
|
2022-02-19 18:21:11 +00:00
|
|
|
pub async fn todo_guild_view(ctx: Context<'_>) -> Result<(), Error> {
|
|
|
|
let values = sqlx::query!(
|
|
|
|
"SELECT todos.id, value FROM todos
|
2021-10-30 19:57:33 +00:00
|
|
|
INNER JOIN guilds ON todos.guild_id = guilds.id
|
2021-11-15 08:09:48 +00:00
|
|
|
WHERE guilds.guild = ?",
|
2022-02-19 18:21:11 +00:00
|
|
|
ctx.guild_id().unwrap().0,
|
|
|
|
)
|
|
|
|
.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.0));
|
|
|
|
|
|
|
|
ctx.send(|r| {
|
|
|
|
*r = resp;
|
|
|
|
r
|
|
|
|
})
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Manage the channel todo list
|
2022-02-20 12:19:39 +00:00
|
|
|
#[poise::command(
|
|
|
|
slash_command,
|
|
|
|
rename = "channel",
|
|
|
|
check = "guild_only",
|
|
|
|
identifying_name = "todo_channel_base"
|
|
|
|
)]
|
2022-02-19 18:21:11 +00:00
|
|
|
pub async fn todo_channel_base(_ctx: Context<'_>) -> Result<(), Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Add an item to the channel todo list
|
2022-02-20 12:19:39 +00:00
|
|
|
#[poise::command(
|
|
|
|
slash_command,
|
|
|
|
rename = "add",
|
|
|
|
check = "guild_only",
|
|
|
|
identifying_name = "todo_channel_add"
|
|
|
|
)]
|
2022-02-19 18:21:11 +00:00
|
|
|
pub async fn todo_channel_add(
|
|
|
|
ctx: Context<'_>,
|
|
|
|
#[description = "The task to add to the todo list"] task: String,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
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,
|
|
|
|
task
|
|
|
|
)
|
|
|
|
.execute(&ctx.data().database)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
ctx.say("Item added to todo list").await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// View and remove from the channel todo list
|
2022-02-20 12:19:39 +00:00
|
|
|
#[poise::command(
|
|
|
|
slash_command,
|
|
|
|
rename = "view",
|
|
|
|
check = "guild_only",
|
|
|
|
identifying_name = "todo_channel_view"
|
|
|
|
)]
|
2022-02-19 18:21:11 +00:00
|
|
|
pub async fn todo_channel_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().0,
|
|
|
|
)
|
|
|
|
.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().0), ctx.guild_id().map(|g| g.0));
|
|
|
|
|
|
|
|
ctx.send(|r| {
|
|
|
|
*r = resp;
|
|
|
|
r
|
|
|
|
})
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Manage your personal todo list
|
2022-02-20 12:19:39 +00:00
|
|
|
#[poise::command(slash_command, rename = "user", identifying_name = "todo_user_base")]
|
2022-02-19 18:21:11 +00:00
|
|
|
pub async fn todo_user_base(_ctx: Context<'_>) -> Result<(), Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Add an item to your personal todo list
|
2022-02-20 12:19:39 +00:00
|
|
|
#[poise::command(slash_command, rename = "add", identifying_name = "todo_user_add")]
|
2022-02-19 18:21:11 +00:00
|
|
|
pub async fn todo_user_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.0,
|
|
|
|
task
|
|
|
|
)
|
|
|
|
.execute(&ctx.data().database)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
ctx.say("Item added to todo list").await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// View and remove from your personal todo list
|
2022-02-20 12:19:39 +00:00
|
|
|
#[poise::command(slash_command, rename = "view", identifying_name = "todo_user_view")]
|
2022-02-19 18:21:11 +00:00
|
|
|
pub async fn todo_user_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.0,
|
|
|
|
)
|
|
|
|
.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.0), None, None);
|
|
|
|
|
|
|
|
ctx.send(|r| {
|
|
|
|
*r = resp;
|
|
|
|
r
|
|
|
|
})
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
Ok(())
|
2021-09-27 16:34:13 +00:00
|
|
|
}
|
2021-10-02 21:54:34 +00:00
|
|
|
|
2021-10-11 20:19:08 +00:00
|
|
|
pub fn max_todo_page(todo_values: &[(usize, String)]) -> usize {
|
2021-10-02 21:54:34 +00:00
|
|
|
let mut rows = 0;
|
|
|
|
let mut char_count = 0;
|
|
|
|
|
2021-10-11 20:19:08 +00:00
|
|
|
todo_values.iter().enumerate().map(|(c, (_, v))| format!("{}: {}", c, v)).fold(
|
2021-10-02 21:54:34 +00:00
|
|
|
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(
|
2021-10-11 20:19:08 +00:00
|
|
|
todo_values: &[(usize, String)],
|
2021-10-02 21:54:34 +00:00
|
|
|
page: usize,
|
|
|
|
user_id: Option<u64>,
|
|
|
|
channel_id: Option<u64>,
|
|
|
|
guild_id: Option<u64>,
|
2022-02-19 18:21:11 +00:00
|
|
|
) -> CreateReply {
|
2021-10-26 19:11:19 +00:00
|
|
|
let pager = TodoPager::new(page, user_id, channel_id, guild_id);
|
2021-10-02 21:54:34 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2021-10-11 20:19:08 +00:00
|
|
|
let (todo_ids, display_vec): (Vec<usize>, Vec<String>) = todo_values
|
2021-10-02 21:54:34 +00:00
|
|
|
.iter()
|
|
|
|
.enumerate()
|
2021-10-11 20:19:08 +00:00
|
|
|
.map(|(c, (i, v))| (i, format!("`{}`: {}", c + 1, v)))
|
|
|
|
.skip_while(|(_, p)| {
|
2021-10-02 21:54:34 +00:00
|
|
|
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
|
|
|
|
})
|
2021-10-11 20:19:08 +00:00
|
|
|
.take_while(|(_, p)| {
|
2021-10-02 21:54:34 +00:00
|
|
|
rows += 1;
|
|
|
|
char_count += p.len();
|
|
|
|
|
|
|
|
char_count < EMBED_DESCRIPTION_MAX_LENGTH && rows <= SELECT_MAX_ENTRIES
|
|
|
|
})
|
2021-10-11 20:19:08 +00:00
|
|
|
.unzip();
|
2021-10-02 21:54:34 +00:00
|
|
|
|
|
|
|
let display = display_vec.join("\n");
|
|
|
|
|
|
|
|
let title = if user_id.is_some() {
|
|
|
|
"Your"
|
|
|
|
} else if channel_id.is_some() {
|
|
|
|
"Channel"
|
|
|
|
} else {
|
|
|
|
"Server"
|
|
|
|
};
|
|
|
|
|
2021-11-15 07:51:38 +00:00
|
|
|
if todo_ids.is_empty() {
|
2022-02-19 18:21:11 +00:00
|
|
|
let mut reply = CreateReply::default();
|
|
|
|
|
|
|
|
reply.embed(|e| {
|
2021-10-13 15:37:15 +00:00
|
|
|
e.title(format!("{} Todo List", title))
|
2021-11-15 07:51:38 +00:00
|
|
|
.description("Todo List Empty!")
|
2021-10-13 15:37:15 +00:00
|
|
|
.footer(|f| f.text(format!("Page {} of {}", page + 1, pages)))
|
|
|
|
.color(*THEME_COLOR)
|
2022-02-19 18:21:11 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
reply
|
2021-11-15 07:51:38 +00:00
|
|
|
} else {
|
|
|
|
let todo_selector =
|
|
|
|
ComponentDataModel::TodoSelector(TodoSelector { page, user_id, channel_id, guild_id });
|
|
|
|
|
2022-02-19 18:21:11 +00:00
|
|
|
let mut reply = CreateReply::default();
|
|
|
|
|
|
|
|
reply
|
2021-11-15 07:51:38 +00:00
|
|
|
.embed(|e| {
|
|
|
|
e.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);
|
|
|
|
|
|
|
|
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(disp.split_once(" ").unwrap_or(("", "")).1)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
opt
|
|
|
|
})
|
2021-10-11 20:19:08 +00:00
|
|
|
})
|
|
|
|
})
|
2022-02-19 18:21:11 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
reply
|
2021-11-15 07:51:38 +00:00
|
|
|
}
|
2021-10-02 21:54:34 +00:00
|
|
|
}
|