Skip to content
This repository has been archived by the owner on Sep 4, 2023. It is now read-only.

Add homepage #74

Merged
merged 17 commits into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Epsilon.Abstractions/Export/IExportDataPackager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ namespace Epsilon.Abstractions.Export;

public interface IExportDataPackager
{
public Task<ExportData> GetExportData(IAsyncEnumerable<ModuleOutcomeResultCollection> data);
public Task<ExportData> GetExportData();
}
20 changes: 20 additions & 0 deletions Epsilon.Abstractions/Model/CoursePage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Epsilon.Abstractions.Model;

public class CoursePage
{
public string Title { get; set; }
public string CreatedAt { get; set; }
public string Url { get; set; }
public string EditingRoles { get; set; }
public string PageId { get; set; }
public string LastEditedBy { get; set; }
public string Published { get; set; }
public string HideFromStudents { get; set; }
public string FrontPage { get; set; }
kn4a-com marked this conversation as resolved.
Show resolved Hide resolved
public string HtmlUrl { get; set; }
public string TodoDate { get; set; }
public string PublishedAt { get; set; }
public string UpdatedAt { get; set; }
public string LockedForUser { get; set; }
public string Body { get; set; }
}
3 changes: 2 additions & 1 deletion Epsilon.Abstractions/Model/ExportData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{
public class ExportData
{
public string PersonaHtml { get; set; } = string.Empty;
public IEnumerable<CourseModule> CourseModules { get; set; } = Enumerable.Empty<CourseModule>();
}
}
}
20 changes: 20 additions & 0 deletions Epsilon.Canvas.Abstractions/Model/Page.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Text.Json.Serialization;

namespace Epsilon.Canvas.Abstractions.Model;

public record Page(
[property: JsonPropertyName("title")] string? Title,
[property: JsonPropertyName("created_at")] string? CreatedAt,
[property: JsonPropertyName("url")] string? Url,
[property: JsonPropertyName("editing_roles")] string? EditingRoles,
[property: JsonPropertyName("page_id")] int? PageId,
[property: JsonPropertyName("published")] bool? Published,
[property: JsonPropertyName("hide_from_students")] bool? HideFromStudents,
[property: JsonPropertyName("front_page")] bool? FrontPage,
[property: JsonPropertyName("html_url")] string? HTMLUrl,
[property: JsonPropertyName("todo_date")] DateTime? TodoDate,
[property: JsonPropertyName("publish_at")] DateTime? PublishAt,
[property: JsonPropertyName("updated_at")] DateTime? UpdatedAt,
[property: JsonPropertyName("locked_for_user")] bool? LockedForUser,
[property: JsonPropertyName("body")] string? Body
);
6 changes: 6 additions & 0 deletions Epsilon.Canvas.Abstractions/Service/IFileHttpService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Epsilon.Canvas.Abstractions.Service;

public interface IFileHttpService
{
Task<IEnumerable<byte>?> GetFileByteArray(string url);
}
10 changes: 10 additions & 0 deletions Epsilon.Canvas.Abstractions/Service/IPageHttpService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Epsilon.Canvas.Abstractions.Model;

namespace Epsilon.Canvas.Abstractions.Service;

public interface IPageHttpService
{
Task<string> GetPageByName(int courseId, string pageName);

Task<IEnumerable<Page>?> GetAll(int courseId, IEnumerable<string> include);
}
9 changes: 5 additions & 4 deletions Epsilon.Canvas/CanvasModuleCollectionFetcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ IOutcomeHttpService outcomeService
_outcomeService = outcomeService;
}

public async IAsyncEnumerable<ModuleOutcomeResultCollection> GetAll(int courseId, IEnumerable<string>? allowedModules)
public async IAsyncEnumerable<ModuleOutcomeResultCollection> GetAll(int courseId,
IEnumerable<string>? allowedModules)
{
var response = await _outcomeService.GetResults(courseId, new[] { "outcomes", "alignments" });
var modules = await _moduleService.GetAll(courseId, new[] { "items" });
var response = await _outcomeService.GetResults(courseId, new[] {"outcomes", "alignments"});
var modules = await _moduleService.GetAll(courseId, new[] {"items"});

Debug.Assert(response != null, nameof(response) + " != null");
Debug.Assert(modules != null, nameof(modules) + " != null");
Expand All @@ -41,7 +42,7 @@ public async IAsyncEnumerable<ModuleOutcomeResultCollection> GetAll(int courseId

yield return new ModuleOutcomeResultCollection(module, new OutcomeResultCollection(
response.OutcomeResults.Where(r => ids.Contains(r.Link.Alignment)),
response.Links with { Alignments = response.Links.Alignments.Where(a => ids.Contains(a.Id)) }
response.Links with {Alignments = response.Links.Alignments.Where(a => ids.Contains(a.Id))}
));
}
}
Expand Down
7 changes: 5 additions & 2 deletions Epsilon.Canvas/CanvasServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,20 @@ public static IServiceCollection AddCanvas(this IServiceCollection services, ICo
var settings = provider.GetRequiredService<IOptions<CanvasSettings>>().Value;

client.BaseAddress = settings.ApiUrl;
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", settings.AccessToken);
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", settings.AccessToken);
});

services.AddHttpClient<IPaginatorHttpService, PaginatorHttpService>(CanvasHttpClient);
services.AddHttpClient<IModuleHttpService, ModuleHttpService>(CanvasHttpClient);
services.AddHttpClient<IAssignmentHttpService, AssignmentHttpService>(CanvasHttpClient);
services.AddHttpClient<IOutcomeHttpService, OutcomeHttpService>(CanvasHttpClient);
services.AddHttpClient<ISubmissionHttpService, SubmissionHttpService>(CanvasHttpClient);
services.AddHttpClient<IPageHttpService, PageHttpService>(CanvasHttpClient);
services.AddHttpClient<IFileHttpService, FileHttpService>(CanvasHttpClient);

services.AddScoped<ILinkHeaderConverter, LinkHeaderConverter>();

services.AddScoped<ICanvasModuleCollectionFetcher, CanvasModuleCollectionFetcher>();

return services;
Expand Down
2 changes: 1 addition & 1 deletion Epsilon.Canvas/Epsilon.Canvas.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.46" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
</ItemGroup>
Expand Down
36 changes: 36 additions & 0 deletions Epsilon.Canvas/Service/FileHttpService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Net;
using System.Net.Http.Json;
using Epsilon.Abstractions.Http;
using Epsilon.Canvas.Abstractions.Converter;
using Epsilon.Canvas.Abstractions.Model;
using Epsilon.Canvas.Abstractions.Service;
using HtmlAgilityPack;

namespace Epsilon.Canvas.Service;

public class FileHttpService : HttpService, IFileHttpService
{
public FileHttpService(HttpClient client) : base(client)
{
}

public async Task<IEnumerable<byte>?> GetFileByteArray(string url)
{
var client = new HttpClient();
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show resolved Hide resolved
var response = new byte[0];
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show resolved Hide resolved
try
{
response = await Client.GetByteArrayAsync(url);
}
catch (Exception e)
{
throw new Exception($"Error in GetFileByteArray: {e.Message}");
}
Fixed Show fixed Hide fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show resolved Hide resolved
finally
{
client?.Dispose();
}

return response;
}
}
61 changes: 61 additions & 0 deletions Epsilon.Canvas/Service/PageHttpService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Net;
using System.Net.Http.Json;
using Epsilon.Abstractions.Http;
using Epsilon.Canvas.Abstractions.Model;
using Epsilon.Canvas.Abstractions.Service;

namespace Epsilon.Canvas.Service;

public class PageHttpService : HttpService, IPageHttpService
{
public PageHttpService(HttpClient client) : base(client)
{
}

public async Task<string?> GetPageByName(int courseId, string pageName)
{
var request = new HttpRequestMessage();
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show resolved Hide resolved
try
{
request = new HttpRequestMessage(HttpMethod.Get, $"v1/courses/{courseId}/{pageName}");
var response = await Client.SendAsync(request);
request.Dispose();
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show resolved Hide resolved

if (response.StatusCode == HttpStatusCode.OK)
return (await response.Content.ReadFromJsonAsync<Page>()).Body;
}
catch (Exception e)
{
throw new Exception($"Error in GetPageByName: {e.Message}");
}
Fixed Show fixed Hide fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show resolved Hide resolved
finally
{
request?.Dispose();
}

return null;
}

public async Task<IEnumerable<Page>?> GetAll(int courseId, IEnumerable<string> include)
{
var request = new HttpRequestMessage();
Fixed Show fixed Hide fixed
try
{
request = new HttpRequestMessage(HttpMethod.Get, $"v1/courses/{courseId}/pages");
var response = await Client.SendAsync(request);

if (response.StatusCode == HttpStatusCode.OK)
return await response.Content.ReadFromJsonAsync<IEnumerable<Page>>();
}
catch (Exception e)
{
throw new Exception($"Error in GetAll: {e.Message}");
}
Fixed Show fixed Hide fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show resolved Hide resolved
finally
{
request?.Dispose();
}

return null;
}
}
12 changes: 5 additions & 7 deletions Epsilon.Cli/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ public class Startup : IHostedService
private readonly IHostApplicationLifetime _lifetime;
private readonly ExportOptions _exportOptions;
private readonly CanvasSettings _canvasSettings;
private readonly ICanvasModuleCollectionFetcher _collectionFetcher;
private readonly IModuleExporterCollection _exporterCollection;
private readonly IExportDataPackager _exporterDataCollection;

Expand All @@ -24,15 +23,13 @@ public Startup(
IHostApplicationLifetime lifetime,
IOptions<CanvasSettings> canvasSettings,
IOptions<ExportOptions> exportSettings,
ICanvasModuleCollectionFetcher collectionFetcher,
IModuleExporterCollection exporterCollection,
IExportDataPackager exporterDataCollection)
{
_logger = logger;
_canvasSettings = canvasSettings.Value;
_exportOptions = exportSettings.Value;
_lifetime = lifetime;
_collectionFetcher = collectionFetcher;
_exporterCollection = exporterCollection;
_exporterDataCollection = exporterDataCollection;
}
Expand Down Expand Up @@ -65,12 +62,11 @@ private async Task ExecuteAsync()
return;
}

var modules = _exportOptions.Modules?.Split(",");
_logger.LogInformation("Targeting Canvas course: {CourseId}, at {Url}", _canvasSettings.CourseId,
_canvasSettings.ApiUrl);
_logger.LogInformation("Downloading results, this may take a few seconds...");
var items = _collectionFetcher.GetAll(_canvasSettings.CourseId, modules);
var formattedItems = await _exporterDataCollection.GetExportData(items);

var formattedItems = await _exporterDataCollection.GetExportData();

var formats = _exportOptions.Formats.Split(",");
var exporters = _exporterCollection.DetermineExporters(formats).ToArray();
Expand All @@ -82,7 +78,9 @@ private async Task ExecuteAsync()
_logger.LogInformation("Exporting to {Format} using {Exporter}...", format, exporter.GetType().Name);
var stream = await exporter.Export(formattedItems, format);

await using var fileStream = new FileStream($"{_exportOptions.FormattedOutputName}.{exporter.FileExtension}", FileMode.Create, FileAccess.Write);
await using var fileStream =
new FileStream($"{_exportOptions.FormattedOutputName}.{exporter.FileExtension}", FileMode.Create,
FileAccess.Write);

stream.Position = 0; // Reset position to zero to prepare for copy
await stream.CopyToAsync(fileStream);
Expand Down
1 change: 0 additions & 1 deletion Epsilon/Epsilon.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
<PackageReference Include="DocumentFormat.OpenXml" Version="2.18.0" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
</ItemGroup>

</Project>
33 changes: 28 additions & 5 deletions Epsilon/Export/ExportDataPackager.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,42 @@
using System.Diagnostics;
using Epsilon.Abstractions.Export;
using Epsilon.Abstractions.Model;
using Epsilon.Canvas.Abstractions.Model;
using Epsilon.Canvas;
using Epsilon.Canvas.Abstractions;
using Epsilon.Canvas.Abstractions.Service;
using Microsoft.Extensions.Options;

namespace Epsilon.Export;

public class ExportDataPackager : IExportDataPackager
{
public async Task<ExportData> GetExportData(IAsyncEnumerable<ModuleOutcomeResultCollection> data)
private readonly ICanvasModuleCollectionFetcher _moduleCollectionFetcher;
private readonly IPageHttpService _pageService;
private readonly ExportOptions _exportOptions;
private readonly CanvasSettings _canvasSettings;

public ExportDataPackager(ICanvasModuleCollectionFetcher moduleCollectionFetcher, IPageHttpService pageService,
IOptions<CanvasSettings> canvasSettings, IOptions<ExportOptions> exportOptions)
{
_moduleCollectionFetcher = moduleCollectionFetcher;
_pageService = pageService;
_exportOptions = exportOptions.Value;
_canvasSettings = canvasSettings.Value;
}

public async Task<ExportData> GetExportData()
{
var modules = _exportOptions.Modules?.Split(",");
var courseId = _canvasSettings.CourseId;

var moduleOutcomes = _moduleCollectionFetcher.GetAll(courseId, modules);
var personaHtml = await _pageService.GetPageByName(courseId, "front_page");

var output = new List<CourseModule>();

await foreach (var item in data.Where(m => m.Collection.OutcomeResults.Any()))
await foreach (var item in moduleOutcomes.Where(m => m.Collection.OutcomeResults.Any()))
{
var module = new CourseModule { Name = item.Module.Name };
var module = new CourseModule {Name = item.Module.Name};
var links = item.Collection.Links;

Debug.Assert(links != null, nameof(links) + " != null");
Expand Down Expand Up @@ -56,6 +79,6 @@ public async Task<ExportData> GetExportData(IAsyncEnumerable<ModuleOutcomeResult
output.Add(module);
}

return new ExportData { CourseModules = output };
return new ExportData {CourseModules = output, PersonaHtml = personaHtml};
}
}
Loading