mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-25 23:28:33 -06:00
got rubric creation working
This commit is contained in:
@@ -147,7 +147,7 @@
|
|||||||
&& planner.AssignmentNeedsUpdates(Assignment)
|
&& planner.AssignmentNeedsUpdates(Assignment)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
<div>need to update canvas</div>
|
<div>Need to update canvas</div>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -164,17 +164,9 @@
|
|||||||
<div class="col">
|
<div class="col">
|
||||||
@if(Assignment.use_template)
|
@if(Assignment.use_template)
|
||||||
{
|
{
|
||||||
var template = planner.LocalCourse?.AssignmentTemplates.First((t) => t.Id == Assignment.template_id);
|
var html = Assignment.GetDescriptionHtml(planner.LocalCourse?.AssignmentTemplates);
|
||||||
if(template == null)
|
|
||||||
{
|
|
||||||
System.Console.WriteLine($"Could not find template fof assignment, {Assignment.template_id}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var html = AssignmentTemplate.GetHtml(template, Assignment);
|
|
||||||
@((MarkupString) html)
|
@((MarkupString) html)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@Assignment.description
|
@Assignment.description
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ public class CoursePlanner
|
|||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Console.WriteLine("syncing with canvas");
|
||||||
LoadingCanvasData = true;
|
LoadingCanvasData = true;
|
||||||
StateHasChanged?.Invoke();
|
StateHasChanged?.Invoke();
|
||||||
|
|
||||||
@@ -111,10 +112,15 @@ public class CoursePlanner
|
|||||||
await ensureAllModulesCreated(canvasId);
|
await ensureAllModulesCreated(canvasId);
|
||||||
await reloadModules_UpdateLocalModulesWithNewId(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;
|
LoadingCanvasData = false;
|
||||||
StateHasChanged?.Invoke();
|
StateHasChanged?.Invoke();
|
||||||
|
Console.WriteLine("done syncing with canvas\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task reloadModules_UpdateLocalModulesWithNewId(ulong canvasId)
|
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 (
|
if (
|
||||||
LocalCourse == null
|
LocalCourse == null
|
||||||
@@ -160,7 +166,7 @@ public class CoursePlanner
|
|||||||
|
|
||||||
var moduleTasks = LocalCourse.Modules.Select(async m =>
|
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);
|
var assignments = await Task.WhenAll(assignmentTasks);
|
||||||
return m with { Assignments = assignments };
|
return m with { Assignments = assignments };
|
||||||
});
|
});
|
||||||
@@ -169,7 +175,7 @@ public class CoursePlanner
|
|||||||
LocalCourse = LocalCourse with { Modules = modules };
|
LocalCourse = LocalCourse with { Modules = modules };
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<LocalAssignment> ensureAssignmentInCanvas_returnUpdated(
|
private async Task<LocalAssignment> syncAssignmentToCanvas(
|
||||||
LocalAssignment localAssignment
|
LocalAssignment localAssignment
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -187,11 +193,13 @@ public class CoursePlanner
|
|||||||
var canvasAssignment = CanvasAssignments.FirstOrDefault(
|
var canvasAssignment = CanvasAssignments.FirstOrDefault(
|
||||||
ca => ca.Id == localAssignment.canvasId
|
ca => ca.Id == localAssignment.canvasId
|
||||||
);
|
);
|
||||||
string localHtmlDescription = getAssignmentDescriptionHtml(localAssignment);
|
string localHtmlDescription = localAssignment.GetDescriptionHtml(
|
||||||
|
LocalCourse.AssignmentTemplates
|
||||||
|
);
|
||||||
|
|
||||||
if (canvasAssignment != null)
|
if (canvasAssignment != null)
|
||||||
{
|
{
|
||||||
var assignmentNeedsUpdates = AssignmentNeedsUpdates(localAssignment);
|
var assignmentNeedsUpdates = AssignmentNeedsUpdates(localAssignment, quiet: false);
|
||||||
if (assignmentNeedsUpdates)
|
if (assignmentNeedsUpdates)
|
||||||
{
|
{
|
||||||
await canvas.Assignments.Update(courseId: canvasId, localAssignment, localHtmlDescription);
|
await canvas.Assignments.Update(courseId: canvasId, localAssignment, localHtmlDescription);
|
||||||
@@ -217,21 +225,7 @@ public class CoursePlanner
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getAssignmentDescriptionHtml(LocalAssignment localAssignment)
|
public bool AssignmentNeedsUpdates(LocalAssignment localAssignment, bool quiet = true)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
LocalCourse == null
|
LocalCourse == null
|
||||||
@@ -245,7 +239,7 @@ public class CoursePlanner
|
|||||||
|
|
||||||
var canvasAssignment = CanvasAssignments.First(ca => ca.Id == localAssignment.canvasId);
|
var canvasAssignment = CanvasAssignments.First(ca => ca.Id == localAssignment.canvasId);
|
||||||
|
|
||||||
var localHtmlDescription = getAssignmentDescriptionHtml(localAssignment);
|
var localHtmlDescription = localAssignment.GetDescriptionHtml(LocalCourse.AssignmentTemplates);
|
||||||
|
|
||||||
var canvasHtmlDescription = canvasAssignment.Description;
|
var canvasHtmlDescription = canvasAssignment.Description;
|
||||||
canvasHtmlDescription = Regex.Replace(canvasHtmlDescription, "<script.*script>", "");
|
canvasHtmlDescription = Regex.Replace(canvasHtmlDescription, "<script.*script>", "");
|
||||||
@@ -260,6 +254,8 @@ public class CoursePlanner
|
|||||||
localAssignment.submission_types.Select(t => t.ToString())
|
localAssignment.submission_types.Select(t => t.ToString())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
if (!dueDatesSame)
|
if (!dueDatesSame)
|
||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
$"Due dates different for {localAssignment.name}, local: {localAssignment.due_at}, in canvas {canvasAssignment.DueAt}"
|
$"Due dates different for {localAssignment.name}, local: {localAssignment.due_at}, in canvas {canvasAssignment.DueAt}"
|
||||||
@@ -290,6 +286,7 @@ public class CoursePlanner
|
|||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
$"Submission Types different for {localAssignment.name}, local: {JsonSerializer.Serialize(localAssignment.submission_types.Select(t => t.ToString()))}, in canvas {JsonSerializer.Serialize(canvasAssignment.SubmissionTypes)}"
|
$"Submission Types different for {localAssignment.name}, local: {JsonSerializer.Serialize(localAssignment.submission_types.Select(t => t.ToString()))}, in canvas {JsonSerializer.Serialize(canvasAssignment.SubmissionTypes)}"
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return !nameSame
|
return !nameSame
|
||||||
|| !dueDatesSame
|
|| !dueDatesSame
|
||||||
|
|||||||
37
Management/Models/CanvasModels/Assignments/CanvasRubric.cs
Normal file
37
Management/Models/CanvasModels/Assignments/CanvasRubric.cs
Normal file
@@ -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<CanvasRubricCriteria> Data { get; set; }
|
||||||
|
|
||||||
|
// assessments
|
||||||
|
// associations
|
||||||
|
}
|
||||||
@@ -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; }
|
||||||
|
|
||||||
|
}
|
||||||
@@ -15,16 +15,16 @@ public record AssignmentTemplate
|
|||||||
|
|
||||||
return matches.Select(match => match.Groups[1].Value);
|
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<string, string> entry in assignment.template_variables)
|
// foreach (KeyValuePair<string, string> entry in assignment.template_variables)
|
||||||
{
|
// {
|
||||||
html = html.Replace($"%7B%7B{entry.Key}%7D%7D", entry.Value);
|
// html = html.Replace($"%7B%7B{entry.Key}%7D%7D", entry.Value);
|
||||||
}
|
// }
|
||||||
return html;
|
// return html;
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,4 +38,41 @@ public record LocalAssignment
|
|||||||
public DateTime due_at { get; init; }
|
public DateTime due_at { get; init; }
|
||||||
public int points_possible { get; init; }
|
public int points_possible { get; init; }
|
||||||
public IEnumerable<SubmissionType> submission_types { get; init; } = new SubmissionType[] { };
|
public IEnumerable<SubmissionType> submission_types { get; init; } = new SubmissionType[] { };
|
||||||
|
|
||||||
|
public string GetRubricHtml()
|
||||||
|
{
|
||||||
|
var output = "<h1>Rubric</h1><pre><code class=\"language-json\">[\n";
|
||||||
|
|
||||||
|
var lineStrings = rubric.Select(
|
||||||
|
item => $" {{\"label\": \"{item.Label}\", \"points\": {item.Points}}}"
|
||||||
|
);
|
||||||
|
output += string.Join(",\n", lineStrings);
|
||||||
|
output += "\n]</code></pre>";
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetDescriptionHtml(IEnumerable<AssignmentTemplate>? 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<string, string> entry in template_variables)
|
||||||
|
{
|
||||||
|
html = html.Replace($"%7B%7B{entry.Key}%7D%7D", entry.Value);
|
||||||
|
}
|
||||||
|
return html + "<hr>" + rubricHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Markdig.Markdown.ToHtml(description) + "<hr>" + rubricHtml;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,12 +22,7 @@ public class CanvasAssignmentService
|
|||||||
return assignmentResponse.SelectMany(
|
return assignmentResponse.SelectMany(
|
||||||
assignments =>
|
assignments =>
|
||||||
assignments.Select(
|
assignments.Select(
|
||||||
a =>
|
a => a with { DueAt = a.DueAt?.ToLocalTime(), LockAt = a.LockAt?.ToLocalTime() }
|
||||||
a with
|
|
||||||
{
|
|
||||||
DueAt = a.DueAt?.ToLocalTime(),
|
|
||||||
LockAt = a.LockAt?.ToLocalTime()
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -85,5 +80,75 @@ public class CanvasAssignmentService
|
|||||||
var bodyObj = new { assignment = body };
|
var bodyObj = new { assignment = body };
|
||||||
request.AddBody(bodyObj);
|
request.AddBody(bodyObj);
|
||||||
await webRequestor.PutAsync(request);
|
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<int, object>();
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
foreach (var rubricItem in localAssignment.rubric)
|
||||||
|
{
|
||||||
|
var ratings = new Dictionary<int, object>
|
||||||
|
{
|
||||||
|
{ 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<CanvasRubricCreationResponse>(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<CanvasAssignment>(
|
||||||
|
pointAdjustmentRequest
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
using CanvasModel.Assignments;
|
||||||
|
|
||||||
|
public record CanvasRubricCreationResponse
|
||||||
|
{
|
||||||
|
public required CanvasRubric rubric { get; set; }
|
||||||
|
public CanvasRubricAssociation? rubric_association { get; set; }
|
||||||
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
using RestSharp;
|
using RestSharp;
|
||||||
|
|
||||||
namespace Management.Services.Canvas;
|
namespace Management.Services.Canvas;
|
||||||
|
|
||||||
public class CanvasServiceUtils
|
public class CanvasServiceUtils
|
||||||
{
|
{
|
||||||
private const string BaseUrl = "https://snow.instructure.com/api/v1/";
|
private const string BaseUrl = "https://snow.instructure.com/api/v1/";
|
||||||
private readonly IWebRequestor webRequestor;
|
private readonly IWebRequestor webRequestor;
|
||||||
|
|
||||||
public CanvasServiceUtils(IWebRequestor webRequestor)
|
public CanvasServiceUtils(IWebRequestor webRequestor)
|
||||||
{
|
{
|
||||||
this.webRequestor = webRequestor;
|
this.webRequestor = webRequestor;
|
||||||
@@ -36,6 +38,7 @@ public class CanvasServiceUtils
|
|||||||
nextUrl = getNextUrl(nextResponse.Headers);
|
nextUrl = getNextUrl(nextResponse.Headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (requestCount > 1)
|
||||||
System.Console.WriteLine($"Requesting {typeof(T)} took {requestCount} requests");
|
System.Console.WriteLine($"Requesting {typeof(T)} took {requestCount} requests");
|
||||||
|
|
||||||
return returnData;
|
return returnData;
|
||||||
|
|||||||
23
README.md
23
README.md
@@ -16,3 +16,26 @@ 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`.
|
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)
|
The issue can be tracked [here](https://github.com/dotnet/razor/issues/6241)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h1>Daily Reading</h1>
|
||||||
|
<p>Read today's assignment and do well please.</p>
|
||||||
|
<p><a href="https://alexmickelson.guru">Github Submit URL</a></p>
|
||||||
|
<hr><h1>Rubric</h1><pre><code class="language-json">[
|
||||||
|
{"label": "More Reading", "points": 5},
|
||||||
|
{"label": "sum to 8", "points": 1},
|
||||||
|
{"label": "(Extra Credit) Rubric Things", "points": 2}
|
||||||
|
]</code></pre>
|
||||||
|
|
||||||
|
<h1>Daily Reading</h1>
|
||||||
|
<p>Read today's assignment and do well please.</p>
|
||||||
|
<p><a href="https://alexmickelson.guru">Github Submit URL</a></p>
|
||||||
|
<hr /><h1>Rubric</h1><pre><code class="language-json">[
|
||||||
|
{"label": "More Reading", "points": 5},
|
||||||
|
{"label": "sum to 8", "points": 1},
|
||||||
|
{"label": "(Extra Credit) Rubric Things", "points": 2}
|
||||||
|
]</code></pre>
|
||||||
Reference in New Issue
Block a user