Skip to content

Commit

Permalink
Added New Endpoint GetMPBySchoolURN (#627)
Browse files Browse the repository at this point in the history
* Added New Endpoint GetMPBySchoolURN
  • Loading branch information
FrostyApeOne authored Oct 14, 2024
1 parent 5976f41 commit 69dc8fc
Show file tree
Hide file tree
Showing 25 changed files with 760 additions and 281 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Mvc;
using System.Net;

namespace Dfe.Academies.Application.Common.Exceptions
{
public class CustomProblemDetails : ProblemDetails
{
public CustomProblemDetails(HttpStatusCode statusCode, string? detail = null)
{
Status = (int)statusCode;
Detail = detail;

Title = statusCode switch
{
HttpStatusCode.NotFound => "Not Found",
HttpStatusCode.Unauthorized => "Unauthorized",
HttpStatusCode.Forbidden => "Forbidden",
HttpStatusCode.BadRequest => "Bad Request",
HttpStatusCode.InternalServerError => "Internal Server Error",
_ => "An error occurred"
};

Type = statusCode switch
{
HttpStatusCode.NotFound => "https://tools.ietf.org/html/rfc9110#section-15.5.5",
HttpStatusCode.Unauthorized => "https://tools.ietf.org/html/rfc7235#section-3.1",
HttpStatusCode.Forbidden => "https://tools.ietf.org/html/rfc7231#section-6.5.3",
HttpStatusCode.BadRequest => "https://tools.ietf.org/html/rfc7231#section-6.5.1",
HttpStatusCode.InternalServerError => "https://tools.ietf.org/html/rfc7231#section-6.6.1",
_ => "https://tools.ietf.org/html/rfc7231#section-6.6.1"
};
}
}
}
20 changes: 20 additions & 0 deletions Dfe.Academies.Application/Common/Models/Result.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Dfe.Academies.Application.Common.Models
{
public class Result<T>
{
public T? Value { get; }
public bool IsSuccess { get; }
public string? Error { get; }

private Result(T value, bool isSuccess, string? error)
{
Value = value;
IsSuccess = isSuccess;
Error = error;
}

public static Result<T> Success(T value) => new Result<T>(value, true, null);
public static Result<T> Failure(string error) => new Result<T>(default!, false, error);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

namespace Dfe.Academies.Application.Constituencies.Queries.GetMemberOfParliamentByConstituencies
{
public record GetMembersOfParliamentByConstituenciesQuery(List<string> ConstituencyNames) : IRequest<List<MemberOfParliament>>;
public record GetMembersOfParliamentByConstituenciesQuery(List<string> ConstituencyNames) : IRequest<Result<List<MemberOfParliament>>>;

public class GetMembersOfParliamentByConstituenciesQueryHandler(
IConstituencyRepository constituencyRepository,
IMapper mapper,
ICacheService<IMemoryCacheType> cacheService)
: IRequestHandler<GetMembersOfParliamentByConstituenciesQuery, List<MemberOfParliament>>
: IRequestHandler<GetMembersOfParliamentByConstituenciesQuery, Result<List<MemberOfParliament>>>
{
public async Task<List<MemberOfParliament>> Handle(GetMembersOfParliamentByConstituenciesQuery request, CancellationToken cancellationToken)
public async Task<Result<List<MemberOfParliament>>> Handle(GetMembersOfParliamentByConstituenciesQuery request, CancellationToken cancellationToken)
{
var cacheKey = $"MemberOfParliament_{CacheKeyHelper.GenerateHashedCacheKey(request.ConstituencyNames)}";

Expand All @@ -28,9 +28,10 @@ public async Task<List<MemberOfParliament>> Handle(GetMembersOfParliamentByConst

var membersOfParliament = await constituenciesQuery
.ProjectTo<MemberOfParliament>(mapper.ConfigurationProvider)
.ToListAsync(cancellationToken);
.ToListAsync(cancellationToken);

return Result<List<MemberOfParliament>>.Success(membersOfParliament);

return membersOfParliament;
}, nameof(GetMembersOfParliamentByConstituenciesQueryHandler));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@

namespace Dfe.Academies.Application.Constituencies.Queries.GetMemberOfParliamentByConstituency
{
public record GetMemberOfParliamentByConstituencyQuery(string ConstituencyName) : IRequest<MemberOfParliament>;
public record GetMemberOfParliamentByConstituencyQuery(string ConstituencyName) : IRequest<Result<MemberOfParliament?>>;

public class GetMemberOfParliamentByConstituencyQueryHandler(
IConstituencyRepository constituencyRepository,
IMapper mapper,
ICacheService<IMemoryCacheType> cacheService)
: IRequestHandler<GetMemberOfParliamentByConstituencyQuery, MemberOfParliament?>
: IRequestHandler<GetMemberOfParliamentByConstituencyQuery, Result<MemberOfParliament?>>
{
public async Task<MemberOfParliament?> Handle(GetMemberOfParliamentByConstituencyQuery request, CancellationToken cancellationToken)
public async Task<Result<MemberOfParliament?>> Handle(GetMemberOfParliamentByConstituencyQuery request, CancellationToken cancellationToken)
{
var cacheKey = $"MemberOfParliament_{CacheKeyHelper.GenerateHashedCacheKey(request.ConstituencyName)}";

Expand All @@ -24,9 +24,15 @@ public class GetMemberOfParliamentByConstituencyQueryHandler(
var constituencyWithMember = await constituencyRepository
.GetMemberOfParliamentByConstituencyAsync(request.ConstituencyName, cancellationToken);

if (constituencyWithMember == null)
{
return Result<MemberOfParliament?>.Failure("Constituency not found.");
}

var result = mapper.Map<MemberOfParliament?>(constituencyWithMember);

return result;
return Result<MemberOfParliament?>.Success(result);

}, nameof(GetMemberOfParliamentByConstituencyQueryHandler));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

namespace Dfe.Academies.Application.Establishment.Queries.GetAllPersonsAssociatedWithAcademyByUrn
{
public record GetAllPersonsAssociatedWithAcademyByUrnQuery(int Urn) : IRequest<List<AcademyGovernance>?>;
public record GetAllPersonsAssociatedWithAcademyByUrnQuery(int Urn) : IRequest<Result<List<AcademyGovernance>?>>;

public class GetAllPersonsAssociatedWithAcademyByUrnQueryHandler(
IEstablishmentQueryService establishmentQueryService,
IMapper mapper,
ICacheService<IMemoryCacheType> cacheService)
: IRequestHandler<GetAllPersonsAssociatedWithAcademyByUrnQuery, List<AcademyGovernance>?>
: IRequestHandler<GetAllPersonsAssociatedWithAcademyByUrnQuery, Result<List<AcademyGovernance>?>>
{
public async Task<List<AcademyGovernance>?> Handle(GetAllPersonsAssociatedWithAcademyByUrnQuery request, CancellationToken cancellationToken)
public async Task<Result<List<AcademyGovernance>?>> Handle(GetAllPersonsAssociatedWithAcademyByUrnQuery request, CancellationToken cancellationToken)
{
var cacheKey = $"PersonsAssociatedWithAcademy_{CacheKeyHelper.GenerateHashedCacheKey(request.Urn.ToString())}";

Expand All @@ -27,12 +27,12 @@ public class GetAllPersonsAssociatedWithAcademyByUrnQueryHandler(

if (query == null)
{
return null;
return Result<List<AcademyGovernance>?>.Failure("Academy not found.");
}

var result = await query
var result = Result<List<AcademyGovernance>?>.Success(await query
.ProjectTo<AcademyGovernance>(mapper.ConfigurationProvider)
.ToListAsync(cancellationToken);
.ToListAsync(cancellationToken));

return result;
}, nameof(GetAllPersonsAssociatedWithAcademyByUrnQueryHandler));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using AutoMapper;
using Dfe.Academies.Application.Common.Models;
using Dfe.Academies.Domain.Interfaces.Repositories;
using DfE.CoreLibs.Caching.Helpers;
using DfE.CoreLibs.Caching.Interfaces;
using MediatR;

namespace Dfe.Academies.Application.Establishment.Queries.GetMemberOfParliamentBySchool
{
public record GetMemberOfParliamentBySchoolQuery(int Urn) : IRequest<Result<MemberOfParliament?>>;

public class GetMemberOfParliamentBySchoolQueryHandler(
IEstablishmentRepository establishmentRepository,
IConstituencyRepository constituencyRepository,
IMapper mapper,
ICacheService<IMemoryCacheType> cacheService)
: IRequestHandler<GetMemberOfParliamentBySchoolQuery, Result<MemberOfParliament?>>
{
public async Task<Result<MemberOfParliament?>> Handle(GetMemberOfParliamentBySchoolQuery request, CancellationToken cancellationToken)
{
var cacheKey = $"MPbySchool_{CacheKeyHelper.GenerateHashedCacheKey(request.Urn.ToString())}";

return await cacheService.GetOrAddAsync(cacheKey, async () =>
{
var establishment = await establishmentRepository.GetEstablishmentByUrn(request.Urn.ToString(), cancellationToken);
if (establishment == null)
{
return Result<MemberOfParliament?>.Failure("School not found.");
}

var constituency = await constituencyRepository.GetMemberOfParliamentByConstituencyAsync(establishment.ParliamentaryConstituency!, cancellationToken);
if (constituency == null)
{
return Result<MemberOfParliament?>.Failure("Constituency not found for the given establishment.");
}

var mp = mapper.Map<MemberOfParliament?>(constituency);

return Result<MemberOfParliament?>.Success(mp);

}, nameof(GetMemberOfParliamentBySchoolQueryHandler));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using FluentValidation;

namespace Dfe.Academies.Application.Establishment.Queries.GetMemberOfParliamentBySchool
{
public class GetMemberOfParliamentBySchoolQueryValidator : AbstractValidator<GetMemberOfParliamentBySchoolQuery>
{
public GetMemberOfParliamentBySchoolQueryValidator()
{
RuleFor(query => query.Urn)
.GreaterThan(0).WithMessage("URN must be greater than 0.")
.NotEmpty().WithMessage("URN is required.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@

namespace Dfe.Academies.Application.Trust.Queries.GetAllPersonsAssociatedWithTrustByTrnOrUkprn
{
public record GetAllPersonsAssociatedWithTrustByTrnOrUkprnQuery(string Id) : IRequest<List<TrustGovernance>?>;
public record GetAllPersonsAssociatedWithTrustByTrnOrUkprnQuery(string Id) : IRequest<Result<List<TrustGovernance>?>>;

public class GetAllPersonsAssociatedWithTrustByTrnOrUkprnQueryHandler(
ITrustQueryService trustQueryService,
IMapper mapper,
ICacheService<IMemoryCacheType> cacheService)
: IRequestHandler<GetAllPersonsAssociatedWithTrustByTrnOrUkprnQuery, List<TrustGovernance>?>
: IRequestHandler<GetAllPersonsAssociatedWithTrustByTrnOrUkprnQuery, Result<List<TrustGovernance>?>>
{
public async Task<List<TrustGovernance>?> Handle(GetAllPersonsAssociatedWithTrustByTrnOrUkprnQuery request, CancellationToken cancellationToken)
public async Task<Result<List<TrustGovernance>?>> Handle(GetAllPersonsAssociatedWithTrustByTrnOrUkprnQuery request, CancellationToken cancellationToken)
{
var idType = IdentifierHelper<string, TrustIdType>.DetermineIdType(request.Id, TrustIdValidator.GetTrustIdValidators());

Expand All @@ -31,12 +31,15 @@ public class GetAllPersonsAssociatedWithTrustByTrnOrUkprnQueryHandler(
return await cacheService.GetOrAddAsync(cacheKey, async () =>
{
var query = trustQueryService.GetTrustGovernanceByGroupIdOrUkprn(groupId, ukPrn);
if (query == null)
{
return Result<List<TrustGovernance>?>.Failure("Trust not found.");
}

return query == null
? null
: await query
return Result<List<TrustGovernance>?>.Success(await query
.ProjectTo<TrustGovernance>(mapper.ConfigurationProvider)
.ToListAsync(cancellationToken);
.ToListAsync(cancellationToken));

}, nameof(GetAllPersonsAssociatedWithTrustByTrnOrUkprnQueryHandler));
}
}
Expand Down
99 changes: 98 additions & 1 deletion Dfe.PersonsApi.Client/Generated/Client.g.cs
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,104 @@ public string BaseUrl
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new PersonsApiException("Academy not found.", status_, responseText_, headers_, null);
throw new PersonsApiException("Academy not found.\nor\nConstituency not found for the given establishment.", status_, responseText_, headers_, null);
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new PersonsApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}

/// <summary>
/// Get Member of Parliament by School (Urn)
/// </summary>
/// <param name="urn">The URN.</param>
/// <returns>Member of Parliament</returns>
/// <exception cref="PersonsApiException">A server side error occurred.</exception>
public virtual System.Threading.Tasks.Task<MemberOfParliament> GetMemberOfParliamentBySchoolUrnAsync(int urn)
{
return GetMemberOfParliamentBySchoolUrnAsync(urn, System.Threading.CancellationToken.None);
}

/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>
/// Get Member of Parliament by School (Urn)
/// </summary>
/// <param name="urn">The URN.</param>
/// <returns>Member of Parliament</returns>
/// <exception cref="PersonsApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task<MemberOfParliament> GetMemberOfParliamentBySchoolUrnAsync(int urn, System.Threading.CancellationToken cancellationToken)
{
if (urn == null)
throw new System.ArgumentNullException("urn");

var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json"));

var urlBuilder_ = new System.Text.StringBuilder();
if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl);
// Operation Path: "v1/Establishments/{urn}/getMpBySchool"
urlBuilder_.Append("v1/Establishments/");
urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(urn, System.Globalization.CultureInfo.InvariantCulture)));
urlBuilder_.Append("/getMpBySchool");

PrepareRequest(client_, request_, urlBuilder_);

var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);

PrepareRequest(client_, request_, url_);

var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = new System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>>();
foreach (var item_ in response_.Headers)
headers_[item_.Key] = item_.Value;
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}

ProcessResponse(client_, response_);

var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<MemberOfParliament>(response_, headers_, cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new PersonsApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
if (status_ == 404)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new PersonsApiException("School Not found.", status_, responseText_, headers_, null);
}
else
{
Expand Down
17 changes: 17 additions & 0 deletions Dfe.PersonsApi.Client/Generated/Contracts.g.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,23 @@ public partial interface IEstablishmentsClient
/// <exception cref="PersonsApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<System.Collections.ObjectModel.ObservableCollection<AcademyGovernance>> GetAllPersonsAssociatedWithAcademyByUrnAsync(int urn, System.Threading.CancellationToken cancellationToken);

/// <summary>
/// Get Member of Parliament by School (Urn)
/// </summary>
/// <param name="urn">The URN.</param>
/// <returns>Member of Parliament</returns>
/// <exception cref="PersonsApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<MemberOfParliament> GetMemberOfParliamentBySchoolUrnAsync(int urn);

/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>
/// Get Member of Parliament by School (Urn)
/// </summary>
/// <param name="urn">The URN.</param>
/// <returns>Member of Parliament</returns>
/// <exception cref="PersonsApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<MemberOfParliament> GetMemberOfParliamentBySchoolUrnAsync(int urn, System.Threading.CancellationToken cancellationToken);

}

[System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")]
Expand Down
Loading

0 comments on commit 69dc8fc

Please sign in to comment.