2021-09-06 12:46:16 +00:00
|
|
|
use std::{convert::TryFrom, fmt};
|
2020-08-10 21:12:26 +00:00
|
|
|
|
2021-09-06 12:46:16 +00:00
|
|
|
use regex_command_attr::command;
|
2020-08-10 21:12:26 +00:00
|
|
|
use serenity::{
|
2021-01-07 21:11:02 +00:00
|
|
|
async_trait,
|
2020-08-10 21:12:26 +00:00
|
|
|
client::Context,
|
2020-10-12 20:01:27 +00:00
|
|
|
constants::MESSAGE_CODE_LIMIT,
|
2020-08-10 21:12:26 +00:00
|
|
|
model::{
|
2020-10-12 20:01:27 +00:00
|
|
|
channel::Message,
|
|
|
|
id::{ChannelId, GuildId, UserId},
|
2020-08-10 21:12:26 +00:00
|
|
|
},
|
|
|
|
};
|
2021-09-06 12:46:16 +00:00
|
|
|
use sqlx::MySqlPool;
|
2020-08-17 23:18:33 +00:00
|
|
|
|
2021-07-16 20:28:51 +00:00
|
|
|
use crate::{
|
|
|
|
command_help, get_ctx_data,
|
2021-09-02 22:38:12 +00:00
|
|
|
models::{user_data::UserData, CtxData},
|
2021-07-16 20:28:51 +00:00
|
|
|
};
|
2020-08-17 23:18:33 +00:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct TodoNotFound;
|
2020-08-17 13:16:52 +00:00
|
|
|
|
2020-08-17 23:18:33 +00:00
|
|
|
impl std::error::Error for TodoNotFound {}
|
|
|
|
impl fmt::Display for TodoNotFound {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "Todo not found")
|
|
|
|
}
|
|
|
|
}
|
2020-08-17 13:16:52 +00:00
|
|
|
|
|
|
|
struct Todo {
|
|
|
|
id: u32,
|
|
|
|
value: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct TodoTarget {
|
|
|
|
user: UserId,
|
|
|
|
guild: Option<GuildId>,
|
|
|
|
channel: Option<ChannelId>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TodoTarget {
|
2020-10-12 17:37:14 +00:00
|
|
|
pub fn command(&self, subcommand_opt: Option<SubCommand>) -> String {
|
|
|
|
let context = if self.channel.is_some() {
|
|
|
|
"channel"
|
2020-10-12 20:01:27 +00:00
|
|
|
} else if self.guild.is_some() {
|
2020-10-12 17:37:14 +00:00
|
|
|
"guild"
|
2020-10-12 20:01:27 +00:00
|
|
|
} else {
|
2020-10-12 17:37:14 +00:00
|
|
|
"user"
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(subcommand) = subcommand_opt {
|
|
|
|
format!("todo {} {}", context, subcommand.to_string())
|
2020-10-12 20:01:27 +00:00
|
|
|
} else {
|
2020-10-12 17:37:14 +00:00
|
|
|
format!("todo {}", context)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-17 23:18:33 +00:00
|
|
|
pub fn name(&self) -> String {
|
|
|
|
if self.channel.is_some() {
|
|
|
|
"Channel"
|
2020-10-12 20:01:27 +00:00
|
|
|
} else if self.guild.is_some() {
|
2020-08-17 23:18:33 +00:00
|
|
|
"Guild"
|
2020-10-12 20:01:27 +00:00
|
|
|
} else {
|
2020-08-17 23:18:33 +00:00
|
|
|
"User"
|
2020-10-12 20:01:27 +00:00
|
|
|
}
|
|
|
|
.to_string()
|
2020-08-17 23:18:33 +00:00
|
|
|
}
|
|
|
|
|
2020-10-12 20:01:27 +00:00
|
|
|
pub async fn view(
|
|
|
|
&self,
|
|
|
|
pool: MySqlPool,
|
|
|
|
) -> Result<Vec<Todo>, Box<dyn std::error::Error + Send + Sync>> {
|
2020-08-17 13:16:52 +00:00
|
|
|
Ok(if let Some(cid) = self.channel {
|
2020-10-12 20:01:27 +00:00
|
|
|
sqlx::query_as!(
|
|
|
|
Todo,
|
2020-08-17 13:16:52 +00:00
|
|
|
"
|
2020-12-19 22:14:16 +00:00
|
|
|
SELECT id, value FROM todos WHERE channel_id = (SELECT id FROM channels WHERE channel = ?)
|
2020-10-12 20:01:27 +00:00
|
|
|
",
|
|
|
|
cid.as_u64()
|
|
|
|
)
|
|
|
|
.fetch_all(&pool)
|
|
|
|
.await?
|
|
|
|
} else if let Some(gid) = self.guild {
|
|
|
|
sqlx::query_as!(
|
|
|
|
Todo,
|
2020-08-17 13:16:52 +00:00
|
|
|
"
|
2020-12-19 22:14:16 +00:00
|
|
|
SELECT id, value FROM todos WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND channel_id IS NULL
|
2020-10-12 20:01:27 +00:00
|
|
|
",
|
|
|
|
gid.as_u64()
|
|
|
|
)
|
|
|
|
.fetch_all(&pool)
|
|
|
|
.await?
|
|
|
|
} else {
|
|
|
|
sqlx::query_as!(
|
|
|
|
Todo,
|
2020-08-17 13:16:52 +00:00
|
|
|
"
|
2020-12-19 22:14:16 +00:00
|
|
|
SELECT id, value FROM todos WHERE user_id = (SELECT id FROM users WHERE user = ?) AND guild_id IS NULL
|
2020-10-12 20:01:27 +00:00
|
|
|
",
|
|
|
|
self.user.as_u64()
|
|
|
|
)
|
|
|
|
.fetch_all(&pool)
|
|
|
|
.await?
|
2020-08-17 13:16:52 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-10-12 20:01:27 +00:00
|
|
|
pub async fn add(
|
|
|
|
&self,
|
|
|
|
value: String,
|
|
|
|
pool: MySqlPool,
|
|
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
2020-08-17 13:16:52 +00:00
|
|
|
if let (Some(cid), Some(gid)) = (self.channel, self.guild) {
|
|
|
|
sqlx::query!(
|
|
|
|
"
|
|
|
|
INSERT INTO todos (user_id, guild_id, channel_id, value) VALUES (
|
|
|
|
(SELECT id FROM users WHERE user = ?),
|
|
|
|
(SELECT id FROM guilds WHERE guild = ?),
|
|
|
|
(SELECT id FROM channels WHERE channel = ?),
|
|
|
|
?
|
|
|
|
)
|
2020-10-12 20:01:27 +00:00
|
|
|
",
|
|
|
|
self.user.as_u64(),
|
|
|
|
gid.as_u64(),
|
|
|
|
cid.as_u64(),
|
|
|
|
value
|
|
|
|
)
|
|
|
|
.execute(&pool)
|
|
|
|
.await?;
|
|
|
|
} else if let Some(gid) = self.guild {
|
2020-08-17 13:16:52 +00:00
|
|
|
sqlx::query!(
|
|
|
|
"
|
|
|
|
INSERT INTO todos (user_id, guild_id, value) VALUES (
|
|
|
|
(SELECT id FROM users WHERE user = ?),
|
|
|
|
(SELECT id FROM guilds WHERE guild = ?),
|
|
|
|
?
|
|
|
|
)
|
2020-10-12 20:01:27 +00:00
|
|
|
",
|
|
|
|
self.user.as_u64(),
|
|
|
|
gid.as_u64(),
|
|
|
|
value
|
|
|
|
)
|
|
|
|
.execute(&pool)
|
|
|
|
.await?;
|
|
|
|
} else {
|
2020-08-17 13:16:52 +00:00
|
|
|
sqlx::query!(
|
|
|
|
"
|
|
|
|
INSERT INTO todos (user_id, value) VALUES (
|
|
|
|
(SELECT id FROM users WHERE user = ?),
|
|
|
|
?
|
|
|
|
)
|
2020-10-12 20:01:27 +00:00
|
|
|
",
|
|
|
|
self.user.as_u64(),
|
|
|
|
value
|
|
|
|
)
|
|
|
|
.execute(&pool)
|
|
|
|
.await?;
|
2020-08-17 13:16:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-10-12 20:01:27 +00:00
|
|
|
pub async fn remove(
|
|
|
|
&self,
|
|
|
|
num: usize,
|
|
|
|
pool: &MySqlPool,
|
|
|
|
) -> Result<Todo, Box<dyn std::error::Error + Sync + Send>> {
|
2020-08-17 23:18:33 +00:00
|
|
|
let todos = self.view(pool.clone()).await?;
|
2020-08-17 13:16:52 +00:00
|
|
|
|
2020-08-17 23:18:33 +00:00
|
|
|
if let Some(removal_todo) = todos.get(num) {
|
2020-10-12 20:01:27 +00:00
|
|
|
let deleting = sqlx::query_as!(
|
|
|
|
Todo,
|
2020-10-12 17:37:14 +00:00
|
|
|
"
|
2020-12-19 22:14:16 +00:00
|
|
|
SELECT id, value FROM todos WHERE id = ?
|
2020-10-12 20:01:27 +00:00
|
|
|
",
|
|
|
|
removal_todo.id
|
|
|
|
)
|
|
|
|
.fetch_one(&pool.clone())
|
|
|
|
.await?;
|
2020-10-12 17:37:14 +00:00
|
|
|
|
2020-08-17 23:18:33 +00:00
|
|
|
sqlx::query!(
|
|
|
|
"
|
|
|
|
DELETE FROM todos WHERE id = ?
|
2020-10-12 20:01:27 +00:00
|
|
|
",
|
|
|
|
removal_todo.id
|
|
|
|
)
|
|
|
|
.execute(pool)
|
|
|
|
.await?;
|
2020-10-12 17:37:14 +00:00
|
|
|
|
|
|
|
Ok(deleting)
|
2020-10-12 20:01:27 +00:00
|
|
|
} else {
|
2020-08-17 23:19:15 +00:00
|
|
|
Err(Box::new(TodoNotFound))
|
2020-08-17 23:18:33 +00:00
|
|
|
}
|
2020-08-17 13:16:52 +00:00
|
|
|
}
|
|
|
|
|
2020-10-12 20:01:27 +00:00
|
|
|
pub async fn clear(
|
|
|
|
&self,
|
|
|
|
pool: &MySqlPool,
|
|
|
|
) -> Result<(), Box<dyn std::error::Error + Sync + Send>> {
|
2020-08-17 13:16:52 +00:00
|
|
|
if let Some(cid) = self.channel {
|
|
|
|
sqlx::query!(
|
|
|
|
"
|
|
|
|
DELETE FROM todos WHERE channel_id = (SELECT id FROM channels WHERE channel = ?)
|
2020-10-12 20:01:27 +00:00
|
|
|
",
|
|
|
|
cid.as_u64()
|
|
|
|
)
|
|
|
|
.execute(pool)
|
|
|
|
.await?;
|
|
|
|
} else if let Some(gid) = self.guild {
|
2020-08-17 13:16:52 +00:00
|
|
|
sqlx::query!(
|
|
|
|
"
|
|
|
|
DELETE FROM todos WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND channel_id IS NULL
|
2020-10-12 20:01:27 +00:00
|
|
|
",
|
|
|
|
gid.as_u64()
|
|
|
|
)
|
|
|
|
.execute(pool)
|
|
|
|
.await?;
|
|
|
|
} else {
|
2020-08-17 13:16:52 +00:00
|
|
|
sqlx::query!(
|
|
|
|
"
|
2020-08-17 23:18:33 +00:00
|
|
|
DELETE FROM todos WHERE user_id = (SELECT id FROM users WHERE user = ?) AND guild_id IS NULL
|
2020-10-12 20:01:27 +00:00
|
|
|
",
|
|
|
|
self.user.as_u64()
|
|
|
|
)
|
|
|
|
.execute(pool)
|
|
|
|
.await?;
|
2020-08-17 13:16:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-10-17 14:21:00 +00:00
|
|
|
|
|
|
|
async fn execute(&self, ctx: &Context, msg: &Message, subcommand: SubCommand, extra: String) {
|
2020-12-18 11:46:22 +00:00
|
|
|
let (pool, lm) = get_ctx_data(&ctx).await;
|
2020-10-17 14:21:00 +00:00
|
|
|
|
|
|
|
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
|
2021-04-12 21:33:02 +00:00
|
|
|
let prefix = ctx.prefix(msg.guild_id).await;
|
2020-10-17 14:21:00 +00:00
|
|
|
|
|
|
|
match subcommand {
|
|
|
|
SubCommand::View => {
|
|
|
|
let todo_items = self.view(pool).await.unwrap();
|
|
|
|
let mut todo_groups = vec!["".to_string()];
|
|
|
|
let mut char_count = 0;
|
|
|
|
|
|
|
|
todo_items.iter().enumerate().for_each(|(count, todo)| {
|
|
|
|
let display = format!("{}: {}\n", count + 1, todo.value);
|
|
|
|
|
|
|
|
if char_count + display.len() > MESSAGE_CODE_LIMIT as usize {
|
|
|
|
char_count = display.len();
|
|
|
|
|
|
|
|
todo_groups.push(display);
|
|
|
|
} else {
|
|
|
|
char_count += display.len();
|
|
|
|
|
|
|
|
let last_group = todo_groups.pop().unwrap();
|
|
|
|
|
|
|
|
todo_groups.push(format!("{}{}", last_group, display));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
for group in todo_groups {
|
|
|
|
let _ = msg
|
|
|
|
.channel_id
|
|
|
|
.send_message(&ctx, |m| {
|
|
|
|
m.embed(|e| e.title(format!("{} Todo", self.name())).description(group))
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SubCommand::Add => {
|
2020-11-22 01:31:50 +00:00
|
|
|
let content = lm
|
|
|
|
.get(&user_data.language, "todo/added")
|
2020-10-17 14:21:00 +00:00
|
|
|
.replacen("{name}", &extra, 1);
|
|
|
|
|
|
|
|
self.add(extra, pool).await.unwrap();
|
|
|
|
|
|
|
|
let _ = msg.channel_id.say(&ctx, content).await;
|
|
|
|
}
|
|
|
|
|
|
|
|
SubCommand::Remove => {
|
2020-11-22 01:31:50 +00:00
|
|
|
if let Ok(num) = extra.parse::<usize>() {
|
2020-10-17 14:21:00 +00:00
|
|
|
if let Ok(todo) = self.remove(num - 1, &pool).await {
|
2020-11-22 01:31:50 +00:00
|
|
|
let content = lm.get(&user_data.language, "todo/removed").replacen(
|
2020-10-17 14:21:00 +00:00
|
|
|
"{}",
|
|
|
|
&todo.value,
|
|
|
|
1,
|
|
|
|
);
|
|
|
|
|
2020-11-22 01:31:50 +00:00
|
|
|
let _ = msg.channel_id.say(&ctx, content).await;
|
2020-10-17 14:21:00 +00:00
|
|
|
} else {
|
2020-11-22 01:31:50 +00:00
|
|
|
let _ = msg
|
|
|
|
.channel_id
|
|
|
|
.say(&ctx, lm.get(&user_data.language, "todo/error_index"))
|
|
|
|
.await;
|
2020-10-17 14:21:00 +00:00
|
|
|
}
|
|
|
|
} else {
|
2020-11-22 01:31:50 +00:00
|
|
|
let content = lm
|
|
|
|
.get(&user_data.language, "todo/error_value")
|
2020-10-17 14:21:00 +00:00
|
|
|
.replacen("{prefix}", &prefix, 1)
|
|
|
|
.replacen("{command}", &self.command(Some(subcommand)), 1);
|
|
|
|
|
2020-11-22 01:31:50 +00:00
|
|
|
let _ = msg.channel_id.say(&ctx, content).await;
|
2020-10-17 14:21:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SubCommand::Clear => {
|
|
|
|
self.clear(&pool).await.unwrap();
|
|
|
|
|
2020-11-22 01:31:50 +00:00
|
|
|
let content = lm.get(&user_data.language, "todo/cleared");
|
2020-10-17 14:21:00 +00:00
|
|
|
|
|
|
|
let _ = msg.channel_id.say(&ctx, content).await;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-10 21:12:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
enum SubCommand {
|
|
|
|
View,
|
|
|
|
Add,
|
|
|
|
Remove,
|
|
|
|
Clear,
|
|
|
|
}
|
|
|
|
|
2020-10-17 01:10:36 +00:00
|
|
|
impl TryFrom<Option<&str>> for SubCommand {
|
|
|
|
type Error = ();
|
|
|
|
|
|
|
|
fn try_from(value: Option<&str>) -> Result<Self, Self::Error> {
|
|
|
|
match value {
|
|
|
|
Some("add") => Ok(SubCommand::Add),
|
|
|
|
|
|
|
|
Some("remove") => Ok(SubCommand::Remove),
|
|
|
|
|
|
|
|
Some("clear") => Ok(SubCommand::Clear),
|
|
|
|
|
2020-10-17 14:21:00 +00:00
|
|
|
None | Some("") => Ok(SubCommand::View),
|
2020-10-17 01:10:36 +00:00
|
|
|
|
|
|
|
Some(_unrecognised) => Err(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-12 17:37:14 +00:00
|
|
|
impl ToString for SubCommand {
|
|
|
|
fn to_string(&self) -> String {
|
|
|
|
match self {
|
|
|
|
SubCommand::View => "",
|
|
|
|
SubCommand::Add => "add",
|
|
|
|
SubCommand::Remove => "remove",
|
|
|
|
SubCommand::Clear => "clear",
|
2020-10-12 20:01:27 +00:00
|
|
|
}
|
|
|
|
.to_string()
|
2020-10-12 17:37:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-17 14:21:00 +00:00
|
|
|
#[async_trait]
|
|
|
|
trait Execute {
|
|
|
|
async fn execute(self, ctx: &Context, msg: &Message, extra: String, target: TodoTarget);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
impl Execute for Result<SubCommand, ()> {
|
|
|
|
async fn execute(self, ctx: &Context, msg: &Message, extra: String, target: TodoTarget) {
|
|
|
|
if let Ok(subcommand) = self {
|
|
|
|
target.execute(ctx, msg, subcommand, extra).await;
|
|
|
|
} else {
|
2021-09-02 22:38:12 +00:00
|
|
|
show_help(ctx, msg, Some(target)).await;
|
2020-10-17 14:21:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-23 13:45:25 +00:00
|
|
|
#[command("todo")]
|
2020-10-26 11:10:00 +00:00
|
|
|
async fn todo_user(ctx: &Context, msg: &Message, args: String) {
|
2020-10-17 01:10:36 +00:00
|
|
|
let mut split = args.split(' ');
|
|
|
|
|
|
|
|
let target = TodoTarget {
|
|
|
|
user: msg.author.id,
|
|
|
|
guild: None,
|
|
|
|
channel: None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let subcommand_opt = SubCommand::try_from(split.next());
|
|
|
|
|
2020-10-17 14:21:00 +00:00
|
|
|
subcommand_opt
|
|
|
|
.execute(ctx, msg, split.collect::<Vec<&str>>().join(" "), target)
|
2020-10-17 01:10:36 +00:00
|
|
|
.await;
|
|
|
|
}
|
|
|
|
|
2021-02-23 13:45:25 +00:00
|
|
|
#[command("todoc")]
|
2020-10-17 14:21:00 +00:00
|
|
|
#[supports_dm(false)]
|
2020-08-18 19:09:21 +00:00
|
|
|
#[permission_level(Managed)]
|
2020-10-26 11:10:00 +00:00
|
|
|
async fn todo_channel(ctx: &Context, msg: &Message, args: String) {
|
2020-09-25 11:48:44 +00:00
|
|
|
let mut split = args.split(' ');
|
2020-08-10 23:26:39 +00:00
|
|
|
|
2020-10-17 14:21:00 +00:00
|
|
|
let target = TodoTarget {
|
|
|
|
user: msg.author.id,
|
|
|
|
guild: msg.guild_id,
|
|
|
|
channel: Some(msg.channel_id),
|
|
|
|
};
|
2020-08-10 23:26:39 +00:00
|
|
|
|
2020-10-17 14:21:00 +00:00
|
|
|
let subcommand_opt = SubCommand::try_from(split.next());
|
2020-08-10 23:26:39 +00:00
|
|
|
|
2020-10-17 14:21:00 +00:00
|
|
|
subcommand_opt
|
|
|
|
.execute(ctx, msg, split.collect::<Vec<&str>>().join(" "), target)
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
|
2020-10-26 19:50:51 +00:00
|
|
|
#[command("todos")]
|
2020-10-17 14:21:00 +00:00
|
|
|
#[supports_dm(false)]
|
|
|
|
#[permission_level(Managed)]
|
2020-10-26 11:10:00 +00:00
|
|
|
async fn todo_guild(ctx: &Context, msg: &Message, args: String) {
|
2020-10-17 14:21:00 +00:00
|
|
|
let mut split = args.split(' ');
|
|
|
|
|
|
|
|
let target = TodoTarget {
|
|
|
|
user: msg.author.id,
|
|
|
|
guild: msg.guild_id,
|
|
|
|
channel: None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let subcommand_opt = SubCommand::try_from(split.next());
|
|
|
|
|
|
|
|
subcommand_opt
|
|
|
|
.execute(ctx, msg, split.collect::<Vec<&str>>().join(" "), target)
|
|
|
|
.await;
|
2020-08-10 21:12:26 +00:00
|
|
|
}
|
|
|
|
|
2020-10-12 17:37:14 +00:00
|
|
|
async fn show_help(ctx: &Context, msg: &Message, target: Option<TodoTarget>) {
|
2020-12-18 11:46:22 +00:00
|
|
|
let (pool, lm) = get_ctx_data(&ctx).await;
|
2020-10-12 17:37:14 +00:00
|
|
|
|
2020-12-18 17:41:36 +00:00
|
|
|
let language = UserData::language_of(&msg.author, &pool);
|
2021-04-12 21:33:02 +00:00
|
|
|
let prefix = ctx.prefix(msg.guild_id);
|
2020-10-12 17:37:14 +00:00
|
|
|
|
2020-11-30 21:55:34 +00:00
|
|
|
let command = match target {
|
2020-12-18 17:41:36 +00:00
|
|
|
None => "todo",
|
2020-11-30 21:55:34 +00:00
|
|
|
Some(t) => {
|
|
|
|
if t.channel.is_some() {
|
2020-12-18 17:41:36 +00:00
|
|
|
"todoc"
|
2020-11-30 21:55:34 +00:00
|
|
|
} else if t.guild.is_some() {
|
2020-12-18 17:41:36 +00:00
|
|
|
"todos"
|
2020-11-30 21:55:34 +00:00
|
|
|
} else {
|
2020-12-18 17:41:36 +00:00
|
|
|
"todo"
|
2020-11-30 21:55:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-12-18 17:41:36 +00:00
|
|
|
command_help(ctx, msg, lm, &prefix.await, &language.await, command).await;
|
2020-10-12 17:37:14 +00:00
|
|
|
}
|