added utility: auto-response cmd
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
pub mod level;
|
||||
pub mod fun;
|
||||
pub mod level;
|
||||
pub mod utility;
|
||||
|
||||
252
src/commands/utility.rs
Normal file
252
src/commands/utility.rs
Normal file
@@ -0,0 +1,252 @@
|
||||
use crate::{Context, Error};
|
||||
use poise::serenity_prelude as serenity;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serenity::prelude::TypeMapKey;
|
||||
use std::collections::HashMap;
|
||||
use surrealdb::Surreal;
|
||||
use surrealdb::engine::remote::ws::Client;
|
||||
|
||||
pub struct DbKey;
|
||||
|
||||
impl TypeMapKey for DbKey {
|
||||
type Value = Surreal<Client>;
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct AutoResponse {
|
||||
pub response: String,
|
||||
pub mention_reply: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct GuildRecord {
|
||||
auto_responses: Option<HashMap<String, AutoResponse>>,
|
||||
}
|
||||
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
prefix_command,
|
||||
guild_only,
|
||||
default_member_permissions = "MANAGE_MESSAGES"
|
||||
)]
|
||||
pub async fn auto_response(
|
||||
ctx: Context<'_>,
|
||||
#[description = "The trigger message"] msg: String,
|
||||
#[description = "The response message"] response: String,
|
||||
#[description = "Reply to the user? (default: false)"] mention_reply: Option<bool>,
|
||||
) -> Result<(), Error> {
|
||||
let guild_id = ctx
|
||||
.guild_id()
|
||||
.ok_or_else(|| Error::msg("Guild only command"))?;
|
||||
let db = &ctx.data().db;
|
||||
|
||||
let mention_reply = mention_reply.unwrap_or(false);
|
||||
let auto_response = AutoResponse {
|
||||
response: response.clone(),
|
||||
mention_reply,
|
||||
};
|
||||
|
||||
let _: Option<serde::de::IgnoredAny> = db
|
||||
.update(("guilds", guild_id.to_string()))
|
||||
.merge(serde_json::json!({
|
||||
"auto_responses": {
|
||||
msg.clone(): auto_response
|
||||
}
|
||||
}))
|
||||
.await?;
|
||||
|
||||
ctx.say(format!(
|
||||
"Auto-response configured: `{}` -> `{}` (Reply: {})",
|
||||
msg, response, mention_reply
|
||||
))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
prefix_command,
|
||||
guild_only,
|
||||
default_member_permissions = "MANAGE_MESSAGES"
|
||||
)]
|
||||
pub async fn view_auto_responses(ctx: Context<'_>) -> Result<(), Error> {
|
||||
let guild_id = ctx
|
||||
.guild_id()
|
||||
.ok_or_else(|| Error::msg("Guild only command"))?;
|
||||
let db = &ctx.data().db;
|
||||
|
||||
let record: Option<GuildRecord> = db.select(("guilds", guild_id.to_string())).await?;
|
||||
|
||||
let mut response = String::new();
|
||||
|
||||
if let Some(record) = record {
|
||||
if let Some(responses) = record.auto_responses {
|
||||
if responses.is_empty() {
|
||||
response = "No auto-responses configured.".to_string();
|
||||
} else {
|
||||
response.push_str("**Auto-Responses:**\n");
|
||||
for (trigger, data) in responses {
|
||||
response.push_str(&format!(
|
||||
"- `{}` -> `{}` (Reply: {})\n",
|
||||
trigger, data.response, data.mention_reply
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
response = "No auto-responses configured.".to_string();
|
||||
}
|
||||
} else {
|
||||
response = "No configuration found for this guild.".to_string();
|
||||
}
|
||||
|
||||
ctx.say(response).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
prefix_command,
|
||||
guild_only,
|
||||
default_member_permissions = "MANAGE_MESSAGES"
|
||||
)]
|
||||
pub async fn delete_auto_response(
|
||||
ctx: Context<'_>,
|
||||
#[description = "The trigger message to delete"] msg: String,
|
||||
) -> Result<(), Error> {
|
||||
let guild_id = ctx
|
||||
.guild_id()
|
||||
.ok_or_else(|| Error::msg("Guild only command"))?;
|
||||
let db = &ctx.data().db;
|
||||
|
||||
// To delete a key from a map in SurrealDB using merge, we might need to fetch, modify, and update,
|
||||
// or use a specific unset operation if supported via JSON merge patch or similar.
|
||||
// SurrealDB merge with `null` value for a key usually removes it? No, that sets it to null.
|
||||
// We should probably fetch the current map, remove the key, and update.
|
||||
|
||||
// Actually, let's try to fetch, modify locally, and update.
|
||||
let record: Option<GuildRecord> = db.select(("guilds", guild_id.to_string())).await?;
|
||||
|
||||
if let Some(record) = record {
|
||||
if let Some(mut responses) = record.auto_responses {
|
||||
if responses.remove(&msg).is_some() {
|
||||
let _: Option<serde::de::IgnoredAny> = db
|
||||
.update(("guilds", guild_id.to_string()))
|
||||
.merge(serde_json::json!({
|
||||
"auto_responses": responses
|
||||
}))
|
||||
.await?;
|
||||
ctx.say(format!("Auto-response for `{}` deleted.", msg))
|
||||
.await?;
|
||||
} else {
|
||||
ctx.say(format!("No auto-response found for `{}`.", msg))
|
||||
.await?;
|
||||
}
|
||||
} else {
|
||||
ctx.say("No auto-responses configured.").await?;
|
||||
}
|
||||
} else {
|
||||
ctx.say("No configuration found for this guild.").await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
prefix_command,
|
||||
guild_only,
|
||||
default_member_permissions = "MANAGE_MESSAGES"
|
||||
)]
|
||||
pub async fn edit_auto_response(
|
||||
ctx: Context<'_>,
|
||||
#[description = "The trigger message to edit"] msg: String,
|
||||
#[description = "The new response message"] new_response: Option<String>,
|
||||
#[description = "Reply to the user?"] new_mention_reply: Option<bool>,
|
||||
) -> Result<(), Error> {
|
||||
let guild_id = ctx
|
||||
.guild_id()
|
||||
.ok_or_else(|| Error::msg("Guild only command"))?;
|
||||
let db = &ctx.data().db;
|
||||
|
||||
let record: Option<GuildRecord> = db.select(("guilds", guild_id.to_string())).await?;
|
||||
|
||||
if let Some(record) = record {
|
||||
if let Some(mut responses) = record.auto_responses {
|
||||
let (response_str, mention_reply_bool) = {
|
||||
if let Some(data) = responses.get_mut(&msg) {
|
||||
if let Some(response) = new_response {
|
||||
data.response = response;
|
||||
}
|
||||
if let Some(mention_reply) = new_mention_reply {
|
||||
data.mention_reply = mention_reply;
|
||||
}
|
||||
(data.response.clone(), data.mention_reply)
|
||||
} else {
|
||||
ctx.say(format!("No auto-response found for `{}`.", msg))
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let _: Option<serde::de::IgnoredAny> = db
|
||||
.update(("guilds", guild_id.to_string()))
|
||||
.merge(serde_json::json!({
|
||||
"auto_responses": responses
|
||||
}))
|
||||
.await?;
|
||||
|
||||
ctx.say(format!(
|
||||
"Auto-response for `{}` updated: `{}` (Reply: {})",
|
||||
msg, response_str, mention_reply_bool
|
||||
))
|
||||
.await?;
|
||||
} else {
|
||||
ctx.say("No auto-responses configured.").await?;
|
||||
}
|
||||
} else {
|
||||
ctx.say("No configuration found for this guild.").await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn process_auto_response(
|
||||
ctx: &serenity::Context,
|
||||
msg: &serenity::Message,
|
||||
) -> Result<(), Error> {
|
||||
if msg.author.bot {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let guild_id = match msg.guild_id {
|
||||
Some(id) => id,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
let data = ctx.data.read().await;
|
||||
let db = match data.get::<DbKey>() {
|
||||
Some(db) => db,
|
||||
None => {
|
||||
tracing::error!("Database connection not found in context data for utility");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let record: Option<GuildRecord> = db.select(("guilds", guild_id.to_string())).await?;
|
||||
|
||||
if let Some(record) = record {
|
||||
if let Some(responses) = record.auto_responses {
|
||||
if let Some(auto_response) = responses.get(&msg.content) {
|
||||
if auto_response.mention_reply {
|
||||
msg.reply(ctx, &auto_response.response).await?;
|
||||
} else {
|
||||
msg.channel_id.say(ctx, &auto_response.response).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -32,6 +32,9 @@ impl EventHandler for Handler {
|
||||
if let Err(e) = crate::commands::level::process_message(&ctx, &msg).await {
|
||||
tracing::error!("Error processing message for leveling: {}", e);
|
||||
}
|
||||
if let Err(e) = crate::commands::utility::process_auto_response(&ctx, &msg).await {
|
||||
tracing::error!("Error processing message for auto-response: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
async fn guild_member_update(
|
||||
|
||||
@@ -61,6 +61,10 @@ async fn main() -> Result<(), Error> {
|
||||
commands::level::set_levelup_message(),
|
||||
commands::level::levelup_role_bridger(),
|
||||
commands::fun::say(),
|
||||
commands::utility::auto_response(),
|
||||
commands::utility::view_auto_responses(),
|
||||
commands::utility::delete_auto_response(),
|
||||
commands::utility::edit_auto_response(),
|
||||
],
|
||||
prefix_options: poise::PrefixFrameworkOptions {
|
||||
prefix: Some("!".into()),
|
||||
@@ -88,6 +92,7 @@ async fn main() -> Result<(), Error> {
|
||||
{
|
||||
let mut data = client.data.write().await;
|
||||
data.insert::<commands::level::DbKey>(db.clone());
|
||||
data.insert::<commands::utility::DbKey>(db.clone());
|
||||
}
|
||||
|
||||
if let Err(why) = client.start_autosharded().await {
|
||||
|
||||
Reference in New Issue
Block a user