Skip to content

Commit

Permalink
Merge pull request #517 from DFE-Digital/connect-fiat-db-to-ui
Browse files Browse the repository at this point in the history
Connect fiat db to UI
  • Loading branch information
dneed-nimble authored Sep 26, 2024
2 parents a550133 + 952eaec commit f0640a3
Show file tree
Hide file tree
Showing 37 changed files with 549 additions and 167 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

- Ofsted data now uses inspection start date as inspection date
- Reduced the load time of the Trust overview page
- DfE contacts now get their data from Fiat Db instead of academies Db
- Edited contacts are now saved to the database

## [Release-7][release-7] (production-2024-09-23.3213)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,9 @@ public static IQueryable<GiasGovernance> FilterBySatOrMat(string uid, string? ur

public async Task<TrustContacts> GetTrustContactsAsync(string uid, string? urn = null)
{
var trm = await GetTrustRelationshipManagerLinkedTo(uid);
var sfso = await GetSfsoLeadLinkedTo(uid);
var governanceContacts = await GetGovernanceContactsAsync(uid, urn);

return new TrustContacts(
trm,
sfso,
governanceContacts.GetValueOrDefault("Accounting Officer"),
governanceContacts.GetValueOrDefault("Chair of Trustees"),
governanceContacts.GetValueOrDefault("Chief Financial Officer"));
Expand Down Expand Up @@ -131,26 +127,6 @@ private static string GetFullName(string forename1, string forename2, string sur
return fullName;
}

private async Task<Person?> GetTrustRelationshipManagerLinkedTo(string uid)
{
return await academiesDbContext.CdmAccounts
.Where(a => a.SipUid == uid)
.Join(academiesDbContext.CdmSystemusers, account => account.SipTrustrelationshipmanager,
systemuser => systemuser.Systemuserid,
(_, systemuser) => new Person(systemuser.Fullname!, systemuser.Internalemailaddress))
.SingleOrDefaultAsync();
}

private async Task<Person?> GetSfsoLeadLinkedTo(string uid)
{
return await academiesDbContext.CdmAccounts
.Where(a => a.SipUid == uid)
.Join(academiesDbContext.CdmSystemusers, account => account.SipAmsdlead,
systemuser => systemuser.Systemuserid,
(_, systemuser) => new Person(systemuser.Fullname!, systemuser.Internalemailaddress))
.SingleOrDefaultAsync();
}

private async Task<Dictionary<string, Person>> GetGovernanceContactsAsync(string uid, string? urn = null)
{
string[] roles = { "Chair of Trustees", "Accounting Officer", "Chief Financial Officer" };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,25 @@

namespace DfE.FindInformationAcademiesTrusts.Data.FiatDb.Contexts;

public interface IFiatDbContext
{
DbSet<Contact> Contacts { get; set; }
Task<int> SaveChangesAsync();
}

[ExcludeFromCodeCoverage(Justification = "Difficult to unit test")]
public sealed class FiatDbContext(
DbContextOptions<FiatDbContext> options,
SetChangedByInterceptor setChangedByInterceptor)
: DbContext(options)
: DbContext(options), IFiatDbContext
{
public DbSet<Contact> Contacts { get; set; }

public async Task<int> SaveChangesAsync()
{
return await base.SaveChangesAsync();
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.AddInterceptors(setChangedByInterceptor);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using DfE.FindInformationAcademiesTrusts.Data.Enums;
using DfE.FindInformationAcademiesTrusts.Data.FiatDb.Contexts;
using DfE.FindInformationAcademiesTrusts.Data.FiatDb.Models;
using DfE.FindInformationAcademiesTrusts.Data.Repositories.Contacts;
using DfE.FindInformationAcademiesTrusts.Data.Repositories.Trust;
using Microsoft.EntityFrameworkCore;

namespace DfE.FindInformationAcademiesTrusts.Data.FiatDb.Repositories;

public interface IContactRepository
{
Task<InternalContacts> GetInternalContactsAsync(string uid);

Task<TrustContactUpdated> UpdateInternalContactsAsync(int uid, string? name, string? email,
ContactRole role);
}

public class ContactRepository(IFiatDbContext fiatDbContext) : IContactRepository
{
public async Task<InternalContacts> GetInternalContactsAsync(string uid)
{
var trm = await GetTrustRelationshipManagerLinkedTo(uid);
var sfso = await GetSfsoLeadLinkedTo(uid);

return new InternalContacts(
trm,
sfso);
}

public async Task<TrustContactUpdated> UpdateInternalContactsAsync(int uid, string? name, string? email,
ContactRole role)
{
var emailUpdated = false;
var nameUpdated = false;
var contact =
await fiatDbContext.Contacts.SingleOrDefaultAsync(contact => contact.Uid == uid && contact.Role == role);
if (contact is null)
{
fiatDbContext.Contacts.Add(new Contact
{ Name = name ?? string.Empty, Email = email ?? string.Empty, Role = role, Uid = uid });
}
else
{
if (contact.Name != name)
{
nameUpdated = true;
contact.Name = name ?? string.Empty;
}

if (contact.Email != email)
{
emailUpdated = true;
contact.Email = email ?? string.Empty;
}
}

await fiatDbContext.SaveChangesAsync();
return new TrustContactUpdated(emailUpdated, nameUpdated);
}

private async Task<InternalContact?> GetTrustRelationshipManagerLinkedTo(string uid)
{
return await fiatDbContext.Contacts.Where(contact =>
contact.Uid == int.Parse(uid) && contact.Role == ContactRole.TrustRelationshipManager)
.Select(contact => new InternalContact(contact.Name, contact.Email,
contact.LastModifiedAtTime, contact.LastModifiedByEmail
)).SingleOrDefaultAsync();
}

private async Task<InternalContact?> GetSfsoLeadLinkedTo(string uid)
{
return await fiatDbContext.Contacts.Where(contact =>
contact.Uid == int.Parse(uid) && contact.Role == ContactRole.SfsoLead)
.Select(contact => new InternalContact(contact.Name, contact.Email,
contact.LastModifiedAtTime, contact.LastModifiedByEmail
)).SingleOrDefaultAsync();
}
}
3 changes: 2 additions & 1 deletion DfE.FindInformationAcademiesTrusts.Data/Enums/Source.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ public enum Source
Mstr,
Cdm,
Mis,
ExploreEducationStatistics
ExploreEducationStatistics,
FiatDb
}
8 changes: 8 additions & 0 deletions DfE.FindInformationAcademiesTrusts.Data/InternalContact.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace DfE.FindInformationAcademiesTrusts.Data;

public record InternalContact(
string FullName,
string Email,
DateTime LastModifiedAtTime,
string LastModifiedByEmail
) : Person(FullName, Email);
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace DfE.FindInformationAcademiesTrusts.Data.Repositories.Contacts;

public record InternalContacts(
InternalContact? TrustRelationshipManager,
InternalContact? SfsoLead
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace DfE.FindInformationAcademiesTrusts.Data.Repositories.Trust;

public record TrustContactUpdated(
bool EmailUpdated,
bool NameUpdated);
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
namespace DfE.FindInformationAcademiesTrusts.Data.Repositories.Trust;

public record TrustContacts(
Person? TrustRelationshipManager,
Person? SfsoLead,
Person? AccountingOfficer,
Person? ChairOfTrustees,
Person? ChiefFinancialOfficer
Expand Down
9 changes: 8 additions & 1 deletion DfE.FindInformationAcademiesTrusts.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DfE.FindInformationAcademie
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DfE.FindInformationAcademiesTrusts.Data.Hardcoded.UnitTests", "tests\DfE.FindInformationAcademiesTrusts.Data.Hardcoded.UnitTests\DfE.FindInformationAcademiesTrusts.Data.Hardcoded.UnitTests.csproj", "{1DF57DAB-F9BA-4810-BD35-BB59996FF7BB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DfE.FindInformationAcademiesTrusts.Data.FiatDb", "DfE.FindInformationAcademiesTrusts.Data.FiatDb\DfE.FindInformationAcademiesTrusts.Data.FiatDb.csproj", "{70A05478-BB89-4051-A38E-F18A4DD5DF64}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DfE.FindInformationAcademiesTrusts.Data.FiatDb", "DfE.FindInformationAcademiesTrusts.Data.FiatDb\DfE.FindInformationAcademiesTrusts.Data.FiatDb.csproj", "{70A05478-BB89-4051-A38E-F18A4DD5DF64}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DfE.FindInformationAcademiesTrusts.Data.FiatDb.UnitTests", "tests\DfE.FindInformationAcademiesTrusts.Data.FiatDb.UnitTests\DfE.FindInformationAcademiesTrusts.Data.FiatDb.UnitTests.csproj", "{187B33C1-628B-4FF4-9A7E-C775F23F6699}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -65,6 +67,10 @@ Global
{70A05478-BB89-4051-A38E-F18A4DD5DF64}.Debug|Any CPU.Build.0 = Debug|Any CPU
{70A05478-BB89-4051-A38E-F18A4DD5DF64}.Release|Any CPU.ActiveCfg = Release|Any CPU
{70A05478-BB89-4051-A38E-F18A4DD5DF64}.Release|Any CPU.Build.0 = Release|Any CPU
{187B33C1-628B-4FF4-9A7E-C775F23F6699}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{187B33C1-628B-4FF4-9A7E-C775F23F6699}.Debug|Any CPU.Build.0 = Debug|Any CPU
{187B33C1-628B-4FF4-9A7E-C775F23F6699}.Release|Any CPU.ActiveCfg = Release|Any CPU
{187B33C1-628B-4FF4-9A7E-C775F23F6699}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -74,6 +80,7 @@ Global
{E20D30CB-8EB1-453B-8C49-77CAFBF16A13} = {E22DC2DA-4EB5-41C6-A41D-349692BCCDBE}
{90AA9D53-B5B0-489F-AEC1-23551EA04BC5} = {E22DC2DA-4EB5-41C6-A41D-349692BCCDBE}
{1DF57DAB-F9BA-4810-BD35-BB59996FF7BB} = {E22DC2DA-4EB5-41C6-A41D-349692BCCDBE}
{187B33C1-628B-4FF4-9A7E-C775F23F6699} = {E22DC2DA-4EB5-41C6-A41D-349692BCCDBE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CEE3F8EE-1688-4C85-8749-E2B3FCB9A5FE}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using DfE.FindInformationAcademiesTrusts.Data.Enums;

namespace DfE.FindInformationAcademiesTrusts.Extensions;

public static class ContactRoleExtensions
{
public static string MapRoleToViewString(this ContactRole role)
{
return role switch
{
ContactRole.TrustRelationshipManager => "Trust relationship manager",
ContactRole.SfsoLead => "SFSO (Schools financial support and oversight) lead",
_ => throw new ArgumentOutOfRangeException(nameof(role))
};
}
}
12 changes: 7 additions & 5 deletions DfE.FindInformationAcademiesTrusts/Pages/Trusts/Contacts.cshtml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
@page
@using DfE.FindInformationAcademiesTrusts.Configuration
@using DfE.FindInformationAcademiesTrusts.Data
@using DfE.FindInformationAcademiesTrusts.Data.Enums
@using DfE.FindInformationAcademiesTrusts.Extensions
@model ContactsModel

@{
Expand Down Expand Up @@ -31,11 +33,11 @@
<div class="govuk-summary-card" data-testid="trust-relationship-manager">
<div class="govuk-summary-card__title-wrapper">
<h3 class="govuk-summary-card__title">
Trust relationship manager
@ContactRole.TrustRelationshipManager.MapRoleToViewString()
</h3>
<feature name="@FeatureFlags.EditContactsUI">
<div class="govuk-summary-card__actions">
<a class="govuk-link" asp-page="/Trusts/Contacts/EditTrustRelationshipManager" asp-route-uid="@Model.Uid">Change<span class="govuk-visually-hidden"> details of this contact (Trust relationship manager)</span></a>
<a class="govuk-link" asp-page="/Trusts/Contacts/EditTrustRelationshipManager" asp-route-uid="@Model.Uid">Change<span class="govuk-visually-hidden"> details of this contact (@ContactRole.TrustRelationshipManager.MapRoleToViewString())</span></a>
</div>
</feature>
</div>
Expand All @@ -44,11 +46,11 @@
<div class="govuk-summary-card" data-testid="sfso-lead">
<div class="govuk-summary-card__title-wrapper">
<h3 class="govuk-summary-card__title">
SFSO (Schools financial support and oversight) lead
@ContactRole.SfsoLead.MapRoleToViewString()
</h3>
<feature name="@FeatureFlags.EditContactsUI">
<div class="govuk-summary-card__actions">
<a class="govuk-link" asp-page="/Trusts/Contacts/EditSfsoLead" asp-route-uid="@Model.Uid">Change<span class="govuk-visually-hidden"> details of this contact (SFSO Lead)</span></a>
<a class="govuk-link" asp-page="/Trusts/Contacts/EditSfsoLead" asp-route-uid="@Model.Uid">Change<span class="govuk-visually-hidden"> details of this contact (@ContactRole.SfsoLead.MapRoleToViewString())</span></a>
</div>
</feature>
</div>
Expand Down Expand Up @@ -109,7 +111,7 @@
<dt class="govuk-summary-list__key">
Email address
</dt>
@if (contactToDisplay?.Email is not null)
@if (!string.IsNullOrWhiteSpace(contactToDisplay?.Email))
{
<dd class="govuk-summary-list__value">
<a class="govuk-link" href="mailto:@contactToDisplay.Email" rel="noopener" target="_blank" data-testid="contact-email">@contactToDisplay.Email</a>
Expand Down
18 changes: 14 additions & 4 deletions DfE.FindInformationAcademiesTrusts/Pages/Trusts/Contacts.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using DfE.FindInformationAcademiesTrusts.Data;
using DfE.FindInformationAcademiesTrusts.Data.Enums;
using DfE.FindInformationAcademiesTrusts.Extensions;
using DfE.FindInformationAcademiesTrusts.Services.DataSource;
using DfE.FindInformationAcademiesTrusts.Services.Trust;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -15,9 +16,9 @@ public class ContactsModel(
{
public Person? ChairOfTrustees { get; set; }
public Person? AccountingOfficer { get; set; }
public Person? SfsoLead { get; set; }
public Person? TrustRelationshipManager { get; set; }
public Person? ChiefFinancialOfficer { get; set; }
public InternalContact? SfsoLead { get; set; }
public InternalContact? TrustRelationshipManager { get; set; }

public const string ContactNameNotAvailableMessage = "No contact name available";

Expand All @@ -32,8 +33,17 @@ public override async Task<IActionResult> OnGetAsync()
(TrustRelationshipManager, SfsoLead, AccountingOfficer, ChairOfTrustees, ChiefFinancialOfficer) =
await TrustService.GetTrustContactsAsync(Uid);

DataSources.Add(new DataSourceListEntry(await DataSourceService.GetAsync(Source.Cdm),
new List<string> { "DfE contacts" }));
DataSources.Add(new DataSourceListEntry(
new DataSourceServiceModel(Source.FiatDb, TrustRelationshipManager?.LastModifiedAtTime, null,
TrustRelationshipManager?.LastModifiedByEmail),
new List<string>
{ ContactRole.TrustRelationshipManager.MapRoleToViewString() }));

DataSources.Add(new DataSourceListEntry(
new DataSourceServiceModel(Source.FiatDb, SfsoLead?.LastModifiedAtTime, null,
SfsoLead?.LastModifiedByEmail),
new List<string>
{ ContactRole.SfsoLead.MapRoleToViewString() }));

DataSources.Add(new DataSourceListEntry(await DataSourceService.GetAsync(Source.Gias), new List<string>
{ "Accounting officer name", "Chief financial officer name", "Chair of trustees name" }));
Expand Down
Loading

0 comments on commit f0640a3

Please sign in to comment.