diff --git a/Management.Test/Markdown/QuizMarkdownTests.cs b/Management.Test/Markdown/QuizMarkdownTests.cs new file mode 100644 index 0000000..ac7c327 --- /dev/null +++ b/Management.Test/Markdown/QuizMarkdownTests.cs @@ -0,0 +1,157 @@ +using LocalModels; + +// try to follow syntax from https://github.com/gpoore/text2qti +public class QuizMarkdownTests +{ + [Test] + public void CanSerializeQuizToMarkdown() + { + var quiz = new LocalQuiz() + { + Id = "string", + CanvasId = 8324723, + Name = "Test Quiz", + Description = @" +# quiz description + +this is my description in markdown + +`here is code` +", + LockAtDueDate = true, + LockAt = DateTime.MaxValue, + DueAt = DateTime.MaxValue, + ShuffleAnswers = true, + OneQuestionAtATime = false, + LocalAssignmentGroupId = "someId", + AllowedAttempts = -1, + Questions = new LocalQuizQuestion[] { } + }; + + var markdown = quiz.ToMarkdown(); + + markdown.Should().Contain("Id: string"); + markdown.Should().Contain("CanvasId: 8324723"); + markdown.Should().Contain("Name: Test Quiz"); + markdown.Should().Contain(quiz.Description); + markdown.Should().Contain("LockAtDueDate: true"); + markdown.Should().Contain("ShuffleAnswers: true"); + markdown.Should().Contain("OneQuestionAtATime: false"); + markdown.Should().Contain("LocalAssignmentGroupId: someId"); + markdown.Should().Contain("AllowedAttempts: -1"); + } + [Test] + public void QuzMarkdownIncludesMultipleChoiceQuestion() + { + var quiz = new LocalQuiz() + { + Id = "string", + CanvasId = 8324723, + Name = "Test Quiz", + Description = "desc", + LockAtDueDate = true, + LockAt = DateTime.MaxValue, + DueAt = DateTime.MaxValue, + ShuffleAnswers = true, + OneQuestionAtATime = false, + LocalAssignmentGroupId = "someId", + AllowedAttempts = -1, + Questions = new LocalQuizQuestion[] + { + new LocalQuizQuestion() + { + CanvasId = 32423, + Id = "someid", + Points = 2, + Text = @"`some type` of question + +with many + +``` +lines +``` +", + QuestionType = QuestionType.MULTIPLE_CHOICE, + Answers = new LocalQuizQuestionAnswer[] + { + new LocalQuizQuestionAnswer() { CanvasId = 324, Id = "asdfa", Correct = true, Text = "true" }, + new LocalQuizQuestionAnswer() { CanvasId = 32544, Id = "wef", Correct = false, Text = "false" + Environment.NewLine +Environment.NewLine + "endline" }, + } + } + } + }; + + var markdown = quiz.ToMarkdown(); + var expectedQuestionString = @" +Points: 2 +`some type` of question + +with many + +``` +lines +``` + +*a) true +b) false + + endline +--- +"; + markdown.Should().Contain(expectedQuestionString); + } +// [Test] +// public void QuzMarkdownIncludesMultipleAnswerQuestion() +// { +// var quiz = new LocalQuiz() +// { +// Id = "string", +// CanvasId = 8324723, +// Name = "Test Quiz", +// Description = "desc", +// LockAtDueDate = true, +// LockAt = DateTime.MaxValue, +// DueAt = DateTime.MaxValue, +// ShuffleAnswers = true, +// OneQuestionAtATime = false, +// LocalAssignmentGroupId = "someId", +// AllowedAttempts = -1, +// Questions = new LocalQuizQuestion[] +// { +// new LocalQuizQuestion() +// { +// CanvasId = 32423, +// Id = "someid", +// Text = @" +// `some type` of question + +// with many + +// ``` +// lines +// ``` +// ", +// QuestionType = QuestionType.MULTIPLE_CHOICE, +// Answers = new LocalQuizQuestionAnswer[] +// { +// new LocalQuizQuestionAnswer() { CanvasId = 324, Id = "asdfa", Correct = true, Text = "true" }, +// new LocalQuizQuestionAnswer() { CanvasId = 32544, Id = "wef", Correct = false, Text = "false" + Environment.NewLine +Environment.NewLine + "endline" }, +// } +// }, +// new LocalQuizQuestion() +// { +// CanvasId = 3253, +// Id = "somesdid", +// Text = "oneline question", +// QuestionType = QuestionType.MULTIPLE_ANSWERS, +// Answers = new LocalQuizQuestionAnswer[] +// { +// new LocalQuizQuestionAnswer() { CanvasId = 3324, Id = "asdfsa", Correct = true, Text = "true" }, +// new LocalQuizQuestionAnswer() { CanvasId = 325344, Id = "wsef", Correct = true, Text = "false"}, +// } +// } +// } +// }; +// var markdown = quiz.ToMarkdown(); +// } +} \ No newline at end of file diff --git a/Management.Web/Shared/Module/NewQuiz.razor b/Management.Web/Shared/Module/NewQuiz.razor index 2829667..80fe8cf 100644 --- a/Management.Web/Shared/Module/NewQuiz.razor +++ b/Management.Web/Shared/Module/NewQuiz.razor @@ -20,6 +20,7 @@ { Id = Guid.NewGuid().ToString(), Name=Name, + Description = "", }; if(planner.LocalCourse != null) { diff --git a/Management/Models/Local/LocalQuiz.cs b/Management/Models/Local/LocalQuiz.cs index 3d222d5..a61da64 100644 --- a/Management/Models/Local/LocalQuiz.cs +++ b/Management/Models/Local/LocalQuiz.cs @@ -4,15 +4,15 @@ namespace LocalModels; public record LocalQuiz { - public string Id { get; init; } = ""; + public required string Id { get; init; } public ulong? CanvasId { get; init; } = null; - public string Name { get; init; } = ""; - public string Description { get; init; } = ""; - public bool LockAtDueDate { get; init; } + public required string Name { get; init; } + public required string Description { get; init; } + public bool LockAtDueDate { get; init; } = true; public DateTime? LockAt { get; init; } public DateTime DueAt { get; init; } - public bool ShuffleAnswers { get; init; } - public bool OneQuestionAtATime { get; init; } + public bool ShuffleAnswers { get; init; } = true; + public bool OneQuestionAtATime { get; init; } = false; public string? LocalAssignmentGroupId { get; init; } public int AllowedAttempts { get; init; } = -1; // -1 is infinite // public bool ShowCorrectAnswers { get; init; } @@ -34,4 +34,26 @@ public record LocalQuiz var yaml = serializer.Serialize(this); return yaml; } + + public string ToMarkdown() + { + var questionMarkdownArray = Questions.Select(q => q.ToMarkdown()).ToArray(); + var questionDelimiter = Environment.NewLine + "---" + Environment.NewLine; + var questionMarkdown = string.Join(questionDelimiter, questionMarkdownArray); + + return $@"Name: {Name} +Id: {Id} +CanvasId: {CanvasId} +LockAtDueDate: {LockAtDueDate.ToString().ToLower()} +LockAt: {LockAt} +DueAt: {DueAt} +ShuffleAnswers: {ShuffleAnswers.ToString().ToLower()} +OneQuestionAtATime: {OneQuestionAtATime.ToString().ToLower()} +LocalAssignmentGroupId: {LocalAssignmentGroupId} +AllowedAttempts: {AllowedAttempts} +Description: {Description} +--- +{questionMarkdown} +"; + } } diff --git a/Management/Models/Local/LocalQuizQuestion.cs b/Management/Models/Local/LocalQuizQuestion.cs index c21d296..6ec578d 100644 --- a/Management/Models/Local/LocalQuizQuestion.cs +++ b/Management/Models/Local/LocalQuizQuestion.cs @@ -4,12 +4,37 @@ public record LocalQuizQuestion { public ulong? CanvasId { get; set; } public string Id { get; set; } = ""; - public string Text { get; init; } = string.Empty; + public string Text { get; init; } = string.Empty; public string HtmlText => Markdig.Markdown.ToHtml(Text); public string QuestionType { get; init; } = string.Empty; public int Points { get; init; } public IEnumerable Answers { get; init; } = Enumerable.Empty(); + public string ToMarkdown() + { + var answerArray = Answers.Select((answer, i) => + { + var questionLetter = (char)(i + 97); + var isMultipleChoice = QuestionType == "multiple_choice"; + + var correctIndicator = answer.Correct ? "*" : isMultipleChoice ? "" : " "; + + + var questionTypeIndicator = isMultipleChoice + ? $"{correctIndicator}{questionLetter}) " + : $"[{correctIndicator}] "; + + var textWithSpecificNewline = answer.Text.Replace(Environment.NewLine, Environment.NewLine + " "); + return $"{questionTypeIndicator}{textWithSpecificNewline}"; + }); + var answersText = string.Join(Environment.NewLine, answerArray); + + return $@"Points: {Points} +{Text} +{answersText} +--- +"; + } } public static class QuestionType diff --git a/Management/Models/Local/LocalQuizQuestionAnswer.cs b/Management/Models/Local/LocalQuizQuestionAnswer.cs index 8afbcfd..c0d05ec 100644 --- a/Management/Models/Local/LocalQuizQuestionAnswer.cs +++ b/Management/Models/Local/LocalQuizQuestionAnswer.cs @@ -10,4 +10,5 @@ public record LocalQuizQuestionAnswer public string Text { get; init; } = string.Empty; public string HtmlText => Markdig.Markdown.ToHtml(Text); + } diff --git a/test.md b/test.md new file mode 100644 index 0000000..3c1ac9e --- /dev/null +++ b/test.md @@ -0,0 +1,11 @@ +--- +*a) true +b) false + + endline +--- +*a) true +b) false + + endline +--- diff --git a/tmptxt.txt b/tmptxt.txt new file mode 100644 index 0000000..4673940 --- /dev/null +++ b/tmptxt.txt @@ -0,0 +1,44 @@ + Expected markdown "Name: Test Quiz +Id: string +CanvasId: 8324723 +LockAtDueDate: true +LockAt: 12/31/9999 11:59:59 PM +DueAt: 12/31/9999 11:59:59 PM +ShuffleAnswers: true +OneQuestionAtATime: false +LocalAssignmentGroupId: someId +AllowedAttempts: -1 +Description: desc +--- +Points: 2 +`some type` of question + +with many + +``` +lines +``` + + +- *true +- false + +endline +--- + +" to contain " +Points: 2 +`some type` of question + +with many + +``` +lines +``` + +- *true +- false + +endline +--- +". \ No newline at end of file