Added command and functionality to stop interviews

This commit is contained in:
Toastie 2024-12-27 16:43:55 +13:00
parent 47ff409902
commit 556f082aa2
Signed by: toastie_t0ast
GPG key ID: 27F3B6855AFD40A4
7 changed files with 179 additions and 74 deletions

View file

@ -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

View file

@ -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.");
}
}
}

View file

@ -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");

View file

@ -206,7 +206,7 @@ public class NewCommand
if (Config.interviewsEnabled)
{
Interviewer.StartInterview(ticketChannel);
await Interviewer.StartInterview(ticketChannel);
}
if (staffID != 0)

View file

@ -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.");
}
}
}

View file

@ -12,37 +12,51 @@ namespace SupportChild.Interviews;
public static class Interviewer
{
public static async void StartInterview(DiscordChannel channel)
public static async Task<bool> 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<bool> 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<bool> 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)

View file

@ -194,7 +194,7 @@ internal static class SupportChild
typeof(RemoveCategoryCommand),
typeof(RemoveMessageCommand),
typeof(RemoveStaffCommand),
typeof(RestartInterviewCommand),
typeof(InterviewCommands),
typeof(SayCommand),
typeof(SetSummaryCommand),
typeof(StatusCommand),