using System.Collections; using System.Text; using System.Text.RegularExpressions; using YamlDotNet.Serialization; namespace LocalModels; public record RubricItem { public static readonly string extraCredit = "(Extra Credit) "; public required string Label { get; set; } public required int Points { get; set; } public bool IsExtraCredit => Label.Contains(extraCredit.ToLower(), StringComparison.CurrentCultureIgnoreCase); } public static class SubmissionType { public static readonly string ONLINE_TEXT_ENTRY = "online_text_entry"; public static readonly string ONLINE_UPLOAD = "online_upload"; public static readonly string ONLINE_QUIZ = "online_quiz"; // public static readonly string ON_PAPER = "on_paper"; public static readonly string DISCUSSION_TOPIC = "discussion_topic"; // public static readonly string EXTERNAL_TOOL = "external_tool"; public static readonly string ONLINE_URL = "online_url"; // public static readonly string MEDIA_RECORDING = "media_recording"; // public static readonly string STUDENT_ANNOTATION = "student_annotation"; public static readonly string NONE = "none"; public static readonly IEnumerable AllTypes = new string[] { ONLINE_TEXT_ENTRY, ONLINE_UPLOAD, ONLINE_QUIZ, // ON_PAPER, DISCUSSION_TOPIC, // EXTERNAL_TOOL, ONLINE_URL, // MEDIA_RECORDING, // STUDENT_ANNOTATION, NONE, }; } public record LocalAssignment { public ulong? CanvasId { get; init; } = null; public string Name { get; init; } = ""; public string Description { get; init; } = ""; public bool LockAtDueDate { get; init; } public IEnumerable Rubric { get; init; } = Array.Empty(); public DateTime? LockAt { get; init; } public DateTime DueAt { get; init; } public string? LocalAssignmentGroupName { get; init; } public int PointsPossible => Rubric.Sum(r => r.IsExtraCredit ? 0 : r.Points); public IEnumerable SubmissionTypes { get; init; } = Array.Empty(); public string GetRubricHtml() { var output = "

Rubric

[\n";

    var lineStrings = Rubric.Select(
      item => $"  {{\"label\": \"{item.Label}\", \"points\": {item.Points}}}"
    );
    output += string.Join(",\n", lineStrings);
    output += "\n]
"; return output; } public string GetDescriptionHtml() { var rubricHtml = GetRubricHtml(); return Markdig.Markdown.ToHtml(Description) + "
" + rubricHtml; } public ulong? GetCanvasAssignmentGroupId(IEnumerable assignmentGroups) => assignmentGroups .FirstOrDefault(g => g.Name == LocalAssignmentGroupName)? .CanvasId; public string ToYaml() { var serializer = new SerializerBuilder().DisableAliases().Build(); var yaml = serializer.Serialize(this); return yaml; } public string ToMarkdown() { var assignmentYaml = ToYaml(); var assignmentMarkdown = "```yaml" + Environment.NewLine + assignmentYaml + "```" + Environment.NewLine + "" + Environment.NewLine + Description; return assignmentMarkdown; } public string RubricToMarkdown() { var builder = new StringBuilder(); foreach (var item in Rubric) { var pointLabel = item.Points > 1 ? "pts" : "pt"; builder.Append($"- {item.Points}{pointLabel}: {item.Label}" + Environment.NewLine); } return builder.ToString(); } public static IEnumerable ParseRubricMarkdown(string rawMarkdown) { var lines = rawMarkdown.Trim().Split(Environment.NewLine); var items = lines.Select(parseIndividualRubricItemMarkdown).ToArray(); return items; } private static RubricItem parseIndividualRubricItemMarkdown(string rawMarkdown) { var pointsPattern = @"\s*-\s*(\d+)\s*pt(s)?:"; var match = Regex.Match(rawMarkdown, pointsPattern); if (!match.Success) throw new RubricMarkdownParseException($"points not found: {rawMarkdown}"); var points = int.Parse(match.Groups[1].Value); var label = string.Join(": ", rawMarkdown.Split(": ").Skip(1)); return new RubricItem() { Points = points, Label = label }; } } public class RubricMarkdownParseException : Exception { public RubricMarkdownParseException(string message) : base(message) { } }