Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ dotnet build
Confirm tests are passing locally
```sh
dotnet test
```
```

```sh
docker compose up --build -d
Expand Down
6 changes: 4 additions & 2 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
services:
web:
profiles: [web, all]
container_name: cypd_web
build:
context: ./src
Expand All @@ -10,7 +11,7 @@
environment:
- ASPNETCORE_ENVIRONMENT=${ASPNETCORE_ENVIRONMENT:-Development}
- ASPNETCORE_URLS=http://+:8080
- ConnectionStrings__Postgres=${POSTGRES_CONNECTION_STRING:-Host=db;Database=helloworld;Username=postgres;Password=postgres}
- ConnectionStrings__Postgres=${POSTGRES_CONNECTION_STRING:-Host=db;Database=cypd;Username=postgres;Password=postgres}
- ConnectionStrings__AzureStorage=${AZURE_STORAGE_CONNECTION_STRING:-DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;QueueEndpoint=http://azurite:10001/devstoreaccount1;}
- DfeSignIn__BaseUrl=${DFESIGNIN_BASEURL:-https://test-api.signin.education.gov.uk/}
- DfeSignIn__ClientId=${DFESIGNIN_CLIENTID}
Expand All @@ -24,6 +25,7 @@
- azurite

rules_engine:
profiles: [rules_engine, all]
container_name: cypd_rules_engine
build:
context: ./src
Expand Down Expand Up @@ -52,7 +54,7 @@
container_name: cypd_db
image: postgres:16
environment:
- POSTGRES_DB=helloworld
- POSTGRES_DB=cypd
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
ports:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Security.Claims;
using System.Text.Json.Nodes;
using DfE.CheckPerformanceData.Application.DfESignInApiClient;

namespace DfE.CheckPerformanceData.Application.ClaimsEnrichment;

public interface IClaimsEnrichmentService
{
Task EnrichAsync(ClaimsIdentity identity);
}


public class ClaimsEnrichmentService: IClaimsEnrichmentService
{
private readonly IDfESignInApiClient _apiClient;

public ClaimsEnrichmentService(IDfESignInApiClient apiClient)
{
_apiClient = apiClient;
}
public async Task EnrichAsync(ClaimsIdentity identity)
{
var userid = identity.FindFirst(ClaimTypes.NameIdentifier)?.Value;

var orgJson = identity.FindFirst("organisation")?.Value ?? "{}";
var org = JsonNode.Parse(orgJson);
var orgId = org["id"]?.ToString() ?? string.Empty;

Check warning on line 27 in src/DfE.CheckPerformanceData.Application/ClaimsEnrichment/IClaimsEnrichmentService.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

var organisation = await _apiClient.GetOrganisationAsync(userid, orgId);

Check warning on line 29 in src/DfE.CheckPerformanceData.Application/ClaimsEnrichment/IClaimsEnrichmentService.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'userId' in 'Task<OrganisationDto?> IDfESignInApiClient.GetOrganisationAsync(string userId, string organisationId)'.

identity.AddClaim(new Claim("low_age", organisation.StatutoryLowAge.ToString()));

Check warning on line 31 in src/DfE.CheckPerformanceData.Application/ClaimsEnrichment/IClaimsEnrichmentService.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'value' in 'Claim.Claim(string type, string value)'.

Check warning on line 31 in src/DfE.CheckPerformanceData.Application/ClaimsEnrichment/IClaimsEnrichmentService.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.
identity.AddClaim(new Claim("high_age", organisation.StatutoryHighAge.ToString()));

Check warning on line 32 in src/DfE.CheckPerformanceData.Application/ClaimsEnrichment/IClaimsEnrichmentService.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'value' in 'Claim.Claim(string type, string value)'.
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Text.Json.Serialization;

namespace DfE.CheckPerformanceData.Application.DfESignInApiClient;

public class OrganisationDto
{
public string Id { get; init; }

Check warning on line 7 in src/DfE.CheckPerformanceData.Application/DfESignInApiClient/OrganisationDto.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Id' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
public string Name { get; init; } = string.Empty;
public string? LegalName { get; init; }

Expand All @@ -18,6 +20,9 @@
public int? StatutoryHighAge { get; init; }
public string? LegacyId { get; init; }
public string? CompanyRegistrationNumber { get; init; }

[JsonIgnore]
public string? LAESTAB { get; set; }
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ namespace DfE.CheckPerformanceData.Application;

public interface IPortalDbContext
{
DbSet<Workflow> Workflows { get; }
DbSet<CheckingWindow> CheckingWindows { get; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}
17 changes: 17 additions & 0 deletions src/DfE.CheckPerformanceData.Domain/Entities/CheckingWindow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace DfE.CheckPerformanceData.Domain.Entities;

public class CheckingWindow
{
public int Id { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public OrganisationTypes OrganisationType { get; set; }
public string Title { get; set; }

Check warning on line 9 in src/DfE.CheckPerformanceData.Domain/Entities/CheckingWindow.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Title' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
}

public enum OrganisationTypes
{
KS2, //3-11
KS4, //11-16
Post16 //16-18
}
8 changes: 0 additions & 8 deletions src/DfE.CheckPerformanceData.Domain/Entities/Workflow.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,4 @@
<PackageReference Include="System.IdentityModel.Tokens.Jwt" />
</ItemGroup>

<ItemGroup>
<Folder Include="Persistence\Repositories\" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using DfE.CheckPerformanceData.Infrastructure.DfeSignInApiClient;
using System.Security.Claims;
using DfE.CheckPerformanceData.Application.ClaimsEnrichment;
using DfE.CheckPerformanceData.Infrastructure.DfeSignInApiClient;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.Configuration;
Expand Down Expand Up @@ -55,7 +57,20 @@ public static IServiceCollection AddDfeSignInAuthentication(this IServiceCollect
{
//ctx.HttpContext.Response.Headers.Add("Cache-Control", "no-store");
return Task.CompletedTask;
};
};

options.Events.OnUserInformationReceived = ctx =>
{
return Task.CompletedTask;
};

options.Events.OnTokenValidated = async ctx =>
{
var enrichmentService = ctx.HttpContext.RequestServices
.GetRequiredService<IClaimsEnrichmentService>();

await enrichmentService.EnrichAsync((ClaimsIdentity)ctx.Principal!.Identity!);
};
});

return services;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
using DfE.CheckPerformanceData.Application.DfESignInApiClient;

namespace DfE.CheckPerformanceData.Infrastructure.DfeSignInApiClient;
Expand All @@ -14,8 +16,38 @@ public DfeSignInApiClient(HttpClient httpClient)

public async Task<OrganisationDto?> GetOrganisationAsync(string userId, string organisationId)
{
var userOrganisations = await _httpClient.GetFromJsonAsync<List<OrganisationDto>>($"users/{userId}/organisations");
//var organisationsJson = await _httpClient.GetStringAsync($"users/{userId}/organisations");
var userOrganisations = await _httpClient.GetFromJsonAsync<List<OrganisationDto>>($"users/{userId}/organisations",
new JsonSerializerOptions()
{
Converters = { new OrganisationDtoJsonConverter() }
});

return userOrganisations?.FirstOrDefault(o => o.Id == organisationId);
}
}

public class OrganisationDtoJsonConverter : JsonConverter<OrganisationDto>
{
public override OrganisationDto Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using var document = JsonDocument.ParseValue(ref reader);
var root = document.RootElement;

var dto = JsonSerializer.Deserialize<OrganisationDto>(root.GetRawText(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });


if (root.TryGetProperty("localAuthority", out var localAuthorityElement))
{
var orgCode = localAuthorityElement.GetProperty("code").GetString();
var orgId = root.GetProperty("establishmentNumber").GetString();

dto.LAESTAB = $"{orgCode}{orgId}";
}

return dto;
}

public override void Write(Utf8JsonWriter writer, OrganisationDto value, JsonSerializerOptions options) =>
throw new NotImplementedException();
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;

#nullable disable

namespace DfE.CheckPerformanceData.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "CheckingWindows",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
StartDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
EndDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
OrganisationType = table.Column<int>(type: "integer", nullable: false),
Title = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CheckingWindows", x => x.Id);
});
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "CheckingWindows");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// <auto-generated />
using System;
using DfE.CheckPerformanceData.Infrastructure.Persistence;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;

#nullable disable

namespace DfE.CheckPerformanceData.Infrastructure.Migrations
{
[DbContext(typeof(PortalDbContext))]
partial class PortalDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);

NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);

modelBuilder.Entity("DfE.CheckPerformanceData.Domain.Entities.CheckingWindow", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");

NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));

b.Property<DateTime>("EndDate")
.HasColumnType("timestamp with time zone");

b.Property<int>("OrganisationType")
.HasColumnType("integer");

b.Property<DateTime>("StartDate")
.HasColumnType("timestamp with time zone");

b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");

b.HasKey("Id");

b.ToTable("CheckingWindows");
});
#pragma warning restore 612, 618
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ namespace DfE.CheckPerformanceData.Infrastructure.Persistence;

public class PortalDbContext(DbContextOptions<PortalDbContext> options) : DbContext(options), IPortalDbContext
{
public DbSet<Workflow> Workflows => Set<Workflow>();
public DbSet<CheckingWindow> CheckingWindows => Set<CheckingWindow>();
}
Loading
Loading