Rename message-type to step-type

This commit is contained in:
Toastie 2025-02-04 19:55:25 +13:00
parent a5c722cebf
commit 6f7003ba62
Signed by: toastie_t0ast
GPG key ID: 0861BE54AD481DC7
5 changed files with 87 additions and 84 deletions

View file

@ -47,12 +47,16 @@ public class InterviewTemplateCommands
" \"interview\":\n" +
" {\n" +
" \"message\": \"\",\n" +
" \"message-type\": \"\",\n" +
" \"step-type\": \"\",\n" +
" \"color\": \"\",\n" +
" \"steps\":\n" +
" {\n" +
" \n" +
" }\n" +
" },\n" +
" \"definitions\":\n" +
" {\n" +
" \n" +
" }\n" +
"}";
MemoryStream stream = new(Encoding.UTF8.GetBytes(defaultTemplate));
@ -138,7 +142,6 @@ public class InterviewTemplateCommands
definition.Value.Validate(ref errors, ref warnings, "definitions." + definition.Key, template.definitions, 0, 0);
}
if (errors.Count != 0)
{
string errorString = string.Join("```\n```", errors);

View file

@ -11,7 +11,7 @@ using Newtonsoft.Json.Serialization;
namespace SupportChild.Interviews;
public enum MessageType
public enum StepType
{
// TODO: Support multiselector as separate type
ERROR,
@ -89,8 +89,8 @@ public class InterviewStep
// The type of message.
[JsonConverter(typeof(StringEnumConverter))]
[JsonProperty("message-type")]
public MessageType messageType;
[JsonProperty("step-type")]
public StepType stepType;
// Colour of the message embed.
[JsonProperty("color")]
@ -289,29 +289,29 @@ public class InterviewStep
{
++summaryFieldCount;
summaryMaxLength += summaryField.Length;
switch (messageType)
switch (stepType)
{
case MessageType.BUTTONS:
case MessageType.TEXT_SELECTOR:
case StepType.BUTTONS:
case StepType.TEXT_SELECTOR:
// Get the longest button/selector text
if (steps.Count > 0)
{
summaryMaxLength += steps.Max(kv => kv.Key.Length);
}
break;
case MessageType.USER_SELECTOR:
case MessageType.ROLE_SELECTOR:
case MessageType.MENTIONABLE_SELECTOR:
case MessageType.CHANNEL_SELECTOR:
case StepType.USER_SELECTOR:
case StepType.ROLE_SELECTOR:
case StepType.MENTIONABLE_SELECTOR:
case StepType.CHANNEL_SELECTOR:
// Approximate length of a mention
summaryMaxLength += 23;
break;
case MessageType.TEXT_INPUT:
case StepType.TEXT_INPUT:
summaryMaxLength += Math.Min(maxLength ?? 1024, 1024);
break;
case MessageType.INTERVIEW_END:
case MessageType.ERROR:
case MessageType.REFERENCE_END:
case StepType.INTERVIEW_END:
case StepType.ERROR:
case StepType.REFERENCE_END:
default:
break;
}
@ -323,36 +323,36 @@ public class InterviewStep
}
// TODO: Add url button here when implemented
if (messageType is MessageType.REFERENCE_END)
if (stepType is StepType.REFERENCE_END)
{
if (!string.IsNullOrWhiteSpace(message))
{
warnings.Add("The message parameter on '" + messageType + "' steps have no effect.\n\n> " + stepID + ".message");
warnings.Add("The message parameter on '" + stepType + "' steps have no effect.\n\n> " + stepID + ".message");
}
}
else
{
if (string.IsNullOrWhiteSpace(message))
{
errors.Add("'" + messageType + "' steps must have a message parameter.\n\n> " + stepID + ".message");
errors.Add("'" + stepType + "' steps must have a message parameter.\n\n> " + stepID + ".message");
}
}
if (messageType is MessageType.ERROR or MessageType.INTERVIEW_END or MessageType.REFERENCE_END)
if (stepType is StepType.ERROR or StepType.INTERVIEW_END or StepType.REFERENCE_END)
{
if (steps.Count > 0 || references.Count > 0)
{
warnings.Add("Steps of the type '" + messageType + "' cannot have child steps.\n\n> " + stepID + ".message-type");
warnings.Add("Steps of the type '" + stepType + "' cannot have child steps.\n\n> " + stepID + ".step-type");
}
if (!string.IsNullOrWhiteSpace(summaryField))
{
warnings.Add("Steps of the type '" + messageType + "' cannot have summary field names.\n\n> " + stepID + ".summary-field");
warnings.Add("Steps of the type '" + stepType + "' cannot have summary field names.\n\n> " + stepID + ".summary-field");
}
}
else if (steps.Count == 0 && references.Count == 0)
{
errors.Add("Steps of the type '" + messageType + "' must have at least one child step.\n\n> " + stepID + ".message-type");
errors.Add("Steps of the type '" + stepType + "' must have at least one child step.\n\n> " + stepID + ".step-type");
}
foreach (KeyValuePair<string, ReferencedInterviewStep> reference in references)
@ -365,7 +365,7 @@ public class InterviewStep
{
List<InterviewStep> allChildSteps = [];
referencedStep.GetAllSteps(ref allChildSteps);
if (allChildSteps.Any(s => s.messageType == MessageType.REFERENCE_END))
if (allChildSteps.Any(s => s.stepType == StepType.REFERENCE_END))
{
errors.Add("The '" + FormatJSONKey(stepID + ".step-references", reference.Key) + "' reference needs an after-reference-step as the '" + reference.Value.id + "' definition contains a REFERENCE_END step.");
}
@ -387,29 +387,29 @@ public class InterviewStep
}
}
if (parent?.messageType is not MessageType.BUTTONS && buttonStyle != null)
if (parent?.stepType is not StepType.BUTTONS && buttonStyle != null)
{
warnings.Add("Button styles have no effect on child steps of a '" + parent?.messageType + "' step.\n\n> " + stepID + ".button-style");
warnings.Add("Button styles have no effect on child steps of a '" + parent?.stepType + "' step.\n\n> " + stepID + ".button-style");
}
if (parent?.messageType is not MessageType.TEXT_SELECTOR && selectorDescription != null)
if (parent?.stepType is not StepType.TEXT_SELECTOR && selectorDescription != null)
{
warnings.Add("Selector descriptions have no effect on child steps of a '" + parent?.messageType + "' step.\n\n> " + stepID + ".selector-description");
warnings.Add("Selector descriptions have no effect on child steps of a '" + parent?.stepType + "' step.\n\n> " + stepID + ".selector-description");
}
if (messageType is not MessageType.TEXT_SELECTOR && selectorPlaceholder != null)
if (stepType is not StepType.TEXT_SELECTOR && selectorPlaceholder != null)
{
warnings.Add("Selector placeholders have no effect on steps of the type '" + messageType + "'.\n\n> " + stepID + ".selector-placeholder");
warnings.Add("Selector placeholders have no effect on steps of the type '" + stepType + "'.\n\n> " + stepID + ".selector-placeholder");
}
if (messageType is not MessageType.TEXT_INPUT && maxLength != null)
if (stepType is not StepType.TEXT_INPUT && maxLength != null)
{
warnings.Add("Max length has no effect on steps of the type '" + messageType + "'.\n\n> " + stepID + ".max-length");
warnings.Add("Max length has no effect on steps of the type '" + stepType + "'.\n\n> " + stepID + ".max-length");
}
if (messageType is not MessageType.TEXT_INPUT && minLength != null)
if (stepType is not StepType.TEXT_INPUT && minLength != null)
{
warnings.Add("Min length has no effect on steps of the type '" + messageType + "'.\n\n> " + stepID + ".min-length");
warnings.Add("Min length has no effect on steps of the type '" + stepType + "'.\n\n> " + stepID + ".min-length");
}
foreach (KeyValuePair<string, InterviewStep> step in steps)

View file

@ -152,7 +152,7 @@ public static class Interviewer
componentID = interaction.Data.Values[0];
break;
case DiscordComponentType.Button:
componentID = interaction.Data.CustomId.Replace("supportboi_interviewbutton ", "");
componentID = interaction.Data.CustomId.Replace("supportchild_interviewbutton ", "");
break;
case DiscordComponentType.ActionRow:
case DiscordComponentType.FormInput:
@ -188,7 +188,7 @@ public static class Interviewer
}
}
Logger.Error("The interview for channel " + interaction.Channel.Id + " reached a step of type " + currentStep.messageType + " which has no valid next step. Their selection was:\n" + answer);
Logger.Error("The interview for channel " + interaction.Channel.Id + " reached a step of type " + currentStep.stepType + " which has no valid next step. Their selection was:\n" + answer);
DiscordMessage followupMessage = await interaction.CreateFollowupMessageAsync(new DiscordFollowupMessageBuilder().AddEmbed(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
@ -225,7 +225,7 @@ public static class Interviewer
step = definition.Value;
step.buttonStyle = reference.buttonStyle;
step.selectorDescription = reference.selectorDescription;
if (step.messageType != MessageType.ERROR)
if (step.stepType != StepType.ERROR)
{
step.afterReferenceStep = reference.afterReferenceStep;
}
@ -264,7 +264,7 @@ public static class Interviewer
}
// The user responded to a question which does not take a text response.
if (currentStep.messageType != MessageType.TEXT_INPUT)
if (currentStep.stepType != StepType.TEXT_INPUT)
{
return;
}
@ -308,7 +308,7 @@ public static class Interviewer
return;
}
Logger.Error("The interview for channel " + answerMessage.Channel.Id + " reached a step of type " + currentStep.messageType + " which has no valid next step. Their message was:\n" + answerMessage.Content);
Logger.Error("The interview for channel " + answerMessage.Channel.Id + " reached a step of type " + currentStep.stepType + " which has no valid next step. Their message was:\n" + answerMessage.Content);
DiscordMessage errorMessage = await answerMessage.RespondAsync(new DiscordEmbedBuilder
{
Description = "Error: Could not determine the next question based on your answer. Check your response and ask an admin to check the bot logs if this seems incorrect.",
@ -326,7 +326,7 @@ public static class Interviewer
DiscordMessage answerMessage = null)
{
// The error message type should not alter anything about the interview.
if (nextStep.messageType != MessageType.ERROR)
if (nextStep.stepType != StepType.ERROR)
{
previousStep.answer = answer;
@ -335,15 +335,15 @@ public static class Interviewer
}
// Create next step, or finish the interview.
switch (nextStep.messageType)
switch (nextStep.stepType)
{
case MessageType.TEXT_INPUT:
case MessageType.BUTTONS:
case MessageType.TEXT_SELECTOR:
case MessageType.ROLE_SELECTOR:
case MessageType.USER_SELECTOR:
case MessageType.CHANNEL_SELECTOR:
case MessageType.MENTIONABLE_SELECTOR:
case StepType.TEXT_INPUT:
case StepType.BUTTONS:
case StepType.TEXT_SELECTOR:
case StepType.ROLE_SELECTOR:
case StepType.USER_SELECTOR:
case StepType.CHANNEL_SELECTOR:
case StepType.MENTIONABLE_SELECTOR:
if (!ConvertReferences(interview, nextStep, out string errID))
{
if (answerMessage != null)
@ -364,7 +364,7 @@ public static class Interviewer
await SendNextMessage(interview, channel, nextStep);
Database.SaveInterview(interview);
break;
case MessageType.INTERVIEW_END:
case StepType.INTERVIEW_END:
DiscordEmbedBuilder endEmbed = new()
{
Color = Utilities.StringToColor(nextStep.color),
@ -389,7 +389,7 @@ public static class Interviewer
Logger.Error("Could not delete interview from database. Channel ID: " + channel.Id);
}
return;
case MessageType.REFERENCE_END:
case StepType.REFERENCE_END:
if (interview.interviewRoot.TryGetTakenSteps(out List<InterviewStep> previousSteps))
{
foreach (InterviewStep step in previousSteps)
@ -397,7 +397,7 @@ public static class Interviewer
if (step.afterReferenceStep != null)
{
// If the referenced step is also a reference end, skip it and try to find another.
if (step.afterReferenceStep.messageType == MessageType.REFERENCE_END)
if (step.afterReferenceStep.stepType == StepType.REFERENCE_END)
{
step.afterReferenceStep = null;
}
@ -436,7 +436,7 @@ public static class Interviewer
Logger.Error("Could not find a step to return to after a reference step in channel " + channel.Id);
return;
case MessageType.ERROR:
case StepType.ERROR:
default:
DiscordEmbedBuilder errorEmbed = new()
{
@ -527,9 +527,9 @@ public static class Interviewer
AddSummary(interview, ref embed);
}
switch (step.messageType)
switch (step.stepType)
{
case MessageType.BUTTONS:
case StepType.BUTTONS:
int nrOfButtons = 0;
for (int nrOfButtonRows = 0; nrOfButtonRows < 5 && nrOfButtons < step.steps.Count; nrOfButtonRows++)
{
@ -537,12 +537,12 @@ public static class Interviewer
for (; nrOfButtons < 5 * (nrOfButtonRows + 1) && nrOfButtons < step.steps.Count; nrOfButtons++)
{
(string stepPattern, InterviewStep nextStep) = step.steps.ToArray()[nrOfButtons];
buttonRow.Add(new DiscordButtonComponent(nextStep.GetButtonStyle(), "supportboi_interviewbutton " + nrOfButtons, stepPattern));
buttonRow.Add(new DiscordButtonComponent(nextStep.GetButtonStyle(), "supportchild_interviewbutton " + nrOfButtons, stepPattern));
}
msgBuilder.AddComponents(buttonRow);
}
break;
case MessageType.TEXT_SELECTOR:
case StepType.TEXT_SELECTOR:
List<DiscordSelectComponent> selectionComponents = [];
int selectionOptions = 0;
@ -555,33 +555,33 @@ public static class Interviewer
categoryOptions.Add(new DiscordSelectComponentOption(stepPattern, selectionOptions.ToString(), nextStep.selectorDescription));
}
selectionComponents.Add(new DiscordSelectComponent("supportboi_interviewselector " + selectionBoxes,
selectionComponents.Add(new DiscordSelectComponent("supportchild_interviewselector " + selectionBoxes,
string.IsNullOrWhiteSpace(step.selectorPlaceholder) ? "Select an option..." : step.selectorPlaceholder, categoryOptions));
}
msgBuilder.AddComponents(selectionComponents);
break;
case MessageType.ROLE_SELECTOR:
msgBuilder.AddComponents(new DiscordRoleSelectComponent("supportboi_interviewroleselector",
case StepType.ROLE_SELECTOR:
msgBuilder.AddComponents(new DiscordRoleSelectComponent("supportchild_interviewroleselector",
string.IsNullOrWhiteSpace(step.selectorPlaceholder) ? "Select a role..." : step.selectorPlaceholder));
break;
case MessageType.USER_SELECTOR:
msgBuilder.AddComponents(new DiscordUserSelectComponent("supportboi_interviewuserselector",
case StepType.USER_SELECTOR:
msgBuilder.AddComponents(new DiscordUserSelectComponent("supportchild_interviewuserselector",
string.IsNullOrWhiteSpace(step.selectorPlaceholder) ? "Select a user..." : step.selectorPlaceholder));
break;
case MessageType.CHANNEL_SELECTOR:
msgBuilder.AddComponents(new DiscordChannelSelectComponent("supportboi_interviewchannelselector",
case StepType.CHANNEL_SELECTOR:
msgBuilder.AddComponents(new DiscordChannelSelectComponent("supportchild_interviewchannelselector",
string.IsNullOrWhiteSpace(step.selectorPlaceholder) ? "Select a channel..." : step.selectorPlaceholder));
break;
case MessageType.MENTIONABLE_SELECTOR:
msgBuilder.AddComponents(new DiscordMentionableSelectComponent("supportboi_interviewmentionableselector",
case StepType.MENTIONABLE_SELECTOR:
msgBuilder.AddComponents(new DiscordMentionableSelectComponent("supportchild_interviewmentionableselector",
string.IsNullOrWhiteSpace(step.selectorPlaceholder) ? "Select a user or role..." : step.selectorPlaceholder));
break;
case MessageType.TEXT_INPUT:
case StepType.TEXT_INPUT:
embed.WithFooter("Reply to this message with your answer. You cannot include images or files.");
break;
case MessageType.INTERVIEW_END:
case MessageType.ERROR:
case StepType.INTERVIEW_END:
case StepType.ERROR:
default:
break;
}

View file

@ -56,13 +56,13 @@
"message": {
"type": "string",
"title": "Message",
"description": "The text in the embed message that will be sent to the user when they reach this step. Required for all message types except 'REFERENCE_END'.",
"description": "The text in the embed message that will be sent to the user when they reach this step. Required for all step types except 'REFERENCE_END'.",
"minLength": 1
},
"message-type": {
"step-type": {
"type": "string",
"title": "Message Type",
"description": "The type of message, decides what the bot will do when the user gets to this step.",
"title": "Step Type",
"description": "Decides what the bot will do when the user gets to this step.",
"enum": [
"ERROR",
"INTERVIEW_END",
@ -198,7 +198,7 @@
"description": "If the user has already answered a question with the same summary-field as this step the answer will be merged with the existing answer using this delimiter. If this is not set the old answer will be replaced by the new one."
}
},
"required": [ "message-type" ],
"required": [ "step-type" ],
"unevaluatedProperties": false
}
},

View file

@ -60,7 +60,7 @@ It is highly recommended to use the interview template JSON schema to get live v
}
```
5. Open an interview template, you should now get suggestions for things like message types and color names, and error highlighting for any invalid sections.
5. Open an interview template, you should now get suggestions for things like step types and color names, and error highlighting for any invalid sections.
</details>
@ -87,7 +87,7 @@ Here is a simple example of an interview asking a user for their favourite colou
"interview":
{
"message": "What is your favourite colour?",
"message-type": "BUTTONS",
"step-type": "BUTTONS",
"color": "BLUE",
"summary-field": "Favourite colour",
"step-references":
@ -108,7 +108,7 @@ Here is a simple example of an interview asking a user for their favourite colou
"Blue":
{
"message": "Summary",
"message-type": "INTERVIEW_END",
"step-type": "INTERVIEW_END",
"add-summary": true,
"color": "BLUE",
"button-style": "PRIMARY",
@ -117,7 +117,7 @@ Here is a simple example of an interview asking a user for their favourite colou
"Gray":
{
"message": "Summary",
"message-type": "INTERVIEW_END",
"step-type": "INTERVIEW_END",
"add-summary": true,
"color": "GRAY",
"button-style": "SECONDARY",
@ -130,7 +130,7 @@ Here is a simple example of an interview asking a user for their favourite colou
"green":
{
"message": "Summary",
"message-type": "INTERVIEW_END",
"step-type": "INTERVIEW_END",
"add-summary": true,
"color": "GREEN",
"steps": {}
@ -138,7 +138,7 @@ Here is a simple example of an interview asking a user for their favourite colou
"red":
{
"message": "Summary",
"message-type": "INTERVIEW_END",
"step-type": "INTERVIEW_END",
"add-summary": true,
"color": "RED",
"steps": {}
@ -175,17 +175,17 @@ Here is a simple example of an interview asking a user for their favourite colou
<td>Yes</td>
<td>String</td>
<td>
The text in the embed message that will be sent to the user when they reach this step. Required for all message types except `REFERENCE_END`.
The text in the embed message that will be sent to the user when they reach this step. Required for all step types except `REFERENCE_END`.
</td>
</tr>
<tr>
<td>
`message-type`
`step-type`
</td>
<td>Yes</td>
<td>String</td>
<td>
The type of message, decides what the bot will do when the user gets to this step. See the list of message types below for more info.
Decides what the bot will do when the user gets to this step. See the list of step types below for more info.
<!-- For whatever reason this tag cannot be indented -->
</td>
@ -339,9 +339,9 @@ If the user answers several questions with the same `summary-field` the last ans
| `selector-description` | No | Same as the `selector-description` property in a normal step. |
| `after-reference-step` | No | If the step tree you referenced using the `id` ends in a `REFERENCE_END` the interview will continue from here when the user reaches it. |
### Message Types
### Step Types
| Message Type | Description |
| Step Type | Description |
|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `ERROR` | Sends an error message but does not stop the interview. The interview remains on the same step as before allowing the user to try again. |
| `INTERVIEW_END` | End the interview and deletes the previous messages if enabled in the config. |