Add prefix customization command
This commit is contained in:
@@ -253,6 +253,36 @@ impl Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_or_create_by_id(
|
||||||
|
id: u64,
|
||||||
|
session: &Session,
|
||||||
|
http: &Client,
|
||||||
|
) -> Result<Self, DatabaseOrDiscordError> {
|
||||||
|
let server = Server::get_by_id(id, session)
|
||||||
|
.await
|
||||||
|
.map_err(DatabaseOrDiscordError::Database)?;
|
||||||
|
|
||||||
|
if let Some(server) = server {
|
||||||
|
Ok(server)
|
||||||
|
} else {
|
||||||
|
let server: Server = http
|
||||||
|
.guild(Id::new(id))
|
||||||
|
.await
|
||||||
|
.map_err(DatabaseOrDiscordError::Discord)?
|
||||||
|
.model()
|
||||||
|
.await
|
||||||
|
.map_err(|_| DatabaseOrDiscordError::DiscordDeserializationFailed)?
|
||||||
|
.into();
|
||||||
|
|
||||||
|
server
|
||||||
|
.insert(session)
|
||||||
|
.await
|
||||||
|
.map_err(DatabaseOrDiscordError::Database)?;
|
||||||
|
|
||||||
|
Ok(server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn insert(&self, session: &Session) -> Result<(), DatabaseError> {
|
pub async fn insert(&self, session: &Session) -> Result<(), DatabaseError> {
|
||||||
session
|
session
|
||||||
.query_unpaged(
|
.query_unpaged(
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ impl FromArguments for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consumes the entire remaining string as a single argument. If no string is remaining, it
|
||||||
|
/// returns an empty string.
|
||||||
|
///
|
||||||
|
/// Parsing this argument type never fails.
|
||||||
pub struct GreedyString(pub String);
|
pub struct GreedyString(pub String);
|
||||||
|
|
||||||
impl FromArguments for GreedyString {
|
impl FromArguments for GreedyString {
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ pub enum CommandError {
|
|||||||
|
|
||||||
#[error("A database operation failed due to an inconsistent state")]
|
#[error("A database operation failed due to an inconsistent state")]
|
||||||
DatabaseInconsistentState,
|
DatabaseInconsistentState,
|
||||||
|
|
||||||
|
#[error("The command was used in DMs, but it can only be used in servers")]
|
||||||
|
ServerCommandRunInDMs,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@@ -66,7 +69,10 @@ pub fn get_command_parts<'a>(prefix: &str, message: &'a str) -> Option<CommandPa
|
|||||||
.to_ascii_lowercase()
|
.to_ascii_lowercase()
|
||||||
.starts_with(&prefix.to_ascii_lowercase())
|
.starts_with(&prefix.to_ascii_lowercase())
|
||||||
{
|
{
|
||||||
let message = message_trimmed_start.split_at(prefix.len()).1.trim_ascii_start();
|
let message = message_trimmed_start
|
||||||
|
.split_at(prefix.len())
|
||||||
|
.1
|
||||||
|
.trim_ascii_start();
|
||||||
|
|
||||||
match message.split_once(" ") {
|
match message.split_once(" ") {
|
||||||
Some((name, args)) => Some(CommandParts::new(name, args)),
|
Some((name, args)) => Some(CommandParts::new(name, args)),
|
||||||
|
|||||||
@@ -32,7 +32,10 @@ impl<T: Send + Sync + 'static> OnMessageHandler<T> for CommandRunner {
|
|||||||
|
|
||||||
if let Some(command) = command {
|
if let Some(command) = command {
|
||||||
command
|
command
|
||||||
.execute(CommandContext::new(event, rt.clone(), &prefixes[0]), parts.args)
|
.execute(
|
||||||
|
CommandContext::new(event, rt.clone(), &prefixes[0]),
|
||||||
|
parts.args,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
constants::DEFAULT_PREFIX,
|
||||||
|
database::models::Server,
|
||||||
|
discord::sanitizing::SanitizeDiscordMarkdown,
|
||||||
|
framework::commands::{
|
||||||
|
Command, CommandError,
|
||||||
|
arguments::{Argument, GreedyString, ParseArguments},
|
||||||
|
context::CommandContext,
|
||||||
|
},
|
||||||
|
state::State,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PrefixCommand;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Command<State> for PrefixCommand {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"prefix"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn aliases(&self) -> &'static [&'static str] {
|
||||||
|
&["p"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description(&self) -> &'static str {
|
||||||
|
"Sets the command prefix for the server."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arguments(&self) -> &'static [Argument] {
|
||||||
|
&[Argument {
|
||||||
|
name: "prefix",
|
||||||
|
is_optional: true,
|
||||||
|
is_greedy: true,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(
|
||||||
|
&self,
|
||||||
|
ctx: CommandContext<'_, State>,
|
||||||
|
args: &str,
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let prefix: GreedyString = ParseArguments::parse(args).unwrap();
|
||||||
|
let mut prefix = prefix.trim();
|
||||||
|
|
||||||
|
let mut server = Server::get_or_create_by_id(
|
||||||
|
ctx.event
|
||||||
|
.guild_id
|
||||||
|
.ok_or(CommandError::ServerCommandRunInDMs)?
|
||||||
|
.get(),
|
||||||
|
&ctx.rt.state.db,
|
||||||
|
&ctx.rt.http,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.inspect_err(|e| log::error!("Failed to get or create server: {e}"))
|
||||||
|
.map_err(|_| CommandError::DatabaseQueryFailed)?;
|
||||||
|
|
||||||
|
if prefix.is_empty() {
|
||||||
|
prefix = DEFAULT_PREFIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
server.prefix = prefix.to_string();
|
||||||
|
server
|
||||||
|
.upsert(&ctx.rt.state.db)
|
||||||
|
.await
|
||||||
|
.map_err(|_| CommandError::DatabaseQueryFailed)?;
|
||||||
|
|
||||||
|
ctx.send()
|
||||||
|
.content(format!(
|
||||||
|
"✅ Prefix updated! Run `{}help` to see the new prefix.",
|
||||||
|
prefix.sanitize(false)
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
log::error!("Failed to send prefix update message: {e}");
|
||||||
|
CommandError::MessageSendingFailed
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
//! Adding, updating, and removing servers from the database.
|
//! Syncing servers with the database and server configuration commands.
|
||||||
//!
|
//!
|
||||||
//! This sub-module is responsible for registering servers in the database, updating them when they
|
//! This sub-module is responsible for registering servers in the database, updating them when they
|
||||||
//! update, and removing them when they get deleted or Payphone is kicked.
|
//! update, and removing them when they get deleted or Payphone is kicked.
|
||||||
|
|
||||||
|
pub mod commands;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
|
|||||||
+13
-4
@@ -116,18 +116,26 @@ use tower_http::services::ServeDir;
|
|||||||
use twilight_gateway::Intents;
|
use twilight_gateway::Intents;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{Args, Commands}, constants::DEFAULT_PREFIX, database::models::Server, framework::{
|
cli::{Args, Commands},
|
||||||
|
constants::DEFAULT_PREFIX,
|
||||||
|
database::models::Server,
|
||||||
|
framework::{
|
||||||
bot::{Bot, PrefixGetter},
|
bot::{Bot, PrefixGetter},
|
||||||
runtime::Runtime,
|
runtime::Runtime,
|
||||||
}, groups::{
|
},
|
||||||
|
groups::{
|
||||||
about::{commands::HelpCommand, components::HelpGoBackButton},
|
about::{commands::HelpCommand, components::HelpGoBackButton},
|
||||||
calls::{
|
calls::{
|
||||||
commands::{CallCommand, HangupCommand, SkipCommand},
|
commands::{CallCommand, HangupCommand, SkipCommand},
|
||||||
events::MessageRedirector,
|
events::MessageRedirector,
|
||||||
},
|
},
|
||||||
gateway::events::{ReadyHandler, ReconnectHandler},
|
gateway::events::{ReadyHandler, ReconnectHandler},
|
||||||
servers::events::{ServerCreateHandler, ServerDeleteHandler, ServerUpdateHandler},
|
servers::{
|
||||||
}, state::State
|
commands::PrefixCommand,
|
||||||
|
events::{ServerCreateHandler, ServerDeleteHandler, ServerUpdateHandler},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
state::State,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
@@ -217,6 +225,7 @@ async fn start(token: String, database_addr: String) {
|
|||||||
.command(CallCommand::new())
|
.command(CallCommand::new())
|
||||||
.command(SkipCommand)
|
.command(SkipCommand)
|
||||||
.command(HangupCommand)
|
.command(HangupCommand)
|
||||||
|
.command(PrefixCommand)
|
||||||
.component(HelpGoBackButton)
|
.component(HelpGoBackButton)
|
||||||
.on_ready(ReadyHandler)
|
.on_ready(ReadyHandler)
|
||||||
.on_reconnect(ReconnectHandler)
|
.on_reconnect(ReconnectHandler)
|
||||||
|
|||||||
Reference in New Issue
Block a user