Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get Establishment by Trust Repository method #410

Merged
merged 10 commits into from
Nov 9, 2023
Merged
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
9 changes: 8 additions & 1 deletion Dfe.Academies.Api.Infrastructure/MstrContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public MstrContext(DbContextOptions<MstrContext> options) : base(options)
public DbSet<TrustType> TrustTypes { get; set; } = null!;
public DbSet<Establishment> Establishments { get; set; } = null!;
public DbSet<EstablishmentType> EstablishmentTypes { get; set; } = null!;
public DbSet<EducationEstablishmentTrust> EducationEstablishmentTrusts { get; set; } = null!;
public DbSet<LocalAuthority> LocalAuthorities { get; set; } = null!;

public DbSet<IfdPipeline> IfdPipelines { get; set; } = null!;
Expand All @@ -31,6 +32,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)

modelBuilder.Entity<Establishment>(ConfigureEstablishment);
modelBuilder.Entity<EstablishmentType>(ConfigureEstablishmentType);
modelBuilder.Entity<EducationEstablishmentTrust>(ConfigureEducationEstablishmentTrust);
modelBuilder.Entity<LocalAuthority>(ConfigureLocalAuthority);
modelBuilder.Entity<IfdPipeline>(ConfigureIfdPipeline);

Expand Down Expand Up @@ -211,7 +213,12 @@ void ConfigureTrustType(EntityTypeBuilder<TrustType> trustTypeConfiguration)

trustTypeConfiguration.ToTable("Ref_TrustType", DEFAULT_SCHEMA);
}

private void ConfigureEducationEstablishmentTrust(EntityTypeBuilder<EducationEstablishmentTrust> entityBuilder)
{
entityBuilder.HasKey(e => e.SK);
entityBuilder.ToTable("EducationEstablishmentTrust", DEFAULT_SCHEMA);

}
void ConfigureLocalAuthority(EntityTypeBuilder<LocalAuthority> localAuthorityConfiguration)
{
localAuthorityConfiguration.HasKey(e => e.SK).HasName("SK");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Dfe.Academies.Academisation.Data.Repositories;
using Dfe.Academies.Domain.Establishment;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel;
using static System.Net.Mime.MediaTypeNames;

namespace Dfe.Academies.Infrastructure.Repositories
Expand All @@ -26,23 +27,23 @@ public EstablishmentRepository(MstrContext context) : base(context)
}
public async Task<List<Establishment>> Search(string name, string ukPrn, string urn, CancellationToken cancellationToken)
{
IQueryable<Establishment> query = DefaultIncludes();

query = !string.IsNullOrEmpty(name)
? query.Where(establishment => establishment.EstablishmentName.Contains(name))
: query;

query = !string.IsNullOrEmpty(ukPrn)
? query.Where(establishment => establishment.UKPRN.Contains(ukPrn))
: query;

query = !string.IsNullOrEmpty(urn)
? query.Where(establishment => establishment.URN.ToString().Contains(urn))
: query;

return await query.OrderBy(establishment => establishment.SK)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
IQueryable<Establishment> query = DefaultIncludes().AsNoTracking();
if (!string.IsNullOrEmpty(name))
{
query = query.Where(e => e.EstablishmentName.Contains(name));
}
if (!string.IsNullOrEmpty(ukPrn))
{
query = query.Where(e => e.UKPRN == ukPrn);
}
if (!string.IsNullOrEmpty(urn))
{
if (int.TryParse(urn, out var urnAsNumber))
{
query = query.Where(e => e.URN == urnAsNumber);
}
}
return await query.ToListAsync(cancellationToken);
}
public async Task<IEnumerable<int>> GetURNsByRegion(string[] regions, CancellationToken cancellationToken)
{
Expand All @@ -62,6 +63,25 @@ public async Task<List<Establishment>> GetByUrns(int[] urns, CancellationToken c
.ToListAsync(cancellationToken);
}

public async Task<List<Establishment>> GetByTrust(long? trustId, CancellationToken cancellationToken)
{
var establishmentIds = await context.EducationEstablishmentTrusts
.Where(eet => eet.FK_Trust == Convert.ToInt32(trustId))
.Select(eet => (long)eet.FK_EducationEstablishment)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);

var establishments = await DefaultIncludes()
.Where(e => establishmentIds.Contains(e.SK))
.ToListAsync(cancellationToken)
.ConfigureAwait(false);


return establishments;
}



private IQueryable<Establishment> DefaultIncludes()
{
var x = dbSet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@

return trust;
}
public async Task<Trust?> GetTrustByCompaniesHouseNumber(string companiesHouseNumber, CancellationToken cancellationToken)
{
var trust = await dbSet
.Include(x => x.TrustType)
.SingleOrDefaultAsync(x => x.CompaniesHouseNumber == companiesHouseNumber).ConfigureAwait(false);

return trust;
}

public async Task<List<Trust>> GetTrustsByUkprns(string[] ukprns, CancellationToken cancellationToken)
{
Expand All @@ -37,8 +45,8 @@
}

IOrderedQueryable<Trust> filteredGroups = dbSet
.Where(trust => (trust.Name.Contains(name) ||

Check warning on line 48 in Dfe.Academies.Api.Infrastructure/Repositories/TrustRepository.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Dereference of a possibly null reference.

Check warning on line 48 in Dfe.Academies.Api.Infrastructure/Repositories/TrustRepository.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Possible null reference argument for parameter 'value' in 'bool string.Contains(string value)'.
trust.UKPRN.Contains(ukPrn) ||

Check warning on line 49 in Dfe.Academies.Api.Infrastructure/Repositories/TrustRepository.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Dereference of a possibly null reference.

Check warning on line 49 in Dfe.Academies.Api.Infrastructure/Repositories/TrustRepository.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Possible null reference argument for parameter 'value' in 'bool string.Contains(string value)'.
trust.CompaniesHouseNumber.Contains(companiesHouseNumber))
&& (
trust.TrustType.Name == "Single-academy trust" ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ public async Task GetByUkprn_WhenEstablishmentReturnedFromRepo_EstablishmentDtoI
// Arrange
var establishment = _fixture.Create<Domain.Establishment.Establishment?>();
var mockRepo = new Mock<IEstablishmentRepository>();
var mockTrustRepo = new Mock<ITrustRepository>();

string ukprn = "1010101";
mockRepo.Setup(x => x.GetEstablishmentByUkprn(It.Is<string>(v => v == ukprn), It.IsAny<CancellationToken>())).Returns(Task.FromResult(establishment));

var establishmentQueries = new EstablishmentQueries(
mockRepo.Object);
mockRepo.Object, mockTrustRepo.Object);

CancellationToken cancellationToken = default(global::System.Threading.CancellationToken);

Expand All @@ -51,11 +53,12 @@ public async Task GetByUrn_WhenEstablishmentReturnedFromRepo_EstablishmentDtoIsR
// Arrange
var establishment = _fixture.Create<Domain.Establishment.Establishment?>();
var mockRepo = new Mock<IEstablishmentRepository>();
var mockTrustRepo = new Mock<ITrustRepository>();
string urn = "1010101";
mockRepo.Setup(x => x.GetEstablishmentByUrn(It.Is<string>(v => v == urn), It.IsAny<CancellationToken>())).Returns(Task.FromResult(establishment));

var establishmentQueries = new EstablishmentQueries(
mockRepo.Object);
mockRepo.Object, mockTrustRepo.Object);

CancellationToken cancellationToken = default(global::System.Threading.CancellationToken);

Expand All @@ -75,13 +78,14 @@ public async Task Search_WhenEstablishmentsReturnedFromRepo_EstablishmentDtoList
// Arrange
var establishments = _fixture.Create<List<Domain.Establishment.Establishment>>();
var mockRepo = new Mock<IEstablishmentRepository>();
var mockTrustRepo = new Mock<ITrustRepository>();
string urn = "1010101";
string name = "Test name";
string ukPrn = "Test UkPrn";
mockRepo.Setup(x => x.Search(It.Is<string>(v => v == name), It.Is<string>(v => v == ukPrn), It.Is<string>(v => v == urn), It.IsAny<CancellationToken>())).Returns(Task.FromResult(establishments));

var establishmentQueries = new EstablishmentQueries(
mockRepo.Object);
mockRepo.Object, mockTrustRepo.Object);

CancellationToken cancellationToken = default(global::System.Threading.CancellationToken);

Expand All @@ -107,10 +111,11 @@ public async Task GetURNsByRegion_WhenEstablishmentUrnsReturnedFromRepo_IEnumebr
string[] regions = _fixture.Create<string[]>();
var establishmentUrns = _fixture.Create<List<int>>().AsEnumerable();
var mockRepo = new Mock<IEstablishmentRepository>();
var mockTrustRepo = new Mock<ITrustRepository>();
mockRepo.Setup(x => x.GetURNsByRegion(It.Is<string[]>(v => v == regions), It.IsAny<CancellationToken>())).Returns(Task.FromResult(establishmentUrns));

var establishmentQueries = new EstablishmentQueries(
mockRepo.Object);
mockRepo.Object, mockTrustRepo.Object);
CancellationToken cancellationToken = default(global::System.Threading.CancellationToken);

// Act
Expand All @@ -131,10 +136,11 @@ public async Task GetByUrns_WhenEstablishmentsReturnedFromRepo_ListOfEstablishme
int[] Urns = _fixture.Create<int[]>();
var establishments = _fixture.Create<List<Domain.Establishment.Establishment>>();
var mockRepo = new Mock<IEstablishmentRepository>();
var mockTrustRepo = new Mock<ITrustRepository>();
mockRepo.Setup(x => x.GetByUrns(It.Is<int[]>(v => v == Urns), It.IsAny<CancellationToken>())).Returns(Task.FromResult(establishments));

var establishmentQueries = new EstablishmentQueries(
mockRepo.Object);
mockRepo.Object, mockTrustRepo.Object);
CancellationToken cancellationToken = default(global::System.Threading.CancellationToken);
// Act
var result = await establishmentQueries.GetByUrns(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@
using System.Threading;
using System;
using Dfe.Academies.Application.Builders;
using Dfe.Academies.Domain.Trust;

namespace Dfe.Academies.Application.Queries.Establishment
{
public class EstablishmentQueries : IEstablishmentQueries
{
private readonly IEstablishmentRepository _establishmentRepository;
private readonly ITrustRepository _trustRepository;

public EstablishmentQueries(IEstablishmentRepository establishmentRepository)
public EstablishmentQueries(IEstablishmentRepository establishmentRepository, ITrustRepository trustRepository)
{
_establishmentRepository = establishmentRepository;
_trustRepository = trustRepository;
}
public async Task<EstablishmentDto?> GetByUkprn(string ukprn, CancellationToken cancellationToken)
{
Expand All @@ -37,6 +40,12 @@ public async Task<IEnumerable<int>> GetURNsByRegion(string[] regions, Cancellati

return URNs;
}
public async Task<List<EstablishmentDto>> GetByTrust(string trustUkprn, CancellationToken cancellationToken)
{
var trust = await _trustRepository.GetTrustByUkprn(trustUkprn, cancellationToken);
var establishments = await _establishmentRepository.GetByTrust(trust.SK, cancellationToken).ConfigureAwait(false);
return establishments.Select(MapToEstablishmentDto).ToList();
}
public async Task<List<EstablishmentDto>> GetByUrns(int[] Urns, CancellationToken cancellationToken)
{
var establishments = await _establishmentRepository.GetByUrns(Urns, cancellationToken).ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public interface IEstablishmentQueries
Task<EstablishmentDto?> GetByUrn(string urn, CancellationToken cancellationToken);
Task<(List<EstablishmentDto>, int)> Search(string name, string ukPrn, string urn, CancellationToken cancellationToken);
Task<IEnumerable<int>> GetURNsByRegion(string[] regions, CancellationToken cancellationToken);
Task<List<EstablishmentDto>> GetByUrns(int[] Urns, CancellationToken cancellationToken);
Task<List<EstablishmentDto>> GetByUrns(int[] Urns, CancellationToken cancellationToken);
Task<List<EstablishmentDto>> GetByTrust(string trustUkprn, CancellationToken cancellationToken);
}
}
1 change: 1 addition & 0 deletions Dfe.Academies.Application/Queries/Trust/ITrustQueries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Dfe.Academies.Application.Queries.Trust
public interface ITrustQueries
{
Task<TrustDto?> GetByUkprn(string ukprn, CancellationToken cancellationToken);
Task<TrustDto?> GetByCompaniesHouseNumber(string companiesHouseNumber, CancellationToken cancellationToken);
Task<List<TrustDto>> GetByUkprns(string[] ukprns, CancellationToken cancellationToken);
Task<(List<TrustDto>, int)> Search(int page, int count, string name, string ukPrn, string companiesHouseNumber, CancellationToken cancellationToken);
}
Expand Down
5 changes: 5 additions & 0 deletions Dfe.Academies.Application/Queries/Trust/TrustQueries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ public TrustQueries(ITrustRepository trustRepository)
var trust = await _trustRepository.GetTrustByUkprn(ukprn, cancellationToken).ConfigureAwait(false);
return trust == null ? null : MapToTrustDto(trust);
}
public async Task<TrustDto?> GetByCompaniesHouseNumber(string companiesHouseNumber, CancellationToken cancellationToken)
{
var trust = await _trustRepository.GetTrustByCompaniesHouseNumber(companiesHouseNumber, cancellationToken).ConfigureAwait(false);
return trust == null ? null : MapToTrustDto(trust);
}

public async Task<(List<TrustDto>, int)> Search(int page, int count, string name, string ukPrn, string companiesHouseNumber, CancellationToken cancellationToken)
{
Expand Down
22 changes: 22 additions & 0 deletions Dfe.Academies.Domain/Establishment/EducationEstablishmentTrust.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dfe.Academies.Domain.Establishment
{
public class EducationEstablishmentTrust
{
public int SK { get; set; }

// Foreign keys
public int FK_Trust { get; set; }
public int FK_EducationEstablishment { get; set; }

// Navigation properties
public virtual Trust.Trust Trust { get; set; }

Check warning on line 18 in Dfe.Academies.Domain/Establishment/EducationEstablishmentTrust.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Non-nullable property 'Trust' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public virtual Establishment Establishment { get; set; }

Check warning on line 19 in Dfe.Academies.Domain/Establishment/EducationEstablishmentTrust.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Non-nullable property 'Establishment' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ public interface IEstablishmentRepository : IGenericRepository<Establishment>
Task<Establishment?> GetEstablishmentByUrn(string urn, CancellationToken cancellationToken);
Task<List<Establishment>> Search(string name, string ukPrn,
string urn, CancellationToken cancellationToken);
Task<IEnumerable<int>> GetURNsByRegion(string[] regions, CancellationToken cancellationToken);
Task<IEnumerable<int>> GetURNsByRegion(string[] regions, CancellationToken cancellationToken);
Task<List<Establishment>> GetByTrust(long? trustId, CancellationToken cancellationToken);
Task<List<Establishment>> GetByUrns(int[] Urns, CancellationToken cancellationToken);
}
}
1 change: 1 addition & 0 deletions Dfe.Academies.Domain/Trust/ITrustRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Dfe.Academies.Domain.Trust
public interface ITrustRepository : IGenericRepository<Trust>
{
Task<Trust?> GetTrustByUkprn(string ukprn, CancellationToken cancellationToken);
Task<Trust?> GetTrustByCompaniesHouseNumber(string companiesHouseNumber, CancellationToken cancellationToken);
Task<List<Trust>> GetTrustsByUkprns(string[] ukprns, CancellationToken cancellationToken);
Task<List<Trust>> Search(int page, int count, string name, string ukPrn,
string companiesHouseNumber, CancellationToken cancellationToken);
Expand Down
28 changes: 28 additions & 0 deletions TramsDataApi/Controllers/V4/EstablishmentsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,5 +168,33 @@
var response = new List<EstablishmentDto>(establishments);
return Ok(response);
}
/// <summary>
/// Retrieves a list of establishments by their Trust UK Provider Reference Number (UKPRN) identifier.
/// </summary>
/// <param name="trustUkprn">Contains the Trust UK Provider Reference Number (UKPRN) identifier of the establishments.</param>
/// /// <param name="cancellationToken"></param>
/// <returns>List of establishments or NotFound if none are available.</returns>
[HttpGet]
[Route("establishments/trust")]
[SwaggerOperation(Summary = "Get Establishments by Trust", Description = "Returns a list of establishments specified by Trust UKPRN.")]
[SwaggerResponse(200, "Successfully found and returned the establishments.")]
[SwaggerResponse(404, "Establishments with specified Trust UKPRN not found.")]
public async Task<ActionResult<List<EstablishmentDto>>> GetByTrust([FromQuery] string trustUkprn, CancellationToken cancellationToken)
{
var commaSeparatedRequestTrust = string.Join(",", trustUkprn);
_logger.LogInformation($"Attemping to get establishments by Trust UKPRN : {commaSeparatedRequestTrust}");

Check notice

Code scanning / SonarCloud

Logging should not be vulnerable to injection attacks Low

Change this code to not log user-controlled data. See more on SonarCloud

var establishments = await _establishmentQueries.GetByTrust(trustUkprn, cancellationToken).ConfigureAwait(false);

if (establishments == null)
{
_logger.LogInformation($"No establishment was found with the requested Trust UKPRN : {commaSeparatedRequestTrust}");

Check notice

Code scanning / SonarCloud

Logging should not be vulnerable to injection attacks Low

Change this code to not log user-controlled data. See more on SonarCloud
return NotFound();
}

_logger.LogInformation($"Returning Establishments for Trust with specific UKPRN : {commaSeparatedRequestTrust}");

Check notice

Code scanning / SonarCloud

Logging should not be vulnerable to injection attacks Low

Change this code to not log user-controlled data. See more on SonarCloud
var response = new List<EstablishmentDto>(establishments);
return Ok(response);
}
}
}
26 changes: 26 additions & 0 deletions TramsDataApi/Controllers/V4/TrustsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,32 @@
_logger.LogDebug(JsonSerializer.Serialize(trust));
return Ok(trust);
}
/// <summary>
/// Retrieves a Trust by its Companies House Number.
/// </summary>
/// <param name="companiesHouseNumber">The Companies House Number identifier.</param>
/// <param name="cancellationToken"></param>
/// <returns>A Trust or NotFound if not available.</returns>
[HttpGet]
[Route("trust/{companiesHouseNumber}")]
[SwaggerOperation(Summary = "Retrieve Trust by Companies House Number", Description = "Returns a Trust identified by Companies House Number.")]
[SwaggerResponse(200, "Successfully found and returned the Trust.")]
[SwaggerResponse(404, "Trust with specified Companies House Number not found.")]
public async Task<ActionResult<TrustDto>> GetTrustByCompaniesHouseNumber(string companiesHouseNumber, CancellationToken cancellationToken)
{
_logger.LogInformation($"Attempting to get trust by Companies House Number {companiesHouseNumber}");

Check notice

Code scanning / SonarCloud

Logging should not be vulnerable to injection attacks Low

Change this code to not log user-controlled data. See more on SonarCloud
var trust = await _trustQueries.GetByCompaniesHouseNumber(companiesHouseNumber, cancellationToken).ConfigureAwait(false);

if (trust == null)
{
_logger.LogInformation($"No trust found for Companies House Number {companiesHouseNumber}");

Check notice

Code scanning / SonarCloud

Logging should not be vulnerable to injection attacks Low

Change this code to not log user-controlled data. See more on SonarCloud
return NotFound();
}

_logger.LogInformation($"Returning trust found by Companies House Number {companiesHouseNumber}");

Check notice

Code scanning / SonarCloud

Logging should not be vulnerable to injection attacks Low

Change this code to not log user-controlled data. See more on SonarCloud
_logger.LogDebug(JsonSerializer.Serialize(trust));
return Ok(trust);
}

/// <summary>
/// Searches for Trusts based on query parameters.
Expand Down
Loading