quizzes and assignments support negative and floating point values

This commit is contained in:
2024-03-26 14:35:22 -06:00
parent 6a2c4a5673
commit 035c46b284
11 changed files with 112 additions and 35 deletions

View File

@@ -220,4 +220,52 @@ Which events are triggered when the user clicks on an input field?
short_answer"; short_answer";
questionMarkdown.Should().Contain(expectedMarkdown); questionMarkdown.Should().Contain(expectedMarkdown);
} }
[Test]
public void NegativePoints_IsAllowed()
{
var rawMarkdownQuiz = @"
Name: Test Quiz
ShuffleAnswers: true
OneQuestionAtATime: false
DueAt: 2023-08-21T23:59:00
LockAt: 2023-08-21T23:59:00
AssignmentGroup: Assignments
AllowedAttempts: -1
Description: this is the
multi line
description
---
Points: -4
Which events are triggered when the user clicks on an input field?
short answer
";
var quiz = LocalQuiz.ParseMarkdown(rawMarkdownQuiz);
var firstQuestion = quiz.Questions.First();
firstQuestion.Points.Should().Be(-4);
}
[Test]
public void FloatingPointPoints_IsAllowed()
{
var rawMarkdownQuiz = @"
Name: Test Quiz
ShuffleAnswers: true
OneQuestionAtATime: false
DueAt: 2023-08-21T23:59:00
LockAt: 2023-08-21T23:59:00
AssignmentGroup: Assignments
AllowedAttempts: -1
Description: this is the
multi line
description
---
Points: 4.56
Which events are triggered when the user clicks on an input field?
short answer
";
var quiz = LocalQuiz.ParseMarkdown(rawMarkdownQuiz);
var firstQuestion = quiz.Questions.First();
firstQuestion.Points.Should().Be(4.56);
}
} }

View File

@@ -68,4 +68,35 @@ public class RubricMarkdownTests
rubric.First().IsExtraCredit.Should().BeTrue(); rubric.First().IsExtraCredit.Should().BeTrue();
rubric.First().Label.Should().Be("(Extra Credit) this is the task"); rubric.First().Label.Should().Be("(Extra Credit) this is the task");
} }
[Test]
public void TestCanParseFloatingPointNubmers()
{
var rawRubric = @"
- 1.5pt: this is the task
";
var rubric = LocalAssignment.ParseRubricMarkdown(rawRubric);
rubric.First().Points.Should().Be(1.5);
}
[Test]
public void TestCanParseNegativeNubmers()
{
var rawRubric = @"
- -2pt: this is the task
";
var rubric = LocalAssignment.ParseRubricMarkdown(rawRubric);
rubric.First().Points.Should().Be(-2.0);
}
[Test]
public void TestCanParseNegativeFloatingPointNubmers()
{
var rawRubric = @"
- -2895.00053pt: this is the task
";
var rubric = LocalAssignment.ParseRubricMarkdown(rawRubric);
rubric.First().Points.Should().Be(-2895.00053);
}
} }

View File

@@ -61,9 +61,7 @@
private MarkupString preview { get private MarkupString preview { get
{ {
var pipeline = new MarkdownPipelineBuilder() return (MarkupString)MarkdownService.Render(assignmentContext?.Assignment?.Description ?? "");
.UsePipeTables().Build();
return (MarkupString)Markdown.ToHtml(assignmentContext?.Assignment?.Description ?? "", pipeline);
} }
} }
private string HelpText() private string HelpText()

View File

@@ -22,8 +22,8 @@
assignmentContext.StateHasChanged -= reload; assignmentContext.StateHasChanged -= reload;
} }
private int requiredPoints => assignmentContext?.Assignment?.Rubric.Where(r => !r.IsExtraCredit).Select(r => r.Points).Sum() ?? 0; private double requiredPoints => assignmentContext?.Assignment?.Rubric.Where(r => !r.IsExtraCredit).Select(r => r.Points).Sum() ?? 0;
private int extraCreditPoints => assignmentContext?.Assignment?.Rubric.Where(r => r.IsExtraCredit).Select(r => r.Points).Sum() ?? 0; private double extraCreditPoints => assignmentContext?.Assignment?.Rubric.Where(r => r.IsExtraCredit).Select(r => r.Points).Sum() ?? 0;
} }
@if(assignmentContext != null) @if(assignmentContext != null)
@@ -58,4 +58,4 @@
Extra Credit Points @extraCreditPoints Extra Credit Points @extraCreditPoints
</div> </div>
</div> </div>
} }

View File

@@ -28,7 +28,7 @@
private string rawText { get; set; } = string.Empty; private string rawText { get; set; } = string.Empty;
private string? error = null; private string? error = null;
private MarkupString preview { get => (MarkupString)Markdown.ToHtml(pageContext?.Page?.Text ?? ""); } private MarkupString preview { get => (MarkupString)MarkdownService.Render(pageContext?.Page?.Text ?? ""); }
private void handleChange(string newRawPage) private void handleChange(string newRawPage)
{ {

View File

@@ -96,7 +96,7 @@
private string canvasQuizUrl => private string canvasQuizUrl =>
$"https://snow.instructure.com/courses/{planner.LocalCourse?.Settings.CanvasId}/quizzes/{quizInCanvas?.Id}"; $"https://snow.instructure.com/courses/{planner.LocalCourse?.Settings.CanvasId}/quizzes/{quizInCanvas?.Id}";
private int? quizPoints => quizContext.Quiz?.Questions.Sum(q => q.Points); private double? quizPoints => quizContext.Quiz?.Questions.Sum(q => q.Points);
private bool showHelp = false; private bool showHelp = false;
private readonly static string exampleMarkdownQuestion = @"QUESTION REFERENCE private readonly static string exampleMarkdownQuestion = @"QUESTION REFERENCE

View File

@@ -20,7 +20,7 @@ public record LocalAssignment : IModuleItem
public string? LocalAssignmentGroupName { get; init; } public string? LocalAssignmentGroupName { get; init; }
public IEnumerable<string> SubmissionTypes { get; init; } = Array.Empty<string>(); public IEnumerable<string> SubmissionTypes { get; init; } = Array.Empty<string>();
public IEnumerable<RubricItem> Rubric { get; init; } = Array.Empty<RubricItem>(); public IEnumerable<RubricItem> Rubric { get; init; } = Array.Empty<RubricItem>();
public int PointsPossible => Rubric.Sum(r => r.IsExtraCredit ? 0 : r.Points); public double PointsPossible => Rubric.Sum(r => r.IsExtraCredit ? 0 : r.Points);
public string GetDescriptionHtml() public string GetDescriptionHtml()

View File

@@ -89,12 +89,12 @@ public static class LocalAssignmentMarkdownParser
private static RubricItem parseIndividualRubricItemMarkdown(string rawMarkdown) private static RubricItem parseIndividualRubricItemMarkdown(string rawMarkdown)
{ {
var pointsPattern = @"\s*-\s*(\d+)\s*pt(s)?:"; var pointsPattern = @"\s*-\s*(-?\d+(?:\.\d+)?)\s*pt(s)?:";
var match = Regex.Match(rawMarkdown, pointsPattern); var match = Regex.Match(rawMarkdown, pointsPattern);
if (!match.Success) if (!match.Success)
throw new RubricMarkdownParseException($"points not found: {rawMarkdown}"); throw new RubricMarkdownParseException($"points not found: {rawMarkdown}");
var points = int.Parse(match.Groups[1].Value); var points = double.Parse(match.Groups[1].Value);
var label = string.Join(": ", rawMarkdown.Split(": ").Skip(1)); var label = string.Join(": ", rawMarkdown.Split(": ").Skip(1));

View File

@@ -4,6 +4,6 @@ public record RubricItem
{ {
public static readonly string extraCredit = "(Extra Credit) "; public static readonly string extraCredit = "(Extra Credit) ";
public required string Label { get; set; } public required string Label { get; set; }
public required int Points { get; set; } public required double Points { get; set; }
public bool IsExtraCredit => Label.Contains(extraCredit.ToLower(), StringComparison.CurrentCultureIgnoreCase); public bool IsExtraCredit => Label.Contains(extraCredit.ToLower(), StringComparison.CurrentCultureIgnoreCase);
} }

View File

@@ -8,7 +8,7 @@ public record LocalQuizQuestion
public string Text { get; init; } = string.Empty; public string Text { get; init; } = string.Empty;
public string HtmlText => MarkdownService.Render(Text); public string HtmlText => MarkdownService.Render(Text);
public string QuestionType { get; init; } = string.Empty; public string QuestionType { get; init; } = string.Empty;
public int Points { get; init; } public double Points { get; init; }
public IEnumerable<LocalQuizQuestionAnswer> Answers { get; init; } = public IEnumerable<LocalQuizQuestionAnswer> Answers { get; init; } =
Enumerable.Empty<LocalQuizQuestionAnswer>(); Enumerable.Empty<LocalQuizQuestionAnswer>();
public string ToMarkdown() public string ToMarkdown()
@@ -59,9 +59,9 @@ public record LocalQuizQuestion
var textHasPoints = lines.Length > 0 var textHasPoints = lines.Length > 0
&& lines.First().Contains(": ") && lines.First().Contains(": ")
&& lines.First().Split(": ").Length > 1 && lines.First().Split(": ").Length > 1
&& int.TryParse(lines.First().Split(": ")[1], out _); && double.TryParse(lines.First().Split(": ")[1], out _);
int points = firstLineIsPoints && textHasPoints ? int.Parse(lines.First().Split(": ")[1]) : 1; double points = firstLineIsPoints && textHasPoints ? double.Parse(lines.First().Split(": ")[1]) : 1;
var linesWithoutPoints = firstLineIsPoints ? lines[1..] : lines; var linesWithoutPoints = firstLineIsPoints ? lines[1..] : lines;

View File

@@ -19,24 +19,24 @@ services:
- ~/projects/faculty/4620_Distributed/2024Spring/modules:/app/storage/distributed - ~/projects/faculty/4620_Distributed/2024Spring/modules:/app/storage/distributed
- ~/projects/faculty/3840_Telemetry/2024Spring_alex/modules:/app/storage/telemetry_and_operations - ~/projects/faculty/3840_Telemetry/2024Spring_alex/modules:/app/storage/telemetry_and_operations
collector: # collector:
image: otel/opentelemetry-collector-contrib # image: otel/opentelemetry-collector-contrib
volumes: # volumes:
- ./canvas-development/otel-collector-config.yml:/etc/otelcol-contrib/config.yaml # - ./canvas-development/otel-collector-config.yml:/etc/otelcol-contrib/config.yaml
ports: # ports:
- 1888:1888 # pprof extension # - 1888:1888 # pprof extension
- 8888:8888 # Prometheus metrics exposed by the Collector # - 8888:8888 # Prometheus metrics exposed by the Collector
- 8889:8889 # Prometheus exporter metrics # - 8889:8889 # Prometheus exporter metrics
- 13133:13133 # health_check extension # - 13133:13133 # health_check extension
- 4317:4317 # OTLP gRPC receiver # - 4317:4317 # OTLP gRPC receiver
- 4318:4318 # OTLP http receiver # - 4318:4318 # OTLP http receiver
- 55679:55679 # zpages extension # - 55679:55679 # zpages extension
zipkin: # zipkin:
image: ghcr.io/openzipkin/zipkin-slim # image: ghcr.io/openzipkin/zipkin-slim
# Environment settings are defined here https://github.com/openzipkin/zipkin/blob/master/zipkin-server/README.md#environment-variables # # Environment settings are defined here https://github.com/openzipkin/zipkin/blob/master/zipkin-server/README.md#environment-variables
environment: # environment:
- STORAGE_TYPE=mem # - STORAGE_TYPE=mem
ports: # ports:
- 9411:9411 # - 9411:9411
# command: --logging.level.zipkin2=DEBUG # # command: --logging.level.zipkin2=DEBUG