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

Add competence profile data model #76

Merged
Show file tree
Hide file tree
Changes from 3 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
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -646,4 +646,8 @@ fabric.properties
### VisualStudio Patch ###
# Additional files built by Visual Studio

# End of https://www.toptal.com/developers/gitignore/api/csharp,rider,visualstudio,dotnetcore
# End of https://www.toptal.com/developers/gitignore/api/csharp,rider,visualstudio,dotnetcore

appsettings.json
appsettings.*.json
!appsettings.example.json
6 changes: 6 additions & 0 deletions Epsilon.Abstractions/Model/CompetenceProfile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Epsilon.Abstractions.Model;

public record CompetenceProfile(
HboIDomain HboIDomain,
IEnumerable<CompetenceProfileOutcome> CompetenceProfileOutcomes
);
9 changes: 9 additions & 0 deletions Epsilon.Abstractions/Model/CompetenceProfileOutcome.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Epsilon.Abstractions.Model;

public record CompetenceProfileOutcome(
string ArchitectureLayer,
string Activity,
int MasteryLevel,
int Grade,
DateTime AssessedAt
);
38 changes: 38 additions & 0 deletions Epsilon.Abstractions/Model/HboIDomain.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
namespace Epsilon.Abstractions.Model;

public record HboIDomain(
IEnumerable<ArchitectureLayer> ArchitectureLayers,
IEnumerable<Activity> Activities,
IEnumerable<MasteryLevel> MasteryLevels
)
{
public static readonly HboIDomain HboIDomain2018 = new(
new[]
{
new ArchitectureLayer("Hardware Interfacing", "#8D9292"),
new ArchitectureLayer("Infrastructure", "#6EA7D4"),
new ArchitectureLayer("Organisational Processes", "#D16557"),
new ArchitectureLayer("User Interaction", "#E29C53"),
new ArchitectureLayer("Software", "#96B9C0")
},
new[]
{
new Activity("Manage & Control"),
new Activity("Analysis"),
new Activity("Advise"),
new Activity("Design"),
new Activity("Realisation")
},
new[]
{
new MasteryLevel(1, "#00B0F0"),
new MasteryLevel(2, "#00B050"),
new MasteryLevel(3, "#FFFC00"),
new MasteryLevel(4)
}
);
}

public record ArchitectureLayer(string Value, string? Color = null);
public record Activity(string Value, string? Color = null);
public record MasteryLevel(int Value, string? Color = null);
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Epsilon.Canvas.Abstractions.Model;
using Epsilon.Canvas.Abstractions.QueryResponse;
HansenSven marked this conversation as resolved.
Show resolved Hide resolved

namespace Epsilon.Canvas.Abstractions;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Text.Json.Serialization;

namespace Epsilon.Canvas.Abstractions.QueryResponse;

public record GetUserSubmissionOutcomes(
HansenSven marked this conversation as resolved.
Show resolved Hide resolved
[property: JsonPropertyName("data")] CourseData? Data
);

public record CourseData(
[property: JsonPropertyName("course")] Course? Course
);

public record Course(
[property: JsonPropertyName("name")] string Name,
[property: JsonPropertyName("submissionsConnection")] SubmissionsConnection? SubmissionsConnection
);

public record SubmissionsConnection(
[property: JsonPropertyName("nodes")] List<Node>? Nodes
);

public record Node(
[property: JsonPropertyName("assignment")] Assignment? Assignment,
[property: JsonPropertyName("rubricAssessmentsConnection")] RubricAssessmentsConnection? RubricAssessmentsConnection
);

public record Assignment(
[property: JsonPropertyName("name")] string Name,
[property: JsonPropertyName("modules")] List<Module>? Modules
);

public record Module(
[property: JsonPropertyName("name")] string Name
);

public record RubricAssessmentsConnection(
[property: JsonPropertyName("nodes")] List<RubricAssessmentNode>? Nodes
);

public record RubricAssessmentNode(
[property: JsonPropertyName("assessmentRatings")] List<AssessmentRating>? AssessmentRatings,
[property: JsonPropertyName("user")] User? User
);

public record AssessmentRating(
[property: JsonPropertyName("points")] double? Points,
[property: JsonPropertyName("outcome")] Outcome? Outcome
);

public record Outcome(
[property: JsonPropertyName("title")] string Title
);

public record User(
[property: JsonPropertyName("name")] string Name
);
6 changes: 6 additions & 0 deletions Epsilon.Canvas.Abstractions/Service/IGraphQlHttpService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Epsilon.Canvas.Abstractions.Service;

public interface IGraphQlHttpService
{
public Task<T?> Query<T>(string query);
}
1 change: 1 addition & 0 deletions Epsilon.Canvas/CanvasModuleCollectionFetcher.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Diagnostics;
using Epsilon.Canvas.Abstractions;
using Epsilon.Canvas.Abstractions.Model;
using Epsilon.Canvas.Abstractions.QueryResponse;
using Epsilon.Canvas.Abstractions.Service;
using Microsoft.Extensions.Logging;

Expand Down
1 change: 1 addition & 0 deletions Epsilon.Canvas/CanvasServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public static IServiceCollection AddCanvas(this IServiceCollection services, ICo
services.AddHttpClient<IAssignmentHttpService, AssignmentHttpService>(CanvasHttpClient);
services.AddHttpClient<IOutcomeHttpService, OutcomeHttpService>(CanvasHttpClient);
services.AddHttpClient<ISubmissionHttpService, SubmissionHttpService>(CanvasHttpClient);
services.AddHttpClient<IGraphQlHttpService, GraphQlHttpService>(CanvasHttpClient);

services.AddScoped<ILinkHeaderConverter, LinkHeaderConverter>();

Expand Down
35 changes: 35 additions & 0 deletions Epsilon.Canvas/QueryConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace Epsilon.Canvas;

public static class QueryConstants
{
public const string GetUserSubmissionOutcomes = @"
query GetUserSubmissionOutcomes {
course(id: $courseId) {
name
submissionsConnection {
nodes {
assignment {
name
modules {
name
}
}
rubricAssessmentsConnection {
nodes {
assessmentRatings {
points
outcome {
title
}
}
user {
name
}
}
}
}
}
}
}
";
}
22 changes: 22 additions & 0 deletions Epsilon.Canvas/Service/GraphQlHttpService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Net.Http.Json;
using Epsilon.Abstractions.Http;
using Epsilon.Canvas.Abstractions.Service;

namespace Epsilon.Canvas.Service;

public class GraphQlHttpService : HttpService, IGraphQlHttpService
{
public GraphQlHttpService(HttpClient client) : base(client)
{ }

public async Task<T?> Query<T>(string query)
{
var request = new HttpRequestMessage(HttpMethod.Post, "/api/graphql") {
Content = new FormUrlEncodedContent(new Dictionary<string, string>() {{"query", query}})
};

var response = await Client.SendAsync(request);

return await response.Content.ReadFromJsonAsync<T>();
}
}
65 changes: 65 additions & 0 deletions Epsilon.Host.WebApi/Controllers/ComponentController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using Epsilon.Abstractions.Model;
using Epsilon.Canvas;
using Epsilon.Canvas.Abstractions;
using Epsilon.Canvas.Abstractions.QueryResponse;
using Epsilon.Canvas.Abstractions.Service;
using Microsoft.AspNetCore.Mvc;

namespace Epsilon.Host.WebApi.Controllers;

[ApiController]
[Route("component")]
public class ComponentController : ControllerBase
{
private readonly IGraphQlHttpService _graphQlService;
private readonly IConfiguration _configuration;

public ComponentController(IGraphQlHttpService graphQlService, IConfiguration configuration)
{
_graphQlService = graphQlService;
_configuration = configuration;
}

[HttpGet("competence_profile")]
public ActionResult<GetUserSubmissionOutcomes> GetCompetenceProfile([FromQuery] DateTime startDate, [FromQuery] DateTime endDate)
{
var courseId = _configuration["Canvas:CourseId"];
var query = QueryConstants.GetUserSubmissionOutcomes.Replace("$courseId", courseId);

return _graphQlService.Query<GetUserSubmissionOutcomes>(query).Result!;
}

[HttpGet("competence_profile_mock")]
public ActionResult<CompetenceProfile> GetMockCompetenceProfile([FromQuery] DateTime startDate, [FromQuery] DateTime endDate)
{
var competenceProfileOutcomes = new List<CompetenceProfileOutcome>();
for (var i = 0; i < 5; i++)
{
competenceProfileOutcomes.Add(GetRandomCompetenceProfileOutcome());
}

return new CompetenceProfile(
HboIDomain.HboIDomain2018,
competenceProfileOutcomes
);
}

private static CompetenceProfileOutcome GetRandomCompetenceProfileOutcome()
{
return new CompetenceProfileOutcome(
GetRandom(HboIDomain.HboIDomain2018.ArchitectureLayers).Value,
GetRandom(HboIDomain.HboIDomain2018.Activities).Value,
GetRandom(HboIDomain.HboIDomain2018.MasteryLevels).Value,
GetRandom(new[] { 0, 3, 4, 5 }),
DateTime.Now
);
}

private static T GetRandom<T>(IEnumerable<T> items)
{
var random = new Random();
var itemsArray = items.ToArray();
var index = random.Next(0, itemsArray.Length);
return itemsArray.ElementAt(index);
}
HansenSven marked this conversation as resolved.
Show resolved Hide resolved
}
2 changes: 1 addition & 1 deletion Epsilon.Host.WebApi/Epsilon.Host.WebApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</ItemGroup>

<ItemGroup>
<Folder Include="Controllers" />
<ProjectReference Include="..\Epsilon\Epsilon.csproj" />
</ItemGroup>

</Project>
6 changes: 6 additions & 0 deletions Epsilon.Host.WebApi/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
using Epsilon.Canvas;
using Epsilon.Canvas.Abstractions.Service;
using Epsilon.Canvas.Service;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var canvasConfiguration = builder.Configuration.GetSection("Canvas");

builder.Services.AddCanvas(canvasConfiguration);
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
Expand Down
8 changes: 0 additions & 8 deletions Epsilon.Host.WebApi/appsettings.Development.json

This file was deleted.