mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-26 23:58:31 -06:00
breaking up logic for canvas syncronization
This commit is contained in:
@@ -144,7 +144,10 @@
|
|||||||
&& planner.LocalCourse.CanvasId != null
|
&& planner.LocalCourse.CanvasId != null
|
||||||
&& planner.CanvasAssignments != null
|
&& planner.CanvasAssignments != null
|
||||||
&& planner.CanvasModules != null
|
&& planner.CanvasModules != null
|
||||||
&& planner.AssignmentNeedsUpdates(Assignment)
|
&& Assignment.NeedsUpdates(
|
||||||
|
planner.CanvasAssignments,
|
||||||
|
planner.LocalCourse.AssignmentTemplates
|
||||||
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
<div>Need to update canvas</div>
|
<div>Need to update canvas</div>
|
||||||
|
|||||||
@@ -97,14 +97,15 @@ public class CoursePlanner
|
|||||||
var canvasId =
|
var canvasId =
|
||||||
LocalCourse.CanvasId ?? throw new Exception("no course canvas id to sync with canvas");
|
LocalCourse.CanvasId ?? throw new Exception("no course canvas id to sync with canvas");
|
||||||
|
|
||||||
await ensureAllModulesExistInCanvas(canvasId);
|
await LocalCourse.EnsureAllModulesExistInCanvas(canvasId, CanvasModules, canvas);
|
||||||
CanvasModules = await canvas.GetModules(canvasId);
|
CanvasModules = await canvas.GetModules(canvasId);
|
||||||
await sortCanvasModules(canvasId);
|
|
||||||
|
await LocalCourse.SortCanvasModules(canvasId, CanvasModules, canvas);
|
||||||
CanvasModulesItems = await canvas.GetAllModulesItems(canvasId, CanvasModules);
|
CanvasModulesItems = await canvas.GetAllModulesItems(canvasId, CanvasModules);
|
||||||
|
|
||||||
await syncModulesWithCanvasData(canvasId);
|
LocalCourse = await LocalCourse.SyncModulesWithCanvasData(canvasId, CanvasModules, canvas);
|
||||||
|
|
||||||
await syncAssignmentsWithCanvas(canvasId);
|
await LocalCourse.SyncAssignmentsWithCanvas(canvasId, CanvasAssignments, canvas);
|
||||||
CanvasAssignments = await canvas.Assignments.GetAll(canvasId);
|
CanvasAssignments = await canvas.Assignments.GetAll(canvasId);
|
||||||
|
|
||||||
await syncModuleItemsWithCanvas(canvasId);
|
await syncModuleItemsWithCanvas(canvasId);
|
||||||
@@ -115,185 +116,6 @@ public class CoursePlanner
|
|||||||
Console.WriteLine("done syncing with canvas\n");
|
Console.WriteLine("done syncing with canvas\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task syncModulesWithCanvasData(ulong canvasId)
|
|
||||||
{
|
|
||||||
if (LocalCourse == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CanvasModules = await canvas.GetModules(canvasId);
|
|
||||||
LocalCourse = LocalCourse with
|
|
||||||
{
|
|
||||||
Modules = LocalCourse.Modules.Select(m =>
|
|
||||||
{
|
|
||||||
var canvasModule = CanvasModules.FirstOrDefault(cm => cm.Name == m.Name);
|
|
||||||
return canvasModule == null ? m : m with { CanvasId = canvasModule.Id };
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ensureAllModulesExistInCanvas(ulong canvasId)
|
|
||||||
{
|
|
||||||
if (LocalCourse == null || CanvasModules == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var module in LocalCourse.Modules)
|
|
||||||
{
|
|
||||||
var canvasModule = CanvasModules.FirstOrDefault(cm => cm.Id == module.CanvasId);
|
|
||||||
if (canvasModule == null)
|
|
||||||
{
|
|
||||||
await canvas.CreateModule(canvasId, module.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task sortCanvasModules(ulong canvasId)
|
|
||||||
{
|
|
||||||
if (LocalCourse == null)
|
|
||||||
throw new Exception("cannot sort modules, no course selected");
|
|
||||||
if (CanvasModules == null)
|
|
||||||
throw new Exception("cannot sort modules, no canvas modules loaded");
|
|
||||||
|
|
||||||
var currentCanvasPositions = CanvasModules.ToDictionary(m => m.Id, m => m.Position);
|
|
||||||
foreach (var (localModule, i) in LocalCourse.Modules.Select((m, i) => (m, i)))
|
|
||||||
{
|
|
||||||
var correctPosition = i + 1;
|
|
||||||
var moduleCanvasId =
|
|
||||||
localModule.CanvasId ?? throw new Exception("cannot sort module if no module canvas id");
|
|
||||||
var currentCanvasPosition = currentCanvasPositions[moduleCanvasId];
|
|
||||||
if (currentCanvasPosition != correctPosition)
|
|
||||||
{
|
|
||||||
await canvas.UpdateModule(canvasId, moduleCanvasId, localModule.Name, correctPosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task syncAssignmentsWithCanvas(ulong canvasId)
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
LocalCourse == null
|
|
||||||
|| LocalCourse.CanvasId == null
|
|
||||||
|| CanvasAssignments == null
|
|
||||||
|| CanvasModules == null
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var moduleTasks = LocalCourse.Modules.Select(async m =>
|
|
||||||
{
|
|
||||||
var assignmentTasks = m.Assignments.Select(syncAssignmentToCanvas);
|
|
||||||
var assignments = await Task.WhenAll(assignmentTasks);
|
|
||||||
return m with { Assignments = assignments };
|
|
||||||
});
|
|
||||||
|
|
||||||
var modules = await Task.WhenAll(moduleTasks);
|
|
||||||
LocalCourse = LocalCourse with { Modules = modules };
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<LocalAssignment> syncAssignmentToCanvas(LocalAssignment localAssignment)
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
LocalCourse == null
|
|
||||||
|| LocalCourse.CanvasId == null
|
|
||||||
|| CanvasAssignments == null
|
|
||||||
|| CanvasModules == null
|
|
||||||
)
|
|
||||||
throw new Exception(
|
|
||||||
"cannot create canvas assignment if local course is null or other values not set"
|
|
||||||
);
|
|
||||||
|
|
||||||
ulong canvasId = LocalCourse.CanvasId ?? throw new Exception("no canvas id to create course");
|
|
||||||
var canvasAssignment = CanvasAssignments.FirstOrDefault(
|
|
||||||
ca => ca.Id == localAssignment.canvasId
|
|
||||||
);
|
|
||||||
string localHtmlDescription = localAssignment.GetDescriptionHtml(
|
|
||||||
LocalCourse.AssignmentTemplates
|
|
||||||
);
|
|
||||||
|
|
||||||
if (canvasAssignment != null)
|
|
||||||
{
|
|
||||||
var assignmentNeedsUpdates = AssignmentNeedsUpdates(localAssignment, quiet: false);
|
|
||||||
if (assignmentNeedsUpdates)
|
|
||||||
{
|
|
||||||
await canvas.Assignments.Update(courseId: canvasId, localAssignment, localHtmlDescription);
|
|
||||||
}
|
|
||||||
return localAssignment;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return await canvas.Assignments.Create(canvasId, localAssignment, localHtmlDescription);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AssignmentNeedsUpdates(LocalAssignment localAssignment, bool quiet = true)
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
LocalCourse == null
|
|
||||||
|| LocalCourse.CanvasId == null
|
|
||||||
|| CanvasAssignments == null
|
|
||||||
|| CanvasModules == null
|
|
||||||
)
|
|
||||||
throw new Exception(
|
|
||||||
"cannot check if assignment needs updates if local course is null or other values not set"
|
|
||||||
);
|
|
||||||
|
|
||||||
var canvasAssignment = CanvasAssignments.First(ca => ca.Id == localAssignment.canvasId);
|
|
||||||
|
|
||||||
var localHtmlDescription = localAssignment.GetDescriptionHtml(LocalCourse.AssignmentTemplates);
|
|
||||||
|
|
||||||
var canvasHtmlDescription = canvasAssignment.Description;
|
|
||||||
canvasHtmlDescription = Regex.Replace(canvasHtmlDescription, "<script.*script>", "");
|
|
||||||
canvasHtmlDescription = Regex.Replace(canvasHtmlDescription, "<link .*\">", "");
|
|
||||||
|
|
||||||
var dueDatesSame = canvasAssignment.DueAt == localAssignment.due_at;
|
|
||||||
var descriptionSame = canvasHtmlDescription == localHtmlDescription;
|
|
||||||
var nameSame = canvasAssignment.Name == localAssignment.name;
|
|
||||||
var lockDateSame = canvasAssignment.LockAt == localAssignment.lock_at;
|
|
||||||
var pointsSame = canvasAssignment.PointsPossible == localAssignment.points_possible;
|
|
||||||
var submissionTypesSame = canvasAssignment.SubmissionTypes.SequenceEqual(
|
|
||||||
localAssignment.submission_types.Select(t => t.ToString())
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!quiet)
|
|
||||||
{
|
|
||||||
if (!dueDatesSame)
|
|
||||||
Console.WriteLine(
|
|
||||||
$"Due dates different for {localAssignment.name}, local: {localAssignment.due_at}, in canvas {canvasAssignment.DueAt}"
|
|
||||||
);
|
|
||||||
|
|
||||||
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
|
|
||||||
|| !lockDateSame
|
|
||||||
|| !descriptionSame
|
|
||||||
|| !pointsSame
|
|
||||||
|| !submissionTypesSame;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task syncModuleItemsWithCanvas(ulong canvasId)
|
private async Task syncModuleItemsWithCanvas(ulong canvasId)
|
||||||
{
|
{
|
||||||
if (LocalCourse == null)
|
if (LocalCourse == null)
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using CanvasModel.Assignments;
|
||||||
|
using CanvasModel.Modules;
|
||||||
|
using LocalModels;
|
||||||
|
using Management.Services.Canvas;
|
||||||
|
|
||||||
|
namespace Management.Planner;
|
||||||
|
|
||||||
|
public static class CoursePlannerSyncronizationExtensions
|
||||||
|
{
|
||||||
|
internal static async Task EnsureAllModulesExistInCanvas(
|
||||||
|
this LocalCourse localCourse,
|
||||||
|
ulong canvasId,
|
||||||
|
IEnumerable<CanvasModule> canvasModules,
|
||||||
|
CanvasService canvas
|
||||||
|
)
|
||||||
|
{
|
||||||
|
foreach (var module in localCourse.Modules)
|
||||||
|
{
|
||||||
|
var canvasModule = canvasModules.FirstOrDefault(cm => cm.Id == module.CanvasId);
|
||||||
|
if (canvasModule == null)
|
||||||
|
{
|
||||||
|
await canvas.CreateModule(canvasId, module.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static async Task SortCanvasModules(
|
||||||
|
this LocalCourse localCourse,
|
||||||
|
ulong canvasId,
|
||||||
|
IEnumerable<CanvasModule> canvasModules,
|
||||||
|
CanvasService canvas
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var currentCanvasPositions = canvasModules.ToDictionary(m => m.Id, m => m.Position);
|
||||||
|
foreach (var (localModule, i) in localCourse.Modules.Select((m, i) => (m, i)))
|
||||||
|
{
|
||||||
|
var correctPosition = i + 1;
|
||||||
|
var moduleCanvasId =
|
||||||
|
localModule.CanvasId ?? throw new Exception("cannot sort module if no module canvas id");
|
||||||
|
var currentCanvasPosition = currentCanvasPositions[moduleCanvasId];
|
||||||
|
if (currentCanvasPosition != correctPosition)
|
||||||
|
{
|
||||||
|
await canvas.UpdateModule(canvasId, moduleCanvasId, localModule.Name, correctPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static async Task<LocalCourse> SyncModulesWithCanvasData(
|
||||||
|
this LocalCourse localCourse,
|
||||||
|
ulong canvasId,
|
||||||
|
IEnumerable<CanvasModule> canvasModules,
|
||||||
|
CanvasService canvas
|
||||||
|
)
|
||||||
|
{
|
||||||
|
canvasModules = await canvas.GetModules(canvasId);
|
||||||
|
return localCourse with
|
||||||
|
{
|
||||||
|
Modules = localCourse.Modules.Select(m =>
|
||||||
|
{
|
||||||
|
var canvasModule = canvasModules.FirstOrDefault(cm => cm.Name == m.Name);
|
||||||
|
return canvasModule == null ? m : m with { CanvasId = canvasModule.Id };
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static async Task<LocalAssignment> SyncToCanvas(
|
||||||
|
this LocalCourse localCourse,
|
||||||
|
ulong canvasId,
|
||||||
|
LocalAssignment localAssignment,
|
||||||
|
IEnumerable<CanvasAssignment> canvasAssignments,
|
||||||
|
CanvasService canvas
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var canvasAssignment = canvasAssignments.FirstOrDefault(
|
||||||
|
ca => ca.Id == localAssignment.canvasId
|
||||||
|
);
|
||||||
|
string localHtmlDescription = localAssignment.GetDescriptionHtml(
|
||||||
|
localCourse.AssignmentTemplates
|
||||||
|
);
|
||||||
|
|
||||||
|
if (canvasAssignment != null)
|
||||||
|
{
|
||||||
|
var assignmentNeedsUpdates = localAssignment.NeedsUpdates(
|
||||||
|
canvasAssignments,
|
||||||
|
localCourse.AssignmentTemplates,
|
||||||
|
quiet: false
|
||||||
|
);
|
||||||
|
if (assignmentNeedsUpdates)
|
||||||
|
{
|
||||||
|
await canvas.Assignments.Update(courseId: canvasId, localAssignment, localHtmlDescription);
|
||||||
|
}
|
||||||
|
return localAssignment;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return await canvas.Assignments.Create(canvasId, localAssignment, localHtmlDescription);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool NeedsUpdates(
|
||||||
|
this LocalAssignment localAssignment,
|
||||||
|
IEnumerable<CanvasAssignment> canvasAssignments,
|
||||||
|
IEnumerable<AssignmentTemplate> courseAssignmentTemplates,
|
||||||
|
bool quiet = true
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var canvasAssignment = canvasAssignments.First(ca => ca.Id == localAssignment.canvasId);
|
||||||
|
|
||||||
|
var localHtmlDescription = localAssignment.GetDescriptionHtml(courseAssignmentTemplates);
|
||||||
|
|
||||||
|
var canvasHtmlDescription = canvasAssignment.Description;
|
||||||
|
canvasHtmlDescription = Regex.Replace(canvasHtmlDescription, "<script.*script>", "");
|
||||||
|
canvasHtmlDescription = Regex.Replace(canvasHtmlDescription, "<link .*\">", "");
|
||||||
|
|
||||||
|
var dueDatesSame = canvasAssignment.DueAt == localAssignment.due_at;
|
||||||
|
var descriptionSame = canvasHtmlDescription == localHtmlDescription;
|
||||||
|
var nameSame = canvasAssignment.Name == localAssignment.name;
|
||||||
|
var lockDateSame = canvasAssignment.LockAt == localAssignment.lock_at;
|
||||||
|
var pointsSame = canvasAssignment.PointsPossible == localAssignment.points_possible;
|
||||||
|
var submissionTypesSame = canvasAssignment.SubmissionTypes.SequenceEqual(
|
||||||
|
localAssignment.submission_types.Select(t => t.ToString())
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
|
if (!dueDatesSame)
|
||||||
|
Console.WriteLine(
|
||||||
|
$"Due dates different for {localAssignment.name}, local: {localAssignment.due_at}, in canvas {canvasAssignment.DueAt}"
|
||||||
|
);
|
||||||
|
|
||||||
|
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
|
||||||
|
|| !lockDateSame
|
||||||
|
|| !descriptionSame
|
||||||
|
|| !pointsSame
|
||||||
|
|| !submissionTypesSame;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static async Task<LocalCourse> SyncAssignmentsWithCanvas(
|
||||||
|
this LocalCourse localCourse,
|
||||||
|
ulong canvasId,
|
||||||
|
IEnumerable<CanvasAssignment> canvasAssignments,
|
||||||
|
CanvasService canvas
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var moduleTasks = localCourse.Modules.Select(async m =>
|
||||||
|
{
|
||||||
|
var assignmentTasks = m.Assignments.Select(
|
||||||
|
(a) => localCourse.SyncToCanvas(canvasId, a, canvasAssignments, canvas)
|
||||||
|
);
|
||||||
|
var assignments = await Task.WhenAll(assignmentTasks);
|
||||||
|
return m with { Assignments = assignments };
|
||||||
|
});
|
||||||
|
|
||||||
|
var modules = await Task.WhenAll(moduleTasks);
|
||||||
|
return localCourse with { Modules = modules };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -89,17 +89,17 @@ public class WebRequestor : IWebRequestor
|
|||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
catch (System.NotSupportedException exception)
|
catch (System.NotSupportedException )
|
||||||
{
|
{
|
||||||
Console.WriteLine(response.Content);
|
Console.WriteLine(response.Content);
|
||||||
throw exception;
|
throw;
|
||||||
}
|
}
|
||||||
catch (JsonException ex)
|
catch (JsonException)
|
||||||
{
|
{
|
||||||
System.Console.WriteLine(response.ResponseUri);
|
System.Console.WriteLine(response.ResponseUri);
|
||||||
System.Console.WriteLine(response.Content);
|
System.Console.WriteLine(response.Content);
|
||||||
Console.WriteLine($"An error occurred during deserialization: {ex.Message}");
|
Console.WriteLine($"An error occurred during deserialization");
|
||||||
throw ex;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user