Added extra validation for templates
This commit is contained in:
parent
2553ad5c69
commit
414ace3dcc
2 changed files with 100 additions and 2 deletions
|
@ -279,6 +279,22 @@ public class AdminCommands
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (interview != null)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<ulong, Interviewer.ValidatedInterviewQuestion> interviewRoot in interview)
|
||||||
|
{
|
||||||
|
interviewRoot.Value.Validate(ref errors, out int summaryCount, out int summaryMaxLength);
|
||||||
|
if (summaryCount > 25)
|
||||||
|
{
|
||||||
|
errors.Add("A summary cannot contain more than 25 fields, but you have " + summaryCount + " fields in one of your interview branches.");
|
||||||
|
}
|
||||||
|
if (summaryMaxLength >= 6000)
|
||||||
|
{
|
||||||
|
errors.Add("A summary cannot contain more than 6000 characters, but one of your branches has the possibility of its summary reaching " + summaryMaxLength + " characters.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (errors.Count != 0)
|
if (errors.Count != 0)
|
||||||
{
|
{
|
||||||
string errorString = string.Join("\n\n", errors);
|
string errorString = string.Join("\n\n", errors);
|
||||||
|
|
|
@ -46,6 +46,8 @@ public static class Interviewer
|
||||||
// The entire interview tree is serialized and stored in the database in order to record responses as they are made.
|
// The entire interview tree is serialized and stored in the database in order to record responses as they are made.
|
||||||
public class InterviewQuestion
|
public class InterviewQuestion
|
||||||
{
|
{
|
||||||
|
// TODO: String selector entry description
|
||||||
|
|
||||||
// Title of the message embed.
|
// Title of the message embed.
|
||||||
[JsonProperty("title")]
|
[JsonProperty("title")]
|
||||||
public string title;
|
public string title;
|
||||||
|
@ -236,6 +238,85 @@ public static class Interviewer
|
||||||
|
|
||||||
[JsonProperty("paths", Required = Required.Always)]
|
[JsonProperty("paths", Required = Required.Always)]
|
||||||
public Dictionary<string, ValidatedInterviewQuestion> paths;
|
public Dictionary<string, ValidatedInterviewQuestion> paths;
|
||||||
|
|
||||||
|
public void Validate(ref List<string> errors, out int summaryCount, out int summaryMaxLength)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(message))
|
||||||
|
{
|
||||||
|
errors.Add("Message cannot be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type is QuestionType.ERROR or QuestionType.END_WITH_SUMMARY or QuestionType.END_WITHOUT_SUMMARY)
|
||||||
|
{
|
||||||
|
if (paths.Count > 0)
|
||||||
|
{
|
||||||
|
errors.Add("'" + type + "' questions cannot have child paths.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (paths.Count == 0)
|
||||||
|
{
|
||||||
|
errors.Add("'" + type + "' questions must have at least one child path.");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<int> summaryCounts = new List<int>();
|
||||||
|
Dictionary<string, int> childMaxLengths = new Dictionary<string, int>();
|
||||||
|
foreach (KeyValuePair<string, ValidatedInterviewQuestion> path in paths)
|
||||||
|
{
|
||||||
|
path.Value.Validate(ref errors, out int summaries, out int maxLen);
|
||||||
|
summaryCounts.Add(summaries);
|
||||||
|
childMaxLengths.Add(path.Key, maxLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
summaryCount = summaryCounts.Count == 0 ? 0 : summaryCounts.Max();
|
||||||
|
|
||||||
|
string childPathString = "";
|
||||||
|
int childMaxLength = 0;
|
||||||
|
if (childMaxLengths.Count != 0)
|
||||||
|
{
|
||||||
|
(childPathString, childMaxLength) = childMaxLengths.ToArray().MaxBy(x => x.Key.Length + x.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
summaryMaxLength = childMaxLength;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(summaryField))
|
||||||
|
{
|
||||||
|
++summaryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only count summaries that end in a summary question.
|
||||||
|
if (type == QuestionType.END_WITH_SUMMARY)
|
||||||
|
{
|
||||||
|
summaryMaxLength = message?.Length ?? 0;
|
||||||
|
summaryMaxLength += title?.Length ?? 0;
|
||||||
|
}
|
||||||
|
// Only add to the total max length if the summary field is not empty. That way we know this branch ends in a summary.
|
||||||
|
else if (summaryMaxLength > 0 && !string.IsNullOrEmpty(summaryField))
|
||||||
|
{
|
||||||
|
summaryMaxLength += summaryField.Length;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case QuestionType.BUTTONS:
|
||||||
|
case QuestionType.TEXT_SELECTOR:
|
||||||
|
summaryMaxLength += childPathString.Length;
|
||||||
|
break;
|
||||||
|
case QuestionType.USER_SELECTOR:
|
||||||
|
case QuestionType.ROLE_SELECTOR:
|
||||||
|
case QuestionType.MENTIONABLE_SELECTOR:
|
||||||
|
case QuestionType.CHANNEL_SELECTOR:
|
||||||
|
// Approximate length of a mention
|
||||||
|
summaryMaxLength += 23;
|
||||||
|
break;
|
||||||
|
case QuestionType.TEXT_INPUT:
|
||||||
|
summaryMaxLength += (maxLength == 0 ? 1024 : Math.Min(maxLength, 1024));
|
||||||
|
break;
|
||||||
|
case QuestionType.END_WITH_SUMMARY:
|
||||||
|
case QuestionType.END_WITHOUT_SUMMARY:
|
||||||
|
case QuestionType.ERROR:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<ulong, InterviewQuestion> activeInterviews = [];
|
private static Dictionary<ulong, InterviewQuestion> activeInterviews = [];
|
||||||
|
@ -335,7 +416,6 @@ public static class Interviewer
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// TODO: Debug this with the new selectors
|
|
||||||
await interaction.CreateResponseAsync(DiscordInteractionResponseType.UpdateMessage);
|
await interaction.CreateResponseAsync(DiscordInteractionResponseType.UpdateMessage);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -376,8 +456,10 @@ public static class Interviewer
|
||||||
case DiscordComponentType.Button:
|
case DiscordComponentType.Button:
|
||||||
componentID = interaction.Data.CustomId.Replace("supportchild_interviewbutton ", "");
|
componentID = interaction.Data.CustomId.Replace("supportchild_interviewbutton ", "");
|
||||||
break;
|
break;
|
||||||
|
case DiscordComponentType.ActionRow:
|
||||||
|
case DiscordComponentType.FormInput:
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException("Tried to process an invalid component type: " + interaction.Data.ComponentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The different mentionable selectors provide the actual answer, while the others just return the ID.
|
// The different mentionable selectors provide the actual answer, while the others just return the ID.
|
||||||
|
|
Loading…
Reference in a new issue