Started interview system PoC
This commit is contained in:
parent
32f5518891
commit
7f13161853
4 changed files with 166 additions and 2 deletions
|
@ -238,6 +238,11 @@ public class NewCommand : ApplicationCommandModule
|
|||
// Refreshes the channel as changes were made to it above
|
||||
ticketChannel = await SupportChild.discordClient.GetChannelAsync(ticketChannel.Id);
|
||||
|
||||
if (ticketChannel.Parent?.IsCategory ?? false)
|
||||
{
|
||||
Interviewer.StartInterview(ticketChannel);
|
||||
}
|
||||
|
||||
if (staffID != 0)
|
||||
{
|
||||
await ticketChannel.SendMessageAsync(new DiscordEmbedBuilder
|
||||
|
|
|
@ -98,5 +98,8 @@ internal static class Config
|
|||
database = json.SelectToken("database.name")?.Value<string>() ?? "supportchild";
|
||||
username = json.SelectToken("database.user")?.Value<string>() ?? "supportchild";
|
||||
password = json.SelectToken("database.password")?.Value<string>() ?? "";
|
||||
|
||||
// Set up interviewer
|
||||
Interviewer.ParseConfig(json.SelectToken("interviews"));
|
||||
}
|
||||
}
|
137
Interviewer.cs
Normal file
137
Interviewer.cs
Normal file
|
@ -0,0 +1,137 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DSharpPlus;
|
||||
using DSharpPlus.Entities;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace SupportChild;
|
||||
|
||||
public static class Interviewer
|
||||
{
|
||||
public enum QuestionType
|
||||
{
|
||||
DONE,
|
||||
FAIL,
|
||||
BUTTONS,
|
||||
SELECTOR,
|
||||
TEXT_INPUT
|
||||
}
|
||||
|
||||
// A tree of questions representing an interview.
|
||||
// The tree is generated by the config file when a new ticket is opened or the restart interview command is used.
|
||||
// Additional components not specified in the config file are populated as the interview progresses.
|
||||
// The entire interview tree is serialized and stored in the database in order to record responses as they are made.
|
||||
public struct InterviewQuestion
|
||||
{
|
||||
// Message contents sent to the user.
|
||||
public string message;
|
||||
|
||||
// The type of question.
|
||||
public QuestionType type;
|
||||
|
||||
// Colour of the message embed.
|
||||
public string color;
|
||||
|
||||
// The ID of this message, populated after it has been sent.
|
||||
public ulong messageID;
|
||||
|
||||
// Used as label for this question in the post-interview summary.
|
||||
public string summaryField;
|
||||
|
||||
// The user's response to the question.
|
||||
public string answer;
|
||||
|
||||
// The ID of the user's answer message, populated after it has been received.
|
||||
public ulong answerID;
|
||||
|
||||
// Possible questions to ask next, or DONE/FAIL type in order to finish interview.
|
||||
public Dictionary<string, InterviewQuestion> paths;
|
||||
}
|
||||
|
||||
private static Dictionary<ulong, InterviewQuestion> categoryInterviews = [];
|
||||
|
||||
public static void ParseConfig(JToken interviewConfig)
|
||||
{
|
||||
categoryInterviews = JsonConvert.DeserializeObject<Dictionary<ulong, InterviewQuestion>>(interviewConfig.ToString());
|
||||
}
|
||||
|
||||
public static void StartInterview(DiscordChannel channel)
|
||||
{
|
||||
if (channel.Parent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (categoryInterviews.TryGetValue(channel.Parent.Id, out InterviewQuestion interview))
|
||||
{
|
||||
CreateQuestion(channel, interview);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ProcessResponse(DiscordChannel channel, string response)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private static async void CreateQuestion(DiscordChannel channel, InterviewQuestion question)
|
||||
{
|
||||
DiscordMessageBuilder msgBuilder = new DiscordMessageBuilder
|
||||
{
|
||||
Embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Color = Utilities.StringToColor(question.color),
|
||||
Description = question.message
|
||||
}
|
||||
};
|
||||
|
||||
switch (question.type)
|
||||
{
|
||||
case QuestionType.BUTTONS:
|
||||
int nrOfButtons = 0;
|
||||
for (int nrOfButtonRows = 0; nrOfButtonRows < 5 && nrOfButtons < question.paths.Count; nrOfButtonRows++)
|
||||
{
|
||||
List<DiscordButtonComponent> buttonRow = [];
|
||||
for (; nrOfButtons < 5 * (nrOfButtonRows + 1) && nrOfButtons < question.paths.Count; nrOfButtons++)
|
||||
{
|
||||
buttonRow.Add(new DiscordButtonComponent(ButtonStyle.Primary, "supportboi_interviewbutton " + nrOfButtons, question.paths.ToArray()[nrOfButtons].Key));
|
||||
}
|
||||
msgBuilder.AddComponents(buttonRow);
|
||||
}
|
||||
break;
|
||||
case QuestionType.SELECTOR:
|
||||
List<DiscordSelectComponent> selectionComponents = [];
|
||||
|
||||
int selectionOptions = 0;
|
||||
for (int selectionBoxes = 0; selectionBoxes < 5 && selectionOptions < question.paths.Count; selectionBoxes++)
|
||||
{
|
||||
List<DiscordSelectComponentOption> categoryOptions = [];
|
||||
for (; selectionOptions < 25 * (selectionBoxes + 1) && selectionOptions < question.paths.Count; selectionOptions++)
|
||||
{
|
||||
categoryOptions.Add(new DiscordSelectComponentOption(question.paths.ToArray()[selectionOptions].Key, selectionOptions.ToString()));
|
||||
}
|
||||
selectionComponents.Add(new DiscordSelectComponent("supportboi_interviewselector " + selectionBoxes, "Select an option...", categoryOptions, false, 0, 1));
|
||||
}
|
||||
|
||||
msgBuilder.AddComponents(selectionComponents);
|
||||
break;
|
||||
case QuestionType.TEXT_INPUT:
|
||||
// TODO: Add embed footer with response info
|
||||
break;
|
||||
case QuestionType.DONE:
|
||||
case QuestionType.FAIL:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DiscordMessage message = await channel.SendMessageAsync(msgBuilder);
|
||||
question.messageID = message.Id;
|
||||
|
||||
// TODO: Save interview progress
|
||||
}
|
||||
|
||||
public static void CreateSummary()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
# More info: https://dsharpplus.github.io/api/DSharpPlus.TimestampFormat.html
|
||||
timestamp-format: "RelativeTime"
|
||||
|
||||
# Whether or not staff members should be randomly assigned tickets when they are made. Individual staff members can opt out using the toggleactive command.
|
||||
# Whether staff members should be randomly assigned tickets when they are made. Individual staff members can opt out using the toggleactive command.
|
||||
random-assignment: true
|
||||
|
||||
# If set to true the rasssign command will include staff members set as inactive if a specific role is specified in the command.
|
||||
|
@ -60,4 +60,23 @@ database:
|
|||
|
||||
# Username and password for authentication
|
||||
user: ""
|
||||
password: ""
|
||||
password: ""
|
||||
|
||||
# TODO: May want to move interview entries to subkey to make room for additional interview settings
|
||||
interviews:
|
||||
000000000000000000:
|
||||
message: "Are you appealing your own ban or on behalf of another user?"
|
||||
type: "BUTTONS"
|
||||
color: "CYAN"
|
||||
paths:
|
||||
- "My own ban": # TODO: Can I add button color support somehow?
|
||||
text: "What is your user name?"
|
||||
type: "TEXT_INPUT"
|
||||
summary-field: "Username"
|
||||
paths:
|
||||
- ".*":
|
||||
text: "Please write your appeal below, motivate why you think you should be unbanned."
|
||||
- "Another user's ban":
|
||||
text: "You can only appeal your own ban. Please close this ticket."
|
||||
type: "FAIL"
|
||||
color: "CYAN"
|
Loading…
Reference in a new issue