mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-25 15:18:32 -06:00
i liked syncing more before i cared about order
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,4 +3,5 @@ bin/
|
||||
.env
|
||||
*.env
|
||||
storage/
|
||||
tmp.json
|
||||
tmp.json
|
||||
tmp*.json
|
||||
@@ -95,6 +95,13 @@
|
||||
>
|
||||
Sync With Canvas
|
||||
</button>
|
||||
<a
|
||||
class="btn btn-outline-secondary"
|
||||
target="_blank"
|
||||
href="@($"{Environment.GetEnvironmentVariable("CANVAS_URL")}/courses/{planner.LocalCourse.CanvasId}")"
|
||||
>
|
||||
View In Canvas
|
||||
</a>
|
||||
|
||||
@if(planner.LoadingCanvasData)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ global using CanvasModel.EnrollmentTerms;
|
||||
global using CanvasModel.Courses;
|
||||
global using CanvasModel;
|
||||
global using LocalModels;
|
||||
global using Management.Planner;
|
||||
global using Management.Web.Shared.Components;
|
||||
global using Management.Web.Shared.Course;
|
||||
|
||||
@@ -17,6 +18,16 @@ DotEnv.Load();
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
var canvas_token = Environment.GetEnvironmentVariable("CANVAS_TOKEN");
|
||||
if (canvas_token == null)
|
||||
throw new Exception("CANVAS_TOKEN is null");
|
||||
var canvas_url = Environment.GetEnvironmentVariable("CANVAS_URL");
|
||||
if (canvas_url == null)
|
||||
{
|
||||
Console.WriteLine("CANVAS_URL is null, defaulting to https://snow.instructure.com");
|
||||
Environment.SetEnvironmentVariable("CANVAS_URL", "https://snow.instructure.com");
|
||||
}
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorPages();
|
||||
builder.Services.AddServerSideBlazor();
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
|
||||
@if (localCourses != null)
|
||||
{
|
||||
<h3 >Stored Courses</h3>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
private string name { get; set; } = String.Empty;
|
||||
private bool lockAtDueDate { get; set; }
|
||||
private IEnumerable<RubricItem> rubric { get; set; } = Enumerable.Empty<RubricItem>();
|
||||
private IEnumerable<SubmissionType> submissionTypes { get; set; } = Enumerable.Empty<SubmissionType>();
|
||||
private IEnumerable<string> submissionTypes { get; set; } = Enumerable.Empty<string>();
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
@using System.Reflection
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter, EditorRequired]
|
||||
public IEnumerable<SubmissionType> Types { get; set; } = Enumerable.Empty<SubmissionType>();
|
||||
public IEnumerable<string> Types { get; set; } = Enumerable.Empty<string>();
|
||||
|
||||
[Parameter, EditorRequired]
|
||||
public Action<IEnumerable<SubmissionType>> SetTypes { get; set; } = (_) => {};
|
||||
private string getLabel(SubmissionType type)
|
||||
public Action<IEnumerable<string>> SetTypes { get; set; } = (_) => {};
|
||||
private string getLabel(string type)
|
||||
{
|
||||
return type.ToString().Replace("_", "") + "switch";
|
||||
}
|
||||
@@ -14,7 +16,7 @@
|
||||
<h5>Submission Types</h5>
|
||||
<div class="row">
|
||||
|
||||
@foreach (var submissionType in (SubmissionType[])Enum.GetValues(typeof(SubmissionType)))
|
||||
@foreach (var submissionType in SubmissionType.AllTypes)
|
||||
{
|
||||
<div class="col-4">
|
||||
<div class="form-check form-switch">
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
lock_at = null,
|
||||
due_at = DateTime.Now,
|
||||
points_possible = 10,
|
||||
submission_types = new SubmissionType[] { SubmissionType.online_text_entry }
|
||||
submission_types = new string[] { SubmissionType.online_text_entry }
|
||||
};
|
||||
|
||||
if(planner.LocalCourse != null)
|
||||
|
||||
@@ -6,6 +6,18 @@
|
||||
[Parameter]
|
||||
[EditorRequired]
|
||||
public LocalAssignment Assignment { get; set; } = new();
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
planner.StateHasChanged += reload;
|
||||
}
|
||||
private void reload()
|
||||
{
|
||||
this.InvokeAsync(this.StateHasChanged);
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
planner.StateHasChanged -= reload;
|
||||
}
|
||||
|
||||
private void dropOnDate(DateTime dropDate)
|
||||
{
|
||||
|
||||
@@ -7,6 +7,8 @@ using CanvasModel.Modules;
|
||||
using Management.Services.Canvas;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Management.Planner;
|
||||
|
||||
public class CoursePlanner
|
||||
{
|
||||
private readonly YamlManager yamlManager;
|
||||
@@ -32,7 +34,8 @@ public class CoursePlanner
|
||||
return;
|
||||
}
|
||||
|
||||
var verifiedCourse = cleanupCourse(value);
|
||||
var verifiedCourse = value.GeneralCourseCleanup();
|
||||
|
||||
// ignore initial load of course
|
||||
if (_localCourse != null)
|
||||
{
|
||||
@@ -44,53 +47,34 @@ public class CoursePlanner
|
||||
}
|
||||
public event Action? StateHasChanged;
|
||||
|
||||
private LocalCourse cleanupCourse(LocalCourse incomingCourse)
|
||||
{
|
||||
var modulesWithUniqueAssignments = incomingCourse.Modules.Select(
|
||||
module => module with { Assignments = module.Assignments.DistinctBy(a => a.id) }
|
||||
);
|
||||
public IEnumerable<CanvasAssignment>? CanvasAssignments { get; internal set; }
|
||||
public IEnumerable<CanvasModule>? CanvasModules { get; internal set; }
|
||||
public Dictionary<ulong, IEnumerable<CanvasModuleItem>>? CanvasModulesItems { get; internal set; }
|
||||
|
||||
return incomingCourse with
|
||||
{
|
||||
Modules = modulesWithUniqueAssignments
|
||||
};
|
||||
}
|
||||
|
||||
private IEnumerable<CanvasAssignment>? canvasAssignments = null;
|
||||
|
||||
public IEnumerable<CanvasAssignment>? CanvasAssignments
|
||||
{
|
||||
get => canvasAssignments;
|
||||
set
|
||||
{
|
||||
canvasAssignments = value;
|
||||
StateHasChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
private IEnumerable<CanvasModule>? canvasModules = null;
|
||||
public IEnumerable<CanvasModule>? CanvasModules
|
||||
{
|
||||
get => canvasModules;
|
||||
set
|
||||
{
|
||||
canvasModules = value;
|
||||
StateHasChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task LoadCanvasData()
|
||||
public async Task<(
|
||||
IEnumerable<CanvasAssignment> CanvasAssignments,
|
||||
IEnumerable<CanvasModule> CanvasModules,
|
||||
Dictionary<ulong, IEnumerable<CanvasModuleItem>> CanvasModulesItems
|
||||
)> LoadCanvasData()
|
||||
{
|
||||
LoadingCanvasData = true;
|
||||
StateHasChanged?.Invoke();
|
||||
|
||||
Thread.Sleep(1000);
|
||||
var canvasId =
|
||||
LocalCourse?.CanvasId ?? throw new Exception("no canvas id found for selected course");
|
||||
CanvasAssignments = await canvas.Assignments.GetAll(canvasId);
|
||||
CanvasModules = await canvas.GetModules(canvasId);
|
||||
|
||||
var assignmentsTask = canvas.Assignments.GetAll(canvasId);
|
||||
var modulesTask = canvas.GetModules(canvasId);
|
||||
|
||||
CanvasAssignments = await assignmentsTask;
|
||||
CanvasModules = await modulesTask;
|
||||
|
||||
CanvasModulesItems = await canvas.GetAllModulesItems(canvasId, CanvasModules);
|
||||
// Console.WriteLine(JsonSerializer.Serialize(CanvasModulesItems));
|
||||
|
||||
LoadingCanvasData = false;
|
||||
StateHasChanged?.Invoke();
|
||||
return (CanvasAssignments, CanvasModules, CanvasModulesItems);
|
||||
}
|
||||
|
||||
public async Task SyncWithCanvas()
|
||||
@@ -107,22 +91,31 @@ public class CoursePlanner
|
||||
LoadingCanvasData = true;
|
||||
StateHasChanged?.Invoke();
|
||||
|
||||
var (canvasAssignments, canvasModules, canvasModuleItems) = await LoadCanvasData();
|
||||
LocalCourse = LocalCourse.deleteCanvasIdsThatNoLongerExist(canvasModules, canvasAssignments);
|
||||
|
||||
var canvasId =
|
||||
LocalCourse.CanvasId ?? throw new Exception("no course canvas id to sync with canvas");
|
||||
await ensureAllModulesCreated(canvasId);
|
||||
await reloadModules_UpdateLocalModulesWithNewId(canvasId);
|
||||
|
||||
await ensureAllModulesExistInCanvas(canvasId);
|
||||
CanvasModules = await canvas.GetModules(canvasId);
|
||||
await sortCanvasModules(canvasId);
|
||||
CanvasModulesItems = await canvas.GetAllModulesItems(canvasId, CanvasModules);
|
||||
|
||||
await syncModulesWithCanvasData(canvasId);
|
||||
|
||||
await syncAssignmentsWithCanvas(canvasId);
|
||||
|
||||
CanvasAssignments = await canvas.Assignments.GetAll(canvasId);
|
||||
CanvasModules = await canvas.GetModules(canvasId);
|
||||
|
||||
await syncModuleItemsWithCanvas(canvasId);
|
||||
CanvasModulesItems = await canvas.GetAllModulesItems(canvasId, CanvasModules);
|
||||
|
||||
LoadingCanvasData = false;
|
||||
StateHasChanged?.Invoke();
|
||||
Console.WriteLine("done syncing with canvas\n");
|
||||
}
|
||||
|
||||
private async Task reloadModules_UpdateLocalModulesWithNewId(ulong canvasId)
|
||||
private async Task syncModulesWithCanvasData(ulong canvasId)
|
||||
{
|
||||
if (LocalCourse == null)
|
||||
return;
|
||||
@@ -138,7 +131,7 @@ public class CoursePlanner
|
||||
};
|
||||
}
|
||||
|
||||
private async Task ensureAllModulesCreated(ulong canvasId)
|
||||
private async Task ensureAllModulesExistInCanvas(ulong canvasId)
|
||||
{
|
||||
if (LocalCourse == null || CanvasModules == null)
|
||||
return;
|
||||
@@ -153,6 +146,27 @@ public class CoursePlanner
|
||||
}
|
||||
}
|
||||
|
||||
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 (
|
||||
@@ -205,11 +219,7 @@ public class CoursePlanner
|
||||
}
|
||||
else
|
||||
{
|
||||
return await canvas.Assignments.Create(
|
||||
canvasId,
|
||||
localAssignment,
|
||||
localHtmlDescription
|
||||
);
|
||||
return await canvas.Assignments.Create(canvasId, localAssignment, localHtmlDescription);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,6 +294,94 @@ public class CoursePlanner
|
||||
|| !submissionTypesSame;
|
||||
}
|
||||
|
||||
private async Task syncModuleItemsWithCanvas(ulong canvasId)
|
||||
{
|
||||
if (LocalCourse == null)
|
||||
throw new Exception("cannot sync modules without localcourse selected");
|
||||
if (CanvasModulesItems == null)
|
||||
throw new Exception("cannot sync modules with canvas if they are not loaded in the variable");
|
||||
|
||||
foreach (var localModule in LocalCourse.Modules)
|
||||
{
|
||||
var moduleCanvasId =
|
||||
localModule.CanvasId
|
||||
?? throw new Exception("cannot sync canvas modules items if module not synced with canvas");
|
||||
|
||||
bool anyUpdated = await ensureAllItemsCreated(canvasId, localModule, moduleCanvasId);
|
||||
|
||||
var canvasModuleItems = anyUpdated
|
||||
? await canvas.GetModuleItems(canvasId, moduleCanvasId)
|
||||
: CanvasModulesItems[moduleCanvasId];
|
||||
|
||||
await sortModuleItems(canvasId, localModule, moduleCanvasId, canvasModuleItems);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task sortModuleItems(
|
||||
ulong canvasId,
|
||||
LocalModule localModule,
|
||||
ulong moduleCanvasId,
|
||||
IEnumerable<CanvasModuleItem> canvasModuleItems
|
||||
)
|
||||
{
|
||||
var localItemsWithCorrectOrder = localModule.Assignments
|
||||
.OrderBy(a => a.due_at)
|
||||
.Select((a, i) => (Assignment: a, Position: i + 1));
|
||||
|
||||
var canvasContentIdsByCurrentPosition =
|
||||
canvasModuleItems.ToDictionary(item => item.Position, item => item.ContentId)
|
||||
?? new Dictionary<int, ulong?>();
|
||||
|
||||
foreach (var (localAssignment, position) in localItemsWithCorrectOrder)
|
||||
{
|
||||
var itemIsInCorrectOrder =
|
||||
canvasContentIdsByCurrentPosition.ContainsKey(position)
|
||||
&& canvasContentIdsByCurrentPosition[position] == localAssignment.canvasId;
|
||||
|
||||
var currentCanvasItem = canvasModuleItems.First(i => i.ContentId == localAssignment.canvasId);
|
||||
if (!itemIsInCorrectOrder)
|
||||
{
|
||||
await canvas.UpdateModuleItem(
|
||||
canvasId,
|
||||
moduleCanvasId,
|
||||
currentCanvasItem with
|
||||
{
|
||||
Position = position
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> ensureAllItemsCreated(
|
||||
ulong canvasId,
|
||||
LocalModule localModule,
|
||||
ulong moduleCanvasId
|
||||
)
|
||||
{
|
||||
var anyUpdated = false;
|
||||
foreach (var localAssignment in localModule.Assignments)
|
||||
{
|
||||
var canvasModuleItemContentIds = CanvasModulesItems[moduleCanvasId].Select(i => i.ContentId);
|
||||
if (!canvasModuleItemContentIds.Contains(localAssignment.canvasId))
|
||||
{
|
||||
var canvasAssignmentId =
|
||||
localAssignment.canvasId
|
||||
?? throw new Exception("cannot create module item if assignment does not have canvas id");
|
||||
await canvas.CreateModuleItem(
|
||||
canvasId,
|
||||
moduleCanvasId,
|
||||
localAssignment.name,
|
||||
"Assignment",
|
||||
canvasAssignmentId
|
||||
);
|
||||
anyUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
return anyUpdated;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
LocalCourse = null;
|
||||
|
||||
83
Management/Features/Configuration/CoursePlannerExtensions.cs
Normal file
83
Management/Features/Configuration/CoursePlannerExtensions.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using CanvasModel.Assignments;
|
||||
using CanvasModel.Modules;
|
||||
using LocalModels;
|
||||
|
||||
namespace Management.Planner;
|
||||
|
||||
public static class CoursePlannerExtensions
|
||||
{
|
||||
public static LocalCourse GeneralCourseCleanup(this LocalCourse incomingCourse)
|
||||
{
|
||||
var modulesWithUniqueAssignments = incomingCourse.Modules.Select(
|
||||
module =>
|
||||
module with
|
||||
{
|
||||
Assignments = module.Assignments.OrderBy(a => a.due_at).DistinctBy(a => a.id)
|
||||
}
|
||||
);
|
||||
|
||||
return incomingCourse with
|
||||
{
|
||||
Modules = modulesWithUniqueAssignments
|
||||
};
|
||||
}
|
||||
|
||||
public static LocalCourse deleteCanvasIdsThatNoLongerExist(
|
||||
this LocalCourse localCourse,
|
||||
IEnumerable<CanvasModule> canvasModules,
|
||||
IEnumerable<CanvasAssignment> canvasAssignments
|
||||
)
|
||||
{
|
||||
Console.WriteLine("checking canvas ids still exist");
|
||||
|
||||
var correctedModules = localCourse.Modules
|
||||
.Select((m) => m.validateCanvasIds(canvasModules, canvasAssignments))
|
||||
.ToArray();
|
||||
|
||||
return localCourse with
|
||||
{
|
||||
Modules = correctedModules
|
||||
};
|
||||
}
|
||||
|
||||
private static LocalModule validateCanvasIds(
|
||||
this LocalModule module,
|
||||
IEnumerable<CanvasModule> canvasModules,
|
||||
IEnumerable<CanvasAssignment> canvasAssignments
|
||||
)
|
||||
{
|
||||
var moduleIdInCanvas = canvasModules.FirstOrDefault(m => m.Id == module.CanvasId) != null;
|
||||
var moduleWithAssignments = module with
|
||||
{
|
||||
Assignments = module.Assignments
|
||||
.Select((a) => a.validateAssignmentForCanvasId(canvasAssignments))
|
||||
.ToArray()
|
||||
};
|
||||
|
||||
if (!moduleIdInCanvas)
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"no id in canvas for module, removing old canvas id: {moduleWithAssignments.Name}"
|
||||
);
|
||||
return moduleWithAssignments with { CanvasId = null };
|
||||
}
|
||||
return moduleWithAssignments;
|
||||
}
|
||||
|
||||
private static LocalAssignment validateAssignmentForCanvasId(
|
||||
this LocalAssignment assignment,
|
||||
IEnumerable<CanvasAssignment> canvasAssignments
|
||||
)
|
||||
{
|
||||
var assignmentIdInCanvas =
|
||||
canvasAssignments.FirstOrDefault(ca => ca.Id == assignment.canvasId) != null;
|
||||
if (!assignmentIdInCanvas)
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"no id in canvas for assignment, removing old canvas id: {assignment.name}"
|
||||
);
|
||||
return assignment with { canvasId = null };
|
||||
}
|
||||
return assignment;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ namespace CanvasModel.Modules;
|
||||
public record CanvasModuleItem(
|
||||
[property: JsonPropertyName("id")] ulong Id,
|
||||
[property: JsonPropertyName("module_id")] ulong ModuleId,
|
||||
[property: JsonPropertyName("position")] uint Position,
|
||||
[property: JsonPropertyName("position")] int Position,
|
||||
[property: JsonPropertyName("title")] string Title,
|
||||
[property: JsonPropertyName("indent")] uint? Indent,
|
||||
[property: JsonPropertyName("type")] string Type,
|
||||
@@ -17,4 +17,4 @@ public record CanvasModuleItem(
|
||||
[property: JsonPropertyName("completion_requirement")]
|
||||
CanvasCompletionRequirement? CompletionRequirement,
|
||||
[property: JsonPropertyName("published")] bool? Published
|
||||
);
|
||||
);
|
||||
@@ -8,24 +8,37 @@ public record RubricItem
|
||||
public int Points { get; set; } = 0;
|
||||
}
|
||||
|
||||
public enum SubmissionType
|
||||
public static class SubmissionType
|
||||
{
|
||||
online_text_entry,
|
||||
online_upload,
|
||||
online_quiz,
|
||||
on_paper,
|
||||
discussion_topic,
|
||||
external_tool,
|
||||
online_url,
|
||||
media_recording,
|
||||
student_annotation,
|
||||
none,
|
||||
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<string> AllTypes = new string[]
|
||||
{
|
||||
SubmissionType.online_text_entry,
|
||||
SubmissionType.online_upload,
|
||||
SubmissionType.online_quiz,
|
||||
SubmissionType.on_paper,
|
||||
SubmissionType.discussion_topic,
|
||||
SubmissionType.external_tool,
|
||||
SubmissionType.online_url,
|
||||
SubmissionType.media_recording,
|
||||
SubmissionType.student_annotation,
|
||||
SubmissionType.none,
|
||||
};
|
||||
}
|
||||
|
||||
public record LocalAssignment
|
||||
{
|
||||
public string id { get; init; } = "";
|
||||
public ulong? canvasId = null;
|
||||
public ulong? canvasId { get; init; } = null;
|
||||
public string name { get; init; } = "";
|
||||
public string description { get; init; } = "";
|
||||
public bool use_template { get; init; } = false;
|
||||
@@ -37,7 +50,7 @@ public record LocalAssignment
|
||||
public DateTime? lock_at { get; init; }
|
||||
public DateTime due_at { get; init; }
|
||||
public int points_possible { get; init; }
|
||||
public IEnumerable<SubmissionType> submission_types { get; init; } = new SubmissionType[] { };
|
||||
public IEnumerable<string> submission_types { get; init; } = new string[] { };
|
||||
|
||||
public string GetRubricHtml()
|
||||
{
|
||||
|
||||
@@ -52,12 +52,14 @@ public class CanvasAssignmentService
|
||||
if (canvasAssignment == null)
|
||||
throw new Exception("created canvas assignment was null");
|
||||
|
||||
await CreateRubric(courseId, localAssignment);
|
||||
|
||||
return localAssignment with
|
||||
var updatedLocalAssignment = localAssignment with
|
||||
{
|
||||
canvasId = canvasAssignment.Id
|
||||
};
|
||||
|
||||
await CreateRubric(courseId, updatedLocalAssignment);
|
||||
|
||||
return updatedLocalAssignment;
|
||||
}
|
||||
|
||||
public async Task Update(ulong courseId, LocalAssignment localAssignment, string htmlDescription)
|
||||
|
||||
@@ -4,6 +4,7 @@ using CanvasModel.Courses;
|
||||
using CanvasModel.EnrollmentTerms;
|
||||
using CanvasModel.Modules;
|
||||
using RestSharp;
|
||||
|
||||
namespace Management.Services.Canvas;
|
||||
|
||||
public class CanvasService
|
||||
@@ -75,6 +76,53 @@ public class CanvasService
|
||||
await webRequestor.PostAsync(request);
|
||||
}
|
||||
|
||||
public async Task UpdateModule(ulong courseId, ulong moduleId, string name, int position)
|
||||
{
|
||||
Console.WriteLine($"Updating Module: {name}");
|
||||
var url = $"courses/{courseId}/modules/{moduleId}";
|
||||
var body = new { module = new { name = name, position = position } };
|
||||
var request = new RestRequest(url);
|
||||
request.AddBody(body);
|
||||
|
||||
await webRequestor.PutAsync(request);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<CanvasModuleItem>> GetModuleItems(ulong courseId, ulong moduleId)
|
||||
{
|
||||
var url = $"courses/{courseId}/modules/{moduleId}/items";
|
||||
var request = new RestRequest(url);
|
||||
var (items, response) = await webRequestor.GetAsync<IEnumerable<CanvasModuleItem>>(request);
|
||||
if (items == null)
|
||||
throw new Exception($"Error getting canvas module items for {url}");
|
||||
return items;
|
||||
}
|
||||
|
||||
public async Task<Dictionary<ulong, IEnumerable<CanvasModuleItem>>> GetAllModulesItems(
|
||||
ulong courseId,
|
||||
IEnumerable<CanvasModule> modules
|
||||
)
|
||||
{
|
||||
var itemsTasks = modules.Select(
|
||||
async (m) =>
|
||||
{
|
||||
var items = await GetModuleItems(courseId, m.Id);
|
||||
return (m, items);
|
||||
}
|
||||
);
|
||||
|
||||
var output = new Dictionary<ulong, IEnumerable<CanvasModuleItem>>();
|
||||
var itemTasksResult = await Task.WhenAll(itemsTasks);
|
||||
foreach (var (module, items) in itemTasksResult)
|
||||
{
|
||||
if (module == null || items == null)
|
||||
throw new Exception(
|
||||
"i'm not sure how we got here, but module and items are null after looking up module items"
|
||||
);
|
||||
output[module.Id] = items;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<EnrollmentTermModel>> GetCurrentTermsFor(
|
||||
DateTime? _queryDate = null
|
||||
)
|
||||
@@ -90,4 +138,50 @@ public class CanvasService
|
||||
|
||||
return currentTerms;
|
||||
}
|
||||
|
||||
public async Task UpdateModuleItem(
|
||||
ulong canvasCourseId,
|
||||
ulong canvasModuleId,
|
||||
CanvasModuleItem item
|
||||
)
|
||||
{
|
||||
Console.WriteLine($"updating module item {item.Title}");
|
||||
var url = $"courses/{canvasCourseId}/modules/{canvasModuleId}/items/{item.Id}";
|
||||
var body = new { module_item = new { title = item.Title, position = item.Position } };
|
||||
var request = new RestRequest(url);
|
||||
request.AddBody(body);
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
|
||||
var (newItem, response) = await webRequestor.PutAsync<CanvasModuleItem>(request);
|
||||
if (newItem == null)
|
||||
throw new Exception("something went wrong updating module item");
|
||||
}
|
||||
|
||||
public async Task CreateModuleItem(
|
||||
ulong canvasCourseId,
|
||||
ulong canvasModuleId,
|
||||
string title,
|
||||
string type,
|
||||
ulong contentId
|
||||
)
|
||||
{
|
||||
Console.WriteLine($"creating new module item {title}");
|
||||
var url = $"courses/{canvasCourseId}/modules/{canvasModuleId}/items";
|
||||
var body = new
|
||||
{
|
||||
module_item = new
|
||||
{
|
||||
title = title,
|
||||
type = type.ToString(),
|
||||
content_id = contentId,
|
||||
}
|
||||
};
|
||||
var request = new RestRequest(url);
|
||||
request.AddBody(body);
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
|
||||
var (newItem, response) = await webRequestor.PostAsync<CanvasModuleItem>(request);
|
||||
if (newItem == null)
|
||||
throw new Exception("something went wrong updating module item");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ using RestSharp;
|
||||
|
||||
public class WebRequestor : IWebRequestor
|
||||
{
|
||||
private const string BaseUrl = "https://snow.instructure.com/api/v1/";
|
||||
private string BaseUrl = Environment.GetEnvironmentVariable("CANVAS_URL") + "/api/v1/";
|
||||
private string token;
|
||||
private RestClient client;
|
||||
|
||||
@@ -49,13 +49,13 @@ public class WebRequestor : IWebRequestor
|
||||
public async Task<RestResponse> PutAsync(RestRequest request)
|
||||
{
|
||||
var response = await client.ExecutePutAsync(request);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
System.Console.WriteLine(response.Content);
|
||||
System.Console.WriteLine(response.ResponseUri);
|
||||
System.Console.WriteLine("error with response");
|
||||
throw new Exception("error with response");
|
||||
}
|
||||
// if (!response.IsSuccessful)
|
||||
// {
|
||||
// System.Console.WriteLine(response.Content);
|
||||
// System.Console.WriteLine(response.ResponseUri);
|
||||
// System.Console.WriteLine("error with response");
|
||||
// throw new Exception("error with response");
|
||||
// }
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -79,23 +79,20 @@ public class WebRequestor : IWebRequestor
|
||||
}
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = JsonSerializer.Deserialize<T>(response.Content!);
|
||||
var data = JsonSerializer.Deserialize<T>(response.Content!);
|
||||
|
||||
if (data == null)
|
||||
{
|
||||
System.Console.WriteLine(response.Content);
|
||||
System.Console.WriteLine(response.ResponseUri);
|
||||
System.Console.WriteLine("could not parse response, got empty object");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
catch (System.NotSupportedException exception)
|
||||
if (data == null)
|
||||
{
|
||||
Console.WriteLine(response.Content);
|
||||
throw exception;
|
||||
System.Console.WriteLine(response.Content);
|
||||
System.Console.WriteLine(response.ResponseUri);
|
||||
System.Console.WriteLine("could not parse response, got empty object");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
catch (System.NotSupportedException exception)
|
||||
{
|
||||
Console.WriteLine(response.Content);
|
||||
throw exception;
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,6 @@ public class YamlManager
|
||||
var serializer = new SerializerBuilder().Build();
|
||||
var yaml = serializer.Serialize(course);
|
||||
|
||||
// System.Console.WriteLine(yaml);
|
||||
return yaml;
|
||||
}
|
||||
|
||||
@@ -17,8 +16,8 @@ public class YamlManager
|
||||
{
|
||||
var deserializer = new DeserializerBuilder().Build();
|
||||
|
||||
var person = deserializer.Deserialize<LocalCourse>(rawCourse);
|
||||
return person;
|
||||
var course = deserializer.Deserialize<LocalCourse>(rawCourse);
|
||||
return course;
|
||||
}
|
||||
|
||||
public async Task SaveCourseAsync(LocalCourse course)
|
||||
@@ -44,7 +43,9 @@ public class YamlManager
|
||||
var fileNames = Directory.GetFiles(path);
|
||||
|
||||
var courses = await Task.WhenAll(
|
||||
fileNames.Select(async n => ParseCourse(await File.ReadAllTextAsync($"../storage/{n}")))
|
||||
fileNames
|
||||
.Where(name => name.EndsWith(".yml"))
|
||||
.Select(async n => ParseCourse(await File.ReadAllTextAsync($"../storage/{n}")))
|
||||
);
|
||||
return courses;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user