diff --git a/Management.Web/Shared/Module/Assignment/AssignmentDetails.razor b/Management.Web/Shared/Module/Assignment/AssignmentDetails.razor
index 01eb365..416aff0 100644
--- a/Management.Web/Shared/Module/Assignment/AssignmentDetails.razor
+++ b/Management.Web/Shared/Module/Assignment/AssignmentDetails.razor
@@ -147,7 +147,7 @@
&& planner.AssignmentNeedsUpdates(Assignment)
)
{
-
@if(Assignment.use_template)
{
- var template = planner.LocalCourse?.AssignmentTemplates.First((t) => t.Id == Assignment.template_id);
- if(template == null)
- {
- System.Console.WriteLine($"Could not find template fof assignment, {Assignment.template_id}");
- }
- else
- {
- var html = AssignmentTemplate.GetHtml(template, Assignment);
- @((MarkupString) html)
- }
+ var html = Assignment.GetDescriptionHtml(planner.LocalCourse?.AssignmentTemplates);
+ @((MarkupString) html)
}
else
{
diff --git a/Management/Features/Configuration/CoursePlanner.cs b/Management/Features/Configuration/CoursePlanner.cs
index 483fd59..008aa6a 100644
--- a/Management/Features/Configuration/CoursePlanner.cs
+++ b/Management/Features/Configuration/CoursePlanner.cs
@@ -103,6 +103,7 @@ public class CoursePlanner
)
return;
+ Console.WriteLine("syncing with canvas");
LoadingCanvasData = true;
StateHasChanged?.Invoke();
@@ -111,10 +112,15 @@ public class CoursePlanner
await ensureAllModulesCreated(canvasId);
await reloadModules_UpdateLocalModulesWithNewId(canvasId);
- await ensureAllAssignmentsCreated_updateIds(canvasId);
+ await syncAssignmentsWithCanvas(canvasId);
+
+
+ CanvasAssignments = await canvas.Assignments.GetAll(canvasId);
+ CanvasModules = await canvas.GetModules(canvasId);
LoadingCanvasData = false;
StateHasChanged?.Invoke();
+ Console.WriteLine("done syncing with canvas\n");
}
private async Task reloadModules_UpdateLocalModulesWithNewId(ulong canvasId)
@@ -148,7 +154,7 @@ public class CoursePlanner
}
}
- private async Task ensureAllAssignmentsCreated_updateIds(ulong canvasId)
+ private async Task syncAssignmentsWithCanvas(ulong canvasId)
{
if (
LocalCourse == null
@@ -160,7 +166,7 @@ public class CoursePlanner
var moduleTasks = LocalCourse.Modules.Select(async m =>
{
- var assignmentTasks = m.Assignments.Select(ensureAssignmentInCanvas_returnUpdated);
+ var assignmentTasks = m.Assignments.Select(syncAssignmentToCanvas);
var assignments = await Task.WhenAll(assignmentTasks);
return m with { Assignments = assignments };
});
@@ -169,7 +175,7 @@ public class CoursePlanner
LocalCourse = LocalCourse with { Modules = modules };
}
- private async Task
ensureAssignmentInCanvas_returnUpdated(
+ private async Task syncAssignmentToCanvas(
LocalAssignment localAssignment
)
{
@@ -187,11 +193,13 @@ public class CoursePlanner
var canvasAssignment = CanvasAssignments.FirstOrDefault(
ca => ca.Id == localAssignment.canvasId
);
- string localHtmlDescription = getAssignmentDescriptionHtml(localAssignment);
+ string localHtmlDescription = localAssignment.GetDescriptionHtml(
+ LocalCourse.AssignmentTemplates
+ );
if (canvasAssignment != null)
{
- var assignmentNeedsUpdates = AssignmentNeedsUpdates(localAssignment);
+ var assignmentNeedsUpdates = AssignmentNeedsUpdates(localAssignment, quiet: false);
if (assignmentNeedsUpdates)
{
await canvas.Assignments.Update(courseId: canvasId, localAssignment, localHtmlDescription);
@@ -217,21 +225,7 @@ public class CoursePlanner
}
}
- private string getAssignmentDescriptionHtml(LocalAssignment localAssignment)
- {
- if (LocalCourse == null)
- throw new Exception(
- "cannot get assignment description if local course is null or other values not set"
- );
- return localAssignment.use_template
- ? AssignmentTemplate.GetHtml(
- LocalCourse.AssignmentTemplates.First(t => t.Id == localAssignment.template_id),
- localAssignment
- )
- : Markdig.Markdown.ToHtml(localAssignment.description);
- }
-
- public bool AssignmentNeedsUpdates(LocalAssignment localAssignment)
+ public bool AssignmentNeedsUpdates(LocalAssignment localAssignment, bool quiet = true)
{
if (
LocalCourse == null
@@ -245,7 +239,7 @@ public class CoursePlanner
var canvasAssignment = CanvasAssignments.First(ca => ca.Id == localAssignment.canvasId);
- var localHtmlDescription = getAssignmentDescriptionHtml(localAssignment);
+ var localHtmlDescription = localAssignment.GetDescriptionHtml(LocalCourse.AssignmentTemplates);
var canvasHtmlDescription = canvasAssignment.Description;
canvasHtmlDescription = Regex.Replace(canvasHtmlDescription, "", "");
@@ -259,37 +253,40 @@ public class CoursePlanner
var submissionTypesSame = canvasAssignment.SubmissionTypes.SequenceEqual(
localAssignment.submission_types.Select(t => t.ToString())
);
-
- if (!dueDatesSame)
- Console.WriteLine(
- $"Due dates different for {localAssignment.name}, local: {localAssignment.due_at}, in canvas {canvasAssignment.DueAt}"
- );
-
- if (!descriptionSame)
+
+ if (!quiet)
{
- Console.WriteLine($"descriptions different for {localAssignment.name}");
- Console.WriteLine("Local Description:");
- Console.WriteLine(localHtmlDescription);
- Console.WriteLine("Canvas Description: ");
- Console.WriteLine(canvasHtmlDescription);
- }
+ if (!dueDatesSame)
+ Console.WriteLine(
+ $"Due dates different for {localAssignment.name}, local: {localAssignment.due_at}, in canvas {canvasAssignment.DueAt}"
+ );
- if (!nameSame)
- Console.WriteLine(
- $"names different for {localAssignment.name}, local: {localAssignment.name}, in canvas {canvasAssignment.Name}"
- );
- if (!lockDateSame)
- Console.WriteLine(
- $"Lock Dates different for {localAssignment.name}, local: {localAssignment.lock_at}, in canvas {canvasAssignment.LockAt}"
- );
- if (!pointsSame)
- Console.WriteLine(
- $"Points different for {localAssignment.name}, local: {localAssignment.points_possible}, in canvas {canvasAssignment.PointsPossible}"
- );
- if (!submissionTypesSame)
- Console.WriteLine(
- $"Submission Types different for {localAssignment.name}, local: {JsonSerializer.Serialize(localAssignment.submission_types.Select(t => t.ToString()))}, in canvas {JsonSerializer.Serialize(canvasAssignment.SubmissionTypes)}"
- );
+ if (!descriptionSame)
+ {
+ Console.WriteLine($"descriptions different for {localAssignment.name}");
+ Console.WriteLine("Local Description:");
+ Console.WriteLine(localHtmlDescription);
+ Console.WriteLine("Canvas Description: ");
+ Console.WriteLine(canvasHtmlDescription);
+ }
+
+ if (!nameSame)
+ Console.WriteLine(
+ $"names different for {localAssignment.name}, local: {localAssignment.name}, in canvas {canvasAssignment.Name}"
+ );
+ if (!lockDateSame)
+ Console.WriteLine(
+ $"Lock Dates different for {localAssignment.name}, local: {localAssignment.lock_at}, in canvas {canvasAssignment.LockAt}"
+ );
+ if (!pointsSame)
+ Console.WriteLine(
+ $"Points different for {localAssignment.name}, local: {localAssignment.points_possible}, in canvas {canvasAssignment.PointsPossible}"
+ );
+ if (!submissionTypesSame)
+ Console.WriteLine(
+ $"Submission Types different for {localAssignment.name}, local: {JsonSerializer.Serialize(localAssignment.submission_types.Select(t => t.ToString()))}, in canvas {JsonSerializer.Serialize(canvasAssignment.SubmissionTypes)}"
+ );
+ }
return !nameSame
|| !dueDatesSame
diff --git a/Management/Models/CanvasModels/Assignments/CanvasRubric.cs b/Management/Models/CanvasModels/Assignments/CanvasRubric.cs
new file mode 100644
index 0000000..7fff6dd
--- /dev/null
+++ b/Management/Models/CanvasModels/Assignments/CanvasRubric.cs
@@ -0,0 +1,37 @@
+namespace CanvasModel.Assignments;
+
+public record CanvasRubric
+{
+ [JsonPropertyName("id")]
+ public ulong? Id { get; set; }
+
+ [JsonPropertyName("title")]
+ public required string Title { get; set; }
+
+ [JsonPropertyName("context_id")]
+ public ulong ContextId { get; set; }
+
+ [JsonPropertyName("context_type")]
+ public required string ContextType { get; set; }
+
+ [JsonPropertyName("points_possible")]
+ public double PointsPossible { get; set; }
+
+ [JsonPropertyName("reusable")]
+ public bool Reusable { get; set; }
+
+ [JsonPropertyName("read_only")]
+ public bool ReadOnly { get; set; }
+
+ // [JsonPropertyName("free_form_criterion_comments")]
+ // public bool? FreeFormCriterionComments { get; set; }
+
+ [JsonPropertyName("hide_score_total")]
+ public bool? HideScoreTotal { get; set; }
+
+ // [JsonPropertyName("data")]
+ // public required IEnumerable Data { get; set; }
+
+ // assessments
+ // associations
+}
\ No newline at end of file
diff --git a/Management/Models/CanvasModels/Assignments/CanvasRubricAssociation.cs b/Management/Models/CanvasModels/Assignments/CanvasRubricAssociation.cs
new file mode 100644
index 0000000..8738571
--- /dev/null
+++ b/Management/Models/CanvasModels/Assignments/CanvasRubricAssociation.cs
@@ -0,0 +1,35 @@
+namespace CanvasModel.Assignments;
+
+public record CanvasRubricAssociation
+{
+ [JsonPropertyName("id")]
+ public ulong Id { get; set; }
+
+ [JsonPropertyName("rubrid_id")]
+ public ulong RubricId { get; set; }
+
+ [JsonPropertyName("association_id")]
+ public ulong AssociationId { get; set; }
+
+ [JsonPropertyName("association_type")]
+ public required string AssociationType { get; set; }
+
+ [JsonPropertyName("use_for_grading")]
+ public bool UseForGrading { get; set; }
+
+ [JsonPropertyName("summary_data")]
+ public string? SummaryDaata { get; set; }
+
+ [JsonPropertyName("purpose")]
+ public required string Purpose { get; set; }
+
+ [JsonPropertyName("hide_score_total")]
+ public bool? HideScoreTotal { get; set; }
+
+ [JsonPropertyName("hide_points")]
+ public bool HidePoints { get; set; }
+
+ [JsonPropertyName("hide_outcome-results")]
+ public bool HideOUtcomeResult { get; set; }
+
+}
\ No newline at end of file
diff --git a/Management/Models/Local/AssignmentTemplate.cs b/Management/Models/Local/AssignmentTemplate.cs
index 4d214cf..5d94d31 100644
--- a/Management/Models/Local/AssignmentTemplate.cs
+++ b/Management/Models/Local/AssignmentTemplate.cs
@@ -15,16 +15,16 @@ public record AssignmentTemplate
return matches.Select(match => match.Groups[1].Value);
}
- public static string GetHtml(AssignmentTemplate template, LocalAssignment assignment)
- {
+ // public static string GetHtml(AssignmentTemplate template, LocalAssignment assignment)
+ // {
- var html = Markdig.Markdown.ToHtml(template.Markdown);
+ // var html = Markdig.Markdown.ToHtml(template.Markdown);
- foreach (KeyValuePair entry in assignment.template_variables)
- {
- html = html.Replace($"%7B%7B{entry.Key}%7D%7D", entry.Value);
- }
- return html;
- }
+ // foreach (KeyValuePair entry in assignment.template_variables)
+ // {
+ // html = html.Replace($"%7B%7B{entry.Key}%7D%7D", entry.Value);
+ // }
+ // return html;
+ // }
}
diff --git a/Management/Models/Local/LocalAssignment.cs b/Management/Models/Local/LocalAssignment.cs
index cd86d00..3606b3f 100644
--- a/Management/Models/Local/LocalAssignment.cs
+++ b/Management/Models/Local/LocalAssignment.cs
@@ -38,4 +38,41 @@ public record LocalAssignment
public DateTime due_at { get; init; }
public int points_possible { get; init; }
public IEnumerable submission_types { get; init; } = new SubmissionType[] { };
+
+ 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(IEnumerable? templates)
+ {
+ if (use_template && templates == null)
+ throw new Exception("cannot get description for assignment if templates not provided");
+
+ var rubricHtml = GetRubricHtml();
+
+ if (use_template)
+ {
+ var template = templates?.FirstOrDefault(t => t.Id == template_id);
+ if (template == null)
+ throw new Exception($"Could not find template with id {template_id}");
+
+ var html = Markdig.Markdown.ToHtml(template.Markdown);
+
+ foreach (KeyValuePair entry in template_variables)
+ {
+ html = html.Replace($"%7B%7B{entry.Key}%7D%7D", entry.Value);
+ }
+ return html + "
" + rubricHtml;
+ }
+
+ return Markdig.Markdown.ToHtml(description) + "
" + rubricHtml;
+ }
}
diff --git a/Management/Services/Canvas/CanvasAssignmentService.cs b/Management/Services/Canvas/CanvasAssignmentService.cs
index eaa914e..1b7a2d2 100644
--- a/Management/Services/Canvas/CanvasAssignmentService.cs
+++ b/Management/Services/Canvas/CanvasAssignmentService.cs
@@ -22,12 +22,7 @@ public class CanvasAssignmentService
return assignmentResponse.SelectMany(
assignments =>
assignments.Select(
- a =>
- a with
- {
- DueAt = a.DueAt?.ToLocalTime(),
- LockAt = a.LockAt?.ToLocalTime()
- }
+ a => a with { DueAt = a.DueAt?.ToLocalTime(), LockAt = a.LockAt?.ToLocalTime() }
)
);
}
@@ -85,5 +80,75 @@ public class CanvasAssignmentService
var bodyObj = new { assignment = body };
request.AddBody(bodyObj);
await webRequestor.PutAsync(request);
+
+ await CreateRubric(courseId, localAssignment);
+ }
+
+ public async Task CreateRubric(ulong courseId, LocalAssignment localAssignment)
+ {
+ if (localAssignment.canvasId == null)
+ throw new Exception("cannot create rubric if no canvas id in assignment");
+
+ var criterion = new Dictionary();
+
+ var i = 0;
+ foreach (var rubricItem in localAssignment.rubric)
+ {
+ var ratings = new Dictionary
+ {
+ { 0, new { description = "Full Marks", points = rubricItem.Points } },
+ { 1, new { description = "No Marks", points = 0 } },
+ };
+ criterion[i] = new
+ {
+ description = rubricItem.Label,
+ points = rubricItem.Points,
+ ratings = ratings
+ };
+ i++;
+ }
+
+ // https://canvas.instructure.com/doc/api/rubrics.html#method.rubrics.create
+ var body = new
+ {
+ rubric_association_id = localAssignment.canvasId,
+ rubric = new
+ {
+ title = $"Rubric for Assignment: {localAssignment.name}",
+ association_id = localAssignment.canvasId,
+ association_type = "Assignment",
+ use_for_grading = true,
+ criteria = criterion,
+ },
+ rubric_association = new
+ {
+ association_id = localAssignment.canvasId,
+ association_type = "Assignment",
+ purpose = "grading",
+ use_for_grading = true,
+ }
+ };
+ var creationUrl = $"courses/{courseId}/rubrics";
+ var rubricCreationRequest = new RestRequest(creationUrl);
+ rubricCreationRequest.AddBody(body);
+ rubricCreationRequest.AddHeader("Content-Type", "application/json");
+
+ var (rubricCreationResponse, creationResponse) =
+ await webRequestor.PostAsync(rubricCreationRequest);
+
+ if (rubricCreationResponse == null)
+ throw new Exception("failed to create rubric before association");
+
+ var assignmentPointCorrectionBody = new
+ {
+ assignment = new { points_possible = localAssignment.points_possible }
+ };
+ var adjustmentUrl = $"courses/{courseId}/assignments/{localAssignment.canvasId}";
+ var pointAdjustmentRequest = new RestRequest(adjustmentUrl);
+ pointAdjustmentRequest.AddBody(assignmentPointCorrectionBody);
+ pointAdjustmentRequest.AddHeader("Content-Type", "application/json");
+ var (updatedAssignment, adjustmentResponse) = await webRequestor.PutAsync(
+ pointAdjustmentRequest
+ );
}
}
diff --git a/Management/Services/Canvas/CanvasRequests/CanvasRubricCreationResponse.cs b/Management/Services/Canvas/CanvasRequests/CanvasRubricCreationResponse.cs
new file mode 100644
index 0000000..65cffa4
--- /dev/null
+++ b/Management/Services/Canvas/CanvasRequests/CanvasRubricCreationResponse.cs
@@ -0,0 +1,7 @@
+using CanvasModel.Assignments;
+
+public record CanvasRubricCreationResponse
+{
+ public required CanvasRubric rubric { get; set; }
+ public CanvasRubricAssociation? rubric_association { get; set; }
+}
diff --git a/Management/Services/Canvas/CanvasServiceUtils.cs b/Management/Services/Canvas/CanvasServiceUtils.cs
index 1a40e20..e3f7a72 100644
--- a/Management/Services/Canvas/CanvasServiceUtils.cs
+++ b/Management/Services/Canvas/CanvasServiceUtils.cs
@@ -1,10 +1,12 @@
using RestSharp;
namespace Management.Services.Canvas;
+
public class CanvasServiceUtils
{
private const string BaseUrl = "https://snow.instructure.com/api/v1/";
private readonly IWebRequestor webRequestor;
+
public CanvasServiceUtils(IWebRequestor webRequestor)
{
this.webRequestor = webRequestor;
@@ -36,7 +38,8 @@ public class CanvasServiceUtils
nextUrl = getNextUrl(nextResponse.Headers);
}
- System.Console.WriteLine($"Requesting {typeof(T)} took {requestCount} requests");
+ if (requestCount > 1)
+ System.Console.WriteLine($"Requesting {typeof(T)} took {requestCount} requests");
return returnData;
}
@@ -55,4 +58,4 @@ public class CanvasServiceUtils
.TrimStart('<')
.Replace(" ", "")
.Replace(BaseUrl, "");
-}
\ No newline at end of file
+}
diff --git a/README.md b/README.md
index d0da9ee..e747d46 100644
--- a/README.md
+++ b/README.md
@@ -15,4 +15,27 @@ Development command: `dotnet watch --project Management.Web/`
Apparently the VSCode razor extension was compiled with a preview of dotnet 6... and only uses openssl 1.1. After installing openssl1.1 you can tell vscode to provide it with `export CLR_OPENSSL_VERSION_OVERRIDE=1.1; code ~/projects/canvasManagement`.
-The issue can be tracked [here](https://github.com/dotnet/razor/issues/6241)
\ No newline at end of file
+The issue can be tracked [here](https://github.com/dotnet/razor/issues/6241)
+
+
+
+
+
+
+Daily Reading
+Read today's assignment and do well please.
+Github Submit URL
+
Rubric
[
+ {"label": "More Reading", "points": 5},
+ {"label": "sum to 8", "points": 1},
+ {"label": "(Extra Credit) Rubric Things", "points": 2}
+]
+
+Daily Reading
+Read today's assignment and do well please.
+Github Submit URL
+
Rubric
[
+ {"label": "More Reading", "points": 5},
+ {"label": "sum to 8", "points": 1},
+ {"label": "(Extra Credit) Rubric Things", "points": 2}
+]
\ No newline at end of file