From 7681ae99a3ec4e4cb1584df95df7c860fbaf7b05 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 15:49:34 +0000 Subject: [PATCH] Replace AutoMapper with Mapperly: create ApiMappers, update controllers, fix Extensions/GlobalUsings, delete old files Agent-Logs-Url: https://github.com/DFE-Digital/teaching-record-system/sessions/8b6ce974-583c-4911-8066-c0443ea8a848 Co-authored-by: gunndabad <2041280+gunndabad@users.noreply.github.com> --- TeachingRecordSystem/Directory.Packages.props | 2 +- .../TeachingRecordSystem.Api/Extensions.cs | 36 ++-- .../TeachingRecordSystem.Api/GlobalUsings.cs | 1 - .../Infrastructure/Mapping/OptionMapper.cs | 40 ---- .../TeachingRecordSystem.Api.csproj | 2 +- .../V3/V20240101/ApiMapper.cs | 152 +++++++++++++ .../Controllers/TeacherController.cs | 4 +- .../Controllers/TeachersController.cs | 6 +- .../V3/V20240101/MapperProfile.cs | 39 ---- .../Responses/FindTeachersResponse.cs | 2 - .../V20240101/Responses/GetTeacherResponse.cs | 19 -- .../V3/V20240307/ApiMapper.cs | 29 +++ .../Controllers/TrnRequestsController.cs | 6 +- .../V3/V20240307/MapperProfile.cs | 14 -- .../V3/V20240412/ApiMapper.cs | 15 ++ .../Controllers/TeacherController.cs | 6 +- .../CreateDateOfBirthChangeResponse.cs | 3 - .../Responses/CreateNameChangeResponse.cs | 3 - .../V3/V20240416/ApiMapper.cs | 124 +++++++++++ .../Controllers/TeacherController.cs | 4 +- .../Controllers/TeachersController.cs | 4 +- .../V3/V20240416/MapperProfile.cs | 23 -- .../V20240416/Responses/GetTeacherResponse.cs | 18 -- .../V3/V20240606/ApiMapper.cs | 134 ++++++++++++ .../V20240606/Controllers/PersonController.cs | 8 +- .../Controllers/PersonsController.cs | 6 +- .../Controllers/TrnRequestsController.cs | 6 +- .../V3/V20240606/MapperProfile.cs | 25 --- .../CreateDateOfBirthChangeResponse.cs | 3 - .../Responses/CreateNameChangeResponse.cs | 3 - .../V20240606/Responses/FindPersonResponse.cs | 2 - .../V20240606/Responses/GetPersonResponse.cs | 18 -- .../V3/V20240814/ApiMapper.cs | 78 +++++++ .../Controllers/PersonsController.cs | 6 +- .../V3/V20240814/MapperProfile.cs | 15 -- .../V20240814/Responses/FindPersonResponse.cs | 4 - .../Responses/FindPersonsResponse.cs | 6 - .../V3/V20240912/ApiMapper.cs | 12 ++ .../Controllers/PersonsController.cs | 6 +- .../V3/V20240912/MapperProfile.cs | 11 - .../V3/V20240920/ApiMapper.cs | 157 ++++++++++++++ .../V20240920/Controllers/PersonController.cs | 4 +- .../Controllers/PersonsController.cs | 8 +- .../V3/V20240920/MapperProfile.cs | 13 -- .../V20240920/Responses/FindPersonResponse.cs | 4 - .../Responses/FindPersonsResponse.cs | 6 - .../V20240920/Responses/GetPersonResponse.cs | 17 -- .../V3/V20250203/ApiMapper.cs | 155 ++++++++++++++ .../V20250203/Controllers/PersonController.cs | 4 +- .../Controllers/PersonsController.cs | 10 +- .../Controllers/TrnRequestsController.cs | 6 +- .../V3/V20250203/MapperProfile.cs | 13 -- .../V20250203/Responses/FindPersonResponse.cs | 4 - .../Responses/FindPersonsResponse.cs | 6 - .../V20250203/Responses/GetPersonResponse.cs | 15 -- .../V3/V20250327/ApiMapper.cs | 140 ++++++++++++ .../V20250327/Controllers/PersonController.cs | 4 +- .../Controllers/PersonsController.cs | 8 +- .../V3/V20250327/MapperProfile.cs | 12 -- .../V20250327/Responses/FindPersonResponse.cs | 4 - .../Responses/FindPersonsResponse.cs | 6 - .../V20250327/Responses/GetPersonResponse.cs | 15 -- .../V3/V20250425/ApiMapper.cs | 24 +++ .../Controllers/PersonsController.cs | 4 +- .../Controllers/TrnRequestsController.cs | 8 +- .../V3/V20250425/MapperProfile.cs | 11 - .../V3/V20250627/ApiMapper.cs | 199 ++++++++++++++++++ .../V20250627/Controllers/PersonController.cs | 4 +- .../Controllers/PersonsController.cs | 10 +- .../V3/V20250627/MapperProfile.cs | 22 -- .../V20250627/Responses/FindPersonResponse.cs | 2 - .../Responses/FindPersonsResponse.cs | 5 - .../V20250627/Responses/GetPersonResponse.cs | 6 - .../Controllers/PersonsController.cs | 4 +- .../Controllers/TrnRequestController.cs | 4 +- .../packages.lock.json | 12 +- .../packages.lock.json | 14 +- .../packages.lock.json | 17 +- 78 files changed, 1326 insertions(+), 526 deletions(-) delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Mapping/OptionMapper.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/ApiMapper.cs delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/MapperProfile.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/ApiMapper.cs delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/MapperProfile.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/ApiMapper.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/ApiMapper.cs delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/MapperProfile.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/ApiMapper.cs delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/MapperProfile.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/ApiMapper.cs delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/MapperProfile.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240912/ApiMapper.cs delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240912/MapperProfile.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/ApiMapper.cs delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/MapperProfile.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/ApiMapper.cs delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/MapperProfile.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/ApiMapper.cs delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/MapperProfile.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/ApiMapper.cs delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/MapperProfile.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/ApiMapper.cs delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/MapperProfile.cs diff --git a/TeachingRecordSystem/Directory.Packages.props b/TeachingRecordSystem/Directory.Packages.props index 777b8f931d..46a8aeffa9 100644 --- a/TeachingRecordSystem/Directory.Packages.props +++ b/TeachingRecordSystem/Directory.Packages.props @@ -9,7 +9,7 @@ - + diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Extensions.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Extensions.cs index b631fb3b2f..f65c0f7156 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Extensions.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Extensions.cs @@ -5,11 +5,8 @@ using FluentValidation.AspNetCore; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Formatters; -using OneOf; -using Optional; using TeachingRecordSystem.Api.Infrastructure.ApplicationModel; using TeachingRecordSystem.Api.Infrastructure.Filters; -using TeachingRecordSystem.Api.Infrastructure.Mapping; using TeachingRecordSystem.Api.Infrastructure.ModelBinding; using TeachingRecordSystem.Api.Infrastructure.OpenApi; using TeachingRecordSystem.Api.Infrastructure.RateLimiting; @@ -47,14 +44,6 @@ public static IHostApplicationBuilder AddApiServices(this IHostApplicationBuilde public static IServiceCollection AddApiServices(this IServiceCollection services, IConfiguration configuration, IHostEnvironment environment) { - services.Scan(scan => - { - scan.FromAssemblies(typeof(Extensions).Assembly) - .AddClasses(filter => filter.AssignableTo(typeof(ITypeConverter<,>))) - .AsSelf() - .WithTransientLifetime(); - }); - services .AddMvc(options => { @@ -132,7 +121,7 @@ public static IServiceCollection AddApiServices(this IServiceCollection services .AddWebhookOptions(configuration) .AddOpenApi(configuration) .AddFluentValidation() - .AddAutoMapper() + .AddApiMappers() .AddHttpContextAccessor() .AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining()) .AddSingleton() @@ -156,16 +145,21 @@ public static IServiceCollection AddApiServices(this IServiceCollection services return services; } - private static IServiceCollection AddAutoMapper(this IServiceCollection services) + private static IServiceCollection AddApiMappers(this IServiceCollection services) { - services.AddAutoMapper(cfg => - { - cfg.AddMaps(typeof(Program).Assembly); - cfg.CreateMap(typeof(Option<>), typeof(Option<>)).ConvertUsing(typeof(OptionToOptionTypeConverter<,>)); - cfg.CreateMap(typeof(OneOf<,>), typeof(OneOf<,>)).ConvertUsing(typeof(OneOfToOneOfTypeConverter<,,,>)); - }) - .AddTransient(typeof(WrapWithOptionValueConverter<>)) - .AddTransient(typeof(WrapWithOptionValueConverter<,>)); + services + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton(); return services; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/GlobalUsings.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/GlobalUsings.cs index 80de4427a0..634d42c715 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/GlobalUsings.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/GlobalUsings.cs @@ -1,3 +1,2 @@ -global using AutoMapper; global using TeachingRecordSystem.Core.ApiSchema; global using PostgresModels = TeachingRecordSystem.Core.DataStore.Postgres.Models; diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Mapping/OptionMapper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Mapping/OptionMapper.cs deleted file mode 100644 index 5c88122a11..0000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Infrastructure/Mapping/OptionMapper.cs +++ /dev/null @@ -1,40 +0,0 @@ -using OneOf; -using Optional; - -namespace TeachingRecordSystem.Api.Infrastructure.Mapping; - -public class OptionToOptionTypeConverter : ITypeConverter, Option> -{ - public Option Convert(Option source, Option destination, ResolutionContext context) => - source.Map(source => context.Mapper.Map(source)); -} - -public class WrapWithOptionValueConverter : IValueConverter> -{ - public Option Convert(TSource sourceMember, ResolutionContext context) => - Option.Some(context.Mapper.Map(sourceMember)); -} - -public class WrapWithOptionValueConverter : IValueConverter> -{ - public Option Convert(T sourceMember, ResolutionContext context) => - Option.Some(sourceMember); -} - -public class OneOfToOneOfTypeConverter : ITypeConverter, OneOf> -{ - public OneOf Convert(OneOf source, OneOf destination, ResolutionContext context) - { - return source.Match( - v => OneOf.FromT0(context.Mapper.Map(v)), - v => OneOf.FromT1(context.Mapper.Map(v))); - } -} - -public class FromOneOfT0TypeConverter : ITypeConverter, TDestination> -{ - public TDestination Convert(OneOf source, TDestination destination, ResolutionContext context) - { - return context.Mapper.Map(source.AsT0); - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/TeachingRecordSystem.Api.csproj b/TeachingRecordSystem/src/TeachingRecordSystem.Api/TeachingRecordSystem.Api.csproj index 01c185db83..cec4ae0357 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/TeachingRecordSystem.Api.csproj +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/TeachingRecordSystem.Api.csproj @@ -5,7 +5,7 @@ - + diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/ApiMapper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/ApiMapper.cs new file mode 100644 index 0000000000..1533a3a22f --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/ApiMapper.cs @@ -0,0 +1,152 @@ +using Optional; +using Riok.Mapperly.Abstractions; +using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Api.V3.V20240101.Responses; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; + +namespace TeachingRecordSystem.Api.V3.V20240101; + +[Mapper] +public partial class ApiMapper +{ + public GetTeacherResponse MapGetTeacherResponse(GetPersonResult source) => + new() + { + Trn = source.Trn, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + DateOfBirth = source.DateOfBirth, + NationalInsuranceNumber = source.NationalInsuranceNumber, + PendingNameChange = source.PendingNameChange, + PendingDateOfBirthChange = source.PendingDateOfBirthChange, + Email = source.EmailAddress, + Qts = source.Qts is { } qts ? MapQts(qts) : null, + Eyts = source.Eyts is { } eyts ? MapEyts(eyts) : null, + Induction = source.DqtInduction.Map(d => d is null ? (GetTeacherResponseInduction?)null : MapDqtInduction(d)), + InitialTeacherTraining = source.InitialTeacherTraining.Map( + itt => (IReadOnlyCollection)itt.AsT0 + .Select(MapInitialTeacherTraining).AsReadOnly()), + NpqQualifications = Option.None>(), + MandatoryQualifications = source.MandatoryQualifications.Map( + mqs => (IReadOnlyCollection)mqs + .Select(MapMandatoryQualification).AsReadOnly()), + HigherEducationQualifications = Option.None>(), + Sanctions = source.Sanctions.Map( + ss => (IReadOnlyCollection)ss.Select(MapSanctionInfo).AsReadOnly()), + Alerts = source.Alerts.Map( + alerts => (IReadOnlyCollection)alerts.Select(MapAlertInfo).AsReadOnly()), + PreviousNames = source.PreviousNames.Map( + pns => (IReadOnlyCollection)pns.Select(MapNameInfo).AsReadOnly()), + AllowIdSignInWithProhibitions = source.AllowIdSignInWithProhibitions + }; + + public FindTeachersResponseResult MapFindTeachersResponseResult(FindPersonsResultItem source) => + new() + { + Trn = source.Trn, + DateOfBirth = source.DateOfBirth, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + Sanctions = source.Sanctions.Select(MapSanctionInfo).AsReadOnly(), + PreviousNames = source.PreviousNames.Select(MapNameInfo).AsReadOnly() + }; + + internal GetTeacherResponseQts MapQts(Implementation.Dtos.QtsInfo source) => + new() + { + Awarded = source.HoldsFrom, + CertificateUrl = source.CertificateUrl, + StatusDescription = source.StatusDescription + }; + + internal GetTeacherResponseEyts MapEyts(Implementation.Dtos.EytsInfo source) => + new() + { + Awarded = source.HoldsFrom, + CertificateUrl = source.CertificateUrl, + StatusDescription = source.StatusDescription + }; + + internal GetTeacherResponseInduction MapDqtInduction(GetPersonResultDqtInduction source) => + new() + { + StartDate = source.StartDate, + EndDate = source.EndDate, + Status = MapDqtInductionStatus(source.Status), + StatusDescription = source.StatusDescription, + CertificateUrl = source.CertificateUrl, + Periods = source.Periods.Select(MapInductionPeriod).AsReadOnly() + }; + + private GetTeacherResponseInductionPeriod MapInductionPeriod(GetPersonResultDqtInductionPeriod source) => + new() + { + StartDate = source.StartDate, + EndDate = source.EndDate, + Terms = source.Terms, + AppropriateBody = source.AppropriateBody is { } ab + ? new GetTeacherResponseInductionPeriodAppropriateBody { Name = ab.Name } + : null + }; + + internal GetTeacherResponseInitialTeacherTraining MapInitialTeacherTraining(GetPersonResultInitialTeacherTraining source) => + new() + { + Qualification = source.Qualification is { } q + ? new GetTeacherResponseInitialTeacherTrainingQualification { Name = q.Name } + : null, + StartDate = source.StartDate, + EndDate = source.EndDate, + ProgrammeType = null, + ProgrammeTypeDescription = null, + Result = null, + AgeRange = source.AgeRange is { } ar + ? new GetTeacherResponseInitialTeacherTrainingAgeRange { Description = ar.Description } + : null, + Provider = source.Provider is { } p + ? new GetTeacherResponseInitialTeacherTrainingProvider { Name = p.Name, Ukprn = p.Ukprn } + : null, + Subjects = source.Subjects + .Select(s => new GetTeacherResponseInitialTeacherTrainingSubject { Code = s.Code, Name = s.Name }) + .AsReadOnly() + }; + + private GetTeacherResponseMandatoryQualification MapMandatoryQualification(GetPersonResultMandatoryQualification source) => + new() + { + Awarded = source.EndDate, + Specialism = source.Specialism + }; + + internal SanctionInfo MapSanctionInfo(Implementation.Dtos.SanctionInfo source) => + new() { Code = source.Code, StartDate = source.StartDate }; + + internal AlertInfo MapAlertInfo(Implementation.Dtos.Alert source) => + new() + { + AlertType = AlertType.Prohibition, + DqtSanctionCode = source.AlertType.DqtSanctionCode!, + StartDate = source.StartDate, + EndDate = source.EndDate + }; + + internal NameInfo MapNameInfo(Implementation.Dtos.NameInfo source) => + new() { FirstName = source.FirstName, MiddleName = source.MiddleName, LastName = source.LastName }; + + internal static Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus MapDqtInductionStatus(Implementation.Dtos.DqtInductionStatus source) => + source switch + { + Implementation.Dtos.DqtInductionStatus.Exempt => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Exempt, + Implementation.Dtos.DqtInductionStatus.Fail => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Fail, + Implementation.Dtos.DqtInductionStatus.FailedInWales => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.FailedinWales, + Implementation.Dtos.DqtInductionStatus.InductionExtended => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.InductionExtended, + Implementation.Dtos.DqtInductionStatus.InProgress => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.InProgress, + Implementation.Dtos.DqtInductionStatus.NotYetCompleted => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.NotYetCompleted, + Implementation.Dtos.DqtInductionStatus.Pass => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Pass, + Implementation.Dtos.DqtInductionStatus.PassedInWales => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.PassedinWales, + Implementation.Dtos.DqtInductionStatus.RequiredToComplete => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.RequiredtoComplete, + _ => throw new ArgumentOutOfRangeException(nameof(source)) + }; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Controllers/TeacherController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Controllers/TeacherController.cs index 08ce5552f4..4b6fd29eae 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Controllers/TeacherController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Controllers/TeacherController.cs @@ -11,7 +11,7 @@ namespace TeachingRecordSystem.Api.V3.V20240101.Controllers; [Route("teacher")] -public class TeacherController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class TeacherController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [Authorize(AuthorizationPolicies.IdentityUserWithTrn)] [HttpGet] @@ -36,7 +36,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapGetTeacherResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status403Forbidden); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Controllers/TeachersController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Controllers/TeachersController.cs index decc9b8c24..d756a45696 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Controllers/TeachersController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Controllers/TeachersController.cs @@ -10,7 +10,7 @@ namespace TeachingRecordSystem.Api.V3.V20240101.Controllers; [Route("teachers")] -public class TeachersController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class TeachersController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpGet("{trn}")] [SwaggerOperation( @@ -37,7 +37,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapGetTeacherResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsDeactivated, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsMerged, StatusCodes.Status404NotFound); @@ -113,7 +113,7 @@ public async Task FindTeachersAsync(FindTeachersRequest request) { Total = r.Total, Query = request, - Results = r.Items.Select(mapper.Map).AsReadOnly() + Results = r.Items.Select(mapper.MapFindTeachersResponseResult).AsReadOnly() })); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/MapperProfile.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/MapperProfile.cs deleted file mode 100644 index 7061a5d69c..0000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/MapperProfile.cs +++ /dev/null @@ -1,39 +0,0 @@ -using OneOf; -using TeachingRecordSystem.Api.Infrastructure.Mapping; -using TeachingRecordSystem.Api.V3.Implementation.Operations; -using TeachingRecordSystem.Api.V3.V20240101.Responses; -using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; - -namespace TeachingRecordSystem.Api.V3.V20240101; - -public class MapperProfile : Profile -{ - public MapperProfile() - { - CreateMap().ConvertUsing(); - CreateMap(); - CreateMap(); - CreateMap< - OneOf< - IReadOnlyCollection, - IReadOnlyCollection>, - IReadOnlyCollection>() - .ConvertUsing( - new FromOneOfT0TypeConverter< - IReadOnlyCollection, - IReadOnlyCollection, - IReadOnlyCollection>()); - } -} - -public class AlertInfoTypeConverter : ITypeConverter -{ - public AlertInfo Convert(Implementation.Dtos.Alert source, AlertInfo destination, ResolutionContext context) => - new() - { - AlertType = AlertType.Prohibition, - DqtSanctionCode = source.AlertType.DqtSanctionCode!, - StartDate = source.StartDate, - EndDate = source.EndDate - }; -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Responses/FindTeachersResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Responses/FindTeachersResponse.cs index 58ac277456..b39fb8cc5d 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Responses/FindTeachersResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Responses/FindTeachersResponse.cs @@ -1,4 +1,3 @@ -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Api.V3.V20240101.Requests; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; @@ -11,7 +10,6 @@ public record FindTeachersResponse public required IReadOnlyCollection Results { get; init; } } -[AutoMap(typeof(FindPersonsResultItem))] public record FindTeachersResponseResult { public required string Trn { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Responses/GetTeacherResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Responses/GetTeacherResponse.cs index 9e9b1b37bb..6122646e84 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Responses/GetTeacherResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Responses/GetTeacherResponse.cs @@ -1,12 +1,9 @@ using System.Text.Json.Serialization; -using AutoMapper.Configuration.Annotations; using Optional; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; namespace TeachingRecordSystem.Api.V3.V20240101.Responses; -[AutoMap(typeof(GetPersonResult))] public record GetTeacherResponse { public required string Trn { get; init; } @@ -17,11 +14,9 @@ public record GetTeacherResponse public required string? NationalInsuranceNumber { get; init; } public required Option PendingNameChange { get; init; } public required Option PendingDateOfBirthChange { get; init; } - [SourceMember("EmailAddress")] public required string? Email { get; set; } public required GetTeacherResponseQts? Qts { get; init; } public required GetTeacherResponseEyts? Eyts { get; init; } - [SourceMember(nameof(GetPersonResult.DqtInduction))] public required Option Induction { get; init; } public required Option> InitialTeacherTraining { get; init; } public required Option> NpqQualifications { get; init; } @@ -33,25 +28,20 @@ public record GetTeacherResponse public required Option AllowIdSignInWithProhibitions { get; init; } } -[AutoMap(typeof(Implementation.Dtos.QtsInfo))] public record GetTeacherResponseQts { - [SourceMember(nameof(Implementation.Dtos.QtsInfo.HoldsFrom))] public required DateOnly? Awarded { get; init; } public required string CertificateUrl { get; init; } public required string? StatusDescription { get; init; } } -[AutoMap(typeof(Implementation.Dtos.EytsInfo))] public record GetTeacherResponseEyts { - [SourceMember(nameof(Implementation.Dtos.QtsInfo.HoldsFrom))] public required DateOnly? Awarded { get; init; } public required string CertificateUrl { get; init; } public required string? StatusDescription { get; init; } } -[AutoMap(typeof(GetPersonResultDqtInduction))] public record GetTeacherResponseInduction { public required DateOnly? StartDate { get; init; } @@ -63,7 +53,6 @@ public record GetTeacherResponseInduction public required IReadOnlyCollection Periods { get; init; } } -[AutoMap(typeof(GetPersonResultDqtInductionPeriod))] public record GetTeacherResponseInductionPeriod { public required DateOnly? StartDate { get; init; } @@ -72,13 +61,11 @@ public record GetTeacherResponseInductionPeriod public required GetTeacherResponseInductionPeriodAppropriateBody? AppropriateBody { get; init; } } -[AutoMap(typeof(GetPersonResultInductionPeriodAppropriateBody))] public record GetTeacherResponseInductionPeriodAppropriateBody { public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTraining))] public record GetTeacherResponseInitialTeacherTraining { public required GetTeacherResponseInitialTeacherTrainingQualification? Qualification { get; init; } @@ -92,26 +79,22 @@ public record GetTeacherResponseInitialTeacherTraining public required IReadOnlyCollection Subjects { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingQualification))] public record GetTeacherResponseInitialTeacherTrainingQualification { public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingAgeRange))] public record GetTeacherResponseInitialTeacherTrainingAgeRange { public required string Description { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingProvider))] public record GetTeacherResponseInitialTeacherTrainingProvider { public required string Name { get; init; } public required string Ukprn { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingSubject))] public record GetTeacherResponseInitialTeacherTrainingSubject { public required string Code { get; init; } @@ -131,10 +114,8 @@ public record GetTeacherResponseNpqQualificationType public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultMandatoryQualification))] public record GetTeacherResponseMandatoryQualification { - [SourceMember("EndDate")] public required DateOnly Awarded { get; init; } public required string Specialism { get; init; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/ApiMapper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/ApiMapper.cs new file mode 100644 index 0000000000..be3261f8d6 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/ApiMapper.cs @@ -0,0 +1,29 @@ +using Riok.Mapperly.Abstractions; +using TeachingRecordSystem.Api.V3.Implementation.Dtos; +using V20240307Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20240307.Dtos; + +namespace TeachingRecordSystem.Api.V3.V20240307; + +[Mapper] +public partial class ApiMapper +{ + public V20240307Dtos.TrnRequestInfo MapTrnRequestInfo(TrnRequestInfo source) => + new() + { + RequestId = source.RequestId, + Person = MapTrnRequestPerson(source.Person), + Status = (V20240307Dtos.TrnRequestStatus)(int)source.Status, + Trn = source.Trn + }; + + private V20240307Dtos.TrnRequestPerson MapTrnRequestPerson(TrnRequestInfoPerson source) => + new() + { + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + DateOfBirth = source.DateOfBirth, + Email = source.EmailAddress, + NationalInsuranceNumber = source.NationalInsuranceNumber + }; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/Controllers/TrnRequestsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/Controllers/TrnRequestsController.cs index 22b5a29d00..31d4de7773 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/Controllers/TrnRequestsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/Controllers/TrnRequestsController.cs @@ -10,7 +10,7 @@ namespace TeachingRecordSystem.Api.V3.V20240307.Controllers; [Route("trn-requests")] [Authorize(Policy = AuthorizationPolicies.ApiKey, Roles = ApiRoles.CreateTrn)] -public class TrnRequestsController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class TrnRequestsController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpPost("")] [SwaggerOperation( @@ -43,7 +43,7 @@ public async Task CreateTrnRequestAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapTrnRequestInfo(r))) .MapErrorCode(ApiError.ErrorCodes.TrnRequestAlreadyCreated, StatusCodes.Status409Conflict); } @@ -62,7 +62,7 @@ public async Task GetTrnRequestAsync([FromQuery] string requestId var command = new GetTrnRequestCommand(requestId); var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapTrnRequestInfo(r))) .MapErrorCode(ApiError.ErrorCodes.TrnRequestDoesNotExist, StatusCodes.Status404NotFound); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/MapperProfile.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/MapperProfile.cs deleted file mode 100644 index 468db9ff10..0000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/MapperProfile.cs +++ /dev/null @@ -1,14 +0,0 @@ -using TeachingRecordSystem.Core.ApiSchema.V3.V20240307.Dtos; -#pragma warning disable TRS0001 - -namespace TeachingRecordSystem.Api.V3.V20240307; - -public class MapperProfile : Profile -{ - public MapperProfile() - { - CreateMap(); - CreateMap() - .ForMember(p => p.Email, m => m.MapFrom(p => p.EmailAddress)); - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/ApiMapper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/ApiMapper.cs new file mode 100644 index 0000000000..036bc9f772 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/ApiMapper.cs @@ -0,0 +1,15 @@ +using Riok.Mapperly.Abstractions; +using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Api.V3.V20240412.Responses; + +namespace TeachingRecordSystem.Api.V3.V20240412; + +[Mapper] +public partial class ApiMapper +{ + public CreateNameChangeResponse MapCreateNameChangeResponse(CreateNameChangeRequestResult source) => + new() { CaseNumber = source.CaseNumber }; + + public CreateDateOfBirthChangeResponse MapCreateDateOfBirthChangeResponse(CreateDateOfBirthChangeRequestResult source) => + new() { CaseNumber = source.CaseNumber }; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/Controllers/TeacherController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/Controllers/TeacherController.cs index 734b28a9cd..996a1e0a0c 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/Controllers/TeacherController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/Controllers/TeacherController.cs @@ -10,7 +10,7 @@ namespace TeachingRecordSystem.Api.V3.V20240412.Controllers; [Route("teacher")] -public class TeacherController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class TeacherController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpPost("name-changes")] [SwaggerOperation( @@ -35,7 +35,7 @@ public async Task CreateNameChangeAsync([FromBody] CreateNameChan var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))); + return result.ToActionResult(r => Ok(mapper.MapCreateNameChangeResponse(r))); } [HttpPost("date-of-birth-changes")] @@ -59,6 +59,6 @@ public async Task CreateDateOfBirthChangeAsync([FromBody] CreateD var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))); + return result.ToActionResult(r => Ok(mapper.MapCreateDateOfBirthChangeResponse(r))); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/Responses/CreateDateOfBirthChangeResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/Responses/CreateDateOfBirthChangeResponse.cs index 7579501e66..78cc402e22 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/Responses/CreateDateOfBirthChangeResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/Responses/CreateDateOfBirthChangeResponse.cs @@ -1,8 +1,5 @@ -using TeachingRecordSystem.Api.V3.Implementation.Operations; - namespace TeachingRecordSystem.Api.V3.V20240412.Responses; -[AutoMap(typeof(CreateDateOfBirthChangeRequestResult))] public record CreateDateOfBirthChangeResponse { public required string CaseNumber { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/Responses/CreateNameChangeResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/Responses/CreateNameChangeResponse.cs index d89282b066..8d1f3511cd 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/Responses/CreateNameChangeResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240412/Responses/CreateNameChangeResponse.cs @@ -1,8 +1,5 @@ -using TeachingRecordSystem.Api.V3.Implementation.Operations; - namespace TeachingRecordSystem.Api.V3.V20240412.Responses; -[AutoMap(typeof(CreateNameChangeRequestResult))] public record CreateNameChangeResponse { public required string CaseNumber { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/ApiMapper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/ApiMapper.cs new file mode 100644 index 0000000000..21ac3da353 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/ApiMapper.cs @@ -0,0 +1,124 @@ +using Optional; +using Riok.Mapperly.Abstractions; +using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Api.V3.V20240416.Responses; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; + +namespace TeachingRecordSystem.Api.V3.V20240416; + +[Mapper] +public partial class ApiMapper +{ + public GetTeacherResponse MapGetTeacherResponse(GetPersonResult source) => + new() + { + Trn = source.Trn, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + DateOfBirth = source.DateOfBirth, + NationalInsuranceNumber = source.NationalInsuranceNumber, + PendingNameChange = source.PendingNameChange, + PendingDateOfBirthChange = source.PendingDateOfBirthChange, + Email = source.EmailAddress, + Qts = source.Qts is { } qts ? MapQts(qts) : null, + Eyts = source.Eyts is { } eyts ? MapEyts(eyts) : null, + Induction = source.DqtInduction.Map(d => d is null ? (GetTeacherResponseInduction?)null : MapDqtInduction(d)), + InitialTeacherTraining = source.InitialTeacherTraining.Map( + itt => (IReadOnlyCollection)itt.AsT0 + .Select(MapInitialTeacherTraining).AsReadOnly()), + NpqQualifications = Option.None>(), + MandatoryQualifications = source.MandatoryQualifications.Map( + mqs => (IReadOnlyCollection)mqs + .Select(mq => new GetTeacherResponseMandatoryQualification + { + Awarded = default, + Specialism = mq.Specialism + }).AsReadOnly()), + HigherEducationQualifications = Option.None>(), + Sanctions = source.Sanctions.Map( + ss => (IReadOnlyCollection)ss.Select(MapSanctionInfo).AsReadOnly()), + Alerts = source.Alerts.Map( + alerts => (IReadOnlyCollection)alerts.Select(MapAlertInfo).AsReadOnly()), + PreviousNames = source.PreviousNames.Map( + pns => (IReadOnlyCollection)pns.Select(MapNameInfo).AsReadOnly()), + AllowIdSignInWithProhibitions = source.AllowIdSignInWithProhibitions + }; + + private GetTeacherResponseQts MapQts(Implementation.Dtos.QtsInfo source) => + new() { Awarded = source.HoldsFrom, CertificateUrl = source.CertificateUrl, StatusDescription = source.StatusDescription }; + + private GetTeacherResponseEyts MapEyts(Implementation.Dtos.EytsInfo source) => + new() { Awarded = source.HoldsFrom, CertificateUrl = source.CertificateUrl, StatusDescription = source.StatusDescription }; + + private GetTeacherResponseInduction MapDqtInduction(GetPersonResultDqtInduction source) => + new() + { + StartDate = source.StartDate, + EndDate = source.EndDate, + Status = MapDqtInductionStatus(source.Status), + StatusDescription = source.StatusDescription, + CertificateUrl = source.CertificateUrl, + Periods = source.Periods.Select(p => new GetTeacherResponseInductionPeriod + { + StartDate = p.StartDate, + EndDate = p.EndDate, + Terms = p.Terms, + AppropriateBody = p.AppropriateBody is { } ab + ? new GetTeacherResponseInductionPeriodAppropriateBody { Name = ab.Name } + : null + }).AsReadOnly() + }; + + private GetTeacherResponseInitialTeacherTraining MapInitialTeacherTraining(GetPersonResultInitialTeacherTraining source) => + new() + { + Qualification = source.Qualification is { } q + ? new GetTeacherResponseInitialTeacherTrainingQualification { Name = q.Name } + : null, + StartDate = source.StartDate, + EndDate = source.EndDate, + ProgrammeType = null, + ProgrammeTypeDescription = null, + Result = null, + AgeRange = source.AgeRange is { } ar + ? new GetTeacherResponseInitialTeacherTrainingAgeRange { Description = ar.Description } + : null, + Provider = source.Provider is { } p + ? new GetTeacherResponseInitialTeacherTrainingProvider { Name = p.Name, Ukprn = p.Ukprn } + : null, + Subjects = source.Subjects + .Select(s => new GetTeacherResponseInitialTeacherTrainingSubject { Code = s.Code, Name = s.Name }) + .AsReadOnly() + }; + + private SanctionInfo MapSanctionInfo(Implementation.Dtos.SanctionInfo source) => + new() { Code = source.Code, StartDate = source.StartDate }; + + private AlertInfo MapAlertInfo(Implementation.Dtos.Alert source) => + new() + { + AlertType = AlertType.Prohibition, + DqtSanctionCode = source.AlertType.DqtSanctionCode!, + StartDate = source.StartDate, + EndDate = source.EndDate + }; + + private NameInfo MapNameInfo(Implementation.Dtos.NameInfo source) => + new() { FirstName = source.FirstName, MiddleName = source.MiddleName, LastName = source.LastName }; + + private static Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus MapDqtInductionStatus(Implementation.Dtos.DqtInductionStatus source) => + source switch + { + Implementation.Dtos.DqtInductionStatus.Exempt => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Exempt, + Implementation.Dtos.DqtInductionStatus.Fail => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Fail, + Implementation.Dtos.DqtInductionStatus.FailedInWales => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.FailedinWales, + Implementation.Dtos.DqtInductionStatus.InductionExtended => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.InductionExtended, + Implementation.Dtos.DqtInductionStatus.InProgress => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.InProgress, + Implementation.Dtos.DqtInductionStatus.NotYetCompleted => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.NotYetCompleted, + Implementation.Dtos.DqtInductionStatus.Pass => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Pass, + Implementation.Dtos.DqtInductionStatus.PassedInWales => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.PassedinWales, + Implementation.Dtos.DqtInductionStatus.RequiredToComplete => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.RequiredtoComplete, + _ => throw new ArgumentOutOfRangeException(nameof(source)) + }; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Controllers/TeacherController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Controllers/TeacherController.cs index eef37199a6..c159b5c0a7 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Controllers/TeacherController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Controllers/TeacherController.cs @@ -11,7 +11,7 @@ namespace TeachingRecordSystem.Api.V3.V20240416.Controllers; [Route("teacher")] -public class TeacherController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class TeacherController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [Authorize(AuthorizationPolicies.IdentityUserWithTrn)] [HttpGet] @@ -36,7 +36,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapGetTeacherResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status403Forbidden); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Controllers/TeachersController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Controllers/TeachersController.cs index 4f38e9e15e..b6ca47f46a 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Controllers/TeachersController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Controllers/TeachersController.cs @@ -10,7 +10,7 @@ namespace TeachingRecordSystem.Api.V3.V20240416.Controllers; [Route("teachers")] -public class TeachersController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class TeachersController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpGet("{trn}")] [SwaggerOperation( @@ -38,7 +38,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapGetTeacherResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsDeactivated, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsMerged, StatusCodes.Status404NotFound); diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/MapperProfile.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/MapperProfile.cs deleted file mode 100644 index e66bd19461..0000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/MapperProfile.cs +++ /dev/null @@ -1,23 +0,0 @@ -using OneOf; -using TeachingRecordSystem.Api.Infrastructure.Mapping; -using TeachingRecordSystem.Api.V3.Implementation.Operations; -using TeachingRecordSystem.Api.V3.V20240416.Responses; - -namespace TeachingRecordSystem.Api.V3.V20240416; - -public class MapperProfile : Profile -{ - public MapperProfile() - { - CreateMap< - OneOf< - IReadOnlyCollection, - IReadOnlyCollection>, - IReadOnlyCollection>() - .ConvertUsing( - new FromOneOfT0TypeConverter< - IReadOnlyCollection, - IReadOnlyCollection, - IReadOnlyCollection>()); - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Responses/GetTeacherResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Responses/GetTeacherResponse.cs index 186d639229..2fc85f9c6a 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Responses/GetTeacherResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Responses/GetTeacherResponse.cs @@ -1,12 +1,9 @@ using System.Text.Json.Serialization; -using AutoMapper.Configuration.Annotations; using Optional; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; namespace TeachingRecordSystem.Api.V3.V20240416.Responses; -[AutoMap(typeof(GetPersonResult))] public record GetTeacherResponse { public required string Trn { get; init; } @@ -17,11 +14,9 @@ public record GetTeacherResponse public required string? NationalInsuranceNumber { get; init; } public required Option PendingNameChange { get; init; } public required Option PendingDateOfBirthChange { get; init; } - [SourceMember("EmailAddress")] public required string? Email { get; init; } public required GetTeacherResponseQts? Qts { get; init; } public required GetTeacherResponseEyts? Eyts { get; init; } - [SourceMember(nameof(GetPersonResult.DqtInduction))] public required Option Induction { get; init; } public required Option> InitialTeacherTraining { get; init; } public required Option> NpqQualifications { get; init; } @@ -33,25 +28,20 @@ public record GetTeacherResponse public required Option AllowIdSignInWithProhibitions { get; init; } } -[AutoMap(typeof(Implementation.Dtos.QtsInfo))] public record GetTeacherResponseQts { - [SourceMember(nameof(Implementation.Dtos.QtsInfo.HoldsFrom))] public required DateOnly? Awarded { get; init; } public required string CertificateUrl { get; init; } public required string? StatusDescription { get; init; } } -[AutoMap(typeof(Implementation.Dtos.EytsInfo))] public record GetTeacherResponseEyts { - [SourceMember(nameof(Implementation.Dtos.QtsInfo.HoldsFrom))] public required DateOnly? Awarded { get; init; } public required string CertificateUrl { get; init; } public required string? StatusDescription { get; init; } } -[AutoMap(typeof(GetPersonResultDqtInduction))] public record GetTeacherResponseInduction { public required DateOnly? StartDate { get; init; } @@ -63,7 +53,6 @@ public record GetTeacherResponseInduction public required IReadOnlyCollection Periods { get; init; } } -[AutoMap(typeof(GetPersonResultDqtInductionPeriod))] public record GetTeacherResponseInductionPeriod { public required DateOnly? StartDate { get; init; } @@ -72,13 +61,11 @@ public record GetTeacherResponseInductionPeriod public required GetTeacherResponseInductionPeriodAppropriateBody? AppropriateBody { get; init; } } -[AutoMap(typeof(GetPersonResultInductionPeriodAppropriateBody))] public record GetTeacherResponseInductionPeriodAppropriateBody { public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTraining))] public record GetTeacherResponseInitialTeacherTraining { public required GetTeacherResponseInitialTeacherTrainingQualification? Qualification { get; init; } @@ -92,26 +79,22 @@ public record GetTeacherResponseInitialTeacherTraining public required IReadOnlyCollection Subjects { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingQualification))] public record GetTeacherResponseInitialTeacherTrainingQualification { public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingAgeRange))] public record GetTeacherResponseInitialTeacherTrainingAgeRange { public required string Description { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingProvider))] public record GetTeacherResponseInitialTeacherTrainingProvider { public required string Name { get; init; } public required string Ukprn { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingSubject))] public record GetTeacherResponseInitialTeacherTrainingSubject { public required string Code { get; init; } @@ -131,7 +114,6 @@ public record GetTeacherResponseNpqQualificationType public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultMandatoryQualification))] public record GetTeacherResponseMandatoryQualification { public required DateOnly Awarded { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/ApiMapper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/ApiMapper.cs new file mode 100644 index 0000000000..678bccb79b --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/ApiMapper.cs @@ -0,0 +1,134 @@ +using Optional; +using Riok.Mapperly.Abstractions; +using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Api.V3.V20240606.Responses; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; +using V20240606Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20240606.Dtos; + +namespace TeachingRecordSystem.Api.V3.V20240606; + +[Mapper] +public partial class ApiMapper +{ + public GetPersonResponse MapGetPersonResponse(GetPersonResult source) => + new() + { + Trn = source.Trn, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + DateOfBirth = source.DateOfBirth, + NationalInsuranceNumber = source.NationalInsuranceNumber, + PendingNameChange = source.PendingNameChange, + PendingDateOfBirthChange = source.PendingDateOfBirthChange, + EmailAddress = source.EmailAddress, + Qts = source.Qts is { } qts ? new GetPersonResponseQts { Awarded = qts.HoldsFrom, CertificateUrl = qts.CertificateUrl, StatusDescription = qts.StatusDescription } : null, + Eyts = source.Eyts is { } eyts ? new GetPersonResponseEyts { Awarded = eyts.HoldsFrom, CertificateUrl = eyts.CertificateUrl, StatusDescription = eyts.StatusDescription } : null, + Induction = source.DqtInduction.Map(d => d is null ? (GetPersonResponseInduction?)null : MapDqtInduction(d)), + InitialTeacherTraining = source.InitialTeacherTraining.Map( + itt => (IReadOnlyCollection)itt.AsT0 + .Select(MapInitialTeacherTraining).AsReadOnly()), + NpqQualifications = Option.None>(), + MandatoryQualifications = source.MandatoryQualifications.Map( + mqs => (IReadOnlyCollection)mqs + .Select(mq => new GetPersonResponseMandatoryQualification { Awarded = mq.EndDate, Specialism = mq.Specialism }) + .AsReadOnly()), + HigherEducationQualifications = Option.None>(), + Sanctions = source.Sanctions.Map( + ss => (IReadOnlyCollection)ss.Select(MapSanctionInfo).AsReadOnly()), + Alerts = source.Alerts.Map( + alerts => (IReadOnlyCollection)alerts.Select(MapAlertInfo).AsReadOnly()), + PreviousNames = source.PreviousNames.Map( + pns => (IReadOnlyCollection)pns.Select(MapNameInfo).AsReadOnly()), + AllowIdSignInWithProhibitions = source.AllowIdSignInWithProhibitions + }; + + public FindPersonResponseResult MapFindPersonResponseResult(FindPersonsResultItem source) => + new() + { + Trn = source.Trn, + DateOfBirth = source.DateOfBirth, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + Sanctions = source.Sanctions.Select(MapSanctionInfo).AsReadOnly(), + PreviousNames = source.PreviousNames.Select(MapNameInfo).AsReadOnly() + }; + + public V20240606Dtos.TrnRequestInfo MapTrnRequestInfo(Implementation.Dtos.TrnRequestInfo source) => + new() + { + RequestId = source.RequestId, + Status = (V20240606Dtos.TrnRequestStatus)(int)source.Status, + Trn = source.Trn + }; + + public CreateNameChangeResponse MapCreateNameChangeResponse(CreateNameChangeRequestResult source) => + new() { CaseNumber = source.CaseNumber }; + + public CreateDateOfBirthChangeResponse MapCreateDateOfBirthChangeResponse(CreateDateOfBirthChangeRequestResult source) => + new() { CaseNumber = source.CaseNumber }; + + private GetPersonResponseInduction MapDqtInduction(GetPersonResultDqtInduction source) => + new() + { + StartDate = source.StartDate, + EndDate = source.EndDate, + Status = MapDqtInductionStatus(source.Status), + StatusDescription = source.StatusDescription, + CertificateUrl = source.CertificateUrl, + Periods = source.Periods.Select(p => new GetPersonResponseInductionPeriod + { + StartDate = p.StartDate, + EndDate = p.EndDate, + Terms = p.Terms, + AppropriateBody = p.AppropriateBody is { } ab + ? new GetPersonResponseInductionPeriodAppropriateBody { Name = ab.Name } + : null + }).AsReadOnly() + }; + + private GetPersonResponseInitialTeacherTraining MapInitialTeacherTraining(GetPersonResultInitialTeacherTraining source) => + new() + { + Qualification = source.Qualification is { } q ? new GetPersonResponseInitialTeacherTrainingQualification { Name = q.Name } : null, + StartDate = source.StartDate, + EndDate = source.EndDate, + ProgrammeType = null, + ProgrammeTypeDescription = null, + Result = null, + AgeRange = source.AgeRange is { } ar ? new GetPersonResponseInitialTeacherTrainingAgeRange { Description = ar.Description } : null, + Provider = source.Provider is { } p ? new GetPersonResponseInitialTeacherTrainingProvider { Name = p.Name, Ukprn = p.Ukprn } : null, + Subjects = source.Subjects.Select(s => new GetPersonResponseInitialTeacherTrainingSubject { Code = s.Code, Name = s.Name }).AsReadOnly() + }; + + private SanctionInfo MapSanctionInfo(Implementation.Dtos.SanctionInfo source) => + new() { Code = source.Code, StartDate = source.StartDate }; + + private AlertInfo MapAlertInfo(Implementation.Dtos.Alert source) => + new() + { + AlertType = AlertType.Prohibition, + DqtSanctionCode = source.AlertType.DqtSanctionCode!, + StartDate = source.StartDate, + EndDate = source.EndDate + }; + + private NameInfo MapNameInfo(Implementation.Dtos.NameInfo source) => + new() { FirstName = source.FirstName, MiddleName = source.MiddleName, LastName = source.LastName }; + + private static Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus MapDqtInductionStatus(Implementation.Dtos.DqtInductionStatus source) => + source switch + { + Implementation.Dtos.DqtInductionStatus.Exempt => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Exempt, + Implementation.Dtos.DqtInductionStatus.Fail => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Fail, + Implementation.Dtos.DqtInductionStatus.FailedInWales => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.FailedinWales, + Implementation.Dtos.DqtInductionStatus.InductionExtended => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.InductionExtended, + Implementation.Dtos.DqtInductionStatus.InProgress => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.InProgress, + Implementation.Dtos.DqtInductionStatus.NotYetCompleted => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.NotYetCompleted, + Implementation.Dtos.DqtInductionStatus.Pass => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Pass, + Implementation.Dtos.DqtInductionStatus.PassedInWales => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.PassedinWales, + Implementation.Dtos.DqtInductionStatus.RequiredToComplete => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.RequiredtoComplete, + _ => throw new ArgumentOutOfRangeException(nameof(source)) + }; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/PersonController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/PersonController.cs index bbb35241c9..8e900539af 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/PersonController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/PersonController.cs @@ -11,7 +11,7 @@ namespace TeachingRecordSystem.Api.V3.V20240606.Controllers; [Route("person")] -public class PersonController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [Authorize(AuthorizationPolicies.IdentityUserWithTrn)] [HttpGet] @@ -36,7 +36,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapGetPersonResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status403Forbidden); } @@ -64,7 +64,7 @@ public async Task CreateNameChangeAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))); + return result.ToActionResult(r => Ok(mapper.MapCreateNameChangeResponse(r))); } [HttpPost("date-of-birth-changes")] @@ -89,6 +89,6 @@ public async Task CreateDateOfBirthChangeAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))); + return result.ToActionResult(r => Ok(mapper.MapCreateDateOfBirthChangeResponse(r))); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/PersonsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/PersonsController.cs index dbec409348..7fb5faf727 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/PersonsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/PersonsController.cs @@ -10,7 +10,7 @@ namespace TeachingRecordSystem.Api.V3.V20240606.Controllers; [Route("persons")] -public class PersonsController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonsController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpGet("{trn}")] [SwaggerOperation( @@ -38,7 +38,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapGetPersonResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsDeactivated, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsMerged, StatusCodes.Status404NotFound); @@ -62,7 +62,7 @@ public async Task FindPersonsAsync(FindPersonRequest request) { Total = r.Total, Query = request, - Results = r.Items.Select(mapper.Map).AsReadOnly() + Results = r.Items.Select(mapper.MapFindPersonResponseResult).AsReadOnly() })); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/TrnRequestsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/TrnRequestsController.cs index 02c06c4627..d706e398c3 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/TrnRequestsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/TrnRequestsController.cs @@ -10,7 +10,7 @@ namespace TeachingRecordSystem.Api.V3.V20240606.Controllers; [Route("trn-requests")] [Authorize(Policy = AuthorizationPolicies.ApiKey, Roles = ApiRoles.CreateTrn)] -public class TrnRequestsController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class TrnRequestsController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpPost("")] [SwaggerOperation( @@ -41,7 +41,7 @@ public async Task CreateTrnRequestAsync([FromBody] CreateTrnReque }; var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapTrnRequestInfo(r))) .MapErrorCode(ApiError.ErrorCodes.TrnRequestAlreadyCreated, StatusCodes.Status409Conflict); } @@ -60,7 +60,7 @@ public async Task GetTrnRequestAsync([FromQuery] string requestId var command = new GetTrnRequestCommand(requestId); var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapTrnRequestInfo(r))) .MapErrorCode(ApiError.ErrorCodes.TrnRequestDoesNotExist, StatusCodes.Status404NotFound); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/MapperProfile.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/MapperProfile.cs deleted file mode 100644 index c5e218e2bd..0000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/MapperProfile.cs +++ /dev/null @@ -1,25 +0,0 @@ -using OneOf; -using TeachingRecordSystem.Api.Infrastructure.Mapping; -using TeachingRecordSystem.Api.V3.Implementation.Operations; -using TeachingRecordSystem.Api.V3.V20240606.Responses; -using TeachingRecordSystem.Core.ApiSchema.V3.V20240606.Dtos; - -namespace TeachingRecordSystem.Api.V3.V20240606; - -public class MapperProfile : Profile -{ - public MapperProfile() - { - CreateMap(); - CreateMap< - OneOf< - IReadOnlyCollection, - IReadOnlyCollection>, - IReadOnlyCollection>() - .ConvertUsing( - new FromOneOfT0TypeConverter< - IReadOnlyCollection, - IReadOnlyCollection, - IReadOnlyCollection>()); - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateDateOfBirthChangeResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateDateOfBirthChangeResponse.cs index 8e7584aa4f..f9d75eb452 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateDateOfBirthChangeResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateDateOfBirthChangeResponse.cs @@ -1,8 +1,5 @@ -using TeachingRecordSystem.Api.V3.Implementation.Operations; - namespace TeachingRecordSystem.Api.V3.V20240606.Responses; -[AutoMap(typeof(CreateDateOfBirthChangeRequestResult))] public record CreateDateOfBirthChangeResponse { public required string CaseNumber { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateNameChangeResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateNameChangeResponse.cs index 00e02e519c..6b64461d1e 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateNameChangeResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateNameChangeResponse.cs @@ -1,8 +1,5 @@ -using TeachingRecordSystem.Api.V3.Implementation.Operations; - namespace TeachingRecordSystem.Api.V3.V20240606.Responses; -[AutoMap(typeof(CreateNameChangeRequestResult))] public record CreateNameChangeResponse { public required string CaseNumber { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/FindPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/FindPersonResponse.cs index 6c98b479dd..024ddc1693 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/FindPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/FindPersonResponse.cs @@ -1,4 +1,3 @@ -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Api.V3.V20240606.Requests; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; @@ -11,7 +10,6 @@ public record FindPersonResponse public required IReadOnlyCollection Results { get; init; } } -[AutoMap(typeof(FindPersonsResultItem))] public record FindPersonResponseResult { public required string Trn { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/GetPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/GetPersonResponse.cs index 24547fa128..0861229701 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/GetPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/GetPersonResponse.cs @@ -1,12 +1,9 @@ using System.Text.Json.Serialization; -using AutoMapper.Configuration.Annotations; using Optional; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; namespace TeachingRecordSystem.Api.V3.V20240606.Responses; -[AutoMap(typeof(GetPersonResult))] public record GetPersonResponse { public required string Trn { get; init; } @@ -20,7 +17,6 @@ public record GetPersonResponse public required string? EmailAddress { get; init; } public required GetPersonResponseQts? Qts { get; init; } public required GetPersonResponseEyts? Eyts { get; init; } - [SourceMember(nameof(GetPersonResult.DqtInduction))] public required Option Induction { get; init; } public required Option> InitialTeacherTraining { get; init; } public required Option> NpqQualifications { get; init; } @@ -32,25 +28,20 @@ public record GetPersonResponse public required Option AllowIdSignInWithProhibitions { get; init; } } -[AutoMap(typeof(Implementation.Dtos.QtsInfo))] public record GetPersonResponseQts { - [SourceMember(nameof(Implementation.Dtos.QtsInfo.HoldsFrom))] public required DateOnly? Awarded { get; init; } public required string CertificateUrl { get; init; } public required string? StatusDescription { get; init; } } -[AutoMap(typeof(Implementation.Dtos.EytsInfo))] public record GetPersonResponseEyts { - [SourceMember(nameof(Implementation.Dtos.QtsInfo.HoldsFrom))] public required DateOnly? Awarded { get; init; } public required string CertificateUrl { get; init; } public required string? StatusDescription { get; init; } } -[AutoMap(typeof(GetPersonResultDqtInduction))] public record GetPersonResponseInduction { public required DateOnly? StartDate { get; init; } @@ -62,7 +53,6 @@ public record GetPersonResponseInduction public required IReadOnlyCollection Periods { get; init; } } -[AutoMap(typeof(GetPersonResultDqtInductionPeriod))] public record GetPersonResponseInductionPeriod { public required DateOnly? StartDate { get; init; } @@ -71,13 +61,11 @@ public record GetPersonResponseInductionPeriod public required GetPersonResponseInductionPeriodAppropriateBody? AppropriateBody { get; init; } } -[AutoMap(typeof(GetPersonResultInductionPeriodAppropriateBody))] public record GetPersonResponseInductionPeriodAppropriateBody { public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTraining))] public record GetPersonResponseInitialTeacherTraining { public required GetPersonResponseInitialTeacherTrainingQualification? Qualification { get; init; } @@ -91,26 +79,22 @@ public record GetPersonResponseInitialTeacherTraining public required IReadOnlyCollection Subjects { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingQualification))] public record GetPersonResponseInitialTeacherTrainingQualification { public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingAgeRange))] public record GetPersonResponseInitialTeacherTrainingAgeRange { public required string Description { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingProvider))] public record GetPersonResponseInitialTeacherTrainingProvider { public required string Name { get; init; } public required string Ukprn { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingSubject))] public record GetPersonResponseInitialTeacherTrainingSubject { public required string Code { get; init; } @@ -130,10 +114,8 @@ public record GetPersonResponseNpqQualificationType public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultMandatoryQualification))] public record GetPersonResponseMandatoryQualification { - [SourceMember("EndDate")] public required DateOnly Awarded { get; init; } public required string Specialism { get; init; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/ApiMapper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/ApiMapper.cs new file mode 100644 index 0000000000..baea478235 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/ApiMapper.cs @@ -0,0 +1,78 @@ +using Riok.Mapperly.Abstractions; +using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Api.V3.V20240814.Responses; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; +using V20240814Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; + +namespace TeachingRecordSystem.Api.V3.V20240814; + +[Mapper] +public partial class ApiMapper +{ + public FindPersonsResponse MapFindPersonsResponse(FindPersonsResult source) => + new() + { + Total = source.Total, + Results = source.Items.Select(MapFindPersonsResponseResult).AsReadOnly() + }; + + public FindPersonsResponseResult MapFindPersonsResponseResult(FindPersonsResultItem source) => + new() + { + Trn = source.Trn, + DateOfBirth = source.DateOfBirth, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + Sanctions = source.Sanctions.Select(MapSanctionInfo).AsReadOnly(), + PreviousNames = source.PreviousNames.Select(MapNameInfo).AsReadOnly(), + InductionStatus = source.DqtInductionStatus is { } dqt ? MapDqtInductionStatusInfo(dqt) : null!, + Qts = source.Qts is { } qts ? MapQts(qts) : null, + Eyts = source.Eyts is { } eyts ? MapEyts(eyts) : null + }; + + private V20240814Dtos.DqtInductionStatusInfo MapDqtInductionStatusInfo(Implementation.Dtos.DqtInductionStatusInfo source) => + new() { Status = MapDqtInductionStatus(source.Status), StatusDescription = source.StatusDescription }; + + private V20240814Dtos.QtsInfo MapQts(Implementation.Dtos.QtsInfo source) => + new() { Awarded = source.HoldsFrom, StatusDescription = source.StatusDescription }; + + private V20240814Dtos.EytsInfo MapEyts(Implementation.Dtos.EytsInfo source) => + new() { Awarded = source.HoldsFrom, StatusDescription = source.StatusDescription }; + + private SanctionInfo MapSanctionInfo(Implementation.Dtos.SanctionInfo source) => + new() { Code = source.Code, StartDate = source.StartDate }; + + private NameInfo MapNameInfo(Implementation.Dtos.NameInfo source) => + new() { FirstName = source.FirstName, MiddleName = source.MiddleName, LastName = source.LastName }; + + public FindPersonResponseResult MapFindPersonResponseResult(FindPersonsResultItem source) => + new() + { + Trn = source.Trn, + DateOfBirth = source.DateOfBirth, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + Sanctions = source.Sanctions.Select(MapSanctionInfo).AsReadOnly(), + PreviousNames = source.PreviousNames.Select(MapNameInfo).AsReadOnly(), + InductionStatus = source.DqtInductionStatus is { } dqt ? MapDqtInductionStatusInfo(dqt) : null!, + Qts = source.Qts is { } qts ? MapQts(qts) : null, + Eyts = source.Eyts is { } eyts ? MapEyts(eyts) : null + }; + + private static Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus MapDqtInductionStatus(Implementation.Dtos.DqtInductionStatus source) => + source switch + { + Implementation.Dtos.DqtInductionStatus.Exempt => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Exempt, + Implementation.Dtos.DqtInductionStatus.Fail => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Fail, + Implementation.Dtos.DqtInductionStatus.FailedInWales => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.FailedinWales, + Implementation.Dtos.DqtInductionStatus.InductionExtended => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.InductionExtended, + Implementation.Dtos.DqtInductionStatus.InProgress => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.InProgress, + Implementation.Dtos.DqtInductionStatus.NotYetCompleted => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.NotYetCompleted, + Implementation.Dtos.DqtInductionStatus.Pass => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Pass, + Implementation.Dtos.DqtInductionStatus.PassedInWales => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.PassedinWales, + Implementation.Dtos.DqtInductionStatus.RequiredToComplete => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.RequiredtoComplete, + _ => throw new ArgumentOutOfRangeException(nameof(source)) + }; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Controllers/PersonsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Controllers/PersonsController.cs index 9e823586a6..1d3fb8721c 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Controllers/PersonsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Controllers/PersonsController.cs @@ -9,7 +9,7 @@ namespace TeachingRecordSystem.Api.V3.V20240814.Controllers; [Route("persons")] -public class PersonsController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonsController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpPost("find")] [SwaggerOperation( @@ -23,7 +23,7 @@ public async Task FindPersonsAsync([FromBody] FindPersonsRequest { var command = new FindPersonsByTrnAndDateOfBirthCommand(request.Persons.Select(p => (p.Trn, p.DateOfBirth))); var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))); + return result.ToActionResult(r => Ok(mapper.MapFindPersonsResponse(r))); } [HttpGet("")] @@ -44,7 +44,7 @@ public async Task FindPersonsAsync(FindPersonRequest request) { Total = r.Total, Query = request, - Results = r.Items.Select(mapper.Map).AsReadOnly() + Results = r.Items.Select(mapper.MapFindPersonResponseResult).AsReadOnly() })); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/MapperProfile.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/MapperProfile.cs deleted file mode 100644 index a4dd2562ea..0000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/MapperProfile.cs +++ /dev/null @@ -1,15 +0,0 @@ -using TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; - -namespace TeachingRecordSystem.Api.V3.V20240814; - -public class MapperProfile : Profile -{ - public MapperProfile() - { - CreateMap() - .ForMember(i => i.Awarded, m => m.MapFrom(i => i.HoldsFrom)); - CreateMap(); - CreateMap() - .ForMember(i => i.Awarded, m => m.MapFrom(i => i.HoldsFrom)); - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonResponse.cs index 02e2a4e275..3a6a8d57ce 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonResponse.cs @@ -1,5 +1,3 @@ -using AutoMapper.Configuration.Annotations; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Api.V3.V20240814.Requests; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; @@ -13,7 +11,6 @@ public record FindPersonResponse public required IReadOnlyCollection Results { get; init; } } -[AutoMap(typeof(FindPersonsResultItem))] public record FindPersonResponseResult { public required string Trn { get; init; } @@ -23,7 +20,6 @@ public record FindPersonResponseResult public required string LastName { get; init; } public required IReadOnlyCollection Sanctions { get; init; } public required IReadOnlyCollection PreviousNames { get; init; } - [SourceMember(nameof(FindPersonsResultItem.DqtInductionStatus))] public required DqtInductionStatusInfo InductionStatus { get; init; } public required QtsInfo? Qts { get; init; } public required EytsInfo? Eyts { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonsResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonsResponse.cs index 07a1ee108f..0fe782c656 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonsResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonsResponse.cs @@ -1,19 +1,14 @@ -using AutoMapper.Configuration.Annotations; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; namespace TeachingRecordSystem.Api.V3.V20240814.Responses; -[AutoMap(typeof(FindPersonsResult))] public record FindPersonsResponse { public required int Total { get; init; } - [SourceMember(nameof(FindPersonsResult.Items))] public required IReadOnlyCollection Results { get; init; } } -[AutoMap(typeof(FindPersonsResultItem))] public record FindPersonsResponseResult { public required string Trn { get; init; } @@ -23,7 +18,6 @@ public record FindPersonsResponseResult public required string LastName { get; init; } public required IReadOnlyCollection Sanctions { get; init; } public required IReadOnlyCollection PreviousNames { get; init; } - [SourceMember(nameof(FindPersonsResultItem.DqtInductionStatus))] public required DqtInductionStatusInfo InductionStatus { get; init; } public required QtsInfo? Qts { get; init; } public required EytsInfo? Eyts { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240912/ApiMapper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240912/ApiMapper.cs new file mode 100644 index 0000000000..4042e7c74e --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240912/ApiMapper.cs @@ -0,0 +1,12 @@ +using Riok.Mapperly.Abstractions; +using TeachingRecordSystem.Api.V3.Implementation.Dtos; +using V20240912Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20240912.Dtos; + +namespace TeachingRecordSystem.Api.V3.V20240912; + +[Mapper] +public partial class ApiMapper +{ + public V20240912Dtos.QtlsResponse MapQtlsResponse(QtlsResult source) => + new() { QtsDate = source.QtsDate, Trn = source.Trn }; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240912/Controllers/PersonsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240912/Controllers/PersonsController.cs index abd2ae4c20..7998140850 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240912/Controllers/PersonsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240912/Controllers/PersonsController.cs @@ -9,7 +9,7 @@ namespace TeachingRecordSystem.Api.V3.V20240912.Controllers; [Route("persons")] -public class PersonsController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonsController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpPut("{trn}/qtls")] [SwaggerOperation( @@ -26,7 +26,7 @@ public async Task PutQtlsAsync( var command = new SetQtlsCommand(trn, request.QtsDate); var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapQtlsResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status404NotFound); } @@ -42,7 +42,7 @@ public async Task GetQtlsAsync([FromRoute] string trn) { var command = new GetQtlsCommand(trn); var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapQtlsResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status404NotFound); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240912/MapperProfile.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240912/MapperProfile.cs deleted file mode 100644 index 28c3fa87da..0000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240912/MapperProfile.cs +++ /dev/null @@ -1,11 +0,0 @@ -using TeachingRecordSystem.Core.ApiSchema.V3.V20240912.Dtos; - -namespace TeachingRecordSystem.Api.V3.V20240912; - -public class MapperProfile : Profile -{ - public MapperProfile() - { - CreateMap(); - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/ApiMapper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/ApiMapper.cs new file mode 100644 index 0000000000..0e83cbdadf --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/ApiMapper.cs @@ -0,0 +1,157 @@ +using OneOf; +using Optional; +using Riok.Mapperly.Abstractions; +using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Api.V3.V20240920.Responses; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; +using V20240814Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; +using V20240920Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; + +namespace TeachingRecordSystem.Api.V3.V20240920; + +[Mapper] +public partial class ApiMapper +{ + public GetPersonResponse MapGetPersonResponse(GetPersonResult source) => + new() + { + Trn = source.Trn, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + DateOfBirth = source.DateOfBirth, + NationalInsuranceNumber = source.NationalInsuranceNumber, + PendingNameChange = source.PendingNameChange, + PendingDateOfBirthChange = source.PendingDateOfBirthChange, + EmailAddress = source.EmailAddress, + Qts = source.Qts is { } qts ? new GetPersonResponseQts { Awarded = qts.HoldsFrom, CertificateUrl = qts.CertificateUrl, StatusDescription = qts.StatusDescription } : null, + Eyts = source.Eyts is { } eyts ? new GetPersonResponseEyts { Awarded = eyts.HoldsFrom, CertificateUrl = eyts.CertificateUrl, StatusDescription = eyts.StatusDescription } : null, + Induction = source.DqtInduction.Map(d => d is null ? (GetPersonResponseInduction?)null : MapDqtInduction(d)), + InitialTeacherTraining = source.InitialTeacherTraining.Map(MapIttOneOf), + NpqQualifications = Option.None>(), + MandatoryQualifications = source.MandatoryQualifications.Map( + mqs => (IReadOnlyCollection)mqs + .Select(mq => new GetPersonResponseMandatoryQualification { Awarded = mq.EndDate, Specialism = mq.Specialism }) + .AsReadOnly()), + HigherEducationQualifications = Option.None>(), + Sanctions = source.Sanctions.Map( + ss => (IReadOnlyCollection)ss.Select(MapSanctionInfo).AsReadOnly()), + Alerts = source.Alerts.Map( + alerts => (IReadOnlyCollection)alerts.Select(MapAlert).AsReadOnly()), + PreviousNames = source.PreviousNames.Map( + pns => (IReadOnlyCollection)pns.Select(MapNameInfo).AsReadOnly()), + AllowIdSignInWithProhibitions = source.AllowIdSignInWithProhibitions + }; + + public FindPersonsResponse MapFindPersonsResponse(FindPersonsResult source) => + new() + { + Total = source.Total, + Results = source.Items.Select(MapFindPersonsResponseResult).AsReadOnly() + }; + + public FindPersonsResponseResult MapFindPersonsResponseResult(FindPersonsResultItem source) => + new() + { + Trn = source.Trn, + DateOfBirth = source.DateOfBirth, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + PreviousNames = source.PreviousNames.Select(MapNameInfo).AsReadOnly(), + InductionStatus = source.DqtInductionStatus is { } dqt ? new V20240814Dtos.DqtInductionStatusInfo { Status = MapDqtInductionStatus(dqt.Status), StatusDescription = dqt.StatusDescription } : null!, + Qts = source.Qts is { } qts ? new V20240814Dtos.QtsInfo { Awarded = qts.HoldsFrom, StatusDescription = qts.StatusDescription } : null, + Eyts = source.Eyts is { } eyts ? new V20240814Dtos.EytsInfo { Awarded = eyts.HoldsFrom, StatusDescription = eyts.StatusDescription } : null, + Alerts = source.Alerts.Select(MapAlert).AsReadOnly() + }; + + private OneOf, IReadOnlyCollection> MapIttOneOf( + OneOf, IReadOnlyCollection> source) => + source.Match( + t0 => OneOf, IReadOnlyCollection>.FromT0( + t0.Select(MapInitialTeacherTraining).AsReadOnly()), + t1 => OneOf, IReadOnlyCollection>.FromT1( + t1.Select(i => new GetPersonResponseInitialTeacherTrainingForAppropriateBody + { + Provider = new GetPersonResponseInitialTeacherTrainingProvider { Name = i.Provider.Name, Ukprn = i.Provider.Ukprn } + }).AsReadOnly())); + + private GetPersonResponseInduction MapDqtInduction(GetPersonResultDqtInduction source) => + new() + { + StartDate = source.StartDate, + EndDate = source.EndDate, + Status = MapDqtInductionStatus(source.Status), + StatusDescription = source.StatusDescription, + CertificateUrl = source.CertificateUrl + }; + + private GetPersonResponseInitialTeacherTraining MapInitialTeacherTraining(GetPersonResultInitialTeacherTraining source) => + new() + { + Provider = source.Provider is { } p ? new GetPersonResponseInitialTeacherTrainingProvider { Name = p.Name, Ukprn = p.Ukprn } : null, + Qualification = source.Qualification is { } q ? new GetPersonResponseInitialTeacherTrainingQualification { Name = q.Name } : null, + StartDate = source.StartDate, + EndDate = source.EndDate, + ProgrammeType = null, + ProgrammeTypeDescription = null, + Result = null, + AgeRange = source.AgeRange is { } ar ? new GetPersonResponseInitialTeacherTrainingAgeRange { Description = ar.Description } : null, + Subjects = source.Subjects.Select(s => new GetPersonResponseInitialTeacherTrainingSubject { Code = s.Code, Name = s.Name }).AsReadOnly() + }; + + internal V20240920Dtos.Alert MapAlert(Implementation.Dtos.Alert source) => + new() + { + AlertId = source.AlertId, + AlertType = new V20240920Dtos.AlertType + { + AlertTypeId = source.AlertType.AlertTypeId, + Name = source.AlertType.Name, + AlertCategory = new V20240920Dtos.AlertCategory + { + AlertCategoryId = source.AlertType.AlertCategory.AlertCategoryId, + Name = source.AlertType.AlertCategory.Name + } + }, + Details = source.Details, + StartDate = source.StartDate, + EndDate = source.EndDate + }; + + internal SanctionInfo MapSanctionInfo(Implementation.Dtos.SanctionInfo source) => + new() { Code = source.Code, StartDate = source.StartDate }; + + internal NameInfo MapNameInfo(Implementation.Dtos.NameInfo source) => + new() { FirstName = source.FirstName, MiddleName = source.MiddleName, LastName = source.LastName }; + + public FindPersonResponseResult MapFindPersonResponseResult(FindPersonsResultItem source) => + new() + { + Trn = source.Trn, + DateOfBirth = source.DateOfBirth, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + PreviousNames = source.PreviousNames.Select(MapNameInfo).AsReadOnly(), + InductionStatus = source.DqtInductionStatus is { } dqt ? new V20240814Dtos.DqtInductionStatusInfo { Status = MapDqtInductionStatus(dqt.Status), StatusDescription = dqt.StatusDescription } : null!, + Qts = source.Qts is { } qts ? new V20240814Dtos.QtsInfo { Awarded = qts.HoldsFrom, StatusDescription = qts.StatusDescription } : null, + Eyts = source.Eyts is { } eyts ? new V20240814Dtos.EytsInfo { Awarded = eyts.HoldsFrom, StatusDescription = eyts.StatusDescription } : null, + Alerts = source.Alerts.Select(MapAlert).AsReadOnly() + }; + + private static Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus MapDqtInductionStatus(Implementation.Dtos.DqtInductionStatus source) => + source switch + { + Implementation.Dtos.DqtInductionStatus.Exempt => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Exempt, + Implementation.Dtos.DqtInductionStatus.Fail => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Fail, + Implementation.Dtos.DqtInductionStatus.FailedInWales => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.FailedinWales, + Implementation.Dtos.DqtInductionStatus.InductionExtended => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.InductionExtended, + Implementation.Dtos.DqtInductionStatus.InProgress => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.InProgress, + Implementation.Dtos.DqtInductionStatus.NotYetCompleted => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.NotYetCompleted, + Implementation.Dtos.DqtInductionStatus.Pass => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.Pass, + Implementation.Dtos.DqtInductionStatus.PassedInWales => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.PassedinWales, + Implementation.Dtos.DqtInductionStatus.RequiredToComplete => Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus.RequiredtoComplete, + _ => throw new ArgumentOutOfRangeException(nameof(source)) + }; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Controllers/PersonController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Controllers/PersonController.cs index 3868a993c1..cf04c9060d 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Controllers/PersonController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Controllers/PersonController.cs @@ -11,7 +11,7 @@ namespace TeachingRecordSystem.Api.V3.V20240920.Controllers; [Route("person")] -public class PersonController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [Authorize(AuthorizationPolicies.IdentityUserWithTrn)] [HttpGet] @@ -32,7 +32,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapGetPersonResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status403Forbidden); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Controllers/PersonsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Controllers/PersonsController.cs index da2f5f420d..fb095aea2b 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Controllers/PersonsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Controllers/PersonsController.cs @@ -10,7 +10,7 @@ namespace TeachingRecordSystem.Api.V3.V20240920.Controllers; [Route("persons")] -public class PersonsController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonsController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpGet("{trn}")] [SwaggerOperation( @@ -40,7 +40,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapGetPersonResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsDeactivated, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsMerged, StatusCodes.Status404NotFound) @@ -59,7 +59,7 @@ public async Task FindPersonsAsync([FromBody] FindPersonsRequest { var command = new FindPersonsByTrnAndDateOfBirthCommand(request.Persons.Select(p => (p.Trn, p.DateOfBirth))); var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))); + return result.ToActionResult(r => Ok(mapper.MapFindPersonsResponse(r))); } [HttpGet("")] @@ -80,7 +80,7 @@ public async Task FindPersonsAsync(FindPersonRequest request) { Total = r.Total, Query = request, - Results = r.Items.Select(mapper.Map).AsReadOnly() + Results = r.Items.Select(mapper.MapFindPersonResponseResult).AsReadOnly() })); } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/MapperProfile.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/MapperProfile.cs deleted file mode 100644 index 23001d7d43..0000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/MapperProfile.cs +++ /dev/null @@ -1,13 +0,0 @@ -using TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; - -namespace TeachingRecordSystem.Api.V3.V20240920; - -public class MapperProfile : Profile -{ - public MapperProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonResponse.cs index 945710e721..948b8a0110 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonResponse.cs @@ -1,5 +1,3 @@ -using AutoMapper.Configuration.Annotations; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Api.V3.V20240920.Requests; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; @@ -14,7 +12,6 @@ public record FindPersonResponse public required IReadOnlyCollection Results { get; init; } } -[AutoMap(typeof(FindPersonsResultItem))] public record FindPersonResponseResult { public required string Trn { get; init; } @@ -23,7 +20,6 @@ public record FindPersonResponseResult public required string MiddleName { get; init; } public required string LastName { get; init; } public required IReadOnlyCollection PreviousNames { get; init; } - [SourceMember(nameof(FindPersonsResultItem.DqtInductionStatus))] public required DqtInductionStatusInfo InductionStatus { get; init; } public required QtsInfo? Qts { get; init; } public required EytsInfo? Eyts { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonsResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonsResponse.cs index 0ee19b2806..89b6c77ec1 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonsResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonsResponse.cs @@ -1,20 +1,15 @@ -using AutoMapper.Configuration.Annotations; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; namespace TeachingRecordSystem.Api.V3.V20240920.Responses; -[AutoMap(typeof(FindPersonsResult))] public record FindPersonsResponse { public required int Total { get; init; } - [SourceMember(nameof(FindPersonsResult.Items))] public required IReadOnlyCollection Results { get; init; } } -[AutoMap(typeof(FindPersonsResultItem))] public record FindPersonsResponseResult { public required string Trn { get; init; } @@ -23,7 +18,6 @@ public record FindPersonsResponseResult public required string MiddleName { get; init; } public required string LastName { get; init; } public required IReadOnlyCollection PreviousNames { get; init; } - [SourceMember(nameof(FindPersonsResultItem.DqtInductionStatus))] public required DqtInductionStatusInfo InductionStatus { get; init; } public required QtsInfo? Qts { get; init; } public required EytsInfo? Eyts { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/GetPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/GetPersonResponse.cs index c491cc7f92..0bbf8a4a49 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/GetPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/GetPersonResponse.cs @@ -1,14 +1,11 @@ using System.Text.Json.Serialization; -using AutoMapper.Configuration.Annotations; using OneOf; using Optional; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; namespace TeachingRecordSystem.Api.V3.V20240920.Responses; -[AutoMap(typeof(GetPersonResult))] public record GetPersonResponse { public required string Trn { get; init; } @@ -22,7 +19,6 @@ public record GetPersonResponse public required string? EmailAddress { get; init; } public required GetPersonResponseQts? Qts { get; init; } public required GetPersonResponseEyts? Eyts { get; init; } - [SourceMember(nameof(GetPersonResult.DqtInduction))] public required Option Induction { get; init; } public required Option, IReadOnlyCollection>> InitialTeacherTraining { get; init; } public required Option> NpqQualifications { get; init; } @@ -34,25 +30,20 @@ public record GetPersonResponse public required Option AllowIdSignInWithProhibitions { get; init; } } -[AutoMap(typeof(Implementation.Dtos.QtsInfo))] public record GetPersonResponseQts { - [SourceMember(nameof(Implementation.Dtos.QtsInfo.HoldsFrom))] public required DateOnly? Awarded { get; init; } public required string CertificateUrl { get; init; } public required string? StatusDescription { get; init; } } -[AutoMap(typeof(Implementation.Dtos.EytsInfo))] public record GetPersonResponseEyts { - [SourceMember(nameof(Implementation.Dtos.QtsInfo.HoldsFrom))] public required DateOnly? Awarded { get; init; } public required string CertificateUrl { get; init; } public required string? StatusDescription { get; init; } } -[AutoMap(typeof(GetPersonResultDqtInduction))] public record GetPersonResponseInduction { public required DateOnly? StartDate { get; init; } @@ -63,7 +54,6 @@ public record GetPersonResponseInduction public required string? CertificateUrl { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTraining))] public record GetPersonResponseInitialTeacherTraining { public required GetPersonResponseInitialTeacherTrainingProvider? Provider { get; init; } @@ -77,32 +67,27 @@ public record GetPersonResponseInitialTeacherTraining public required IReadOnlyCollection Subjects { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingForAppropriateBody))] public record GetPersonResponseInitialTeacherTrainingForAppropriateBody { public required GetPersonResponseInitialTeacherTrainingProvider Provider { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingQualification))] public record GetPersonResponseInitialTeacherTrainingQualification { public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingAgeRange))] public record GetPersonResponseInitialTeacherTrainingAgeRange { public required string Description { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingProvider))] public record GetPersonResponseInitialTeacherTrainingProvider { public required string Name { get; init; } public required string Ukprn { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingSubject))] public record GetPersonResponseInitialTeacherTrainingSubject { public required string Code { get; init; } @@ -122,10 +107,8 @@ public record GetPersonResponseNpqQualificationType public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultMandatoryQualification))] public record GetPersonResponseMandatoryQualification { - [SourceMember("EndDate")] public required DateOnly Awarded { get; init; } public required string Specialism { get; init; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/ApiMapper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/ApiMapper.cs new file mode 100644 index 0000000000..63433b0d02 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/ApiMapper.cs @@ -0,0 +1,155 @@ +using OneOf; +using Optional; +using Riok.Mapperly.Abstractions; +using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Api.V3.V20250203.Responses; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; +using V20240606Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20240606.Dtos; +using V20240814Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; +using V20240920Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; +using V20250203Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20250203.Dtos; + +namespace TeachingRecordSystem.Api.V3.V20250203; + +[Mapper] +public partial class ApiMapper +{ + public GetPersonResponse MapGetPersonResponse(GetPersonResult source) => + new() + { + Trn = source.Trn, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + DateOfBirth = source.DateOfBirth, + NationalInsuranceNumber = source.NationalInsuranceNumber, + PendingNameChange = source.PendingNameChange, + PendingDateOfBirthChange = source.PendingDateOfBirthChange, + EmailAddress = source.EmailAddress, + Qts = source.Qts is { } qts ? new GetPersonResponseQts { Awarded = qts.HoldsFrom, StatusDescription = qts.StatusDescription } : null, + Eyts = source.Eyts is { } eyts ? new GetPersonResponseEyts { Awarded = eyts.HoldsFrom, StatusDescription = eyts.StatusDescription } : null, + Induction = source.Induction.Map(ind => new V20250203Dtos.InductionInfo + { + Status = (V20250203Dtos.InductionStatus)(int)ind.Status, + StartDate = ind.StartDate, + CompletedDate = ind.CompletedDate + }), + InitialTeacherTraining = source.InitialTeacherTraining.Map(MapIttOneOf), + NpqQualifications = Option.None>(), + MandatoryQualifications = source.MandatoryQualifications.Map( + mqs => (IReadOnlyCollection)mqs + .Select(mq => new GetPersonResponseMandatoryQualification { Awarded = mq.EndDate, Specialism = mq.Specialism }) + .AsReadOnly()), + Sanctions = source.Sanctions.Map( + ss => (IReadOnlyCollection)ss.Select(MapSanctionInfo).AsReadOnly()), + Alerts = source.Alerts.Map( + alerts => (IReadOnlyCollection)alerts.Select(MapAlert).AsReadOnly()), + PreviousNames = source.PreviousNames.Map( + pns => (IReadOnlyCollection)pns.Select(MapNameInfo).AsReadOnly()), + AllowIdSignInWithProhibitions = source.AllowIdSignInWithProhibitions, + QtlsStatus = (V20250203Dtos.QtlsStatus)(int)source.QtlsStatus + }; + + public FindPersonsResponse MapFindPersonsResponse(FindPersonsResult source) => + new() + { + Total = source.Total, + Results = source.Items.Select(MapFindPersonsResponseResult).AsReadOnly() + }; + + public FindPersonsResponseResult MapFindPersonsResponseResult(FindPersonsResultItem source) => + new() + { + Trn = source.Trn, + DateOfBirth = source.DateOfBirth, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + PreviousNames = source.PreviousNames.Select(MapNameInfo).AsReadOnly(), + Qts = source.Qts is { } qts ? new V20240814Dtos.QtsInfo { Awarded = qts.HoldsFrom, StatusDescription = qts.StatusDescription } : null, + Eyts = source.Eyts is { } eyts ? new V20240814Dtos.EytsInfo { Awarded = eyts.HoldsFrom, StatusDescription = eyts.StatusDescription } : null, + Alerts = source.Alerts.Select(MapAlert).AsReadOnly(), + InductionStatus = (V20250203Dtos.InductionStatus)(int)source.Induction.Status, + QtlsStatus = (V20250203Dtos.QtlsStatus)(int)source.QtlsStatus + }; + + public V20240606Dtos.TrnRequestInfo MapTrnRequestInfo(Implementation.Dtos.TrnRequestInfo source) => + new() + { + RequestId = source.RequestId, + Status = (V20240606Dtos.TrnRequestStatus)(int)source.Status, + Trn = source.Trn + }; + + public Core.Models.Gender MapGender(V20250203Dtos.Gender source) => + (Core.Models.Gender)(int)source; + + public Core.Models.InductionStatus MapInductionStatus(V20250203Dtos.InductionStatus source) => + (Core.Models.InductionStatus)(int)source; + + private OneOf, IReadOnlyCollection> MapIttOneOf( + OneOf, IReadOnlyCollection> source) => + source.Match( + t0 => OneOf, IReadOnlyCollection>.FromT0( + t0.Select(MapInitialTeacherTraining).AsReadOnly()), + t1 => OneOf, IReadOnlyCollection>.FromT1( + t1.Select(i => new GetPersonResponseInitialTeacherTrainingForAppropriateBody + { + Provider = new GetPersonResponseInitialTeacherTrainingProvider { Name = i.Provider.Name, Ukprn = i.Provider.Ukprn } + }).AsReadOnly())); + + private GetPersonResponseInitialTeacherTraining MapInitialTeacherTraining(GetPersonResultInitialTeacherTraining source) => + new() + { + Provider = source.Provider is { } p ? new GetPersonResponseInitialTeacherTrainingProvider { Name = p.Name, Ukprn = p.Ukprn } : null, + Qualification = source.Qualification is { } q ? new GetPersonResponseInitialTeacherTrainingQualification { Name = q.Name } : null, + StartDate = source.StartDate, + EndDate = source.EndDate, + ProgrammeType = null, + ProgrammeTypeDescription = null, + Result = null, + AgeRange = source.AgeRange is { } ar ? new GetPersonResponseInitialTeacherTrainingAgeRange { Description = ar.Description } : null, + Subjects = source.Subjects.Select(s => new GetPersonResponseInitialTeacherTrainingSubject { Code = s.Code, Name = s.Name }).AsReadOnly() + }; + + internal V20240920Dtos.Alert MapAlert(Implementation.Dtos.Alert source) => + new() + { + AlertId = source.AlertId, + AlertType = new V20240920Dtos.AlertType + { + AlertTypeId = source.AlertType.AlertTypeId, + Name = source.AlertType.Name, + AlertCategory = new V20240920Dtos.AlertCategory + { + AlertCategoryId = source.AlertType.AlertCategory.AlertCategoryId, + Name = source.AlertType.AlertCategory.Name + } + }, + Details = source.Details, + StartDate = source.StartDate, + EndDate = source.EndDate + }; + + internal SanctionInfo MapSanctionInfo(Implementation.Dtos.SanctionInfo source) => + new() { Code = source.Code, StartDate = source.StartDate }; + + internal NameInfo MapNameInfo(Implementation.Dtos.NameInfo source) => + new() { FirstName = source.FirstName, MiddleName = source.MiddleName, LastName = source.LastName }; + + public FindPersonResponseResult MapFindPersonResponseResult(FindPersonsResultItem source) => + new() + { + Trn = source.Trn, + DateOfBirth = source.DateOfBirth, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + PreviousNames = source.PreviousNames.Select(MapNameInfo).AsReadOnly(), + Qts = source.Qts is { } qts ? new V20240814Dtos.QtsInfo { Awarded = qts.HoldsFrom, StatusDescription = qts.StatusDescription } : null, + Eyts = source.Eyts is { } eyts ? new V20240814Dtos.EytsInfo { Awarded = eyts.HoldsFrom, StatusDescription = eyts.StatusDescription } : null, + Alerts = source.Alerts.Select(MapAlert).AsReadOnly(), + InductionStatus = (V20250203Dtos.InductionStatus)(int)source.Induction.Status, + QtlsStatus = (V20250203Dtos.QtlsStatus)(int)source.QtlsStatus + }; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Controllers/PersonController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Controllers/PersonController.cs index 0a5cdcf441..034c6f796d 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Controllers/PersonController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Controllers/PersonController.cs @@ -11,7 +11,7 @@ namespace TeachingRecordSystem.Api.V3.V20250203.Controllers; [Route("person")] -public class PersonController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [Authorize(AuthorizationPolicies.IdentityUserWithTrn)] [HttpGet] @@ -32,7 +32,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapGetPersonResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status403Forbidden); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Controllers/PersonsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Controllers/PersonsController.cs index 82ae5ffd01..d09eefc8b9 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Controllers/PersonsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Controllers/PersonsController.cs @@ -10,7 +10,7 @@ namespace TeachingRecordSystem.Api.V3.V20250203.Controllers; [Route("persons")] -public class PersonsController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonsController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpPut("{trn}/cpd-induction")] [SwaggerOperation( @@ -27,7 +27,7 @@ public async Task SetCpdInductionStatusAsync( { var command = new SetCpdInductionStatusCommand( trn, - mapper.Map(request.Status), + mapper.MapInductionStatus(request.Status), request.StartDate, request.CompletedDate, request.ModifiedOn.UtcDateTime); @@ -75,7 +75,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); return result - .ToActionResult(r => Ok(mapper.Map(r))) + .ToActionResult(r => Ok(mapper.MapGetPersonResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsDeactivated, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsMerged, StatusCodes.Status404NotFound) @@ -94,7 +94,7 @@ public async Task FindPersonsAsync([FromBody] FindPersonsRequest { var command = new FindPersonsByTrnAndDateOfBirthCommand(request.Persons.Select(p => (p.Trn, p.DateOfBirth))); var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))); + return result.ToActionResult(r => Ok(mapper.MapFindPersonsResponse(r))); } [HttpGet("")] @@ -115,7 +115,7 @@ public async Task FindPersonsAsync(FindPersonRequest request) { Total = r.Total, Query = request, - Results = r.Items.Select(mapper.Map).AsReadOnly() + Results = r.Items.Select(mapper.MapFindPersonResponseResult).AsReadOnly() })); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Controllers/TrnRequestsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Controllers/TrnRequestsController.cs index 24ab8d3ead..366be8eb27 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Controllers/TrnRequestsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Controllers/TrnRequestsController.cs @@ -11,7 +11,7 @@ namespace TeachingRecordSystem.Api.V3.V20250203.Controllers; [Route("trn-requests")] [Authorize(Policy = AuthorizationPolicies.ApiKey, Roles = ApiRoles.CreateTrn)] -public class TrnRequestsController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class TrnRequestsController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpPost("")] [SwaggerOperation( @@ -39,12 +39,12 @@ public async Task CreateTrnRequestAsync([FromBody] CreateTrnReque NationalInsuranceNumber = request.Person.NationalInsuranceNumber, IdentityVerified = request.IdentityVerified, OneLoginUserSubject = request.OneLoginUserSubject, - Gender = request.Person.Gender is Gender gender ? mapper.Map(gender) : null + Gender = request.Person.Gender is Gender gender ? mapper.MapGender(gender) : null }; var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapTrnRequestInfo(r))) .MapErrorCode(ApiError.ErrorCodes.TrnRequestAlreadyCreated, StatusCodes.Status409Conflict); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/MapperProfile.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/MapperProfile.cs deleted file mode 100644 index 172fea12dd..0000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/MapperProfile.cs +++ /dev/null @@ -1,13 +0,0 @@ -using TeachingRecordSystem.Core.ApiSchema.V3.V20250203.Dtos; -using TrnRequestInfo = TeachingRecordSystem.Core.ApiSchema.V3.V20250203.Dtos.TrnRequestInfo; - -namespace TeachingRecordSystem.Api.V3.V20250203; - -public class MapperProfile : Profile -{ - public MapperProfile() - { - CreateMap(); - CreateMap(); - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Responses/FindPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Responses/FindPersonResponse.cs index 20dc7fc754..af2b999793 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Responses/FindPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Responses/FindPersonResponse.cs @@ -1,5 +1,3 @@ -using AutoMapper.Configuration.Annotations; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Api.V3.V20250203.Requests; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; @@ -16,7 +14,6 @@ public record FindPersonResponse public required IReadOnlyCollection Results { get; init; } } -[AutoMap(typeof(FindPersonsResultItem))] public record FindPersonResponseResult { public required string Trn { get; init; } @@ -28,7 +25,6 @@ public record FindPersonResponseResult public required QtsInfo? Qts { get; init; } public required EytsInfo? Eyts { get; init; } public required IReadOnlyCollection Alerts { get; init; } - [SourceMember("Induction.Status")] public required InductionStatus InductionStatus { get; init; } public required QtlsStatus QtlsStatus { get; set; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Responses/FindPersonsResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Responses/FindPersonsResponse.cs index ef150604f8..de7c81d335 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Responses/FindPersonsResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Responses/FindPersonsResponse.cs @@ -1,5 +1,3 @@ -using AutoMapper.Configuration.Annotations; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; using InductionStatus = TeachingRecordSystem.Core.ApiSchema.V3.V20250203.Dtos.InductionStatus; @@ -8,15 +6,12 @@ namespace TeachingRecordSystem.Api.V3.V20250203.Responses; -[AutoMap(typeof(FindPersonsResult))] public record FindPersonsResponse { public required int Total { get; init; } - [SourceMember(nameof(FindPersonsResult.Items))] public required IReadOnlyCollection Results { get; init; } } -[AutoMap(typeof(FindPersonsResultItem))] public record FindPersonsResponseResult { public required string Trn { get; init; } @@ -28,7 +23,6 @@ public record FindPersonsResponseResult public required QtsInfo? Qts { get; init; } public required EytsInfo? Eyts { get; init; } public required IReadOnlyCollection Alerts { get; init; } - [SourceMember("Induction.Status")] public required InductionStatus InductionStatus { get; init; } public required QtlsStatus QtlsStatus { get; set; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Responses/GetPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Responses/GetPersonResponse.cs index e72720c98f..bf43bd6685 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Responses/GetPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250203/Responses/GetPersonResponse.cs @@ -1,7 +1,5 @@ -using AutoMapper.Configuration.Annotations; using OneOf; using Optional; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20250203.Dtos; @@ -9,7 +7,6 @@ namespace TeachingRecordSystem.Api.V3.V20250203.Responses; -[AutoMap(typeof(GetPersonResult))] public record GetPersonResponse { public required string Trn { get; init; } @@ -34,23 +31,18 @@ public record GetPersonResponse public required QtlsStatus QtlsStatus { get; set; } } -[AutoMap(typeof(Implementation.Dtos.QtsInfo))] public record GetPersonResponseQts { - [SourceMember(nameof(Implementation.Dtos.QtsInfo.HoldsFrom))] public required DateOnly? Awarded { get; init; } public required string? StatusDescription { get; init; } } -[AutoMap(typeof(Implementation.Dtos.EytsInfo))] public record GetPersonResponseEyts { - [SourceMember(nameof(Implementation.Dtos.QtsInfo.HoldsFrom))] public required DateOnly? Awarded { get; init; } public required string? StatusDescription { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTraining))] public record GetPersonResponseInitialTeacherTraining { public required GetPersonResponseInitialTeacherTrainingProvider? Provider { get; init; } @@ -64,32 +56,27 @@ public record GetPersonResponseInitialTeacherTraining public required IReadOnlyCollection Subjects { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingForAppropriateBody))] public record GetPersonResponseInitialTeacherTrainingForAppropriateBody { public required GetPersonResponseInitialTeacherTrainingProvider Provider { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingQualification))] public record GetPersonResponseInitialTeacherTrainingQualification { public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingAgeRange))] public record GetPersonResponseInitialTeacherTrainingAgeRange { public required string Description { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingProvider))] public record GetPersonResponseInitialTeacherTrainingProvider { public required string Name { get; init; } public required string Ukprn { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingSubject))] public record GetPersonResponseInitialTeacherTrainingSubject { public required string Code { get; init; } @@ -108,10 +95,8 @@ public record GetPersonResponseNpqQualificationType public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultMandatoryQualification))] public record GetPersonResponseMandatoryQualification { - [SourceMember("EndDate")] public required DateOnly Awarded { get; init; } public required string Specialism { get; init; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/ApiMapper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/ApiMapper.cs new file mode 100644 index 0000000000..d976ba3d5e --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/ApiMapper.cs @@ -0,0 +1,140 @@ +using OneOf; +using Optional; +using Riok.Mapperly.Abstractions; +using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Api.V3.V20250327.Responses; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; +using V20240920Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; +using V20250203Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20250203.Dtos; +using V20250327Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20250327.Dtos; + +namespace TeachingRecordSystem.Api.V3.V20250327; + +[Mapper] +public partial class ApiMapper +{ + public GetPersonResponse MapGetPersonResponse(GetPersonResult source) => + new() + { + Trn = source.Trn, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + DateOfBirth = source.DateOfBirth, + NationalInsuranceNumber = source.NationalInsuranceNumber, + PendingNameChange = source.PendingNameChange, + PendingDateOfBirthChange = source.PendingDateOfBirthChange, + EmailAddress = source.EmailAddress, + Qts = source.Qts is { } qts ? new GetPersonResponseQts { Awarded = qts.HoldsFrom, StatusDescription = qts.StatusDescription, AwardedOrApprovedCount = qts.AwardedOrApprovedCount } : null, + Eyts = source.Eyts is { } eyts ? new GetPersonResponseEyts { Awarded = eyts.HoldsFrom, StatusDescription = eyts.StatusDescription } : null, + Induction = source.Induction.Map(ind => new V20250203Dtos.InductionInfo + { + Status = (V20250203Dtos.InductionStatus)(int)ind.Status, + StartDate = ind.StartDate, + CompletedDate = ind.CompletedDate + }), + InitialTeacherTraining = source.InitialTeacherTraining.Map(MapIttOneOf), + NpqQualifications = Option.None>(), + MandatoryQualifications = source.MandatoryQualifications.Map( + mqs => (IReadOnlyCollection)mqs + .Select(mq => new GetPersonResponseMandatoryQualification { Awarded = mq.EndDate, Specialism = mq.Specialism }) + .AsReadOnly()), + Sanctions = source.Sanctions.Map( + ss => (IReadOnlyCollection)ss.Select(MapSanctionInfo).AsReadOnly()), + Alerts = source.Alerts.Map( + alerts => (IReadOnlyCollection)alerts.Select(MapAlert).AsReadOnly()), + PreviousNames = source.PreviousNames.Map( + pns => (IReadOnlyCollection)pns.Select(MapNameInfo).AsReadOnly()), + AllowIdSignInWithProhibitions = source.AllowIdSignInWithProhibitions, + QtlsStatus = (V20250203Dtos.QtlsStatus)(int)source.QtlsStatus + }; + + public FindPersonsResponse MapFindPersonsResponse(FindPersonsResult source) => + new() + { + Total = source.Total, + Results = source.Items.Select(MapFindPersonsResponseResult).AsReadOnly() + }; + + public FindPersonsResponseResult MapFindPersonsResponseResult(FindPersonsResultItem source) => + new() + { + Trn = source.Trn, + DateOfBirth = source.DateOfBirth, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + PreviousNames = source.PreviousNames.Select(MapNameInfo).AsReadOnly(), + Qts = source.Qts is { } qts ? new V20250327Dtos.QtsInfo { Awarded = qts.HoldsFrom, StatusDescription = qts.StatusDescription, AwardedOrApprovedCount = qts.AwardedOrApprovedCount } : null, + Eyts = source.Eyts is { } eyts ? new Core.ApiSchema.V3.V20240814.Dtos.EytsInfo { Awarded = eyts.HoldsFrom, StatusDescription = eyts.StatusDescription } : null, + Alerts = source.Alerts.Select(MapAlert).AsReadOnly(), + InductionStatus = (V20250203Dtos.InductionStatus)(int)source.Induction.Status, + QtlsStatus = (V20250203Dtos.QtlsStatus)(int)source.QtlsStatus + }; + + private OneOf, IReadOnlyCollection> MapIttOneOf( + OneOf, IReadOnlyCollection> source) => + source.Match( + t0 => OneOf, IReadOnlyCollection>.FromT0( + t0.Select(MapInitialTeacherTraining).AsReadOnly()), + t1 => OneOf, IReadOnlyCollection>.FromT1( + t1.Select(i => new GetPersonResponseInitialTeacherTrainingForAppropriateBody + { + Provider = new GetPersonResponseInitialTeacherTrainingProvider { Name = i.Provider.Name, Ukprn = i.Provider.Ukprn } + }).AsReadOnly())); + + private GetPersonResponseInitialTeacherTraining MapInitialTeacherTraining(GetPersonResultInitialTeacherTraining source) => + new() + { + Provider = source.Provider is { } p ? new GetPersonResponseInitialTeacherTrainingProvider { Name = p.Name, Ukprn = p.Ukprn } : null, + Qualification = source.Qualification is { } q ? new GetPersonResponseInitialTeacherTrainingQualification { Name = q.Name } : null, + StartDate = source.StartDate, + EndDate = source.EndDate, + ProgrammeType = null, + ProgrammeTypeDescription = null, + Result = null, + AgeRange = source.AgeRange is { } ar ? new GetPersonResponseInitialTeacherTrainingAgeRange { Description = ar.Description } : null, + Subjects = source.Subjects.Select(s => new GetPersonResponseInitialTeacherTrainingSubject { Code = s.Code, Name = s.Name }).AsReadOnly() + }; + + private V20240920Dtos.Alert MapAlert(Implementation.Dtos.Alert source) => + new() + { + AlertId = source.AlertId, + AlertType = new V20240920Dtos.AlertType + { + AlertTypeId = source.AlertType.AlertTypeId, + Name = source.AlertType.Name, + AlertCategory = new V20240920Dtos.AlertCategory + { + AlertCategoryId = source.AlertType.AlertCategory.AlertCategoryId, + Name = source.AlertType.AlertCategory.Name + } + }, + Details = source.Details, + StartDate = source.StartDate, + EndDate = source.EndDate + }; + + private SanctionInfo MapSanctionInfo(Implementation.Dtos.SanctionInfo source) => + new() { Code = source.Code, StartDate = source.StartDate }; + + private NameInfo MapNameInfo(Implementation.Dtos.NameInfo source) => + new() { FirstName = source.FirstName, MiddleName = source.MiddleName, LastName = source.LastName }; + + public FindPersonResponseResult MapFindPersonResponseResult(FindPersonsResultItem source) => + new() + { + Trn = source.Trn, + DateOfBirth = source.DateOfBirth, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + PreviousNames = source.PreviousNames.Select(MapNameInfo).AsReadOnly(), + Qts = source.Qts is { } qts ? new V20250327Dtos.QtsInfo { Awarded = qts.HoldsFrom, StatusDescription = qts.StatusDescription, AwardedOrApprovedCount = qts.AwardedOrApprovedCount } : null, + Eyts = source.Eyts is { } eyts ? new Core.ApiSchema.V3.V20240814.Dtos.EytsInfo { Awarded = eyts.HoldsFrom, StatusDescription = eyts.StatusDescription } : null, + Alerts = source.Alerts.Select(MapAlert).AsReadOnly(), + InductionStatus = (V20250203Dtos.InductionStatus)(int)source.Induction.Status, + QtlsStatus = (V20250203Dtos.QtlsStatus)(int)source.QtlsStatus + }; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Controllers/PersonController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Controllers/PersonController.cs index 2090ba5dc3..137c0209ac 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Controllers/PersonController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Controllers/PersonController.cs @@ -11,7 +11,7 @@ namespace TeachingRecordSystem.Api.V3.V20250327.Controllers; [Route("person")] -public class PersonController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [Authorize(AuthorizationPolicies.IdentityUserWithTrn)] [HttpGet] @@ -32,7 +32,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapGetPersonResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status403Forbidden); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Controllers/PersonsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Controllers/PersonsController.cs index 8c318efb7a..d55843f163 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Controllers/PersonsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Controllers/PersonsController.cs @@ -10,7 +10,7 @@ namespace TeachingRecordSystem.Api.V3.V20250327.Controllers; [Route("persons")] -public class PersonsController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonsController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpGet("{trn}")] [SwaggerOperation( @@ -48,7 +48,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); return result - .ToActionResult(r => Ok(mapper.Map(r))) + .ToActionResult(r => Ok(mapper.MapGetPersonResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsDeactivated, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsMerged, StatusCodes.Status404NotFound) @@ -67,7 +67,7 @@ public async Task FindPersonsAsync([FromBody] FindPersonsRequest { var command = new FindPersonsByTrnAndDateOfBirthCommand(request.Persons.Select(p => (p.Trn, p.DateOfBirth))); var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))); + return result.ToActionResult(r => Ok(mapper.MapFindPersonsResponse(r))); } [HttpGet("")] @@ -88,7 +88,7 @@ public async Task FindPersonsAsync(FindPersonRequest request) { Total = r.Total, Query = request, - Results = r.Items.Select(mapper.Map).AsReadOnly() + Results = r.Items.Select(mapper.MapFindPersonResponseResult).AsReadOnly() })); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/MapperProfile.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/MapperProfile.cs deleted file mode 100644 index b2979b85f4..0000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/MapperProfile.cs +++ /dev/null @@ -1,12 +0,0 @@ -using TeachingRecordSystem.Core.ApiSchema.V3.V20250327.Dtos; - -namespace TeachingRecordSystem.Api.V3.V20250327; - -public class MapperProfile : Profile -{ - public MapperProfile() - { - CreateMap() - .ForMember(i => i.Awarded, m => m.MapFrom(i => i.HoldsFrom)); - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Responses/FindPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Responses/FindPersonResponse.cs index dfb55a7d56..33e9eca564 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Responses/FindPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Responses/FindPersonResponse.cs @@ -1,5 +1,3 @@ -using AutoMapper.Configuration.Annotations; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Api.V3.V20250327.Requests; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; @@ -17,7 +15,6 @@ public record FindPersonResponse public required IReadOnlyCollection Results { get; init; } } -[AutoMap(typeof(FindPersonsResultItem))] public record FindPersonResponseResult { public required string Trn { get; init; } @@ -29,7 +26,6 @@ public record FindPersonResponseResult public required QtsInfo? Qts { get; init; } public required EytsInfo? Eyts { get; init; } public required IReadOnlyCollection Alerts { get; init; } - [SourceMember("Induction.Status")] public required InductionStatus InductionStatus { get; init; } public required QtlsStatus QtlsStatus { get; set; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Responses/FindPersonsResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Responses/FindPersonsResponse.cs index c6f14aa520..e056ab4caf 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Responses/FindPersonsResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Responses/FindPersonsResponse.cs @@ -1,5 +1,3 @@ -using AutoMapper.Configuration.Annotations; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; using InductionStatus = TeachingRecordSystem.Core.ApiSchema.V3.V20250203.Dtos.InductionStatus; @@ -9,15 +7,12 @@ namespace TeachingRecordSystem.Api.V3.V20250327.Responses; -[AutoMap(typeof(FindPersonsResult))] public record FindPersonsResponse { public required int Total { get; init; } - [SourceMember(nameof(FindPersonsResult.Items))] public required IReadOnlyCollection Results { get; init; } } -[AutoMap(typeof(FindPersonsResultItem))] public record FindPersonsResponseResult { public required string Trn { get; init; } @@ -29,7 +24,6 @@ public record FindPersonsResponseResult public required QtsInfo? Qts { get; init; } public required EytsInfo? Eyts { get; init; } public required IReadOnlyCollection Alerts { get; init; } - [SourceMember("Induction.Status")] public required InductionStatus InductionStatus { get; init; } public required QtlsStatus QtlsStatus { get; set; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Responses/GetPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Responses/GetPersonResponse.cs index 59c37a2a3f..23c648b1d7 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Responses/GetPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250327/Responses/GetPersonResponse.cs @@ -1,7 +1,5 @@ -using AutoMapper.Configuration.Annotations; using OneOf; using Optional; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20250203.Dtos; @@ -9,7 +7,6 @@ namespace TeachingRecordSystem.Api.V3.V20250327.Responses; -[AutoMap(typeof(GetPersonResult))] public record GetPersonResponse { public required string Trn { get; init; } @@ -34,24 +31,19 @@ public record GetPersonResponse public required QtlsStatus QtlsStatus { get; set; } } -[AutoMap(typeof(Implementation.Dtos.QtsInfo))] public record GetPersonResponseQts { - [SourceMember(nameof(Implementation.Dtos.QtsInfo.HoldsFrom))] public required DateOnly? Awarded { get; init; } public required string? StatusDescription { get; init; } public required int AwardedOrApprovedCount { get; init; } } -[AutoMap(typeof(Implementation.Dtos.EytsInfo))] public record GetPersonResponseEyts { - [SourceMember(nameof(Implementation.Dtos.QtsInfo.HoldsFrom))] public required DateOnly? Awarded { get; init; } public required string? StatusDescription { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTraining))] public record GetPersonResponseInitialTeacherTraining { public required GetPersonResponseInitialTeacherTrainingProvider? Provider { get; init; } @@ -65,32 +57,27 @@ public record GetPersonResponseInitialTeacherTraining public required IReadOnlyCollection Subjects { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingForAppropriateBody))] public record GetPersonResponseInitialTeacherTrainingForAppropriateBody { public required GetPersonResponseInitialTeacherTrainingProvider Provider { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingQualification))] public record GetPersonResponseInitialTeacherTrainingQualification { public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingAgeRange))] public record GetPersonResponseInitialTeacherTrainingAgeRange { public required string Description { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingProvider))] public record GetPersonResponseInitialTeacherTrainingProvider { public required string Name { get; init; } public required string Ukprn { get; init; } } -[AutoMap(typeof(GetPersonResultInitialTeacherTrainingSubject))] public record GetPersonResponseInitialTeacherTrainingSubject { public required string Code { get; init; } @@ -109,10 +96,8 @@ public record GetPersonResponseNpqQualificationType public required string Name { get; init; } } -[AutoMap(typeof(GetPersonResultMandatoryQualification))] public record GetPersonResponseMandatoryQualification { - [SourceMember("EndDate")] public required DateOnly Awarded { get; init; } public required string Specialism { get; init; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/ApiMapper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/ApiMapper.cs new file mode 100644 index 0000000000..f67cadbf2b --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/ApiMapper.cs @@ -0,0 +1,24 @@ +using Riok.Mapperly.Abstractions; +using TeachingRecordSystem.Api.V3.Implementation.Dtos; +using V20240606Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20240606.Dtos; +using V20250203Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20250203.Dtos; +using V20250425Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20250425.Dtos; + +namespace TeachingRecordSystem.Api.V3.V20250425; + +[Mapper] +public partial class ApiMapper +{ + public V20250425Dtos.TrnRequestInfo MapTrnRequestInfo(TrnRequestInfo source) => + new() + { + RequestId = source.RequestId, + Status = (V20240606Dtos.TrnRequestStatus)(int)source.Status, + Trn = source.Trn, + PotentialDuplicate = source.PotentialDuplicate, + AccessYourTeachingQualificationsLink = source.AccessYourTeachingQualificationsLink + }; + + public Core.Models.Gender MapGender(V20250203Dtos.Gender source) => + (Core.Models.Gender)(int)source; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/Controllers/PersonsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/Controllers/PersonsController.cs index 36a48edd68..3923718a4d 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/Controllers/PersonsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/Controllers/PersonsController.cs @@ -11,7 +11,7 @@ namespace TeachingRecordSystem.Api.V3.V20250425.Controllers; [Route("persons")] -public class PersonsController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonsController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpPut("{trn}/professional-statuses/{reference}")] [SwaggerOperation( @@ -73,7 +73,7 @@ public async Task SetPiiAsync( DateOfBirth = request.DateOfBirth, EmailAddress = request.EmailAddress, NationalInsuranceNumber = request.NationalInsuranceNumber, - Gender = request.Gender is Gender gender ? mapper.Map(gender) : null + Gender = request.Gender is Gender gender ? mapper.MapGender(gender) : null }; var result = await commandDispatcher.DispatchAsync(command); diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/Controllers/TrnRequestsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/Controllers/TrnRequestsController.cs index 2091a1892e..639aaeb759 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/Controllers/TrnRequestsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/Controllers/TrnRequestsController.cs @@ -11,7 +11,7 @@ namespace TeachingRecordSystem.Api.V3.V20250425.Controllers; [Route("trn-requests")] [Authorize(Policy = AuthorizationPolicies.ApiKey, Roles = ApiRoles.CreateTrn)] -public class TrnRequestsController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class TrnRequestsController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpPost("")] [SwaggerOperation( @@ -39,12 +39,12 @@ public async Task CreateTrnRequestAsync([FromBody] CreateTrnReque NationalInsuranceNumber = request.Person.NationalInsuranceNumber, IdentityVerified = request.IdentityVerified, OneLoginUserSubject = request.OneLoginUserSubject, - Gender = request.Person.Gender is Gender gender ? mapper.Map(gender) : null + Gender = request.Person.Gender is Gender gender ? mapper.MapGender(gender) : null }; var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapTrnRequestInfo(r))) .MapErrorCode(ApiError.ErrorCodes.TrnRequestAlreadyCreated, StatusCodes.Status409Conflict); } @@ -63,7 +63,7 @@ public async Task GetTrnRequestAsync([FromQuery] string requestId var command = new GetTrnRequestCommand(requestId); var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapTrnRequestInfo(r))) .MapErrorCode(ApiError.ErrorCodes.TrnRequestDoesNotExist, StatusCodes.Status404NotFound); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/MapperProfile.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/MapperProfile.cs deleted file mode 100644 index eb5344ee7d..0000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250425/MapperProfile.cs +++ /dev/null @@ -1,11 +0,0 @@ -using TeachingRecordSystem.Core.ApiSchema.V3.V20250425.Dtos; - -namespace TeachingRecordSystem.Api.V3.V20250425; - -public class MapperProfile : Profile -{ - public MapperProfile() - { - CreateMap(); - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/ApiMapper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/ApiMapper.cs new file mode 100644 index 0000000000..50692b3634 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/ApiMapper.cs @@ -0,0 +1,199 @@ +using OneOf; +using Riok.Mapperly.Abstractions; +using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Api.V3.V20250627.Responses; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; +using V20240920Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; +using V20250203Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20250203.Dtos; +using V20250627Dtos = TeachingRecordSystem.Core.ApiSchema.V3.V20250627.Dtos; + +namespace TeachingRecordSystem.Api.V3.V20250627; + +[Mapper] +public partial class ApiMapper +{ + public GetPersonResponse MapGetPersonResponse(GetPersonResult source) => + new() + { + Trn = source.Trn, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + DateOfBirth = source.DateOfBirth, + NationalInsuranceNumber = source.NationalInsuranceNumber, + PendingNameChange = source.PendingNameChange, + PendingDateOfBirthChange = source.PendingDateOfBirthChange, + EmailAddress = source.EmailAddress, + Qts = source.Qts is { } qts ? MapQtsInfo(qts) : null, + Eyts = source.Eyts is { } eyts ? MapEytsInfo(eyts) : null, + Induction = source.Induction.Map(MapInductionInfo), + RoutesToProfessionalStatuses = source.RoutesToProfessionalStatuses.Map(MapRoutesOneOf), + MandatoryQualifications = source.MandatoryQualifications.Map( + mqs => (IReadOnlyCollection)mqs + .Select(mq => new GetPersonResponseMandatoryQualification + { + MandatoryQualificationId = mq.MandatoryQualificationId, + EndDate = mq.EndDate, + Specialism = mq.Specialism + }).AsReadOnly()), + Alerts = source.Alerts.Map( + alerts => (IReadOnlyCollection)alerts.Select(MapAlert).AsReadOnly()), + PreviousNames = source.PreviousNames.Map( + pns => (IReadOnlyCollection)pns.Select(MapNameInfo).AsReadOnly()), + AllowIdSignInWithProhibitions = source.AllowIdSignInWithProhibitions, + QtlsStatus = (V20250203Dtos.QtlsStatus)(int)source.QtlsStatus + }; + + public FindPersonsResponse MapFindPersonsResponse(FindPersonsResult source) => + new() + { + Total = source.Total, + Results = source.Items.Select(MapFindPersonsResponseResult).AsReadOnly() + }; + + public FindPersonsResponseResult MapFindPersonsResponseResult(FindPersonsResultItem source) => + new() + { + Trn = source.Trn, + DateOfBirth = source.DateOfBirth, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + PreviousNames = source.PreviousNames.Select(MapNameInfo).AsReadOnly(), + Qts = source.Qts is { } qts ? MapQtsInfo(qts) : null, + Eyts = source.Eyts is { } eyts ? MapEytsInfo(eyts) : null, + Alerts = source.Alerts.Select(MapAlert).AsReadOnly(), + Induction = source.Induction is { } ind ? MapInductionInfo(ind) : null, + QtlsStatus = (V20250203Dtos.QtlsStatus)(int)source.QtlsStatus + }; + + public Core.Models.RouteToProfessionalStatusStatus MapRouteToProfessionalStatusStatus( + V20250627Dtos.RouteToProfessionalStatusStatus source) => + (Core.Models.RouteToProfessionalStatusStatus)(int)source; + + private OneOf, IReadOnlyCollection> MapRoutesOneOf( + OneOf, IReadOnlyCollection> source) => + source.Match( + t0 => OneOf, IReadOnlyCollection>.FromT0( + t0.Select(MapRouteToProfessionalStatus).AsReadOnly()), + t1 => OneOf, IReadOnlyCollection>.FromT1( + t1.Select(i => new GetPersonResponseRouteToProfessionalStatusForAppropriateBody + { + TrainingProvider = MapTrainingProvider(i.TrainingProvider) + }).AsReadOnly())); + + private GetPersonResponseRouteToProfessionalStatus MapRouteToProfessionalStatus(GetPersonResultRouteToProfessionalStatus source) => + new() + { + RouteToProfessionalStatusId = source.RouteToProfessionalStatusId, + RouteToProfessionalStatusType = MapRouteToProfessionalStatusType(source.RouteToProfessionalStatusType), + Status = (V20250627Dtos.RouteToProfessionalStatusStatus)(int)source.Status, + HoldsFrom = source.HoldsFrom, + TrainingStartDate = source.TrainingStartDate, + TrainingEndDate = source.TrainingEndDate, + TrainingSubjects = source.TrainingSubjects.Select(MapTrainingSubject).AsReadOnly(), + TrainingAgeSpecialism = source.TrainingAgeSpecialism is { } ta ? MapTrainingAgeSpecialism(ta) : null, + TrainingCountry = source.TrainingCountry is { } tc ? new V20250627Dtos.TrainingCountry { Reference = tc.Reference, Name = tc.Name } : null, + TrainingProvider = source.TrainingProvider is { } tp ? MapTrainingProvider(tp) : null, + DegreeType = source.DegreeType is { } dt ? new V20250627Dtos.DegreeType { DegreeTypeId = dt.DegreeTypeId, Name = dt.Name } : null, + InductionExemption = new GetPersonResponseProfessionalStatusInductionExemption + { + IsExempt = source.InductionExemption.IsExempt, + ExemptionReasons = source.InductionExemption.ExemptionReasons + .Select(MapInductionExemptionReason) + .AsReadOnly() + } + }; + + private V20250627Dtos.InductionInfo MapInductionInfo(Implementation.Dtos.InductionInfo source) => + new() + { + Status = (V20250203Dtos.InductionStatus)(int)source.Status, + StartDate = source.StartDate, + CompletedDate = source.CompletedDate, + ExemptionReasons = source.ExemptionReasons.Select(MapInductionExemptionReason).AsReadOnly() + }; + + private V20250627Dtos.QtsInfo MapQtsInfo(Implementation.Dtos.QtsInfo source) => + new() + { + HoldsFrom = source.HoldsFrom, + Routes = source.Routes.Select(r => new V20250627Dtos.QtsInfoRoute + { + RouteToProfessionalStatusType = MapRouteToProfessionalStatusType(r.RouteToProfessionalStatusType) + }).AsReadOnly() + }; + + private V20250627Dtos.EytsInfo MapEytsInfo(Implementation.Dtos.EytsInfo source) => + new() + { + HoldsFrom = source.HoldsFrom, + Routes = source.Routes.Select(r => new V20250627Dtos.EytsInfoRoute + { + RouteToProfessionalStatusType = MapRouteToProfessionalStatusType(r.RouteToProfessionalStatusType) + }).AsReadOnly() + }; + + private V20250627Dtos.RouteToProfessionalStatusType MapRouteToProfessionalStatusType(PostgresModels.RouteToProfessionalStatusType source) => + new() + { + RouteToProfessionalStatusTypeId = source.RouteToProfessionalStatusTypeId, + Name = source.Name, + ProfessionalStatusType = (V20250627Dtos.ProfessionalStatusType)(int)source.ProfessionalStatusType + }; + + private V20250627Dtos.TrainingSubject MapTrainingSubject(PostgresModels.TrainingSubject source) => + new() { Reference = source.Reference, Name = source.Name }; + + private V20250627Dtos.TrainingProvider MapTrainingProvider(PostgresModels.TrainingProvider source) => + new() { Ukprn = source.Ukprn!, Name = source.Name }; + + private V20250627Dtos.TrainingAgeSpecialism MapTrainingAgeSpecialism(Implementation.Dtos.TrainingAgeSpecialism source) => + new() + { + Type = (Core.ApiSchema.V3.V20250425.Dtos.TrainingAgeSpecialismType)(int)source.Type!.Value, + From = source.From, + To = source.To + }; + + private V20250627Dtos.InductionExemptionReason MapInductionExemptionReason(PostgresModels.InductionExemptionReason source) => + new() { InductionExemptionReasonId = source.InductionExemptionReasonId, Name = source.Name }; + + private V20240920Dtos.Alert MapAlert(Implementation.Dtos.Alert source) => + new() + { + AlertId = source.AlertId, + AlertType = new V20240920Dtos.AlertType + { + AlertTypeId = source.AlertType.AlertTypeId, + Name = source.AlertType.Name, + AlertCategory = new V20240920Dtos.AlertCategory + { + AlertCategoryId = source.AlertType.AlertCategory.AlertCategoryId, + Name = source.AlertType.AlertCategory.Name + } + }, + Details = source.Details, + StartDate = source.StartDate, + EndDate = source.EndDate + }; + + private NameInfo MapNameInfo(Implementation.Dtos.NameInfo source) => + new() { FirstName = source.FirstName, MiddleName = source.MiddleName, LastName = source.LastName }; + + public FindPersonResponseResult MapFindPersonResponseResult(FindPersonsResultItem source) => + new() + { + Trn = source.Trn, + DateOfBirth = source.DateOfBirth, + FirstName = source.FirstName, + MiddleName = source.MiddleName, + LastName = source.LastName, + PreviousNames = source.PreviousNames.Select(MapNameInfo).AsReadOnly(), + Qts = source.Qts is { } qts ? MapQtsInfo(qts) : null, + Eyts = source.Eyts is { } eyts ? MapEytsInfo(eyts) : null, + Alerts = source.Alerts.Select(MapAlert).AsReadOnly(), + Induction = source.Induction is { } ind ? MapInductionInfo(ind) : null, + QtlsStatus = (V20250203Dtos.QtlsStatus)(int)source.QtlsStatus + }; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Controllers/PersonController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Controllers/PersonController.cs index b4d239da2e..51863c8912 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Controllers/PersonController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Controllers/PersonController.cs @@ -11,7 +11,7 @@ namespace TeachingRecordSystem.Api.V3.V20250627.Controllers; [Route("person")] -public class PersonController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [Authorize(AuthorizationPolicies.IdentityUserWithTrn)] [HttpGet] @@ -32,7 +32,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))) + return result.ToActionResult(r => Ok(mapper.MapGetPersonResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status403Forbidden); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Controllers/PersonsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Controllers/PersonsController.cs index 31b22374ee..185f55d3be 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Controllers/PersonsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Controllers/PersonsController.cs @@ -12,7 +12,7 @@ namespace TeachingRecordSystem.Api.V3.V20250627.Controllers; [Route("persons")] -public class PersonsController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonsController(ICommandDispatcher commandDispatcher, ApiMapper mapper) : ControllerBase { [HttpGet("{trn}")] [SwaggerOperation( @@ -50,7 +50,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); return result - .ToActionResult(r => Ok(mapper.Map(r))) + .ToActionResult(r => Ok(mapper.MapGetPersonResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsDeactivated, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsMerged, StatusCodes.Status404NotFound) @@ -69,7 +69,7 @@ public async Task FindPersonsAsync([FromBody] FindPersonsRequest { var command = new FindPersonsByTrnAndDateOfBirthCommand(request.Persons.Select(p => (p.Trn, p.DateOfBirth))); var result = await commandDispatcher.DispatchAsync(command); - return result.ToActionResult(r => Ok(mapper.Map(r))); + return result.ToActionResult(r => Ok(mapper.MapFindPersonsResponse(r))); } [HttpGet("")] @@ -90,7 +90,7 @@ public async Task FindPersonsAsync(FindPersonRequest request) { Total = r.Total, Query = request, - Results = r.Items.Select(mapper.Map).AsReadOnly() + Results = r.Items.Select(mapper.MapFindPersonResponseResult).AsReadOnly() })); } @@ -115,7 +115,7 @@ public async Task SetRouteToProfessionalStatusAsync( trn, sourceApplicationReference, request.RouteToProfessionalStatusTypeId, - mapper.Map(request.Status), + mapper.MapRouteToProfessionalStatusStatus(request.Status), request.HoldsFrom, request.TrainingStartDate, request.TrainingEndDate, diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/MapperProfile.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/MapperProfile.cs deleted file mode 100644 index 8132067084..0000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/MapperProfile.cs +++ /dev/null @@ -1,22 +0,0 @@ -using TeachingRecordSystem.Core.ApiSchema.V3.V20250627.Dtos; - -namespace TeachingRecordSystem.Api.V3.V20250627; - -public class MapperProfile : Profile -{ - public MapperProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - } -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Responses/FindPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Responses/FindPersonResponse.cs index 4fb62e6e3d..91415f4ba3 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Responses/FindPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Responses/FindPersonResponse.cs @@ -1,4 +1,3 @@ -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Api.V3.V20250627.Requests; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; @@ -15,7 +14,6 @@ public record FindPersonResponse public required IReadOnlyCollection Results { get; init; } } -[AutoMap(typeof(FindPersonsResultItem))] public record FindPersonResponseResult { public required string Trn { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Responses/FindPersonsResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Responses/FindPersonsResponse.cs index 6cf6c406fe..1e0538be92 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Responses/FindPersonsResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Responses/FindPersonsResponse.cs @@ -1,5 +1,3 @@ -using AutoMapper.Configuration.Annotations; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Core.ApiSchema.V3.V20250627.Dtos; using Alert = TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos.Alert; using NameInfo = TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos.NameInfo; @@ -8,15 +6,12 @@ namespace TeachingRecordSystem.Api.V3.V20250627.Responses; -[AutoMap(typeof(FindPersonsResult))] public record FindPersonsResponse { public required int Total { get; init; } - [SourceMember(nameof(FindPersonsResult.Items))] public required IReadOnlyCollection Results { get; init; } } -[AutoMap(typeof(FindPersonsResultItem))] public record FindPersonsResponseResult { public required string Trn { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Responses/GetPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Responses/GetPersonResponse.cs index f342feed2c..5fb737f7ac 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Responses/GetPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20250627/Responses/GetPersonResponse.cs @@ -1,6 +1,5 @@ using OneOf; using Optional; -using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Core.ApiSchema.V3.V20250627.Dtos; using Alert = TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos.Alert; using EytsInfo = TeachingRecordSystem.Core.ApiSchema.V3.V20250627.Dtos.EytsInfo; @@ -12,7 +11,6 @@ namespace TeachingRecordSystem.Api.V3.V20250627.Responses; -[AutoMap(typeof(GetPersonResult))] public record GetPersonResponse { public required string Trn { get; init; } @@ -35,7 +33,6 @@ public record GetPersonResponse public required QtlsStatus QtlsStatus { get; init; } } -[AutoMap(typeof(GetPersonResultMandatoryQualification))] public record GetPersonResponseMandatoryQualification { public required Guid MandatoryQualificationId { get; init; } @@ -43,7 +40,6 @@ public record GetPersonResponseMandatoryQualification public required string Specialism { get; init; } } -[AutoMap(typeof(GetPersonResultRouteToProfessionalStatus))] public record GetPersonResponseRouteToProfessionalStatus { public required Guid RouteToProfessionalStatusId { get; init; } @@ -60,13 +56,11 @@ public record GetPersonResponseRouteToProfessionalStatus public required GetPersonResponseProfessionalStatusInductionExemption InductionExemption { get; init; } } -[AutoMap(typeof(GetPersonResultRouteToProfessionalStatusForAppropriateBody))] public record GetPersonResponseRouteToProfessionalStatusForAppropriateBody { public required TrainingProvider TrainingProvider { get; init; } } -[AutoMap(typeof(GetPersonResultRouteToProfessionalStatusInductionExemption))] public record GetPersonResponseProfessionalStatusInductionExemption { public required bool IsExempt { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20260120/Controllers/PersonsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20260120/Controllers/PersonsController.cs index ce7d52faf7..638b3efbfa 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20260120/Controllers/PersonsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20260120/Controllers/PersonsController.cs @@ -10,7 +10,7 @@ namespace TeachingRecordSystem.Api.V3.V20260120.Controllers; [Route("persons")] -public class PersonsController(ICommandDispatcher commandDispatcher, IMapper mapper) : ControllerBase +public class PersonsController(ICommandDispatcher commandDispatcher, V20250627.ApiMapper mapper) : ControllerBase { [HttpGet("{trn}")] [SwaggerOperation( @@ -50,7 +50,7 @@ public async Task GetAsync( var result = await commandDispatcher.DispatchAsync(command); return result - .ToActionResult(r => Ok(mapper.Map(r))) + .ToActionResult(r => Ok(mapper.MapGetPersonResponse(r))) .MapErrorCode(ApiError.ErrorCodes.PersonNotFound, StatusCodes.Status404NotFound) .MapErrorCode(ApiError.ErrorCodes.RecordIsDeactivated, StatusCodes.Status410Gone) .MapErrorCode( diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20260416/Controllers/TrnRequestController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20260416/Controllers/TrnRequestController.cs index e82d2d428e..f3f75ae45f 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20260416/Controllers/TrnRequestController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20260416/Controllers/TrnRequestController.cs @@ -8,7 +8,7 @@ namespace TeachingRecordSystem.Api.V3.V20260416.Controllers; [Route("trn-request")] -public class TrnRequestController(ICommandDispatcher commandDispatcher, IMapper mapper, ICurrentUserProvider currentUserProvider) : ControllerBase +public class TrnRequestController(ICommandDispatcher commandDispatcher, V20250425.ApiMapper mapper, ICurrentUserProvider currentUserProvider) : ControllerBase { [HttpPut("activate")] [SwaggerOperation( @@ -31,7 +31,7 @@ public async Task ActivateAsync() return result.ToActionResult( r => StatusCode( r.WasActivated ? StatusCodes.Status200OK : StatusCodes.Status204NoContent, - mapper.Map(r.TrnRequestInfo))) + mapper.MapTrnRequestInfo(r.TrnRequestInfo))) .MapErrorCode(ApiError.ErrorCodes.TrnRequestDoesNotExist, StatusCodes.Status404NotFound); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/packages.lock.json b/TeachingRecordSystem/src/TeachingRecordSystem.Api/packages.lock.json index b4094f3320..361c28d63c 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/packages.lock.json +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/packages.lock.json @@ -2,12 +2,6 @@ "version": 2, "dependencies": { "net10.0": { - "AutoMapper": { - "type": "Direct", - "requested": "[13.0.1, )", - "resolved": "13.0.1", - "contentHash": "/Fx1SbJ16qS7dU4i604Sle+U9VLX+WSNVJggk6MupKVkYvvBm4XqYaeFuf67diHefHKHs50uQIS2YEDFhPCakQ==" - }, "FluentValidation.AspNetCore": { "type": "Direct", "requested": "[11.3.1, )", @@ -66,6 +60,12 @@ "RedisRateLimiting": "1.2.0" } }, + "Riok.Mapperly": { + "type": "Direct", + "requested": "[4.3.1, )", + "resolved": "4.3.1", + "contentHash": "oSE+OVLHyiojrws0QVbQaAT2YKsYbyHqJXPdV7EhGseR/dYgeWS2x1T5qY5I4E+RJkJqMSG+FyZOq4SljWgJWQ==" + }, "Swashbuckle.AspNetCore": { "type": "Direct", "requested": "[6.6.2, )", diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.IntegrationTests/packages.lock.json b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.IntegrationTests/packages.lock.json index 2a24656a2c..ffa468b9ef 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.IntegrationTests/packages.lock.json +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.IntegrationTests/packages.lock.json @@ -830,13 +830,13 @@ "teachingrecordsystem.api": { "type": "Project", "dependencies": { - "AutoMapper": "[13.0.1, )", "FluentValidation.AspNetCore": "[11.3.1, )", "JetBrains.Annotations": "[2025.2.4, )", "MediatR": "[12.2.0, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[10.0.6, )", "Moq": "[4.20.72, )", "RedisRateLimiting.AspNetCore": "[1.2.0, )", + "Riok.Mapperly": "[4.3.1, )", "Swashbuckle.AspNetCore": "[6.6.2, )", "Swashbuckle.AspNetCore.Annotations": "[6.6.2, )", "System.IdentityModel.Tokens.Jwt": "[8.14.0, )", @@ -945,12 +945,6 @@ "StackExchange.Redis": "2.7.4" } }, - "AutoMapper": { - "type": "CentralTransitive", - "requested": "[13.0.1, )", - "resolved": "13.0.1", - "contentHash": "/Fx1SbJ16qS7dU4i604Sle+U9VLX+WSNVJggk6MupKVkYvvBm4XqYaeFuf67diHefHKHs50uQIS2YEDFhPCakQ==" - }, "Azure.Extensions.AspNetCore.DataProtection.Blobs": { "type": "CentralTransitive", "requested": "[1.5.1, )", @@ -1358,6 +1352,12 @@ "resolved": "7.0.0", "contentHash": "AyWlducZGOnmlEVz4PaL3Qv8wcY3ClPZS9CrlDnSVahGd/E9tTEgSFiC8yoV/F6o6P6IYm8xnHFa/vmWT8tfcw==" }, + "Riok.Mapperly": { + "type": "CentralTransitive", + "requested": "[4.3.1, )", + "resolved": "4.3.1", + "contentHash": "oSE+OVLHyiojrws0QVbQaAT2YKsYbyHqJXPdV7EhGseR/dYgeWS2x1T5qY5I4E+RJkJqMSG+FyZOq4SljWgJWQ==" + }, "Scrutor": { "type": "CentralTransitive", "requested": "[7.0.0, )", diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.UnitTests/packages.lock.json b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.UnitTests/packages.lock.json index ee7bed8ed9..9e25c6a039 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.UnitTests/packages.lock.json +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.UnitTests/packages.lock.json @@ -1156,13 +1156,13 @@ "teachingrecordsystem.api": { "type": "Project", "dependencies": { - "AutoMapper": "[13.0.1, )", "FluentValidation.AspNetCore": "[11.3.1, )", "JetBrains.Annotations": "[2025.2.4, )", "MediatR": "[12.2.0, )", "Microsoft.AspNetCore.Authentication.JwtBearer": "[10.0.6, )", "Moq": "[4.20.72, )", "RedisRateLimiting.AspNetCore": "[1.2.0, )", + "Riok.Mapperly": "[4.3.1, )", "Swashbuckle.AspNetCore": "[6.6.2, )", "Swashbuckle.AspNetCore.Annotations": "[6.6.2, )", "System.IdentityModel.Tokens.Jwt": "[8.14.0, )", @@ -1281,15 +1281,6 @@ "StackExchange.Redis": "2.7.4" } }, - "AutoMapper": { - "type": "CentralTransitive", - "requested": "[13.0.1, )", - "resolved": "13.0.1", - "contentHash": "/Fx1SbJ16qS7dU4i604Sle+U9VLX+WSNVJggk6MupKVkYvvBm4XqYaeFuf67diHefHKHs50uQIS2YEDFhPCakQ==", - "dependencies": { - "Microsoft.Extensions.Options": "6.0.0" - } - }, "Azure.Extensions.AspNetCore.DataProtection.Blobs": { "type": "CentralTransitive", "requested": "[1.5.1, )", @@ -1838,6 +1829,12 @@ "resolved": "7.0.0", "contentHash": "AyWlducZGOnmlEVz4PaL3Qv8wcY3ClPZS9CrlDnSVahGd/E9tTEgSFiC8yoV/F6o6P6IYm8xnHFa/vmWT8tfcw==" }, + "Riok.Mapperly": { + "type": "CentralTransitive", + "requested": "[4.3.1, )", + "resolved": "4.3.1", + "contentHash": "oSE+OVLHyiojrws0QVbQaAT2YKsYbyHqJXPdV7EhGseR/dYgeWS2x1T5qY5I4E+RJkJqMSG+FyZOq4SljWgJWQ==" + }, "Scrutor": { "type": "CentralTransitive", "requested": "[7.0.0, )",