Files
step3/api/QuestionsApi/Services/QuestionValidator.cs
T

58 lines
3.5 KiB
C#

using QuestionsApi.Models;
namespace QuestionsApi.Services;
public static class QuestionValidator
{
public static string? Validate(UpsertQuestionRequest req)
{
if (string.IsNullOrWhiteSpace(req.ExternalId)) return "externalId required";
if (string.IsNullOrWhiteSpace(req.Stem)) return "stem required";
if (string.IsNullOrWhiteSpace(req.LeadIn)) return "leadIn required";
if (req.Choices.Count < (req.IsPublished ? 5 : 2))
return req.IsPublished ? "published questions require at least five choices" : "at least two choices required";
if (req.Choices.Count > 20) return "questions support at most twenty choices";
if (req.Choices.Any(choice => string.IsNullOrWhiteSpace(choice.Id) || string.IsNullOrWhiteSpace(choice.Text)))
return "choice ids and text are required";
var choiceIds = req.Choices.Select(choice => choice.Id.Trim()).ToList();
if (choiceIds.Distinct(StringComparer.Ordinal).Count() != choiceIds.Count)
return "choice ids must be unique";
if (string.IsNullOrWhiteSpace(req.CorrectChoiceId)) return "correctChoiceId required";
if (!choiceIds.Contains(req.CorrectChoiceId.Trim(), StringComparer.Ordinal))
return "correctChoiceId must match a choice id";
if (string.IsNullOrWhiteSpace(req.Explanation)) return "explanation required";
var choiceIdSet = choiceIds.ToHashSet(StringComparer.Ordinal);
if (!choiceIdSet.SetEquals(req.ChoiceExplanations.Keys))
return "choiceExplanations must contain exactly one entry for every choice";
var incorrectChoiceIds = choiceIdSet
.Where(id => id != req.CorrectChoiceId.Trim())
.ToHashSet(StringComparer.Ordinal);
if (!incorrectChoiceIds.SetEquals(req.WrongAnswerFollowups.Keys))
return "wrongAnswerFollowups must contain exactly one entry for every incorrect choice";
if (req.ChoiceSelectionPercentages.Keys.Any(id => !choiceIdSet.Contains(id)))
return "choiceSelectionPercentages keys must match choice ids";
if (req.ChoiceSelectionPercentages.Any(entry => entry.Value is < 0 or > 100))
return "choiceSelectionPercentages values must be between 0 and 100";
foreach (var entry in req.WrongAnswerFollowups)
{
if (string.IsNullOrWhiteSpace(entry.Value.Prompt)) return "wrongAnswerFollowups prompt required";
if (string.IsNullOrWhiteSpace(entry.Value.TeachingPoint)) return "wrongAnswerFollowups teachingPoint required";
if (entry.Value.Choices.Count == 0) return "wrongAnswerFollowups choices required";
if (entry.Value.Choices.Any(choice => string.IsNullOrWhiteSpace(choice.Id) || string.IsNullOrWhiteSpace(choice.Text)))
return "wrongAnswerFollowups choice ids and text are required";
if (entry.Value.Choices.Select(choice => choice.Id).Distinct(StringComparer.Ordinal).Count() != entry.Value.Choices.Count)
return "wrongAnswerFollowups choice ids must be unique";
if (!entry.Value.Choices.Any(choice => choice.Id == entry.Value.CorrectChoiceId))
return "wrongAnswerFollowups correctChoiceId must match a follow-up choice id";
}
if (string.IsNullOrWhiteSpace(req.System)) return "system required";
if (string.IsNullOrWhiteSpace(req.Discipline)) return "discipline required";
if (req.Difficulty is < 1 or > 5) return "difficulty must be between 1 and 5";
return null;
}
}