diff --git a/Management.Test/Markdown/AssignmentMarkdownTests.cs b/Management.Test/Markdown/AssignmentMarkdownTests.cs index 941f7eb..a29a7d6 100644 --- a/Management.Test/Markdown/AssignmentMarkdownTests.cs +++ b/Management.Test/Markdown/AssignmentMarkdownTests.cs @@ -132,5 +132,25 @@ public class AssignmentMarkdownTests var parsedAssignment = LocalAssignment.ParseMarkdown(assignmentMarkdown); parsedAssignment.Should().BeEquivalentTo(assignment); } + [Fact] + public void Assignments_CanRestrictUploadTypes() + { + var assignment = new LocalAssignment() + { + Name = "test assignment", + Description = "here is the description", + DueAt = new DateTime(), + LockAt = new DateTime(), + SubmissionTypes = [AssignmentSubmissionType.ONLINE_UPLOAD], + AllowedFileUploadExtensions = ["pdf", "txt"], + LocalAssignmentGroupName = "Final Project", + Rubric = new List() {} + }; + + var assignmentMarkdown = assignment.ToMarkdown(); + + var parsedAssignment = LocalAssignment.ParseMarkdown(assignmentMarkdown); + parsedAssignment.Should().BeEquivalentTo(assignment); + } } diff --git a/Management.Web/Pages/AssignmentForm/AssignmentMarkdownEditor.razor b/Management.Web/Pages/AssignmentForm/AssignmentMarkdownEditor.razor index 4c4adc2..52a27a9 100644 --- a/Management.Web/Pages/AssignmentForm/AssignmentMarkdownEditor.razor +++ b/Management.Web/Pages/AssignmentForm/AssignmentMarkdownEditor.razor @@ -72,6 +72,11 @@ SubmissionTypes: - {AssignmentSubmissionType.ONLINE_TEXT_ENTRY} - {AssignmentSubmissionType.ONLINE_UPLOAD} - {AssignmentSubmissionType.DISCUSSION_TOPIC} +AllowedFileUploadExtensions: +- pdf +- jpg +- jpeg +- png Assignment Group Names: - {groupNames} diff --git a/Management/Models/Local/Assignment/LocalAssignment.cs b/Management/Models/Local/Assignment/LocalAssignment.cs index f016182..a31eddf 100644 --- a/Management/Models/Local/Assignment/LocalAssignment.cs +++ b/Management/Models/Local/Assignment/LocalAssignment.cs @@ -19,6 +19,7 @@ public sealed record LocalAssignment : IModuleItem public DateTime DueAt { get; init; } public string? LocalAssignmentGroupName { get; init; } public IEnumerable SubmissionTypes { get; init; } = Array.Empty(); + public IEnumerable AllowedFileUploadExtensions { get; init; } = Array.Empty(); public IEnumerable Rubric { get; init; } = Array.Empty(); public double PointsPossible => Rubric.Sum(r => r.IsExtraCredit ? 0 : r.Points); diff --git a/Management/Models/Local/Assignment/LocalAssignmentMarkdownCreator.cs b/Management/Models/Local/Assignment/LocalAssignmentMarkdownCreator.cs index 8313f71..14e3ec5 100644 --- a/Management/Models/Local/Assignment/LocalAssignmentMarkdownCreator.cs +++ b/Management/Models/Local/Assignment/LocalAssignmentMarkdownCreator.cs @@ -43,6 +43,11 @@ public static class LocalAssignmentMarkdownCreator { builder.Append($"- {submissionType}" + "\n"); } + builder.Append($"AllowedFileUploadExtensions:" + "\n"); + foreach (var fileExtension in assignment.AllowedFileUploadExtensions) + { + builder.Append($"- {fileExtension}" + "\n"); + } return builder.ToString(); } } diff --git a/Management/Models/Local/Assignment/LocalAssignmentMarkdownParser.cs b/Management/Models/Local/Assignment/LocalAssignmentMarkdownParser.cs index 7dec9a8..adb327b 100644 --- a/Management/Models/Local/Assignment/LocalAssignmentMarkdownParser.cs +++ b/Management/Models/Local/Assignment/LocalAssignmentMarkdownParser.cs @@ -9,7 +9,7 @@ public static class LocalAssignmentMarkdownParser public static LocalAssignment ParseMarkdown(string input) { var settingsString = input.Split("---")[0]; - var (name, localAssignmentGroupName, submissionTypes, dueAt, lockAt) = parseSettings(settingsString); + var (name, localAssignmentGroupName, submissionTypes, fileUploadExtensions, dueAt, lockAt) = parseSettings(settingsString); var description = String.Join("---\n", input.Split("---\n")[1..]).Split("## Rubric")[0]; @@ -20,6 +20,7 @@ public static class LocalAssignmentMarkdownParser Name = name.Trim(), LocalAssignmentGroupName = localAssignmentGroupName.Trim(), SubmissionTypes = submissionTypes, + AllowedFileUploadExtensions = fileUploadExtensions, DueAt = dueAt, LockAt = lockAt, Rubric = rubric, @@ -27,22 +28,23 @@ public static class LocalAssignmentMarkdownParser }; } - private static (string name, string assignmentGroupName, List submissionTypes, DateTime dueAt, DateTime? lockAt) parseSettings(string input) + private static (string name, string assignmentGroupName, List submissionTypes, List fileUploadExtensions, DateTime dueAt, DateTime? lockAt) parseSettings(string input) { var name = MarkdownUtils.ExtractLabelValue(input, "Name"); var rawLockAt = MarkdownUtils.ExtractLabelValue(input, "LockAt"); var rawDueAt = MarkdownUtils.ExtractLabelValue(input, "DueAt"); var localAssignmentGroupName = MarkdownUtils.ExtractLabelValue(input, "AssignmentGroupName"); var submissionTypes = parseSubmissionTypes(input); + var fileUploadExtensions = parseFileUploadExtensions(input); DateTime? lockAt = DateTime.TryParse(rawLockAt, out DateTime parsedLockAt) ? parsedLockAt : null; var dueAt = DateTime.TryParse(rawDueAt, out DateTime parsedDueAt) ? parsedDueAt - : throw new QuizMarkdownParseException($"Error with DueAt: {rawDueAt}"); + : throw new AssignmentMarkdownParseException($"Error with DueAt: {rawDueAt}"); - return (name, localAssignmentGroupName, submissionTypes, dueAt, lockAt); + return (name, localAssignmentGroupName, submissionTypes, fileUploadExtensions, dueAt, lockAt); } @@ -76,6 +78,37 @@ public static class LocalAssignmentMarkdownParser return submissionTypes; } + private static List parseFileUploadExtensions(string input) + { + input = input.Replace("\r\n", "\n"); + List allowedFileUploadExtensions = []; + + // Define a regular expression pattern to match the bulleted list items + string startOfTypePattern = @"- (.+)"; + Regex regex = new(startOfTypePattern); + + var words = input.Split("AllowedFileUploadExtensions:"); + if(words.Length < 2) + return []; + var inputAfterSubmissionTypes = words[1]; + + string[] lines = inputAfterSubmissionTypes.Split("\n", StringSplitOptions.RemoveEmptyEntries); + + foreach (string line in lines) + { + string trimmedLine = line.Trim(); + Match match = regex.Match(trimmedLine); + + if (!match.Success) + break; + + string type = match.Groups[1].Value.Trim(); + allowedFileUploadExtensions.Add(type); + } + + return allowedFileUploadExtensions; + } + public static IEnumerable ParseRubricMarkdown(string rawMarkdown)