smarter canvas updates, only update when a change is detected

This commit is contained in:
2023-07-31 14:06:40 -06:00
parent e987df30d3
commit 70db40867c
13 changed files with 465 additions and 204 deletions

View File

@@ -84,6 +84,11 @@
> >
Sync With Canvas Sync With Canvas
</button> </button>
@if(planner.LoadingCanvasData)
{
<Spinner />
}
</div> </div>
<CourseDetails /> <CourseDetails />
} }

View File

@@ -1,6 +1,7 @@
global using System.Text.Json.Serialization; global using System.Text.Json.Serialization;
global using System.Text.Json; global using System.Text.Json;
global using System.ComponentModel.DataAnnotations; global using System.ComponentModel.DataAnnotations;
global using Management.Services.Canvas;
global using CanvasModel.EnrollmentTerms; global using CanvasModel.EnrollmentTerms;
global using CanvasModel.Courses; global using CanvasModel.Courses;
global using CanvasModel; global using CanvasModel;
@@ -19,8 +20,12 @@ var builder = WebApplication.CreateBuilder(args);
// Add services to the container. // Add services to the container.
builder.Services.AddRazorPages(); builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor(); builder.Services.AddServerSideBlazor();
builder.Services.AddScoped<IWebRequestor, WebRequestor>(); builder.Services.AddScoped<IWebRequestor, WebRequestor>();
builder.Services.AddScoped<CanvasServiceUtils>();
builder.Services.AddScoped<CanvasAssignmentService>();
builder.Services.AddScoped<CanvasService, CanvasService>(); builder.Services.AddScoped<CanvasService, CanvasService>();
builder.Services.AddScoped<YamlManager>(); builder.Services.AddScoped<YamlManager>();
builder.Services.AddScoped<CoursePlanner>(); builder.Services.AddScoped<CoursePlanner>();
builder.Services.AddScoped<AssignmentDragContainer>(); builder.Services.AddScoped<AssignmentDragContainer>();

View File

@@ -14,19 +14,24 @@
} }
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
if(
planner.CanvasAssignments == null
&& planner.LocalCourse != null
&& planner.LocalCourse.CanvasId != null
)
{
var canvasId = planner.LocalCourse.CanvasId ?? throw new Exception("no canvas id found for selected course");
planner.CanvasAssignments = await canvas.GetAssignments(canvasId);
planner.CanvasModules = await canvas.GetModules(canvasId);
System.Console.WriteLine(JsonSerializer.Serialize(planner.CanvasAssignments));
}
await base.OnInitializedAsync();
} }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(firstRender)
{
if(
planner.CanvasAssignments == null
&& planner.LocalCourse != null
&& planner.LocalCourse.CanvasId != null
)
{
await planner.LoadCanvasData();
}
}
}
private void reload() private void reload()
{ {

View File

@@ -140,7 +140,19 @@
</h4> </h4>
@if(isSyncedWithCanvas) @if(isSyncedWithCanvas)
{ {
<div>Synced With Canvas</div> @if(planner.LocalCourse != null
&& planner.LocalCourse.CanvasId != null
&& planner.CanvasAssignments != null
&& planner.CanvasModules != null
&& planner.AssignmentNeedsUpdates(Assignment)
)
{
<div>need to update canvas</div>
}
else
{
<div>Canvas is up to date</div>
}
} }
else else
{ {

View File

@@ -4,11 +4,14 @@ using CanvasModel;
using LocalModels; using LocalModels;
using CanvasModel.Assignments; using CanvasModel.Assignments;
using CanvasModel.Modules; using CanvasModel.Modules;
using Management.Services.Canvas;
using System.Text.RegularExpressions;
public class CoursePlanner public class CoursePlanner
{ {
private readonly YamlManager yamlManager; private readonly YamlManager yamlManager;
private readonly CanvasService canvas; private readonly CanvasService canvas;
public bool LoadingCanvasData { get; internal set; } = false;
public CoursePlanner(YamlManager yamlManager, CanvasService canvas) public CoursePlanner(YamlManager yamlManager, CanvasService canvas)
{ {
@@ -29,7 +32,7 @@ public class CoursePlanner
return; return;
} }
var verifiedCourse = verifyCourse(value); var verifiedCourse = cleanupCourse(value);
// ignore initial load of course // ignore initial load of course
if (_localCourse != null) if (_localCourse != null)
{ {
@@ -41,7 +44,7 @@ public class CoursePlanner
} }
public event Action? StateHasChanged; public event Action? StateHasChanged;
private LocalCourse verifyCourse(LocalCourse incomingCourse) private LocalCourse cleanupCourse(LocalCourse incomingCourse)
{ {
var modulesWithUniqueAssignments = incomingCourse.Modules.Select( var modulesWithUniqueAssignments = incomingCourse.Modules.Select(
module => module with { Assignments = module.Assignments.DistinctBy(a => a.id) } module => module with { Assignments = module.Assignments.DistinctBy(a => a.id) }
@@ -53,8 +56,42 @@ public class CoursePlanner
}; };
} }
public IEnumerable<CanvasAssignment>? CanvasAssignments { get; set; } = null; private IEnumerable<CanvasAssignment>? canvasAssignments = null;
public IEnumerable<CanvasModule>? CanvasModules { get; set; } = 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()
{
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);
LoadingCanvasData = false;
StateHasChanged?.Invoke();
}
public async Task SyncWithCanvas() public async Task SyncWithCanvas()
{ {
@@ -66,12 +103,18 @@ public class CoursePlanner
) )
return; return;
LoadingCanvasData = true;
StateHasChanged?.Invoke();
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 ensureAllModulesCreated(canvasId); await ensureAllModulesCreated(canvasId);
await reloadModules_UpdateLocalModulesWithNewId(canvasId); await reloadModules_UpdateLocalModulesWithNewId(canvasId);
await ensureAllAssignmentsCreated_updateIds(canvasId); await ensureAllAssignmentsCreated_updateIds(canvasId);
LoadingCanvasData = false;
StateHasChanged?.Invoke();
} }
private async Task reloadModules_UpdateLocalModulesWithNewId(ulong canvasId) private async Task reloadModules_UpdateLocalModulesWithNewId(ulong canvasId)
@@ -139,21 +182,121 @@ public class CoursePlanner
throw new Exception( throw new Exception(
"cannot create canvas assignment if local course is null or other values not set" "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"); ulong canvasId = LocalCourse.CanvasId ?? throw new Exception("no canvas id to create course");
var canvasAssignment = await canvas.CreateAssignment( var canvasAssignment = CanvasAssignments.FirstOrDefault(
courseId: canvasId, ca => ca.Id == localAssignment.canvasId
name: localAssignment.name, );
submissionTypes: localAssignment.submission_types, string localHtmlDescription = getAssignmentDescriptionHtml(localAssignment);
description: localAssignment.description,
dueAt: localAssignment.due_at, if (canvasAssignment != null)
lockAt: localAssignment.lock_at, {
pointsPossible: localAssignment.points_possible var assignmentNeedsUpdates = AssignmentNeedsUpdates(localAssignment);
if (assignmentNeedsUpdates)
{
await canvas.Assignments.Update(courseId: canvasId, localAssignment, localHtmlDescription);
}
return localAssignment;
}
else
{
var createdAssignment = await canvas.Assignments.Create(
courseId: canvasId,
name: localAssignment.name,
submissionTypes: localAssignment.submission_types,
description: localHtmlDescription,
dueAt: localAssignment.due_at,
lockAt: localAssignment.lock_at,
pointsPossible: localAssignment.points_possible
);
return localAssignment with
{
canvasId = createdAssignment.Id
};
}
}
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)
{
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 = getAssignmentDescriptionHtml(localAssignment);
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())
); );
return localAssignment with if (!dueDatesSame)
Console.WriteLine(
$"Due dates different for {localAssignment.name}, local: {localAssignment.due_at}, in canvas {canvasAssignment.DueAt}"
);
if (!descriptionSame)
{ {
canvasId = canvasAssignment.Id 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;
} }
public void Clear() public void Clear()

View File

@@ -1,3 +1,5 @@
using LocalModels;
public record RubricItem public record RubricItem
{ {
public static readonly string extraCredit = "(Extra Credit) "; public static readonly string extraCredit = "(Extra Credit) ";

View File

@@ -0,0 +1,89 @@
using CanvasModel.Assignments;
using RestSharp;
namespace Management.Services.Canvas;
public class CanvasAssignmentService
{
private IWebRequestor webRequestor;
private readonly CanvasServiceUtils utils;
public CanvasAssignmentService(IWebRequestor webRequestor, CanvasServiceUtils utils)
{
this.webRequestor = webRequestor;
this.utils = utils;
}
public async Task<IEnumerable<CanvasAssignment>> GetAll(ulong courseId)
{
var url = $"courses/{courseId}/assignments";
var request = new RestRequest(url);
var assignmentResponse = await utils.PaginatedRequest<IEnumerable<CanvasAssignment>>(request);
return assignmentResponse.SelectMany(
assignments =>
assignments.Select(
a =>
a with
{
DueAt = a.DueAt?.ToLocalTime(),
LockAt = a.LockAt?.ToLocalTime()
}
)
);
}
public async Task<CanvasAssignment> Create(
ulong courseId,
string name,
IEnumerable<SubmissionType> submissionTypes,
string? description,
DateTime? dueAt,
DateTime? lockAt,
int? pointsPossible
)
{
System.Console.WriteLine($"creating assignment: {name}");
var url = $"courses/{courseId}/assignments";
var request = new RestRequest(url);
var body = new CanvasAssignmentCreationRequest()
{
name = name,
submission_types = submissionTypes.Select(t => t.ToString()),
description = description ?? "",
due_at = dueAt,
lock_at = lockAt,
points_possible = pointsPossible ?? 0
};
request.AddHeader("Content-Type", "application/json");
var bodyObj = new { assignment = body };
request.AddBody(bodyObj);
var (canvasAssignment, response) = await webRequestor.PostAsync<CanvasAssignment>(request);
if (canvasAssignment == null)
throw new Exception("created canvas assignment was null");
return canvasAssignment with
{
DueAt = canvasAssignment.DueAt?.ToLocalTime(),
LockAt = canvasAssignment.LockAt?.ToLocalTime()
};
}
public async Task Update(ulong courseId, LocalAssignment localAssignment, string htmlDescription)
{
System.Console.WriteLine($"updating assignment: {localAssignment.name}");
var url = $"courses/{courseId}/assignments/{localAssignment.canvasId}";
var request = new RestRequest(url);
var body = new CanvasAssignmentCreationRequest()
{
name = localAssignment.name,
submission_types = localAssignment.submission_types.Select(t => t.ToString()),
description = htmlDescription,
due_at = localAssignment.due_at,
lock_at = localAssignment.lock_at,
points_possible = localAssignment.points_possible
};
request.AddHeader("Content-Type", "application/json");
var bodyObj = new { assignment = body };
request.AddBody(bodyObj);
await webRequestor.PutAsync(request);
}
}

View File

@@ -1,3 +1,6 @@
namespace Management.Services.Canvas;
public record CanvasAssignmentCreationRequest public record CanvasAssignmentCreationRequest
{ {
public string? name { get; set; } public string? name { get; set; }

View File

@@ -0,0 +1,93 @@
using CanvasModel;
using CanvasModel.Assignments;
using CanvasModel.Courses;
using CanvasModel.EnrollmentTerms;
using CanvasModel.Modules;
using RestSharp;
namespace Management.Services.Canvas;
public class CanvasService
{
private readonly IWebRequestor webRequestor;
private readonly CanvasServiceUtils utils;
public CanvasAssignmentService Assignments { get; }
public CanvasService(
IWebRequestor webRequestor,
CanvasServiceUtils utils,
CanvasAssignmentService Assignments
)
{
this.webRequestor = webRequestor;
this.utils = utils;
this.Assignments = Assignments;
}
public async Task<IEnumerable<EnrollmentTermModel>> GetTerms()
{
var url = $"accounts/10/terms";
var request = new RestRequest(url);
var termResponses = await utils.PaginatedRequest<RedundantEnrollmentTermsResponse>(request);
var terms = termResponses.Select(r => r.EnrollmentTerms).SelectMany(s => s).ToArray();
return terms;
}
public async Task<IEnumerable<CourseModel>> GetCourses(ulong termId)
{
var url = $"courses";
var request = new RestRequest(url);
var coursesResponse = await utils.PaginatedRequest<IEnumerable<CourseModel>>(request);
return coursesResponse.SelectMany(c => c).Where(c => c.EnrollmentTermId == termId).ToArray();
}
public async Task<CourseModel> GetCourse(ulong courseId)
{
var url = $"courses/{courseId}";
var request = new RestRequest(url);
var (data, response) = await webRequestor.GetAsync<CourseModel>(request);
if (data == null)
{
System.Console.WriteLine(response.Content);
System.Console.WriteLine(response.ResponseUri);
throw new Exception("error getting course from canvas");
}
return data;
}
public async Task<IEnumerable<CanvasModule>> GetModules(ulong courseId)
{
var url = $"courses/{courseId}/modules";
var request = new RestRequest(url);
var modules = await utils.PaginatedRequest<IEnumerable<CanvasModule>>(request);
return modules.SelectMany(c => c).ToArray();
}
public async Task CreateModule(ulong courseId, string name)
{
Console.WriteLine($"Creating Module: {name}");
var url = $"courses/{courseId}/modules";
var request = new RestRequest(url);
request.AddParameter("module[name]", name);
await webRequestor.PostAsync(request);
}
public async Task<IEnumerable<EnrollmentTermModel>> GetCurrentTermsFor(
DateTime? _queryDate = null
)
{
DateTime queryDate = _queryDate ?? DateTime.Now;
var terms = await GetTerms();
var currentTerms = terms
.Where(t => t.EndAt != null && t.EndAt > queryDate && t.EndAt < queryDate.AddYears(1))
.Take(3)
.OrderBy(t => t.StartAt);
return currentTerms;
}
}

View File

@@ -0,0 +1,58 @@
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;
}
internal async Task<IEnumerable<T>> PaginatedRequest<T>(RestRequest request)
{
var requestCount = 1;
request.AddQueryParameter("per_page", "100");
var (data, response) = await webRequestor.GetAsync<T>(request);
if (response.ErrorMessage?.Length > 0)
{
System.Console.WriteLine("error in response");
System.Console.WriteLine(response.ErrorMessage);
throw new Exception("error in response");
}
var returnData = data != null ? new T[] { data } : new T[] { };
var nextUrl = getNextUrl(response.Headers);
while (nextUrl is not null)
{
requestCount += 1;
RestRequest nextRequest = new RestRequest(nextUrl);
var (nextData, nextResponse) = await webRequestor.GetAsync<T>(nextRequest);
if (nextData is not null)
returnData = returnData.Append(nextData).ToArray();
nextUrl = getNextUrl(nextResponse.Headers);
}
System.Console.WriteLine($"Requesting {typeof(T)} took {requestCount} requests");
return returnData;
}
protected static string? getNextUrl(IEnumerable<HeaderParameter>? headers) =>
headers
?.ToList()
.Find(h => h.Name == "Link")
?.Value?.ToString()
?.Split(",")
.Where(url => url.Contains("rel=\"next\""))
.FirstOrDefault()
?.Split(";")
.FirstOrDefault()
?.TrimEnd('>')
.TrimStart('<')
.Replace(" ", "")
.Replace(BaseUrl, "");
}

View File

@@ -1,175 +0,0 @@
using CanvasModel;
using CanvasModel.Assignments;
using CanvasModel.Courses;
using CanvasModel.EnrollmentTerms;
using CanvasModel.Modules;
using RestSharp;
public interface ICanvasService
{
Task<IEnumerable<EnrollmentTermModel>> GetCurrentTermsFor(DateTime? _queryDate = null);
Task<IEnumerable<EnrollmentTermModel>> GetTerms();
}
public class CanvasService : ICanvasService
{
private const string BaseUrl = "https://snow.instructure.com/api/v1/";
private readonly IWebRequestor webRequestor;
public CanvasService(IWebRequestor webRequestor)
{
this.webRequestor = webRequestor;
}
public async Task<IEnumerable<EnrollmentTermModel>> GetTerms()
{
var url = $"accounts/10/terms";
var request = new RestRequest(url);
var termResponses = await PaginatedRequest<RedundantEnrollmentTermsResponse>(request);
var terms = termResponses.Select(r => r.EnrollmentTerms).SelectMany(s => s).ToArray();
return terms;
}
public async Task<IEnumerable<CourseModel>> GetCourses(ulong termId)
{
var url = $"courses";
var request = new RestRequest(url);
var coursesResponse = await PaginatedRequest<IEnumerable<CourseModel>>(request);
return coursesResponse.SelectMany(c => c).Where(c => c.EnrollmentTermId == termId).ToArray();
}
public async Task<CourseModel> GetCourse(ulong courseId)
{
var url = $"courses/{courseId}";
var request = new RestRequest(url);
var (data, response) = await webRequestor.GetAsync<CourseModel>(request);
if (data == null)
{
System.Console.WriteLine(response.Content);
System.Console.WriteLine(response.ResponseUri);
throw new Exception("error getting course from canvas");
}
return data;
}
public async Task<IEnumerable<CanvasAssignment>> GetAssignments(ulong courseId)
{
var url = $"courses/{courseId}/assignments";
var request = new RestRequest(url);
var assignmentResponse = await PaginatedRequest<IEnumerable<CanvasAssignment>>(request);
return assignmentResponse.SelectMany(c => c);
}
public async Task<CanvasAssignment> CreateAssignment(
ulong courseId,
string name,
IEnumerable<SubmissionType> submissionTypes,
string? description,
DateTime? dueAt,
DateTime? lockAt,
int? pointsPossible
)
{
System.Console.WriteLine($"creating assignment: {name}");
var url = $"courses/{courseId}/assignments";
var request = new RestRequest(url);
var body = new CanvasAssignmentCreationRequest()
{
name = name,
submission_types = submissionTypes.Select(t => t.ToString()),
description = description,
due_at = dueAt,
lock_at = lockAt,
points_possible = pointsPossible
};
request.AddHeader("Content-Type", "application/json");
var bodyObj = new { assignment = body };
request.AddBody(bodyObj);
var (canvasAssignment, response) = await webRequestor.PostAsync<CanvasAssignment>(request);
if (canvasAssignment == null)
throw new Exception("created canvas assignment was null");
return canvasAssignment;
}
public async Task<IEnumerable<CanvasModule>> GetModules(ulong courseId)
{
var url = $"courses/{courseId}/modules";
var request = new RestRequest(url);
var modules = await PaginatedRequest<IEnumerable<CanvasModule>>(request);
return modules.SelectMany(c => c).ToArray();
}
public async Task CreateModule(ulong courseId, string name)
{
Console.WriteLine($"Creating Module: {name}");
var url = $"courses/{courseId}/modules";
var request = new RestRequest(url);
request.AddParameter("module[name]", name);
await webRequestor.PostAsync(request);
}
private async Task<IEnumerable<T>> PaginatedRequest<T>(RestRequest request)
{
var requestCount = 1;
request.AddQueryParameter("per_page", "100");
var (data, response) = await webRequestor.GetAsync<T>(request);
if (response.ErrorMessage?.Length > 0)
{
System.Console.WriteLine("error in response");
System.Console.WriteLine(response.ErrorMessage);
throw new Exception("error in response");
}
var returnData = data != null ? new T[] { data } : new T[] { };
var nextUrl = getNextUrl(response.Headers);
while (nextUrl is not null)
{
requestCount += 1;
RestRequest nextRequest = new RestRequest(nextUrl);
var (nextData, nextResponse) = await webRequestor.GetAsync<T>(nextRequest);
if (nextData is not null)
returnData = returnData.Append(nextData).ToArray();
nextUrl = getNextUrl(nextResponse.Headers);
}
System.Console.WriteLine($"Requesting {typeof(T)} took {requestCount} requests");
return returnData;
}
private static string? getNextUrl(IEnumerable<HeaderParameter>? headers) =>
headers
?.ToList()
.Find(h => h.Name == "Link")
?.Value?.ToString()
?.Split(",")
.Where(url => url.Contains("rel=\"next\""))
.FirstOrDefault()
?.Split(";")
.FirstOrDefault()
?.TrimEnd('>')
.TrimStart('<')
.Replace(" ", "")
.Replace(BaseUrl, "");
public async Task<IEnumerable<EnrollmentTermModel>> GetCurrentTermsFor(
DateTime? _queryDate = null
)
{
DateTime queryDate = _queryDate ?? DateTime.Now;
var terms = await GetTerms();
var currentTerms = terms
.Where(t => t.EndAt != null && t.EndAt > queryDate && t.EndAt < queryDate.AddYears(1))
.Take(3)
.OrderBy(t => t.StartAt);
return currentTerms;
}
}

View File

@@ -6,4 +6,6 @@ public interface IWebRequestor
Task<(T?, RestResponse)> GetAsync<T>(RestRequest request); Task<(T?, RestResponse)> GetAsync<T>(RestRequest request);
Task<RestResponse> PostAsync(RestRequest request); Task<RestResponse> PostAsync(RestRequest request);
Task<(T?, RestResponse)> PostAsync<T>(RestRequest request); Task<(T?, RestResponse)> PostAsync<T>(RestRequest request);
Task<RestResponse> PutAsync(RestRequest request);
Task<(T?, RestResponse)> PutAsync<T>(RestRequest request);
} }

View File

@@ -46,7 +46,26 @@ public class WebRequestor : IWebRequestor
return (Deserialize<T>(response), response); return (Deserialize<T>(response), response);
} }
public T? Deserialize<T>(RestResponse response) 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");
}
return response;
}
public async Task<(T?, RestResponse)> PutAsync<T>(RestRequest request)
{
var response = await client.ExecutePutAsync(request);
return (Deserialize<T>(response), response);
}
private T? Deserialize<T>(RestResponse response)
{ {
if (!response.IsSuccessful) if (!response.IsSuccessful)
{ {