Add error handling for buttons and selectors

This commit is contained in:
Toastie 2024-12-26 20:30:56 +13:00
parent 91991c10f2
commit a8d7440a7a
Signed by: toastie_t0ast
GPG key ID: 27F3B6855AFD40A4

View file

@ -204,36 +204,49 @@ public static class Interviewer
public static async Task ProcessButtonOrSelectorResponse(DiscordInteraction interaction) public static async Task ProcessButtonOrSelectorResponse(DiscordInteraction interaction)
{ {
// TODO: Add error responses.
if (interaction?.Channel == null || interaction?.Message == null) if (interaction?.Channel == null || interaction?.Message == null)
{ {
return; return;
} }
// Return if the user didn't select anything // Ignore if option was deselected.
if (interaction.Data.ComponentType == DiscordComponentType.StringSelect && interaction.Data.Values.Length == 0) if (interaction.Data.ComponentType == DiscordComponentType.StringSelect && interaction.Data.Values.Length == 0)
{ {
await interaction.CreateResponseAsync(DiscordInteractionResponseType.UpdateMessage);
return; return;
} }
await interaction.CreateResponseAsync(DiscordInteractionResponseType.DeferredMessageUpdate);
// Return if there is no active interview in this channel // Return if there is no active interview in this channel
if (!activeInterviews.TryGetValue(interaction.Channel.Id, out InterviewQuestion interviewRoot)) if (!activeInterviews.TryGetValue(interaction.Channel.Id, out InterviewQuestion interviewRoot))
{ {
await interaction.CreateResponseAsync(DiscordInteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder()
.AddEmbed(new DiscordEmbedBuilder()
.WithColor(DiscordColor.Red)
.WithDescription("Error: There is no active interview in this ticket, ask an admin to check the bot logs if this seems incorrect."))
.AsEphemeral());
return; return;
} }
// Return if the current question cannot be found in the interview. // Return if the current question cannot be found in the interview.
if (!interviewRoot.TryGetCurrentQuestion(out InterviewQuestion currentQuestion)) if (!interviewRoot.TryGetCurrentQuestion(out InterviewQuestion currentQuestion))
{ {
await interaction.CreateResponseAsync(DiscordInteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder()
.AddEmbed(new DiscordEmbedBuilder()
.WithColor(DiscordColor.Red)
.WithDescription("Error: Something seems to have broken in this interview, you may want to restart it."))
.AsEphemeral());
Logger.Error("The interview for channel " + interaction.Channel.Id + " exists but does not have a message ID set for it's root question");
return; return;
} }
// Check if this button/selector is for an older question. // Check if this button/selector is for an older question.
if (interaction.Message.Id != currentQuestion.messageID) if (interaction.Message.Id != currentQuestion.messageID)
{ {
await interaction.CreateResponseAsync(DiscordInteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder()
.AddEmbed(new DiscordEmbedBuilder()
.WithColor(DiscordColor.Red)
.WithDescription("Error: You have already replied to this question, you have to reply to the latest one."))
.AsEphemeral());
return; return;
} }
@ -256,15 +269,19 @@ public static class Interviewer
if (!int.TryParse(componentID, out int pathIndex)) if (!int.TryParse(componentID, out int pathIndex))
{ {
Logger.Error("Invalid interview button/selector index: " + componentID); Logger.Error("Invalid interview button/selector index: " + componentID);
await interaction.CreateResponseAsync(DiscordInteractionResponseType.UpdateMessage);
return; return;
} }
if (pathIndex >= currentQuestion.paths.Count || pathIndex < 0) if (pathIndex >= currentQuestion.paths.Count || pathIndex < 0)
{ {
Logger.Error("Invalid interview button/selector index: " + pathIndex); Logger.Error("Invalid interview button/selector index: " + pathIndex);
await interaction.CreateResponseAsync(DiscordInteractionResponseType.UpdateMessage);
return; return;
} }
await interaction.CreateResponseAsync(DiscordInteractionResponseType.UpdateMessage);
(string questionString, InterviewQuestion nextQuestion) = currentQuestion.paths.ElementAt(pathIndex); (string questionString, InterviewQuestion nextQuestion) = currentQuestion.paths.ElementAt(pathIndex);
await HandleAnswer(questionString, nextQuestion, interviewRoot, currentQuestion, interaction.Channel); await HandleAnswer(questionString, nextQuestion, interviewRoot, currentQuestion, interaction.Channel);
@ -303,15 +320,19 @@ public static class Interviewer
foreach ((string questionString, InterviewQuestion nextQuestion) in currentQuestion.paths) foreach ((string questionString, InterviewQuestion nextQuestion) in currentQuestion.paths)
{ {
// Skip to the matching path. // Skip to the first matching path.
if (!Regex.IsMatch(message.Content, questionString)) continue; if (!Regex.IsMatch(message.Content, questionString)) continue;
await HandleAnswer(questionString, nextQuestion, interviewRoot, currentQuestion, message.Channel, message); await HandleAnswer(questionString, nextQuestion, interviewRoot, currentQuestion, message.Channel, message);
return; return;
} }
// TODO: No matching path found. // TODO: Make message configurable.
await message.RespondAsync(new DiscordEmbedBuilder
{
Description = "Error: Could not determine the next question based on your answer.",
Color = DiscordColor.Red
});
} }
private static async Task HandleAnswer(string questionString, private static async Task HandleAnswer(string questionString,