Implement the Error trait and improve our custom error

This commit is contained in:
Victor Mignot 2025-01-02 15:21:46 +01:00
parent 6c48eb11ac
commit 0a5a3d366b
Signed by: dala
SSH key fingerprint: SHA256:+3O9MhlDc2tJL0n+E+Myr7nL+74DP9AXdIXHmIqZTkY
10 changed files with 135 additions and 196 deletions

View file

@ -1,7 +1,7 @@
//! Commons elements that are used in while executing the bot commands.
use log::{info, warn};
use std::sync::Arc;
use std::{fmt::Display, sync::Arc};
use serenity::{
async_trait,
@ -18,31 +18,65 @@ use crate::database::Client as DatabaseClient;
/// The kind of errors that can be returned while executing a command.
#[derive(Debug)]
pub enum CommandExecutionError {
pub enum Error {
/// An error that is returned when the `Serenity` crate failed to get the argument from the
/// Discord API payload.
ArgumentExtractionError(String),
InvalidCommand(String),
/// An error that is returned when the cast from the argument value to a Rust type failed.
ArgumentDeserializationError(String),
ArgumentDeserialization(String),
/// The kind of error that is returned when a Database query failed.
DatabaseQueryError(String),
DatabaseQuery(String),
/// Error returned when we fail to extract the context of a Discord commands.
ContextRetrievalError(String),
ContextRetrieval(String),
/// Error returned when sending a command to the discord API failed.
DiscordAPICallError(String),
DiscordAPICall(serenity::Error),
/// Error returned when there was an issue while using a selector embed in the command
/// response.
SelectorError(String),
Selector(String),
/// Error returned when the given command is unknown to Yorokobot.
UnknownCommand(String),
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let string = match self {
Error::InvalidCommand(e) => format!("Received an invalid command: {e}"),
Error::ArgumentDeserialization(e) => {
format!("Failed to deserialize command argument: {e}")
}
Error::DatabaseQuery(e) => format!("Failed to execute a database query: {e}"),
Error::ContextRetrieval(e) => {
format!("Failed to retrieve current session context: {e}")
}
Error::DiscordAPICall(e) => format!("Error during Discord API call: {e}"),
Error::Selector(e) => format!("Met an error while using an embed selector: {e}"),
Error::UnknownCommand(e) => format!("Met an unknown bot command: {e}"),
};
write!(f, "{string}")
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::InvalidCommand(_) => None,
Error::ArgumentDeserialization(_) => None,
Error::DatabaseQuery(_) => None,
Error::ContextRetrieval(_) => None,
Error::DiscordAPICall(error) => error.source(),
Error::Selector(_) => None,
Error::UnknownCommand(_) => None,
}
}
}
/// An option that can/have to be passed to a Discord command.
pub struct BotCommandOption {
pub name: String,
@ -67,11 +101,7 @@ pub trait BotCommand {
fn options_list() -> Vec<BotCommandOption>;
/// Execute the command with the given `context` and using the given `database`.
async fn run(
&self,
context: Context,
database: Arc<DatabaseClient>,
) -> Result<(), CommandExecutionError>;
async fn run(&self, context: Context, database: Arc<DatabaseClient>) -> Result<(), Error>;
/// Extract and deserialize the `index`th value from the command `options`.
fn extract_option_value(

View file

@ -20,7 +20,7 @@ use crate::database::{
Client as DatabaseClient,
};
use super::commons::{BotCommand, BotCommandOption, CommandExecutionError};
use super::commons::{BotCommand, BotCommandOption, Error};
pub struct CreateTagCommand {
interaction: ApplicationCommandInteraction,
@ -50,25 +50,21 @@ impl BotCommand for CreateTagCommand {
CreateTagCommand { interaction }
}
async fn run(
&self,
context: Context,
database: Arc<DatabaseClient>,
) -> Result<(), CommandExecutionError> {
async fn run(&self, context: Context, database: Arc<DatabaseClient>) -> Result<(), Error> {
// Extract tag_name parameter
let tag_name = match self.interaction.data.options.first() {
Some(a) => match &a.resolved {
Some(r) => match r {
CommandDataOptionValue::String(r_str) => Ok(r_str),
_ => Err(CommandExecutionError::ArgumentDeserializationError(
_ => Err(Error::ArgumentDeserialization(
"Received non String argument for the CreateTagCommand".to_string(),
)),
},
None => Err(CommandExecutionError::ArgumentDeserializationError(
None => Err(Error::ArgumentDeserialization(
"Could not deserialize the argument for the CreateTagCommand".to_string(),
)),
},
None => Err(CommandExecutionError::ArgumentExtractionError(
None => Err(Error::InvalidCommand(
"Failed to get the CreateTagCommand argument".to_string(),
)),
}?;
@ -76,7 +72,7 @@ impl BotCommand for CreateTagCommand {
// Extract guild id from Serenity context
let guild_id = match self.interaction.guild_id {
Some(a) => Ok(a.to_string()),
None => Err(CommandExecutionError::ContextRetrievalError(
None => Err(Error::ContextRetrieval(
"Could not fetch guild id from issued command".to_string(),
)),
}?;
@ -84,11 +80,11 @@ impl BotCommand for CreateTagCommand {
let guild = match database.get_by_id::<Guild>(&guild_id).await {
Ok(query) => match query {
Some(r) => Ok(r),
None => Err(CommandExecutionError::ContextRetrievalError(
None => Err(Error::ContextRetrieval(
"Failed to retrieve the guild where the command was issued".to_string(),
)),
},
Err(()) => Err(CommandExecutionError::DatabaseQueryError(
Err(()) => Err(Error::DatabaseQuery(
"Could not access to the database".to_string(),
)),
}?;
@ -113,25 +109,19 @@ impl BotCommand for CreateTagCommand {
.await
{
Ok(_) => Ok(String::from("Tag successfully created.")),
Err(_) => Err(CommandExecutionError::DatabaseQueryError(
Err(_) => Err(Error::DatabaseQuery(
"Could not add new tag to the database".to_string(),
)),
}?
};
match self
.interaction
self.interaction
.create_interaction_response(context.http, |response| {
response
.kind(InteractionResponseType::ChannelMessageWithSource)
.interaction_response_data(|message| message.content(response_content))
})
.await
{
Ok(_) => Ok(()),
Err(_e) => Err(CommandExecutionError::DiscordAPICallError(
"Failed to answer to the initial command".to_string(),
)),
}
.map_err(Error::DiscordAPICall)
}
}

View file

@ -18,7 +18,7 @@ use serenity::{
};
use super::{
commons::{BotCommandOption, CommandExecutionError},
commons::{BotCommandOption, Error},
BotCommand,
};
@ -50,31 +50,27 @@ impl BotCommand for DeleteTagCommand {
}]
}
async fn run(
&self,
context: Context,
database: Arc<DatabaseClient>,
) -> Result<(), CommandExecutionError> {
async fn run(&self, context: Context, database: Arc<DatabaseClient>) -> Result<(), Error> {
let tag_name = match self.interaction.data.options.first() {
Some(a) => match &a.resolved {
Some(r) => match r {
CommandDataOptionValue::String(r_str) => Ok(r_str),
_ => Err(CommandExecutionError::ArgumentDeserializationError(
_ => Err(Error::ArgumentDeserialization(
"Received non String argument for DeleteTagCommand".to_string(),
)),
},
None => Err(CommandExecutionError::ArgumentDeserializationError(
None => Err(Error::ArgumentDeserialization(
"Failed to deserialize argument for DeleteTagCommand".to_string(),
)),
},
None => Err(CommandExecutionError::ArgumentExtractionError(
None => Err(Error::InvalidCommand(
"Failed to find argument in DeleteTagCommand".to_string(),
)),
}?;
let guild_id = match self.interaction.guild_id {
Some(r) => Ok(r.to_string()),
None => Err(CommandExecutionError::ContextRetrievalError(
None => Err(Error::ContextRetrieval(
"Failed to extract guild id from current context".to_string(),
)),
}?;
@ -82,11 +78,11 @@ impl BotCommand for DeleteTagCommand {
let guild = match database.get_by_id::<Guild>(&guild_id).await {
Ok(query) => match query {
Some(r) => Ok(r),
None => Err(CommandExecutionError::ContextRetrievalError(
None => Err(Error::ContextRetrieval(
"Failed to retrieve the guild where the command was issued".to_string(),
)),
},
Err(()) => Err(CommandExecutionError::DatabaseQueryError(
Err(()) => Err(Error::DatabaseQuery(
"Failed to access to the database".to_string(),
)),
}?;
@ -104,7 +100,7 @@ impl BotCommand for DeleteTagCommand {
.await
{
Ok(_) => Ok(String::from("Successfully remove the tag")),
Err(()) => Err(CommandExecutionError::DatabaseQueryError(
Err(()) => Err(Error::DatabaseQuery(
"Failed to remove tag from the database".to_string(),
)),
}?
@ -112,18 +108,12 @@ impl BotCommand for DeleteTagCommand {
String::from("No matching tag for this server.")
};
match self
.interaction
self.interaction
.create_interaction_response(context.http, |r| {
r.kind(InteractionResponseType::ChannelMessageWithSource)
.interaction_response_data(|message| message.content(response))
})
.await
{
Ok(()) => Ok(()),
Err(_e) => Err(CommandExecutionError::DiscordAPICallError(
"Failed to answer the initial command".to_string(),
)),
}
.map_err(Error::DiscordAPICall)
}
}

View file

@ -13,7 +13,7 @@ use serenity::{
use crate::database::{models::Guild, Client as DatabaseClient};
use super::{
commons::{BotCommandOption, CommandExecutionError},
commons::{BotCommandOption, Error},
BotCommand,
};
@ -40,14 +40,10 @@ impl BotCommand for ListTagCommand {
ListTagCommand { interaction }
}
async fn run(
&self,
context: Context,
database: Arc<DatabaseClient>,
) -> Result<(), CommandExecutionError> {
async fn run(&self, context: Context, database: Arc<DatabaseClient>) -> Result<(), Error> {
let guild_id = match self.interaction.guild_id {
Some(id) => Ok(id.to_string()),
None => Err(CommandExecutionError::ContextRetrievalError(
None => Err(Error::ContextRetrieval(
"Failed to extract guild id from current context".to_string(),
)),
}?;
@ -55,11 +51,11 @@ impl BotCommand for ListTagCommand {
let guild = match database.get_by_id::<Guild>(&guild_id).await {
Ok(query) => match query {
Some(r) => Ok(r),
None => Err(CommandExecutionError::ContextRetrievalError(
None => Err(Error::ContextRetrieval(
"Failed to retrieve the guild where the command was issued".to_string(),
)),
},
Err(()) => Err(CommandExecutionError::DatabaseQueryError(
Err(()) => Err(Error::DatabaseQuery(
"Failed to access to the database".to_string(),
)),
}?;
@ -79,19 +75,13 @@ impl BotCommand for ListTagCommand {
}
}
match self
.interaction
self.interaction
.create_interaction_response(context.http, |response| {
response
.kind(InteractionResponseType::ChannelMessageWithSource)
.interaction_response_data(|message| message.content(response_content))
})
.await
{
Ok(()) => Ok(()),
Err(_) => Err(CommandExecutionError::DiscordAPICallError(
"Failed to answer to the initial command".to_string(),
)),
}
.map_err(Error::DiscordAPICall)
}
}

View file

@ -14,7 +14,7 @@ use crate::{
discord::message_builders::embed_builder::EmbedMessageBuilder,
};
use super::commons::{BotCommand, BotCommandOption, CommandExecutionError};
use super::commons::{BotCommand, BotCommandOption, Error};
pub struct SourceCodeCommand {
interaction: ApplicationCommandInteraction,
@ -39,14 +39,9 @@ impl BotCommand for SourceCodeCommand {
SourceCodeCommand { interaction }
}
async fn run(
&self,
context: Context,
_: Arc<DatabaseClient>,
) -> Result<(), CommandExecutionError> {
async fn run(&self, context: Context, _: Arc<DatabaseClient>) -> Result<(), Error> {
let embed_builder = EmbedMessageBuilder::new(&context).await?;
match self
.interaction
self.interaction
.create_interaction_response(context.http, |response| {
response
.kind(InteractionResponseType::ChannelMessageWithSource)
@ -55,11 +50,6 @@ impl BotCommand for SourceCodeCommand {
})
})
.await
{
Ok(()) => Ok(()),
Err(_e) => Err(CommandExecutionError::DiscordAPICallError(
"Failed to answer to the issued command".to_string(),
)),
}
.map_err(Error::DiscordAPICall)
}
}

View file

@ -12,7 +12,7 @@ use serenity::{
};
use super::{
commons::{BotCommandOption, CommandExecutionError},
commons::{BotCommandOption, Error},
BotCommand,
};
use crate::{
@ -43,26 +43,18 @@ impl BotCommand for SubscribeCommand {
vec![]
}
async fn run(
&self,
context: Context,
database: Arc<DatabaseClient>,
) -> Result<(), CommandExecutionError> {
async fn run(&self, context: Context, database: Arc<DatabaseClient>) -> Result<(), Error> {
self.interaction
.create_interaction_response(&context.http, |response| {
response.kind(InteractionResponseType::DeferredChannelMessageWithSource)
})
.await
.map_err(|_e| {
CommandExecutionError::DiscordAPICallError(
"Failed to answer with a temporary response".to_string(),
)
})?;
.map_err(Error::DiscordAPICall)?;
let user_id = self.interaction.user.id.to_string();
let guild_id = match self.interaction.guild_id {
Some(id) => Ok(id.to_string()),
None => Err(CommandExecutionError::ContextRetrievalError(
None => Err(Error::ContextRetrieval(
"Failed to extract guild id from current context".to_string(),
)),
}?;
@ -70,11 +62,11 @@ impl BotCommand for SubscribeCommand {
let guild = match database.get_by_id::<Guild>(&guild_id).await {
Ok(query) => match query {
Some(r) => Ok(r),
None => Err(CommandExecutionError::ContextRetrievalError(
None => Err(Error::ContextRetrieval(
"Failed to retrieve the guild where the command was issued".to_string(),
)),
},
Err(()) => Err(CommandExecutionError::DatabaseQueryError(
Err(()) => Err(Error::DatabaseQuery(
"Failed to access to the database".to_string(),
)),
}?;
@ -117,7 +109,7 @@ impl BotCommand for SubscribeCommand {
)
.await
.map_err(|_| {
CommandExecutionError::DatabaseQueryError(
Error::DatabaseQuery(
"Failed to update user subscriptions in database".to_string(),
)
})?;
@ -125,25 +117,20 @@ impl BotCommand for SubscribeCommand {
let mut response = match self.interaction.get_interaction_response(&context).await {
Ok(r) => Ok(r),
Err(_e) => Err(CommandExecutionError::ContextRetrievalError(
Err(_e) => Err(Error::ContextRetrieval(
"Failed to fetch initial interaction response".to_string(),
)),
}?;
response.delete_reactions(&context).await.map_err(|_e| {
CommandExecutionError::DiscordAPICallError(
"Failed to remove reactions from initial response".to_string(),
)
})?;
response
.delete_reactions(&context)
.await
.map_err(Error::DiscordAPICall)?;
response
.edit(&context, |msg| msg.suppress_embeds(true).content("Done !"))
.await
.map_err(|_e| {
CommandExecutionError::DiscordAPICallError(
"Failed to edit content of the original response message".to_string(),
)
})?;
.map_err(Error::DiscordAPICall)?;
Ok(())
}

View file

@ -14,7 +14,7 @@ use serenity::{
};
use super::{
commons::{BotCommandOption, CommandExecutionError},
commons::{BotCommandOption, Error},
BotCommand,
};
@ -46,25 +46,17 @@ impl BotCommand for TagNotifyCommand {
vec![]
}
async fn run(
&self,
context: Context,
database: Arc<DatabaseClient>,
) -> Result<(), CommandExecutionError> {
async fn run(&self, context: Context, database: Arc<DatabaseClient>) -> Result<(), Error> {
self.interaction
.create_interaction_response(&context.http, |response| {
response.kind(InteractionResponseType::DeferredChannelMessageWithSource)
})
.await
.map_err(|_e| {
CommandExecutionError::DiscordAPICallError(
"Failed to answer with a temporary response".to_string(),
)
})?;
.map_err(Error::DiscordAPICall)?;
let guild_id = match self.interaction.guild_id {
Some(id) => Ok(id.to_string()),
None => Err(CommandExecutionError::ContextRetrievalError(
None => Err(Error::ContextRetrieval(
"Failed to extract guild id from current context".to_string(),
)),
}?;
@ -72,11 +64,11 @@ impl BotCommand for TagNotifyCommand {
let guild = match database.get_by_id::<Guild>(&guild_id).await {
Ok(query) => match query {
Some(r) => Ok(r),
None => Err(CommandExecutionError::ContextRetrievalError(
None => Err(Error::ContextRetrieval(
"Failed to retrieve the guild where the command was issued".to_string(),
)),
},
Err(()) => Err(CommandExecutionError::DatabaseQueryError(
Err(()) => Err(Error::DatabaseQuery(
"Failed to access to the database".to_string(),
)),
}?;
@ -104,7 +96,7 @@ impl BotCommand for TagNotifyCommand {
for selected_tag in selection {
let t = match guild.tags.iter().find(|s| s.name == selected_tag) {
Some(t) => Ok(t),
None => Err(CommandExecutionError::ArgumentExtractionError(
None => Err(Error::InvalidCommand(
"No matching tag found for selection".to_string(),
)),
}?;
@ -128,16 +120,15 @@ impl BotCommand for TagNotifyCommand {
let response = match self.interaction.get_interaction_response(&context).await {
Ok(r) => Ok(r),
Err(_e) => Err(CommandExecutionError::ContextRetrievalError(
Err(_e) => Err(Error::ContextRetrieval(
"Failed to fetch initial interaction response".to_string(),
)),
}?;
response.delete(&context).await.map_err(|_e| {
CommandExecutionError::DiscordAPICallError(
"Failed to remove the embed message".to_string(),
)
})?;
response
.delete(&context)
.await
.map_err(Error::DiscordAPICall)?;
// We have to create a new message as editing the original response will not notify
// the pinged users
@ -150,20 +141,12 @@ impl BotCommand for TagNotifyCommand {
})
})
.await
.map_err(|_e| {
CommandExecutionError::DiscordAPICallError(
"Failed to create a new message to ping users".to_string(),
)
})?;
.map_err(Error::DiscordAPICall)?;
} else {
self.interaction
.delete_original_interaction_response(&context)
.await
.map_err(|_e| {
CommandExecutionError::DiscordAPICallError(
"Failed to delete the original interaction message".to_string(),
)
})?;
.map_err(Error::DiscordAPICall)?;
}
Ok(())

View file

@ -8,7 +8,7 @@ use super::commands::{
use crate::{
database::{models::Guild, Client as DatabaseClient},
discord::commands::{commons::CommandExecutionError, DeleteTagCommand, SubscribeCommand},
discord::commands::{commons::Error, DeleteTagCommand, SubscribeCommand},
};
use serenity::{
async_trait,
@ -153,7 +153,7 @@ impl EventHandler for Handler {
.await
} else {
drop(users_selector);
Err(CommandExecutionError::SelectorError(
Err(Error::Selector(
"User has already a selector running".to_string(),
))
}
@ -170,13 +170,13 @@ impl EventHandler for Handler {
.await
} else {
drop(users_selector);
Err(CommandExecutionError::SelectorError(
Err(Error::Selector(
"User has already a selector running".to_string(),
))
}
}
_ => Err(CommandExecutionError::UnknownCommand(
_ => Err(Error::UnknownCommand(
"Received an unknown command from Discord".to_string(),
)),
};

View file

@ -5,7 +5,7 @@ use serenity::{
prelude::Context,
};
use crate::discord::commands::commons::CommandExecutionError;
use crate::discord::commands::commons::Error;
const HTML_COLOR_CODE: u32 = 0xffffff;
@ -16,11 +16,10 @@ pub struct EmbedMessageBuilder {
}
impl EmbedMessageBuilder {
pub async fn new(context: &Context) -> Result<Self, CommandExecutionError> {
let bot_user = context.http.get_current_user().await.map_err(|_e| {
CommandExecutionError::ContextRetrievalError(
"Failed to get current bot user".to_string(),
)
pub async fn new(context: &Context) -> Result<Self, Error> {
let bot_user =
context.http.get_current_user().await.map_err(|_e| {
Error::ContextRetrieval("Failed to get current bot user".to_string())
})?;
let embed_author = bot_user.name.clone();

View file

@ -11,7 +11,7 @@ use serenity::{
prelude::Context,
};
use crate::discord::commands::commons::CommandExecutionError;
use crate::discord::commands::commons::Error;
use super::embed_builder::EmbedMessageBuilder;
@ -83,9 +83,7 @@ impl<'a> EmbedSelector<'a> {
selector
}
pub async fn get_user_selection(
&mut self,
) -> Result<Option<HashSet<String>>, CommandExecutionError> {
pub async fn get_user_selection(&mut self) -> Result<Option<HashSet<String>>, Error> {
let embed_builder = EmbedMessageBuilder::new(self.context).await?;
match self
@ -107,19 +105,16 @@ impl<'a> EmbedSelector<'a> {
self.display_reactions().await?;
Ok(self.wait_selector_end().await?)
}
Err(_e) => Err(CommandExecutionError::DiscordAPICallError(
"Failed to edit original interaction response".to_string(),
)),
Err(e) => Err(Error::DiscordAPICall(e)),
}
}
async fn display_reactions(&self) -> Result<(), CommandExecutionError> {
async fn display_reactions(&self) -> Result<(), Error> {
if let Some(answer) = &self.embed_answer {
answer.delete_reactions(self.context).await.map_err(|_e| {
CommandExecutionError::DiscordAPICallError(
"Failed to delete reaction on the current selector".to_string(),
)
})?;
answer
.delete_reactions(self.context)
.await
.map_err(Error::DiscordAPICall)?;
for emote in SELECTION_EMOTES[0..self.get_current_page_choice_number()]
.iter()
@ -137,30 +132,24 @@ impl<'a> EmbedSelector<'a> {
Some(a) => a
.react(self.context, ReactionType::Unicode(emote.to_string()))
.await
.map_err(|_e| {
CommandExecutionError::DiscordAPICallError(
"Failed to add reactions on the current selector".to_string(),
)
}),
None => Err(CommandExecutionError::SelectorError(
.map_err(Error::DiscordAPICall),
None => Err(Error::Selector(
"Failed to refresh the reactions of the current selector".to_string(),
)),
}?;
}
Ok(())
} else {
Err(CommandExecutionError::SelectorError(
Err(Error::Selector(
"Tried to delete reaction from a non existent message".to_string(),
))
}
}
async fn wait_selector_end(
&mut self,
) -> Result<Option<HashSet<String>>, CommandExecutionError> {
async fn wait_selector_end(&mut self) -> Result<Option<HashSet<String>>, Error> {
let answer = match &self.embed_answer {
Some(a) => Ok(a),
None => Err(CommandExecutionError::SelectorError(
None => Err(Error::Selector(
"Tried to start collector before sending it".to_string(),
)),
}?;
@ -171,11 +160,7 @@ impl<'a> EmbedSelector<'a> {
.add_message_id(*answer.id.as_u64())
.timeout(Duration::from_secs(COLLECTOR_MAX_DURATION_SEC))
.build()
.map_err(|_e| {
CommandExecutionError::SelectorError(
"Failed to build the EventCollector".to_string(),
)
})?;
.map_err(|_e| Error::Selector("Failed to build the EventCollector".to_string()))?;
while let Some(reaction_event) = collector.next().await {
let reaction = match *reaction_event {
@ -232,11 +217,10 @@ impl<'a> EmbedSelector<'a> {
}
}
reaction.delete(self.context).await.map_err(|_e| {
CommandExecutionError::DiscordAPICallError(
"Failed to delete reaction from selector".to_string(),
)
})?;
reaction
.delete(self.context)
.await
.map_err(Error::DiscordAPICall)?;
}
}
collector.stop();
@ -248,7 +232,7 @@ impl<'a> EmbedSelector<'a> {
}
}
async fn next_page(&mut self) -> Result<(), CommandExecutionError> {
async fn next_page(&mut self) -> Result<(), Error> {
if self.current_page != self.page_number {
self.current_page += 1;
self.refresh_embed_selection().await?;
@ -256,7 +240,7 @@ impl<'a> EmbedSelector<'a> {
Ok(())
}
async fn previous_page(&mut self) -> Result<(), CommandExecutionError> {
async fn previous_page(&mut self) -> Result<(), Error> {
if self.current_page != 1 {
self.current_page -= 1;
self.refresh_embed_selection().await?;
@ -274,7 +258,7 @@ impl<'a> EmbedSelector<'a> {
}
}
async fn refresh_embed_selection(&mut self) -> Result<(), CommandExecutionError> {
async fn refresh_embed_selection(&mut self) -> Result<(), Error> {
let embed_builder = EmbedMessageBuilder::new(self.context).await?;
let curr_choices = self.selectable
@ -295,10 +279,6 @@ impl<'a> EmbedSelector<'a> {
))
})
.await
.map_err(|_e| {
CommandExecutionError::DiscordAPICallError(
"Failed to edit selector content".to_string(),
)
})
.map_err(Error::DiscordAPICall)
}
}