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
|
// Refreshes the channel as changes were made to it above
|
||||||
ticketChannel = await SupportChild.discordClient.GetChannelAsync(ticketChannel.Id);
|
ticketChannel = await SupportChild.discordClient.GetChannelAsync(ticketChannel.Id);
|
||||||
|
|
||||||
|
if (ticketChannel.Parent?.IsCategory ?? false)
|
||||||
|
{
|
||||||
|
Interviewer.StartInterview(ticketChannel);
|
||||||
|
}
|
||||||
|
|
||||||
if (staffID != 0)
|
if (staffID != 0)
|
||||||
{
|
{
|
||||||
await ticketChannel.SendMessageAsync(new DiscordEmbedBuilder
|
await ticketChannel.SendMessageAsync(new DiscordEmbedBuilder
|
||||||
|
|
|
@ -98,5 +98,8 @@ internal static class Config
|
||||||
database = json.SelectToken("database.name")?.Value<string>() ?? "supportchild";
|
database = json.SelectToken("database.name")?.Value<string>() ?? "supportchild";
|
||||||
username = json.SelectToken("database.user")?.Value<string>() ?? "supportchild";
|
username = json.SelectToken("database.user")?.Value<string>() ?? "supportchild";
|
||||||
password = json.SelectToken("database.password")?.Value<string>() ?? "";
|
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
|
# More info: https://dsharpplus.github.io/api/DSharpPlus.TimestampFormat.html
|
||||||
timestamp-format: "RelativeTime"
|
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
|
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.
|
# If set to true the rasssign command will include staff members set as inactive if a specific role is specified in the command.
|
||||||
|
@ -61,3 +61,22 @@ database:
|
||||||
# Username and password for authentication
|
# Username and password for authentication
|
||||||
user: ""
|
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