Skip to content

Commit

Permalink
Merge pull request #447 from DFE-Digital/feature/152436-allow-non-ope…
Browse files Browse the repository at this point in the history
…n-trusts-to-be-searched-for

152436 Allow Trusts that do not have a status of Open to be searched for
  • Loading branch information
nwarms authored Jan 26, 2024
2 parents a042d30 + f18ada3 commit 5c274c7
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 29 deletions.
56 changes: 36 additions & 20 deletions Dfe.Academies.Api.Infrastructure/Repositories/TrustRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,19 @@ public TrustRepository(MstrContext context)

return trust;
}
public async Task<Trust?> GetTrustByCompaniesHouseNumber(string companiesHouseNumber, CancellationToken cancellationToken)

public async Task<Trust?> GetTrustByCompaniesHouseNumber(string companiesHouseNumber,
CancellationToken cancellationToken)
{
var trust = await DefaultIncludes().AsNoTracking()
.SingleOrDefaultAsync(x => x.CompaniesHouseNumber == companiesHouseNumber, cancellationToken).ConfigureAwait(false);
.SingleOrDefaultAsync(x => x.CompaniesHouseNumber == companiesHouseNumber, cancellationToken)
.ConfigureAwait(false);

return trust;
}

public async Task<Trust?> GetTrustByTrustReferenceNumber(string trustReferenceNumber, CancellationToken cancellationToken)
public async Task<Trust?> GetTrustByTrustReferenceNumber(string trustReferenceNumber,
CancellationToken cancellationToken)
{
var trust = await DefaultIncludes().AsNoTracking()
.SingleOrDefaultAsync(x => x.GroupID == trustReferenceNumber, cancellationToken).ConfigureAwait(false);
Expand All @@ -38,32 +42,44 @@ public TrustRepository(MstrContext context)

public async Task<List<Trust>> GetTrustsByUkprns(string[] ukprns, CancellationToken cancellationToken)
{
var trusts = await DefaultIncludes().AsNoTracking().Where(x => ukprns.Contains(x.UKPRN)).ToListAsync(cancellationToken).ConfigureAwait(false);
var trusts = await DefaultIncludes().AsNoTracking().Where(x => ukprns.Contains(x.UKPRN))
.ToListAsync(cancellationToken).ConfigureAwait(false);

return trusts;
}

public async Task<(List<Trust>, int)> Search(int page, int count, string name, string ukPrn, string companiesHouseNumber, CancellationToken cancellationToken)
public async Task<(List<Trust>, int)> Search(int page, int count, string? name, string? ukPrn,
string? companiesHouseNumber, TrustStatus status, CancellationToken cancellationToken)
{
if (name == null && ukPrn == null && companiesHouseNumber == null)
{
IOrderedQueryable<Trust> allTrusts = DefaultIncludes().AsNoTracking().OrderBy(trust => trust.GroupUID);
IOrderedQueryable<Trust> allTrusts = DefaultIncludes().AsNoTracking().OrderBy(trust => trust.GroupUID);

return (await allTrusts.Skip((page - 1) * count)
.Take(count).ToListAsync(cancellationToken).ConfigureAwait(false), allTrusts.Count());
.Take(count).ToListAsync(cancellationToken).ConfigureAwait(false), allTrusts.Count());
}

IQueryable<Trust> filteredGroups = DefaultIncludes().AsNoTracking()
.Where(trust => trust.CompaniesHouseNumber != null
&& (
(name != null && trust.Name != null && trust.Name.Contains(name)) ||
(ukPrn != null && trust.UKPRN != null && trust.UKPRN.Contains(ukPrn)) ||
(companiesHouseNumber != null
&& trust.CompaniesHouseNumber != null
&& trust.CompaniesHouseNumber.Contains(companiesHouseNumber))
)
&& trust.TrustType != null &&
(trust.TrustType.Name == "Single-academy trust" ||
trust.TrustType.Name == "Multi-academy trust"));

if (status == TrustStatus.Open)
{
filteredGroups = filteredGroups.Where(trust => trust.TrustStatus == "Open");
}

IOrderedQueryable<Trust> filteredGroups = DefaultIncludes().AsNoTracking()
.Where(trust => (trust.Name.Contains(name) ||
trust.UKPRN.Contains(ukPrn) ||
trust.CompaniesHouseNumber.Contains(companiesHouseNumber))
&& (
trust.TrustType.Name == "Single-academy trust" ||
trust.TrustType.Name == "Multi-academy trust"
) && trust.TrustStatus == "Open")
.OrderBy(trust => trust.GroupUID);

return (await filteredGroups.Skip((page - 1) * count).Take(count).ToListAsync(cancellationToken).ConfigureAwait(false), filteredGroups.Count());
return (
await filteredGroups.OrderBy(trust => trust.GroupUID).Skip((page - 1) * count).Take(count)
.ToListAsync(cancellationToken).ConfigureAwait(false), filteredGroups.Count());
}

private IQueryable<Trust> DefaultIncludes()
Expand All @@ -75,4 +91,4 @@ private IQueryable<Trust> DefaultIncludes()
return x;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,17 @@ public async Task Search_TrustsReturnedFromRepo_eturnsAListOfTrustDtosInAPagedRe
// Arrange
var trusts = _fixture.Create<List<Domain.Trust.Trust>>();
var mockRepo = new Mock<ITrustRepository>();
mockRepo.Setup(x => x.Search(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult((trusts, trusts.Count)));
mockRepo.Setup(x => x.Search(
It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<TrustStatus>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult((trusts, trusts.Count))
);

var trustQueries = new TrustQueries(mockRepo.Object);
int page = 0;
int count = 0;
string name = null;
string ukPrn = null;
string companiesHouseNumber = null;
TrustStatus status = TrustStatus.Open;
CancellationToken cancellationToken = default(global::System.Threading.CancellationToken);

// Act
Expand All @@ -71,6 +74,7 @@ public async Task Search_TrustsReturnedFromRepo_eturnsAListOfTrustDtosInAPagedRe
name,
ukPrn,
companiesHouseNumber,
status,
cancellationToken);

// Assert
Expand Down
3 changes: 2 additions & 1 deletion Dfe.Academies.Application/Trust/ITrustQueries.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Dfe.Academies.Contracts.V4.Trusts;
using Dfe.Academies.Domain.Trust;

namespace Dfe.Academies.Application.Trust
{
Expand All @@ -8,6 +9,6 @@ public interface ITrustQueries
Task<TrustDto?> GetByCompaniesHouseNumber(string companiesHouseNumber, CancellationToken cancellationToken);
Task<TrustDto?> GetByTrustReferenceNumber(string trustReferenceNumber, 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);
Task<(List<TrustDto>, int)> Search(int page, int count, string name, string ukPrn, string companiesHouseNumber, TrustStatus status, CancellationToken cancellationToken);
}
}
4 changes: 2 additions & 2 deletions Dfe.Academies.Application/Trust/TrustQueries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public TrustQueries(ITrustRepository trustRepository)
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)
public async Task<(List<TrustDto>, int)> Search(int page, int count, string name, string ukPrn, string companiesHouseNumber, TrustStatus status, CancellationToken cancellationToken)
{
var (trusts, recordCount) = await _trustRepository.Search(page, count, name, ukPrn, companiesHouseNumber, cancellationToken).ConfigureAwait(false);
var (trusts, recordCount) = await _trustRepository.Search(page, count, name, ukPrn, companiesHouseNumber, status, cancellationToken).ConfigureAwait(false);

return (trusts.Select(x => MapToTrustDto(x)).ToList(), recordCount);
}
Expand Down
4 changes: 2 additions & 2 deletions Dfe.Academies.Domain/Trust/ITrustRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public interface ITrustRepository
Task<Trust?> GetTrustByCompaniesHouseNumber(string companiesHouseNumber, CancellationToken cancellationToken);
Task<Trust?> GetTrustByTrustReferenceNumber(string trustReferenceNumber, CancellationToken cancellationToken);
Task<List<Trust>> GetTrustsByUkprns(string[] ukprns, CancellationToken cancellationToken);
Task<(List<Trust>, int)> Search(int page, int count, string name, string ukPrn,
string companiesHouseNumber, CancellationToken cancellationToken);
Task<(List<Trust>, int)> Search(int page, int count, string? name, string? ukPrn,
string? companiesHouseNumber, TrustStatus status, CancellationToken cancellationToken);
}
}
7 changes: 7 additions & 0 deletions Dfe.Academies.Domain/Trust/TrustStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Dfe.Academies.Domain.Trust;

public enum TrustStatus
{
Open,
All
}
47 changes: 47 additions & 0 deletions TramsDataApi.Test/Integration/V4/TrustV4IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,53 @@ public async Task Get_SearchByCriteria_ByUkPrn_Returns_Ok(string ukPrn, string s

actualTrust.Ukprn.Should().Be(selectedTrust.UKPRN);
}

[Fact]
public async Task Get_SearchByStatus_Returns_Ok()
{
using var context = _apiFixture.GetMstrContext();

var trustData = BuildSmallTrustSet();
var closedTrust = trustData.First();
closedTrust.TrustStatus = "Closed";

context.Trusts.AddRange(trustData);
await context.SaveChangesAsync();

var trustResponse = await _client.GetAsync($"{_apiUrlPrefix}/trusts?groupName={closedTrust.Name}&status=Open");
trustResponse.StatusCode.Should().Be(HttpStatusCode.OK);

var trustContent = await trustResponse.Content.ReadFromJsonAsync<PagedDataResponse<TrustDto>>();

trustContent.Data.Should().HaveCount(0);
trustContent.Data.Should().NotContain(trust => trust.Ukprn == closedTrust.UKPRN);

var allTrustResponse = await _client.GetAsync($"{_apiUrlPrefix}/trusts?groupName={closedTrust.Name}&status=All");
trustResponse.StatusCode.Should().Be(HttpStatusCode.OK);

var allTrustContent = await allTrustResponse.Content.ReadFromJsonAsync<PagedDataResponse<TrustDto>>();

allTrustContent.Data.Should().HaveCount(1);

allTrustContent.Data.Should().Contain(trust => trust.Ukprn == closedTrust.UKPRN);
}

[Fact]
public async Task Get_SearchByStatus_WIthIncorrectStatus_Returns_400()
{
using var context = _apiFixture.GetMstrContext();

var trustData = BuildSmallTrustSet();
var closedTrust = trustData.First();
closedTrust.TrustStatus = "Closed";

context.Trusts.AddRange(trustData);
await context.SaveChangesAsync();

var trustResponse = await _client.GetAsync($"{_apiUrlPrefix}/trusts?groupName={closedTrust.Name}&status=Wrong");
trustResponse.StatusCode.Should().Be(HttpStatusCode.BadRequest);

}

[Fact]
public async Task Get_SearchByCriteria_NoTrustExists_Returns_Empty_Ok()
Expand Down
6 changes: 4 additions & 2 deletions TramsDataApi/Controllers/V4/TrustsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Dfe.Academies.Application.Trust;
using Dfe.Academies.Contracts.V4;
using Dfe.Academies.Contracts.V4.Trusts;
using Dfe.Academies.Domain.Trust;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Swashbuckle.AspNetCore.Annotations;
Expand Down Expand Up @@ -119,19 +120,20 @@ public async Task<ActionResult<TrustDto>> GetTrustByTrustReferenceNumber(string
/// <param name="cancellationToken"></param>
/// <param name="page">Pagination page.</param>
/// <param name="count">Number of results per page.</param>
/// <param name="status">The status of the trust, defaults to "Open"</param>
/// <returns>A list of Trusts that meet the search criteria.</returns>
[HttpGet]
[Route("trusts")]
[SwaggerOperation(Summary = "Search Trusts", Description = "Returns a list of Trusts based on search criteria.")]
[SwaggerResponse(200, "Successfully executed the search and returned Trusts.")]
public async Task<ActionResult<PagedDataResponse<TrustDto>>> SearchTrusts(string groupName, string ukPrn, string companiesHouseNumber, CancellationToken cancellationToken, int page = 1, int count = 10)
public async Task<ActionResult<PagedDataResponse<TrustDto>>> SearchTrusts(string groupName, string ukPrn, string companiesHouseNumber, CancellationToken cancellationToken, int page = 1, int count = 10, TrustStatus status = TrustStatus.Open)
{
_logger.LogInformation(
"Searching for trusts by groupName \"{name}\", UKPRN \"{prn}\", companiesHouseNumber \"{number}\", page {page}, count {count}",
groupName, ukPrn, companiesHouseNumber, page, count);

var (trusts, recordCount) = await _trustQueries
.Search(page, count, groupName, ukPrn, companiesHouseNumber, cancellationToken).ConfigureAwait(false);
.Search(page, count, groupName, ukPrn, companiesHouseNumber, status, cancellationToken).ConfigureAwait(false);

_logger.LogInformation(
"Found {count} trusts for groupName \"{name}\", UKPRN \"{prn}\", companiesHouseNumber \"{number}\", page {page}, count {count}",
Expand Down
3 changes: 2 additions & 1 deletion TramsDataApi/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Text.Json.Serialization;
using Dfe.Academisation.CorrelationIdMiddleware;

namespace TramsDataApi
Expand Down Expand Up @@ -36,7 +37,7 @@ public Startup(IConfiguration configuration)
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddControllers().AddJsonOptions(c => {c.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());});
services.AddApiVersioning();
services.AddFeatureManagement();

Expand Down

0 comments on commit 5c274c7

Please sign in to comment.