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

Added New Endpoint GetMPBySchoolURN #627

Merged
merged 2 commits into from
Oct 14, 2024
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
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
Loading