diff --git a/Commands/AdminCommands.cs b/Commands/AdminCommands.cs index 5c4de02..9cf1756 100644 --- a/Commands/AdminCommands.cs +++ b/Commands/AdminCommands.cs @@ -1,3 +1,4 @@ +using System; using System.ComponentModel; using System.Threading.Tasks; using DSharpPlus.Commands; @@ -17,7 +18,7 @@ public class AdminCommands [Command("setticket")] [Description("Turns a channel into a ticket. WARNING: Anyone will be able to delete the channel using /close.")] public async Task SetTicket(SlashCommandContext command, - [Parameter("user")][Description("(Optional) The owner of the ticket.")] DiscordUser user = null) + [Parameter("user")] [Description("(Optional) The owner of the ticket.")] DiscordUser user = null) { // Check if ticket exists in the database if (Database.IsOpenTicket(command.Channel.Id)) @@ -63,9 +64,12 @@ public class AdminCommands [Command("unsetticket")] [Description("Deletes a ticket from the ticket system without deleting the channel.")] public async Task UnsetTicket(SlashCommandContext command, - [Parameter("ticket-id")][Description("(Optional) Ticket to unset. Uses the channel you are in by default. Use ticket ID, not channel ID!")] long ticketID = 0) + [Parameter("ticket-id")] [Description("(Optional) Ticket to unset. Uses the channel you are in by default. Use ticket ID, not channel ID!")] long ticketID = 0) { Database.Ticket ticket; + DiscordChannel channel = null; + + await command.DeferResponseAsync(true); if (ticketID == 0) { @@ -79,6 +83,7 @@ public class AdminCommands }, true); return; } + channel = command.Channel; } else { @@ -92,10 +97,22 @@ public class AdminCommands }, true); return; } + + // Find the channel if it still exists + try + { + channel = await command.Guild.GetChannelAsync(ticket.channelID); + } + catch (Exception) { /*ignored*/ } } - Database.TryDeleteInterview(ticket.channelID); + // If the channel exists, stop any ongoing interview + if (channel != null) + { + await Interviewer.StopInterview(channel); + } + // Delete the ticket from the database and respond to command if (Database.DeleteOpenTicket(ticket.id)) { await command.RespondAsync(new DiscordEmbedBuilder diff --git a/Commands/InterviewCommands.cs b/Commands/InterviewCommands.cs new file mode 100644 index 0000000..fb5ae12 --- /dev/null +++ b/Commands/InterviewCommands.cs @@ -0,0 +1,128 @@ +using System.ComponentModel; +using System.Threading.Tasks; +using DSharpPlus.Commands; +using DSharpPlus.Commands.Processors.SlashCommands; +using DSharpPlus.Entities; +using DSharpPlus.Exceptions; +using SupportChild.Interviews; + +namespace SupportChild.Commands; + +[Command("interview")] +[Description("Interview management.")] +public class InterviewCommands +{ + [Command("restart")] + [Description("Restarts the interview in this ticket, using an updated template if available.")] + public async Task Restart(SlashCommandContext command) + { + if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) + { + await command.RespondAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "This channel is not a ticket." + }, true); + return; + } + + await command.DeferResponseAsync(true); + + if (await Interviewer.RestartInterview(command.Channel)) + { + await command.RespondAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Interview restarted." + }, true); + } + else + { + await command.RespondAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "An error occured when trying to restart the interview." + }, true); + } + + try + { + DiscordChannel logChannel = await SupportChild.client.GetChannelAsync(Config.logChannel); + await logChannel.SendMessageAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = command.User.Mention + " restarted interview in " + command.Channel.Mention + ".", + Footer = new DiscordEmbedBuilder.EmbedFooter + { + Text = "Ticket: " + ticket.id.ToString("00000") + } + }); + } + catch (NotFoundException) + { + Logger.Error("Could not find the log channel."); + } + } + + [Command("stop")] + [Description("Stops the interview in this ticket.")] + public async Task Stop(SlashCommandContext command) + { + if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) + { + await command.RespondAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "This channel is not a ticket." + }, true); + return; + } + + if (!Database.TryGetInterview(command.Channel.Id, out InterviewQuestion interviewRoot)) + { + await command.RespondAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "There is no interview open in this ticket.." + }, true); + return; + } + + await command.DeferResponseAsync(true); + + if (await Interviewer.StopInterview(command.Channel)) + { + await command.RespondAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Interview stopped." + }, true); + } + else + { + await command.RespondAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "An error occured when trying to stop the interview." + }, true); + } + + try + { + DiscordChannel logChannel = await SupportChild.client.GetChannelAsync(Config.logChannel); + await logChannel.SendMessageAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = command.User.Mention + " stopped the interview in " + command.Channel.Mention + ".", + Footer = new DiscordEmbedBuilder.EmbedFooter + { + Text = "Ticket: " + ticket.id.ToString("00000") + } + }); + } + catch (NotFoundException) + { + Logger.Error("Could not find the log channel."); + } + } +} \ No newline at end of file diff --git a/Commands/InterviewTemplateCommands.cs b/Commands/InterviewTemplateCommands.cs index 6e2f80d..9505475 100644 --- a/Commands/InterviewTemplateCommands.cs +++ b/Commands/InterviewTemplateCommands.cs @@ -17,7 +17,7 @@ using SupportChild.Interviews; namespace SupportChild.Commands; [Command("interviewtemplate")] -[Description("Administrative commands.")] +[Description("Interview template management.")] public class InterviewTemplateCommands { private static readonly string jsonSchema = Utilities.ReadManifestData("Interviews.interview_template.schema.json"); diff --git a/Commands/NewCommand.cs b/Commands/NewCommand.cs index 832cd6e..b266345 100644 --- a/Commands/NewCommand.cs +++ b/Commands/NewCommand.cs @@ -206,7 +206,7 @@ public class NewCommand if (Config.interviewsEnabled) { - Interviewer.StartInterview(ticketChannel); + await Interviewer.StartInterview(ticketChannel); } if (staffID != 0) diff --git a/Commands/RestartInterviewCommand.cs b/Commands/RestartInterviewCommand.cs deleted file mode 100644 index 981b608..0000000 --- a/Commands/RestartInterviewCommand.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.ComponentModel; -using System.Threading.Tasks; -using DSharpPlus.Commands; -using DSharpPlus.Commands.Processors.SlashCommands; -using DSharpPlus.Entities; -using DSharpPlus.Exceptions; -using SupportChild.Interviews; - -namespace SupportChild.Commands; - -public class RestartInterviewCommand -{ - [Command("restartinterview")] - [Description("Restarts the automated interview in this ticket, using an updated template if available.")] - public async Task OnExecute(SlashCommandContext command) - { - if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) - { - await command.RespondAsync(new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "This channel is not a ticket." - }, true); - return; - } - - await command.DeferResponseAsync(true); - await Interviewer.RestartInterview(command); - await command.RespondAsync(new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Interview restarted." - }, true); - - try - { - DiscordChannel logChannel = await SupportChild.client.GetChannelAsync(Config.logChannel); - await logChannel.SendMessageAsync(new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = command.User.Mention + " restarted interview in " + command.Channel.Mention + ".", - Footer = new DiscordEmbedBuilder.EmbedFooter - { - Text = "Ticket: " + ticket.id.ToString("00000") - } - }); - } - catch (NotFoundException) - { - Logger.Error("Could not find the log channel."); - } - } -} \ No newline at end of file diff --git a/Interviews/Interviewer.cs b/Interviews/Interviewer.cs index 54373be..2405772 100644 --- a/Interviews/Interviewer.cs +++ b/Interviews/Interviewer.cs @@ -12,37 +12,51 @@ namespace SupportChild.Interviews; public static class Interviewer { - public static async void StartInterview(DiscordChannel channel) + public static async Task StartInterview(DiscordChannel channel) { - if (channel.Parent == null) - { - return; - } - if (!Database.TryGetInterviewTemplate(channel.Parent.Id, out InterviewQuestion template)) { - return; + return false; } await CreateQuestion(channel, template); - Database.SaveInterview(channel.Id, template); + return Database.SaveInterview(channel.Id, template); } - public static async Task RestartInterview(SlashCommandContext command) + public static async Task RestartInterview(DiscordChannel channel) { - if (Database.TryGetInterview(command.Channel.Id, out InterviewQuestion interviewRoot)) + if (Database.TryGetInterview(channel.Id, out InterviewQuestion interviewRoot)) { if (Config.deleteMessagesAfterNoSummary) { - await DeletePreviousMessages(interviewRoot, command.Channel); + await DeletePreviousMessages(interviewRoot, channel); } - if (!Database.TryDeleteInterview(command.Channel.Id)) + if (!Database.TryDeleteInterview(channel.Id)) { - Logger.Error("Could not delete interview from database. Channel ID: " + command.Channel.Id); + Logger.Warn("Could not delete interview from database. Channel ID: " + channel.Id); } } - StartInterview(command.Channel); + + return await StartInterview(channel); + } + + public static async Task StopInterview(DiscordChannel channel) + { + if (Database.TryGetInterview(channel.Id, out InterviewQuestion interviewRoot)) + { + if (Config.deleteMessagesAfterNoSummary) + { + await DeletePreviousMessages(interviewRoot, channel); + } + + if (!Database.TryDeleteInterview(channel.Id)) + { + Logger.Warn("Could not delete interview from database. Channel ID: " + channel.Id); + } + } + + return true; } public static async Task ProcessButtonOrSelectorResponse(DiscordInteraction interaction) @@ -180,7 +194,6 @@ public static class Interviewer (string questionString, InterviewQuestion nextQuestion) = currentQuestion.paths.ElementAt(pathIndex); await HandleAnswer(questionString, nextQuestion, interviewRoot, currentQuestion, interaction.Channel); } - } public static async Task ProcessResponseMessage(DiscordMessage answerMessage) diff --git a/SupportChild.cs b/SupportChild.cs index 10279d5..781a397 100644 --- a/SupportChild.cs +++ b/SupportChild.cs @@ -194,7 +194,7 @@ internal static class SupportChild typeof(RemoveCategoryCommand), typeof(RemoveMessageCommand), typeof(RemoveStaffCommand), - typeof(RestartInterviewCommand), + typeof(InterviewCommands), typeof(SayCommand), typeof(SetSummaryCommand), typeof(StatusCommand),