Skip to content

Commit 7d07e30

Browse files
authored
Merge pull request #216 from Rustmail/211-take-command
feat(commands): add take command
2 parents 996d83b + 922cceb commit 7d07e30

12 files changed

Lines changed: 226 additions & 0 deletions

File tree

rustmail/src/bot.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::commands::recover::slash_command::recover::RecoverCommand;
1414
use crate::commands::remove_reminder::slash_command::remove_reminder::RemoveReminderCommand;
1515
use crate::commands::remove_staff::slash_command::remove_staff::RemoveStaffCommand;
1616
use crate::commands::reply::slash_command::reply::ReplyCommand;
17+
use crate::commands::take::slash_command::take::TakeCommand;
1718
use crate::commands::CommandRegistry;
1819
use crate::config::load_config;
1920
use crate::errors::types::ConfigError;
@@ -160,6 +161,7 @@ pub async fn run_bot(
160161
registry.register_command(AddReminderCommand);
161162
registry.register_command(RemoveReminderCommand);
162163
registry.register_command(LogsCommand);
164+
registry.register_command(TakeCommand);
163165

164166
let registry = Arc::new(registry);
165167

rustmail/src/commands/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub mod recover;
2626
pub mod remove_reminder;
2727
pub mod remove_staff;
2828
pub mod reply;
29+
pub mod take;
2930

3031
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
3132

rustmail/src/commands/take/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod slash_command;
2+
pub mod text_command;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod take;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use crate::commands::{BoxFuture, RegistrableCommand};
2+
use crate::config::Config;
3+
use crate::db::threads::is_a_ticket_channel;
4+
use crate::db::get_thread_by_channel_id;
5+
use crate::errors::common::{database_connection_failed, thread_not_found};
6+
use crate::errors::ThreadError::NotAThreadChannel;
7+
use crate::errors::{CommandError, ModmailError, ModmailResult};
8+
use crate::handlers::guild_interaction_handler::InteractionHandler;
9+
use crate::i18n::get_translated_message;
10+
use crate::utils::command::defer_response::defer_response;
11+
use crate::utils::message::message_builder::MessageBuilder;
12+
use serenity::all::{
13+
ChannelId, CommandInteraction, Context, CreateCommand, EditChannel, ResolvedOption,
14+
};
15+
use serenity::FutureExt;
16+
use std::sync::Arc;
17+
18+
pub struct TakeCommand;
19+
20+
#[async_trait::async_trait]
21+
impl RegistrableCommand for TakeCommand {
22+
fn name(&self) -> &'static str {
23+
"take"
24+
}
25+
26+
fn doc<'a>(&self, config: &'a Config) -> BoxFuture<'a, String> {
27+
async move { get_translated_message(config, "help.take", None, None, None, None).await }
28+
.boxed()
29+
}
30+
31+
fn register(&self, config: &Config) -> BoxFuture<'_, Vec<CreateCommand>> {
32+
let config = config.clone();
33+
34+
Box::pin(async move {
35+
let cmd_desc = get_translated_message(
36+
&config,
37+
"slash_command.help_command_description",
38+
None,
39+
None,
40+
None,
41+
None,
42+
)
43+
.await;
44+
45+
vec![CreateCommand::new(self.name()).description(cmd_desc)]
46+
})
47+
}
48+
49+
fn run(
50+
&self,
51+
ctx: &Context,
52+
command: &CommandInteraction,
53+
_options: &[ResolvedOption<'_>],
54+
config: &Config,
55+
_handler: Arc<InteractionHandler>,
56+
) -> BoxFuture<'_, ModmailResult<()>> {
57+
let ctx = ctx.clone();
58+
let command = command.clone();
59+
let config = config.clone();
60+
61+
Box::pin(async move {
62+
let db_pool = config
63+
.db_pool
64+
.as_ref()
65+
.ok_or_else(database_connection_failed)?;
66+
67+
defer_response(&ctx, &command).await?;
68+
69+
if is_a_ticket_channel(command.channel_id, &db_pool).await {
70+
let thread = match get_thread_by_channel_id(
71+
&command.channel_id.to_string(),
72+
db_pool,
73+
)
74+
.await
75+
{
76+
Some(thread) => thread,
77+
None => return Err(thread_not_found()),
78+
};
79+
80+
let parse_thread_id = thread.channel_id.parse::<u64>().unwrap_or(0);
81+
82+
let thread_id = ChannelId::new(parse_thread_id);
83+
84+
let thread_name = thread_id
85+
.name(&ctx)
86+
.await
87+
.unwrap_or_else(|_| "Unknown".to_string());
88+
89+
if thread_name == format!("🔵-{}", command.user.name) {
90+
return Err(ModmailError::Command(CommandError::TicketAlreadyTaken));
91+
}
92+
93+
let _ = thread_id
94+
.edit(
95+
&ctx.http,
96+
EditChannel::new().name(format!("🔵-{}", command.user.name)),
97+
)
98+
.await;
99+
100+
let mut params = std::collections::HashMap::new();
101+
params.insert("staff".to_string(), format!("<@{}>", command.user.id));
102+
103+
let response = MessageBuilder::system_message(&ctx, &config)
104+
.translated_content("take.confirmation", Some(&params), None, None)
105+
.await
106+
.to_channel(command.channel_id)
107+
.build_interaction_message_followup()
108+
.await;
109+
110+
let _ = command.create_followup(ctx.clone(), response).await;
111+
112+
Ok(())
113+
} else {
114+
Err(ModmailError::Thread(NotAThreadChannel))
115+
}
116+
})
117+
}
118+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod take;
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use crate::config::Config;
2+
use crate::db::get_thread_by_channel_id;
3+
use crate::db::threads::is_a_ticket_channel;
4+
use crate::errors::common::{database_connection_failed, thread_not_found};
5+
use crate::errors::ThreadError::NotAThreadChannel;
6+
use crate::errors::{CommandError, ModmailError, ModmailResult};
7+
use crate::handlers::guild_messages_handler::GuildMessagesHandler;
8+
use crate::utils::message::message_builder::MessageBuilder;
9+
use serenity::all::{ChannelId, Context, Message};
10+
use serenity::builder::EditChannel;
11+
use std::sync::Arc;
12+
13+
pub async fn take(
14+
ctx: Context,
15+
msg: Message,
16+
config: &Config,
17+
_handler: Arc<GuildMessagesHandler>,
18+
) -> ModmailResult<()> {
19+
let db_pool = config
20+
.db_pool
21+
.as_ref()
22+
.ok_or_else(database_connection_failed)?;
23+
24+
if is_a_ticket_channel(msg.channel_id, &db_pool).await {
25+
let thread = match get_thread_by_channel_id(&msg.channel_id.to_string(), db_pool).await {
26+
Some(thread) => thread,
27+
None => return Err(thread_not_found()),
28+
};
29+
30+
let parse_thread_id = thread.channel_id.parse::<u64>().unwrap_or(0);
31+
32+
let thread_id = ChannelId::new(parse_thread_id);
33+
34+
let thread_name = thread_id
35+
.name(&ctx)
36+
.await
37+
.unwrap_or_else(|_| "Unknown".to_string());
38+
39+
if thread_name == format!("🔵-{}", msg.author.name) {
40+
return Err(ModmailError::Command(CommandError::TicketAlreadyTaken));
41+
}
42+
43+
let _ = thread_id
44+
.edit(
45+
&ctx.http,
46+
EditChannel::new().name(format!("🔵-{}", msg.author.name)),
47+
)
48+
.await;
49+
50+
let mut params = std::collections::HashMap::new();
51+
params.insert("staff".to_string(), format!("<@{}>", msg.author.id));
52+
53+
let _ = MessageBuilder::system_message(&ctx, config)
54+
.translated_content("take.confirmation", Some(&params), None, None)
55+
.await
56+
.to_channel(msg.channel_id)
57+
.send(true)
58+
.await?;
59+
60+
Ok(())
61+
} else {
62+
Err(ModmailError::Thread(NotAThreadChannel))
63+
}
64+
}

rustmail/src/errors/dictionary.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ impl DictionaryManager {
247247
CommandError::NotInThread() => ("command.not_in_thread".to_string(), None),
248248
CommandError::AlertDoesNotExist => ("alert.alert_not_found".to_string(), None),
249249
CommandError::InvalidReminderFormat => ("add_reminder.helper".to_string(), None),
250+
CommandError::TicketAlreadyTaken => ("take.ticket_already_taken".to_string(), None),
250251
_ => ("command.invalid_format".to_string(), None),
251252
},
252253
ModmailError::Thread(thread_err) => match thread_err {

rustmail/src/errors/types.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ pub enum CommandError {
7979
ReminderAlreadyExists,
8080
AlertDoesNotExist,
8181
InvalidReminderFormat,
82+
TicketAlreadyTaken,
8283
}
8384

8485
#[derive(Debug, Clone)]
@@ -234,6 +235,7 @@ impl fmt::Display for CommandError {
234235
CommandError::ReminderAlreadyExists => write!(f, "A reminder already exists"),
235236
CommandError::AlertDoesNotExist => write!(f, "Alert does not exist"),
236237
CommandError::InvalidReminderFormat => write!(f, "Invalid reminder format"),
238+
CommandError::TicketAlreadyTaken => write!(f, "Ticket already taken"),
237239
}
238240
}
239241
}

rustmail/src/handlers/guild_messages_handler.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::commands::recover::text_command::recover::recover;
1616
use crate::commands::remove_reminder::text_command::remove_reminder::remove_reminder;
1717
use crate::commands::remove_staff::text_command::remove_staff::remove_staff;
1818
use crate::commands::reply::text_command::reply::reply;
19+
use crate::commands::take::text_command::take::take;
1920
use crate::commands::CommandRegistry;
2021
use crate::config::Config;
2122
use crate::db::messages::get_thread_message_by_dm_message_id;
@@ -100,6 +101,7 @@ impl GuildMessagesHandler {
100101
wrap_command!(lock, ["remind", "rem"], add_reminder);
101102
wrap_command!(lock, ["unremind", "urem"], remove_reminder);
102103
wrap_command!(lock, "logs", logs);
104+
wrap_command!(lock, "take", take);
103105

104106
drop(lock);
105107
h

0 commit comments

Comments
 (0)