diff --git a/Epsilon.Canvas.Abstractions/Data/LinkHeader.cs b/Epsilon.Canvas.Abstractions/Data/LinkHeader.cs new file mode 100644 index 00000000..4152fbf4 --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Data/LinkHeader.cs @@ -0,0 +1,64 @@ +using System.Text.RegularExpressions; + +public class LinkHeader +{ + public string FirstLink { get; set; } + public string PrevLink { get; set; } + public string NextLink { get; set; } + public string LastLink { get; set; } + + public static LinkHeader LinksFromHeader(HttpResponseMessage httpResponseMessage) + { + if (httpResponseMessage.Headers.Contains("Link")) + { + return LinkHeader.LinksFromHeader(httpResponseMessage.Headers.GetValues("Link").FirstOrDefault()); + } + + return null; + } + + public static LinkHeader LinksFromHeader(string linkHeaderStr) + { + LinkHeader linkHeader = null; + + if (!string.IsNullOrWhiteSpace(linkHeaderStr)) + { + string[] linkStrings = linkHeaderStr.Split(','); + + if (linkStrings != null && linkStrings.Any()) + { + linkHeader = new LinkHeader(); + + foreach (string linkString in linkStrings) + { + var relMatch = Regex.Match(linkString, "(?<=rel=\").+?(?=\")", RegexOptions.IgnoreCase); + var linkMatch = Regex.Match(linkString, "(?<=<).+?(?=>)", RegexOptions.IgnoreCase); + + if (relMatch.Success && linkMatch.Success) + { + string rel = relMatch.Value.ToUpper(); + string link = linkMatch.Value; + + switch (rel) + { + case "FIRST": + linkHeader.FirstLink = link; + break; + case "PREV": + linkHeader.PrevLink = link; + break; + case "NEXT": + linkHeader.NextLink = link; + break; + case "LAST": + linkHeader.LastLink = link; + break; + } + } + } + } + } + + return linkHeader; + } +} diff --git a/Epsilon.Canvas/Response/OutcomeResultResponse.cs b/Epsilon.Canvas/Response/OutcomeResultResponse.cs index d651b7dc..a72473e7 100644 --- a/Epsilon.Canvas/Response/OutcomeResultResponse.cs +++ b/Epsilon.Canvas/Response/OutcomeResultResponse.cs @@ -5,4 +5,4 @@ namespace Epsilon.Canvas.Response; public record OutcomeResultResponse( [property: JsonPropertyName("outcome_results")] IEnumerable OutcomeResults -); \ No newline at end of file +); diff --git a/Epsilon.Canvas/Service/OutcomeService.cs b/Epsilon.Canvas/Service/OutcomeService.cs index 6da814cf..ce43e0ae 100644 --- a/Epsilon.Canvas/Service/OutcomeService.cs +++ b/Epsilon.Canvas/Service/OutcomeService.cs @@ -1,8 +1,10 @@ -using Epsilon.Canvas.Abstractions.Data; +using Epsilon.Canvas.Abstractions.Data; using Epsilon.Canvas.Abstractions.Services; using Epsilon.Canvas.Response; using Epsilon.Http.Abstractions; using Epsilon.Http.Abstractions.Json; +using Microsoft.Extensions.Logging; +using System.Text.Json; namespace Epsilon.Canvas.Service; @@ -22,9 +24,22 @@ public OutcomeService(HttpClient client) : base(client) public async Task?> AllResults(int courseId, int count = 1000) { - var request = new HttpRequestMessage(HttpMethod.Get, $"v1/courses/{courseId}/outcome_results?per_page={count}"); - var (_, value) = await Client.SendAsync(request); + IEnumerable? res = null; + var page = 1; + do { + var request = new HttpRequestMessage(HttpMethod.Get, $"v1/courses/{courseId}/outcome_results?per_page={count}&offset={res?.Count() ?? 0}&page={page}"); + var (response, value) = await Client.SendAsync(request); + var links = LinkHeader.LinksFromHeader(response); - return value?.OutcomeResults; + res = res == null ? value?.OutcomeResults : res.Concat(value.OutcomeResults); + + if (links.NextLink == null) { + break; + } + + page += 1; + } while (res.Count() % 100 == 0); + + return res; } -} \ No newline at end of file +}