Skip to content

Commit debb2e0

Browse files
committed
feat(snippet): add base for snippet command
1 parent 57eef21 commit debb2e0

18 files changed

Lines changed: 1279 additions & 3 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
-- Add migration script here
2+
CREATE TABLE IF NOT EXISTS "snippets" (
3+
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
4+
"key" TEXT NOT NULL UNIQUE,
5+
"content" TEXT NOT NULL,
6+
"created_by" TEXT NOT NULL,
7+
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
8+
"updated_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
9+
);
10+
11+
CREATE INDEX IF NOT EXISTS "idx_snippets_key" ON "snippets"("key");

rustmail/src/bot.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ pub async fn run_bot(
144144
registry.register_command(TakeCommand);
145145
registry.register_command(ReleaseCommand);
146146
registry.register_command(PingCommand);
147+
registry.register_command(SnippetCommand);
147148

148149
let registry = Arc::new(registry);
149150

rustmail/src/commands/anonreply/text_command/anonreply.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,24 @@ pub async fn anonreply(
2121
.as_ref()
2222
.ok_or_else(database_connection_failed)?;
2323

24-
let content = extract_reply_content(&msg.content, &config.command.prefix, &["anonreply", "ar"]);
24+
let mut content = extract_reply_content(&msg.content, &config.command.prefix, &["anonreply", "ar"]);
25+
26+
if let Some(text) = &content {
27+
if let Some(stripped) = text.strip_prefix("{{").and_then(|s| s.strip_suffix("}}")) {
28+
let snippet_key = stripped.trim();
29+
match get_snippet_by_key(snippet_key, db_pool).await? {
30+
Some(snippet) => {
31+
content = Some(snippet.content);
32+
}
33+
None => {
34+
msg.reply(&ctx.http, format!("❌ Snippet `{}` not found.", snippet_key))
35+
.await?;
36+
return Ok(());
37+
}
38+
}
39+
}
40+
}
41+
2542
let intent = extract_intent(content, &msg.attachments).await;
2643

2744
let Some(intent) = intent else {

rustmail/src/commands/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub mod release;
2828
pub mod remove_reminder;
2929
pub mod remove_staff;
3030
pub mod reply;
31+
pub mod snippet;
3132
pub mod take;
3233

3334
pub use add_reminder::*;
@@ -49,6 +50,7 @@ pub use release::*;
4950
pub use remove_reminder::*;
5051
pub use remove_staff::*;
5152
pub use reply::*;
53+
pub use snippet::*;
5254
pub use take::*;
5355

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

rustmail/src/commands/reply/slash_command/reply.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,15 @@ impl RegistrableCommand for ReplyCommand {
7979
"message",
8080
message_desc,
8181
)
82-
.required(true),
82+
.required(false),
83+
)
84+
.add_option(
85+
CreateCommandOption::new(
86+
CommandOptionType::String,
87+
"snippet",
88+
"Use a snippet instead of typing a message",
89+
)
90+
.required(false),
8391
)
8492
.add_option(
8593
CreateCommandOption::new(
@@ -119,6 +127,7 @@ impl RegistrableCommand for ReplyCommand {
119127
defer_response(&ctx, &command).await?;
120128

121129
let mut content: Option<String> = None;
130+
let mut snippet_key: Option<String> = None;
122131
let mut attachments: Vec<Attachment> = Vec::new();
123132
let mut anonymous: bool = false;
124133

@@ -127,6 +136,9 @@ impl RegistrableCommand for ReplyCommand {
127136
CommandDataOptionValue::String(val) if option.name == "message" => {
128137
content = Some(val.clone());
129138
}
139+
CommandDataOptionValue::String(val) if option.name == "snippet" => {
140+
snippet_key = Some(val.clone());
141+
}
130142
CommandDataOptionValue::Attachment(att_id) if option.name == "attachment" => {
131143
if let Some(att) = command.data.resolved.attachments.get(att_id) {
132144
attachments.push(att.clone());
@@ -138,6 +150,19 @@ impl RegistrableCommand for ReplyCommand {
138150
_ => {}
139151
}
140152
}
153+
154+
if let Some(key) = snippet_key {
155+
match get_snippet_by_key(&key, db_pool).await? {
156+
Some(snippet) => {
157+
content = Some(snippet.content);
158+
}
159+
None => {
160+
return Err(ModmailError::Command(CommandError::CommandFailed(
161+
format!("Snippet '{}' not found", key),
162+
)));
163+
}
164+
}
165+
}
141166

142167
let intent = extract_intent(content, &attachments).await;
143168

rustmail/src/commands/reply/text_command/reply.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,24 @@ pub async fn reply(
2121
.as_ref()
2222
.ok_or_else(database_connection_failed)?;
2323

24-
let content = extract_reply_content(&msg.content, &config.command.prefix, &["reply", "r"]);
24+
let mut content = extract_reply_content(&msg.content, &config.command.prefix, &["reply", "r"]);
25+
26+
if let Some(text) = &content {
27+
if let Some(stripped) = text.strip_prefix("{{").and_then(|s| s.strip_suffix("}}")) {
28+
let snippet_key = stripped.trim();
29+
match get_snippet_by_key(snippet_key, db_pool).await? {
30+
Some(snippet) => {
31+
content = Some(snippet.content);
32+
}
33+
None => {
34+
msg.reply(&ctx.http, format!("❌ Snippet `{}` not found.", snippet_key))
35+
.await?;
36+
return Ok(());
37+
}
38+
}
39+
}
40+
}
41+
2542
let intent = extract_intent(content, &msg.attachments).await;
2643

2744
let Some(intent) = intent else {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub mod slash_command;
2+
pub mod text_command;
3+
4+
pub use slash_command::*;
5+
pub use text_command::*;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub mod snippet;
2+
3+
pub use snippet::*;

0 commit comments

Comments
 (0)