aboutsummaryrefslogtreecommitdiffstats
path: root/src/commands/trigger.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/commands/trigger.rs199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/commands/trigger.rs b/src/commands/trigger.rs
new file mode 100644
index 0000000..7453e03
--- /dev/null
+++ b/src/commands/trigger.rs
@@ -0,0 +1,199 @@
1use poise::serenity_prelude as serenity;
2
3use super::autocomplete::trigger_name;
4use crate::Data;
5use crate::database;
6use crate::error::{Error, Result};
7use crate::lang;
8
9type Context<'a> = poise::Context<'a, Data, Error>;
10
11/// Trigger keyword management
12#[poise::command(
13 slash_command,
14 subcommands("create", "add", "remove", "delete", "list", "help",)
15)]
16pub async fn trigger(_ctx: Context<'_>) -> Result<()> {
17 Ok(())
18}
19
20/// Create a new trigger group
21#[poise::command(slash_command)]
22pub async fn create(
23 ctx: Context<'_>,
24 #[description = "Logical group name"]
25 #[autocomplete = "trigger_name"]
26 name: String,
27) -> Result<()> {
28 match database::create_trigger(&ctx.data().db_pool, &name).await {
29 Ok(_) => {
30 ctx.data().reload_triggers().await;
31 ctx.say(lang::fmt_trigger_created(&name)).await?;
32 }
33 Err(e) => {
34 ctx.say(lang::fmt_trigger_failed(&e)).await?;
35 }
36 }
37 Ok(())
38}
39
40/// Add keywords and/or responses to a trigger group
41#[poise::command(slash_command)]
42pub async fn add(
43 ctx: Context<'_>,
44 #[description = "Existing group name"]
45 #[autocomplete = "trigger_name"]
46 name: String,
47 #[description = "Keywords separated by \\"] trigger_keywords: Option<String>,
48 #[description = "Responses separated by \\"] response: Option<String>,
49) -> Result<()> {
50 let t = database::get_trigger_by_name(&ctx.data().db_pool, &name)
51 .await?
52 .ok_or_else(|| lang::err_trigger_not_found())?;
53
54 let mut modified = false;
55 if let Some(kw) = trigger_keywords {
56 for keyword in kw.split('\\') {
57 let k = keyword.trim();
58 if !k.is_empty() {
59 database::add_keyword(&ctx.data().db_pool, t.id, k).await?;
60 modified = true;
61 }
62 }
63 }
64 if let Some(r) = response {
65 for resp in r.split('\\') {
66 let r = resp.trim();
67 if !r.is_empty() {
68 database::add_response(&ctx.data().db_pool, t.id, r).await?;
69 modified = true;
70 }
71 }
72 }
73
74 if modified {
75 ctx.data().reload_triggers().await;
76 }
77 ctx.say(lang::L_TRIGGER_UPDATED).await?;
78 Ok(())
79}
80
81/// Remove keyword or response from a group
82#[poise::command(slash_command)]
83pub async fn remove(
84 ctx: Context<'_>,
85 #[description = "Group name"]
86 #[autocomplete = "trigger_name"]
87 name: String,
88 #[description = "Keyword to remove"] trigger_keyword: Option<String>,
89 #[description = "Response to remove"] response: Option<String>,
90) -> Result<()> {
91 let t = database::get_trigger_by_name(&ctx.data().db_pool, &name)
92 .await?
93 .ok_or_else(|| lang::err_trigger_not_found())?;
94
95 let mut modified = false;
96 if let Some(kw) = trigger_keyword {
97 database::remove_keyword(&ctx.data().db_pool, t.id, &kw).await?;
98 modified = true;
99 }
100 if let Some(r) = response {
101 database::remove_response(&ctx.data().db_pool, t.id, &r).await?;
102 modified = true;
103 }
104
105 if modified {
106 ctx.data().reload_triggers().await;
107 }
108 ctx.say(lang::L_TRIGGER_UPDATED).await?;
109 Ok(())
110}
111
112/// Delete an entire trigger group
113#[poise::command(slash_command)]
114pub async fn delete(
115 ctx: Context<'_>,
116 #[description = "Group name"]
117 #[autocomplete = "trigger_name"]
118 name: String,
119) -> Result<()> {
120 let t = database::get_trigger_by_name(&ctx.data().db_pool, &name)
121 .await?
122 .ok_or_else(|| lang::err_trigger_not_found())?;
123
124 database::delete_trigger(&ctx.data().db_pool, t.id).await?;
125 ctx.data().reload_triggers().await;
126 ctx.say(lang::fmt_trigger_deleted(&name)).await?;
127 Ok(())
128}
129
130/// List keywords and responses for a group
131#[poise::command(slash_command)]
132pub async fn list(
133 ctx: Context<'_>,
134 #[description = "Group name"]
135 #[autocomplete = "trigger_name"]
136 name: String,
137) -> Result<()> {
138 let t = database::get_trigger_by_name(&ctx.data().db_pool, &name)
139 .await?
140 .ok_or_else(|| lang::err_trigger_not_found())?;
141
142 let keywords = database::get_keywords(&ctx.data().db_pool, t.id).await?;
143 let responses = database::get_responses(&ctx.data().db_pool, t.id).await?;
144
145 let mut embed = serenity::CreateEmbed::default()
146 .title(lang::fmt_trigger_title(&name))
147 .color(0x00aaff);
148
149 embed = embed.field(
150 "Keywords",
151 if keywords.is_empty() {
152 lang::L_TRIGGER_KW_NONE.into()
153 } else {
154 keywords
155 .iter()
156 .map(|r| format!("{r}"))
157 .collect::<Vec<_>>()
158 .join("\n")
159 },
160 false,
161 );
162 embed = embed.field(
163 "Responses",
164 if responses.is_empty() {
165 lang::L_TRIGGER_KW_NONE.into()
166 } else {
167 responses
168 .iter()
169 .map(|r| format!("{r}"))
170 .collect::<Vec<_>>()
171 .join("\n")
172 },
173 false,
174 );
175
176 ctx.send(poise::CreateReply::default().embed(embed)).await?;
177 Ok(())
178}
179
180/// Display trigger command usage info
181#[poise::command(slash_command)]
182pub async fn help(ctx: Context<'_>) -> Result<()> {
183 let help = [
184 "**Trigger Commands**",
185 "`/trigger create <name>` — Create new trigger group",
186 "`/trigger add <name> <trigger> <response>` — Add keywords/responses (separate with \\)",
187 "`/trigger remove <name> <trigger> <response>` — Remove keywords/responses",
188 "`/trigger delete <name>` — Delete entire group",
189 "`/trigger list <name>` — View group details",
190 ]
191 .join("\n");
192
193 ctx.say(help).await?;
194 Ok(())
195}
196
197pub fn commands() -> Vec<poise::Command<Data, Error>> {
198 vec![trigger()]
199}