From 83153cc8acab213ad8fb93af5d4f76b382acfd23 Mon Sep 17 00:00:00 2001 From: James Gunn Date: Fri, 20 Dec 2024 11:58:16 +0000 Subject: [PATCH] Remove DTO source generator --- TeachingRecordSystem/Directory.Build.props | 5 +- TeachingRecordSystem/TeachingRecordSystem.sln | 17 - .../TeachingRecordSystem.Api.Generator.csproj | 14 - .../VersionedDtoGenerator.cs | 431 ------------------ .../packages.lock.json | 110 ----- .../TeachingRecordSystem.Api.csproj | 2 - .../V3/GenerateVersionedDtoAttribute.cs | 9 - .../Operations/CreateTrnRequest.cs | 16 +- .../Controllers/TrnRequestsController.cs | 2 +- .../V20240416/Responses/GetTeacherResponse.cs | 160 ++++++- .../Controllers/TrnRequestsController.cs | 2 +- .../CreateDateOfBirthChangeResponse.cs | 6 +- .../Responses/CreateNameChangeResponse.cs | 6 +- .../V20240606/Responses/FindPersonResponse.cs | 17 +- .../V20240606/Responses/GetPersonResponse.cs | 112 +++-- .../V20240814/Responses/FindPersonResponse.cs | 15 +- .../V20240920/Responses/FindPersonResponse.cs | 24 +- .../Responses/FindPersonsResponse.cs | 19 +- .../V20240920/Responses/GetPersonResponse.cs | 116 ++++- .../V3/VNext/Controllers/PersonController.cs | 2 +- .../V3/VNext/Controllers/PersonsController.cs | 4 - .../Controllers/TrnRequestsController.cs | 4 +- .../VNext/Requests/CreateTrnRequestRequest.cs | 24 +- .../V3/VNext/Requests/FindPersonRequest.cs | 18 + .../V3/VNext/Requests/FindPersonsRequest.cs | 12 + .../Requests/GetPersonRequestIncludes.cs | 24 + .../V3/VNext/Responses/FindPersonResponse.cs | 21 +- .../V3/VNext/Responses/FindPersonsResponse.cs | 19 +- .../V3/VNext/Responses/GetPersonResponse.cs | 119 ++++- .../CreateTrnRequestRequestValidator.cs | 2 +- .../ApiSchema/V3/VNext/Dtos/Gender.cs | 8 + .../V3/VNext/CreateTrnRequestTests.cs | 4 +- .../V3/VersionReferenceTests.cs | 69 +++ 33 files changed, 725 insertions(+), 688 deletions(-) delete mode 100644 TeachingRecordSystem/gen/TeachingRecordSystem.Api.Generator/TeachingRecordSystem.Api.Generator.csproj delete mode 100644 TeachingRecordSystem/gen/TeachingRecordSystem.Api.Generator/VersionedDtoGenerator.cs delete mode 100644 TeachingRecordSystem/gen/TeachingRecordSystem.Api.Generator/packages.lock.json delete mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/GenerateVersionedDtoAttribute.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/FindPersonRequest.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/FindPersonsRequest.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/GetPersonRequestIncludes.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Core/ApiSchema/V3/VNext/Dtos/Gender.cs create mode 100644 TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VersionReferenceTests.cs diff --git a/TeachingRecordSystem/Directory.Build.props b/TeachingRecordSystem/Directory.Build.props index b5428b97e..0fc609c17 100644 --- a/TeachingRecordSystem/Directory.Build.props +++ b/TeachingRecordSystem/Directory.Build.props @@ -7,13 +7,12 @@ true true - true TeachingRecordSystem TeachingRecordSystemTests - + @@ -23,7 +22,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/TeachingRecordSystem/TeachingRecordSystem.sln b/TeachingRecordSystem/TeachingRecordSystem.sln index a3afaf5df..d861cd996 100644 --- a/TeachingRecordSystem/TeachingRecordSystem.sln +++ b/TeachingRecordSystem/TeachingRecordSystem.sln @@ -49,10 +49,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TeachingRecordSystem.UiTest EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TeachingRecordSystem.AuthorizeAccess.EndToEndTests", "tests\TeachingRecordSystem.AuthorizeAccess.EndToEndTests\TeachingRecordSystem.AuthorizeAccess.EndToEndTests.csproj", "{2D7946CB-44D2-431D-A9E1-A4472FACC1DC}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{5E273A79-2EA3-46CD-9049-769F880868FE}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeachingRecordSystem.Api.Generator", "gen\TeachingRecordSystem.Api.Generator\TeachingRecordSystem.Api.Generator.csproj", "{7EA8C0A7-C149-4928-8E37-55D44976D765}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -267,18 +263,6 @@ Global {2D7946CB-44D2-431D-A9E1-A4472FACC1DC}.Release|x64.Build.0 = Release|Any CPU {2D7946CB-44D2-431D-A9E1-A4472FACC1DC}.Release|x86.ActiveCfg = Release|Any CPU {2D7946CB-44D2-431D-A9E1-A4472FACC1DC}.Release|x86.Build.0 = Release|Any CPU - {7EA8C0A7-C149-4928-8E37-55D44976D765}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7EA8C0A7-C149-4928-8E37-55D44976D765}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7EA8C0A7-C149-4928-8E37-55D44976D765}.Debug|x64.ActiveCfg = Debug|Any CPU - {7EA8C0A7-C149-4928-8E37-55D44976D765}.Debug|x64.Build.0 = Debug|Any CPU - {7EA8C0A7-C149-4928-8E37-55D44976D765}.Debug|x86.ActiveCfg = Debug|Any CPU - {7EA8C0A7-C149-4928-8E37-55D44976D765}.Debug|x86.Build.0 = Debug|Any CPU - {7EA8C0A7-C149-4928-8E37-55D44976D765}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7EA8C0A7-C149-4928-8E37-55D44976D765}.Release|Any CPU.Build.0 = Release|Any CPU - {7EA8C0A7-C149-4928-8E37-55D44976D765}.Release|x64.ActiveCfg = Release|Any CPU - {7EA8C0A7-C149-4928-8E37-55D44976D765}.Release|x64.Build.0 = Release|Any CPU - {7EA8C0A7-C149-4928-8E37-55D44976D765}.Release|x86.ActiveCfg = Release|Any CPU - {7EA8C0A7-C149-4928-8E37-55D44976D765}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -301,7 +285,6 @@ Global {08E99A19-AD1F-4F95-BF13-31248D486799} = {91DCFC76-6636-4AC1-B81C-7F8AE1F22116} {B22223A8-9CB0-4B60-B516-18FD684CF01D} = {91DCFC76-6636-4AC1-B81C-7F8AE1F22116} {2D7946CB-44D2-431D-A9E1-A4472FACC1DC} = {91DCFC76-6636-4AC1-B81C-7F8AE1F22116} - {7EA8C0A7-C149-4928-8E37-55D44976D765} = {5E273A79-2EA3-46CD-9049-769F880868FE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {61D239F9-888B-4D01-84BC-9276C92383EA} diff --git a/TeachingRecordSystem/gen/TeachingRecordSystem.Api.Generator/TeachingRecordSystem.Api.Generator.csproj b/TeachingRecordSystem/gen/TeachingRecordSystem.Api.Generator/TeachingRecordSystem.Api.Generator.csproj deleted file mode 100644 index 81d4062f4..000000000 --- a/TeachingRecordSystem/gen/TeachingRecordSystem.Api.Generator/TeachingRecordSystem.Api.Generator.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - netstandard2.0 - false - true - - - - - - - - diff --git a/TeachingRecordSystem/gen/TeachingRecordSystem.Api.Generator/VersionedDtoGenerator.cs b/TeachingRecordSystem/gen/TeachingRecordSystem.Api.Generator/VersionedDtoGenerator.cs deleted file mode 100644 index 57931d519..000000000 --- a/TeachingRecordSystem/gen/TeachingRecordSystem.Api.Generator/VersionedDtoGenerator.cs +++ /dev/null @@ -1,431 +0,0 @@ -using System.Diagnostics; -using System.Text; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using GeneratedTypeInfo = (string DestinationType, string ReferenceType); -using VersionedReference = (string DestinationFullyQualifiedTypeName, string ReferenceFullyQualifiedTypeName, int ReferenceType); - -[Generator(LanguageNames.CSharp)] -public class VersionedDtoGenerator : ISourceGenerator -{ - private const string GenerateVersionedDtoAttributeName = "TeachingRecordSystem.Api.V3.GenerateVersionedDtoAttribute"; - private const string BaseNamespace = "TeachingRecordSystem.Api.V3"; - - private const int RecordReferenceType = 0; - private const int EnumReferenceType = 1; - - public void Execute(GeneratorExecutionContext context) - { - var syntaxReceiver = (SyntaxReceiver)context.SyntaxReceiver!; - - var generatedTypes = new HashSet(); - var generatedRecords = new Dictionary(); - var versionedReferences = new List(); - - foreach (var generateDtoInfo in syntaxReceiver.Records) - { - var semanticModel = context.Compilation.GetSemanticModel(generateDtoInfo.Record.SyntaxTree); - var typeSymbol = (INamedTypeSymbol)semanticModel.GetDeclaredSymbol(generateDtoInfo.Record)!; - var destinationNamespace = typeSymbol.ContainingNamespace.ToString(); - - if (!IsVersionedNamespace(destinationNamespace)) - { - context.ReportDiagnostic( - Diagnostic.Create( - DiagnosticDescriptors.InvalidNamespace, - generateDtoInfo.Location, - messageArgs: destinationNamespace)); - continue; - } - - // Extract the arguments from the GenerateVersionedDtoAttribute - var attr = typeSymbol.GetAttributes().Single(a => a.AttributeClass?.ContainingNamespace + "." + a.AttributeClass?.Name == GenerateVersionedDtoAttributeName); - var sourceType = (INamedTypeSymbol)attr.ConstructorArguments[0].Value!; - var excludeMembers = attr.ConstructorArguments[1].Values!.Select(t => t.Value!.ToString()).ToArray(); - var sourceNamespace = sourceType.ContainingNamespace.ToString(); - - if (!IsVersionedNamespace(sourceNamespace)) - { - context.ReportDiagnostic( - Diagnostic.Create( - DiagnosticDescriptors.InvalidReferenceNamespace, - generateDtoInfo.Location, - messageArgs: sourceNamespace)); - continue; - } - - var sourceFullyQualifiedTypeName = sourceType.ContainingNamespace.ToString() + "." + sourceType.Name; - var destinationVersion = GetTypeVersion(destinationNamespace); - var destinationFullyQualifiedTypeName = destinationNamespace + "." + typeSymbol.Name; - - if (generatedTypes.Any(t => t.DestinationType == destinationFullyQualifiedTypeName)) - { - return; - } - - GeneratePartialRecordDeclaration( - destinationFullyQualifiedTypeName, - sourceFullyQualifiedTypeName, - copyAttributes: false, - excludeMembers); - } - - void EnsureReference(VersionedReference reference) - { - if (!versionedReferences.Contains(reference)) - { - versionedReferences.Add(reference); - - // If the type has already been defined we don't need to generate it - if (context.Compilation.GetTypeByMetadataName(reference.DestinationFullyQualifiedTypeName) is not null) - { - return; - } - - // If we've already generated the type there's nothing to do - if (generatedTypes.Any(t => t.DestinationType == reference.DestinationFullyQualifiedTypeName)) - { - return; - } - - if (reference.ReferenceType == RecordReferenceType) - { - GeneratePartialRecordDeclaration( - reference.DestinationFullyQualifiedTypeName, - reference.ReferenceFullyQualifiedTypeName, - copyAttributes: true, - excludeMembers: []); - } - else - { - Debug.Assert(reference.ReferenceType == EnumReferenceType); - - GenerateEnum( - reference.DestinationFullyQualifiedTypeName, - reference.ReferenceFullyQualifiedTypeName); - } - } - } - - void GeneratePartialRecordDeclaration( - string destinationFullyQualifiedTypeName, - string referenceFullyQualifiedTypeName, - bool copyAttributes, - string[] excludeMembers) - { - var destinationVersion = GetTypeVersion(destinationFullyQualifiedTypeName); - var destinationNamespace = GetNamespaceFromFullyQualifiedTypeName(destinationFullyQualifiedTypeName); - var referenceNamespace = GetNamespaceFromFullyQualifiedTypeName(referenceFullyQualifiedTypeName); - var destinationTypeName = destinationFullyQualifiedTypeName.Split('.').Last(); - - var usings = new HashSet(); - var attributeLists = new List(); - var propertyDeclarations = new List(); - - var referenceTypeSymbol = context.Compilation.GetTypeByMetadataName(referenceFullyQualifiedTypeName); - - // If the reference type was itself generated we need to include the generated members too - generatedRecords.TryGetValue(referenceFullyQualifiedTypeName, out var referenceGeneratedTypeInfo); - - var allProperties = new List<(PropertyDeclarationSyntax PropertySyntax, INamedTypeSymbol? PropertyType)>(); - var allUsings = new List(); - - void AddProperty(PropertyDeclarationSyntax property, INamedTypeSymbol? propertyType) - { - // If this type references another versioned type in the same namespace, add it to the list to ensure it's generated - if (propertyType is not null) - { - RecordReferenceIfTypeIsVersionedAndInSameNamespace(propertyType, referenceNamespace); - } - - propertyDeclarations.Add(property.GetText().ToString()); - allProperties.Add((property, propertyType)); - } - - void AddUsing(UsingDirectiveSyntax usingSyntax) - { - var usingStatement = usingSyntax.GetText().ToString(); - - if (usingSyntax.Name is QualifiedNameSyntax qualifiedNameSyntax) - { - var fullName = qualifiedNameSyntax.Left + "." + qualifiedNameSyntax.Right; - } - - usings.Add(usingStatement); - allUsings.Add(usingSyntax); - } - - foreach (var declaringSyntax in referenceTypeSymbol?.DeclaringSyntaxReferences ?? []) - { - var referenceSyntax = declaringSyntax.GetSyntax(); - var semanticModel = context.Compilation.GetSemanticModel(referenceSyntax.SyntaxTree); - - var rootSyntax = referenceSyntax; - while (rootSyntax.Parent is not null) - { - rootSyntax = rootSyntax.Parent; - } - - foreach (var usingSyntax in rootSyntax.DescendantNodes().OfType()) - { - AddUsing(usingSyntax); - } - - if (copyAttributes) - { - foreach (var attributeList in referenceSyntax.ChildNodes().OfType()) - { - attributeLists.Add(attributeList.GetText().ToString()); - } - } - - foreach (var property in referenceSyntax.DescendantNodes().OfType()) - { - if (excludeMembers.Contains(property.Identifier.ValueText)) - { - continue; - } - - var propertyType = semanticModel.GetTypeInfo(property.Type).Type as INamedTypeSymbol; - - AddProperty(property, propertyType); - } - } - - if (referenceGeneratedTypeInfo is not null) - { - foreach (var @using in referenceGeneratedTypeInfo.Usings) - { - AddUsing(@using); - } - - foreach (var (property, propertyType) in referenceGeneratedTypeInfo.Properties) - { - if (excludeMembers.Contains(property.Identifier.ValueText)) - { - continue; - } - - AddProperty(property, propertyType); - } - } - - var codeBuilder = new StringBuilder(); - - codeBuilder.AppendLine("// "); - codeBuilder.AppendLine("#nullable enable"); - codeBuilder.AppendLine(); - - foreach (var usingStatement in usings) - { - codeBuilder.Append(usingStatement); - } - if (usings.Count > 0) - { - codeBuilder.AppendLine(); - } - - codeBuilder.AppendLine($"namespace {destinationNamespace};"); - codeBuilder.AppendLine(); - - if (copyAttributes) - { - foreach (var attributeList in attributeLists) - { - codeBuilder.Append(attributeList.ToString()); - } - } - - codeBuilder.AppendLine($"public partial record {destinationTypeName}"); - codeBuilder.AppendLine("{"); - foreach (var propertyDeclaration in propertyDeclarations) - { - codeBuilder.Append(propertyDeclaration); - } - codeBuilder.AppendLine("}"); - - var relativeName = destinationNamespace.Substring(BaseNamespace.Length + 1); - context.AddSource($"{relativeName}.{destinationTypeName}.g.cs", codeBuilder.ToString()); - - var generatedTypeInfo = new GeneratedTypeInfo(destinationFullyQualifiedTypeName, referenceFullyQualifiedTypeName); - generatedTypes.Add(generatedTypeInfo); - - var generatedRecordInfo = new GeneratedRecordInfo(allUsings.ToArray(), allProperties.ToArray()); - generatedRecords.Add(destinationFullyQualifiedTypeName, generatedRecordInfo); - - void RecordReferenceIfTypeIsVersionedAndInSameNamespace(INamedTypeSymbol symbol, string @namespace) - { - var fullPropertyType = symbol.ContainingNamespace + "." + symbol.Name; - - if (symbol.ContainingNamespace.ToString() == @namespace && IsVersionedType(fullPropertyType)) - { - if (symbol.TypeKind is not TypeKind.Enum && !(symbol.TypeKind is TypeKind.Class && symbol.IsRecord)) - { - context.ReportDiagnostic( - Diagnostic.Create( - DiagnosticDescriptors.UnsupportedTypeKind, - symbol.Locations.FirstOrDefault(), - messageArgs: symbol.TypeKind.ToString())); - return; - } - - var referenceType = symbol.TypeKind is TypeKind.Enum ? EnumReferenceType : RecordReferenceType; - - EnsureReference((ReplaceVersion(fullPropertyType, destinationVersion), fullPropertyType, referenceType)); - } - - if (symbol.IsGenericType) - { - foreach (var genericArg in symbol.TypeArguments.OfType()) - { - RecordReferenceIfTypeIsVersionedAndInSameNamespace(genericArg, @namespace); - } - } - } - } - - void GenerateEnum( - string destinationFullyQualifiedTypeName, - string referenceFullyQualifiedTypeName) - { - var destinationVersion = GetTypeVersion(destinationFullyQualifiedTypeName); - var destinationNamespace = GetNamespaceFromFullyQualifiedTypeName(destinationFullyQualifiedTypeName); - var referenceVersion = GetTypeVersion(referenceFullyQualifiedTypeName); - - // If the reference enum was itself generated we won't find it in context.Compilation. - // Instead, recursively look for its source type until we find a version that is in the Compilation. - var sourceGeneratedFrom = generatedTypes.FirstOrDefault(g => g.DestinationType == referenceFullyQualifiedTypeName); - if (sourceGeneratedFrom.ReferenceType is not null) - { - GenerateEnum( - destinationFullyQualifiedTypeName, - sourceGeneratedFrom.ReferenceType); - return; - } - - var referenceTypeSymbol = context.Compilation.GetTypeByMetadataName(referenceFullyQualifiedTypeName) ?? - throw new Exception($"Could not find '{referenceFullyQualifiedTypeName}."); - var destinationTypeName = referenceTypeSymbol.Name; - - var declaringSyntax = referenceTypeSymbol.DeclaringSyntaxReferences.Single(); - - var referenceSyntax = declaringSyntax.GetSyntax(); - var semanticModel = context.Compilation.GetSemanticModel(referenceSyntax.SyntaxTree); - - var enumMemberDeclarations = new List(); - - foreach (var member in referenceSyntax.DescendantNodes().OfType()) - { - enumMemberDeclarations.Add(member.GetText().ToString()); - } - - var codeBuilder = new StringBuilder(); - - codeBuilder.AppendLine("// "); - codeBuilder.AppendLine("#nullable enable"); - codeBuilder.AppendLine(); - - codeBuilder.AppendLine($"namespace {destinationNamespace};"); - codeBuilder.AppendLine(); - - codeBuilder.AppendLine($"public enum {destinationTypeName}"); - codeBuilder.AppendLine("{"); - codeBuilder.AppendLine(string.Join(",\n", enumMemberDeclarations)); - codeBuilder.AppendLine("}"); - - var relativeName = destinationNamespace.Substring(BaseNamespace.Length + 1); - context.AddSource($"{relativeName}.{destinationTypeName}.g.cs", codeBuilder.ToString()); - - var generatedTypeInfo = new GeneratedTypeInfo(destinationFullyQualifiedTypeName, referenceFullyQualifiedTypeName); - generatedTypes.Add(generatedTypeInfo); - } - } - - public void Initialize(GeneratorInitializationContext context) - { - context.RegisterForSyntaxNotifications(() => new SyntaxReceiver()); - } - - private static bool IsVersionedType(string typeName) => typeName.StartsWith(BaseNamespace + ".V"); - - private static bool IsVersionedNamespace(string @namespace) => @namespace.StartsWith(BaseNamespace + ".V"); - - private static string ReplaceVersion(string typeName, string newVersion) => - typeName.Replace(GetTypeVersion(typeName), newVersion); - - private static string GetTypeVersion(string typeName) - { - var relativeNamespace = typeName.Substring(BaseNamespace.Length + 1); - return relativeNamespace.Split('.')[0]; - } - - private static string GetNamespaceFromFullyQualifiedTypeName(string typeName) => - typeName.Substring(0, typeName.LastIndexOf('.')); - - private class SyntaxReceiver : ISyntaxReceiver - { - public List Records { get; } = []; - - public void OnVisitSyntaxNode(SyntaxNode syntaxNode) - { - if (syntaxNode is RecordDeclarationSyntax recordDeclarationSyntax) - { - var generateDtoAttrs = recordDeclarationSyntax.AttributeLists.SelectMany(al => al.Attributes) - .Where(a => a.Name is SimpleNameSyntax sns && sns.Identifier.Text is "GenerateVersionedDtoAttribute" or "GenerateVersionedDto"); - - foreach (var attr in generateDtoAttrs) - { - Records.Add(new GenerateDtoInfo(recordDeclarationSyntax, attr, syntaxNode.GetLocation())); - } - } - } - } - - private sealed class GenerateDtoInfo(RecordDeclarationSyntax record, AttributeSyntax attribute, Location location) - { - public RecordDeclarationSyntax Record { get; } = record; - - public AttributeSyntax Attribute { get; } = attribute; - - public Location Location { get; } = location; - } - - private sealed class GeneratedRecordInfo(UsingDirectiveSyntax[] usings, (PropertyDeclarationSyntax Property, INamedTypeSymbol? PropertyType)[] properties) - { - public UsingDirectiveSyntax[] Usings { get; } = usings; - - public (PropertyDeclarationSyntax Property, INamedTypeSymbol? PropertyType)[] Properties { get; } = properties; - } - - internal static class DiagnosticDescriptors - { - private const string Category = "Design"; - - public static DiagnosticDescriptor UnsupportedTypeKind { get; } = new DiagnosticDescriptor( - id: "TRSDTOGEN001", - title: "Unsupported type kind", - messageFormat: "{0} is not a supported type kind.", - category: Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true, - customTags: WellKnownDiagnosticTags.NotConfigurable); - - public static DiagnosticDescriptor InvalidReferenceNamespace { get; } = new DiagnosticDescriptor( - id: "TRSDTOGEN002", - title: "Unsupported reference namespace", - messageFormat: "{0} is not a versioned namespace.", - category: Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true, - customTags: WellKnownDiagnosticTags.NotConfigurable); - - public static DiagnosticDescriptor InvalidNamespace { get; } = new DiagnosticDescriptor( - id: "TRSDTOGEN003", - title: "Unsupported namespace", - messageFormat: "{0} is not a versioned namespace.", - category: Category, - DiagnosticSeverity.Error, - isEnabledByDefault: true, - customTags: WellKnownDiagnosticTags.NotConfigurable); - } -} diff --git a/TeachingRecordSystem/gen/TeachingRecordSystem.Api.Generator/packages.lock.json b/TeachingRecordSystem/gen/TeachingRecordSystem.Api.Generator/packages.lock.json deleted file mode 100644 index 205c94d0a..000000000 --- a/TeachingRecordSystem/gen/TeachingRecordSystem.Api.Generator/packages.lock.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "version": 1, - "dependencies": { - ".NETStandard,Version=v2.0": { - "Microsoft.CodeAnalysis.Analyzers": { - "type": "Direct", - "requested": "[3.3.4, )", - "resolved": "3.3.4", - "contentHash": "AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g==" - }, - "Microsoft.CodeAnalysis.CSharp": { - "type": "Direct", - "requested": "[4.9.2, )", - "resolved": "4.9.2", - "contentHash": "HGIo7E9Mf3exAJbUdYpDFfLoYkSVaHDJXPyusWTYUTBaOPCowGw+Gap5McE1w+K+ryIXre72oiqL88sQHmHBmg==", - "dependencies": { - "Microsoft.CodeAnalysis.Common": "[4.9.2]" - } - }, - "NETStandard.Library": { - "type": "Direct", - "requested": "[2.0.3, )", - "resolved": "2.0.3", - "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0" - } - }, - "Microsoft.CodeAnalysis.Common": { - "type": "Transitive", - "resolved": "4.9.2", - "contentHash": "M5PThug7b2AdxL7xKmQs50KzAQTl9jENw5jMT3iUt16k+DAFlw1S87juU3UuPs3gvBm8trMBSOEvSFDr31c9Vw==", - "dependencies": { - "Microsoft.CodeAnalysis.Analyzers": "3.3.4", - "System.Collections.Immutable": "8.0.0", - "System.Memory": "4.5.5", - "System.Reflection.Metadata": "8.0.0", - "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Encoding.CodePages": "8.0.0", - "System.Threading.Tasks.Extensions": "4.5.4" - } - }, - "Microsoft.NETCore.Platforms": { - "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" - }, - "System.Buffers": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" - }, - "System.Collections.Immutable": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==", - "dependencies": { - "System.Memory": "4.5.5", - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "System.Memory": { - "type": "Transitive", - "resolved": "4.5.5", - "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", - "dependencies": { - "System.Buffers": "4.5.1", - "System.Numerics.Vectors": "4.4.0", - "System.Runtime.CompilerServices.Unsafe": "4.5.3" - } - }, - "System.Numerics.Vectors": { - "type": "Transitive", - "resolved": "4.4.0", - "contentHash": "UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ==" - }, - "System.Reflection.Metadata": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==", - "dependencies": { - "System.Collections.Immutable": "8.0.0", - "System.Memory": "4.5.5" - } - }, - "System.Runtime.CompilerServices.Unsafe": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" - }, - "System.Text.Encoding.CodePages": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "OZIsVplFGaVY90G2SbpgU7EnCoOO5pw1t4ic21dBF3/1omrJFpAGoNAVpPyMVOC90/hvgkGG3VFqR13YgZMQfg==", - "dependencies": { - "System.Memory": "4.5.5", - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "System.Threading.Tasks.Extensions": { - "type": "Transitive", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "4.5.3" - } - } - } - } -} \ No newline at end of file diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/TeachingRecordSystem.Api.csproj b/TeachingRecordSystem/src/TeachingRecordSystem.Api/TeachingRecordSystem.Api.csproj index 612e4e4dd..8a6d880b1 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/TeachingRecordSystem.Api.csproj +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/TeachingRecordSystem.Api.csproj @@ -2,7 +2,6 @@ net8.0 - @@ -34,7 +33,6 @@ - diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/GenerateVersionedDtoAttribute.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/GenerateVersionedDtoAttribute.cs deleted file mode 100644 index 3a9024121..000000000 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/GenerateVersionedDtoAttribute.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace TeachingRecordSystem.Api.V3; - -[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] -public sealed class GenerateVersionedDtoAttribute(Type sourceType, params string[] excludeMembers) : Attribute -{ - public Type SourceType { get; } = sourceType; - - public string[] ExcludeMembers { get; } = excludeMembers; -} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/CreateTrnRequest.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/CreateTrnRequest.cs index 54ff95df1..6c1151a71 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/CreateTrnRequest.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/CreateTrnRequest.cs @@ -22,13 +22,13 @@ public record CreateTrnRequestCommand public required string? NationalInsuranceNumber { get; init; } public required bool? IdentityVerified { get; init; } public required string? OneLoginUserSubject { get; init; } - public required Contact_GenderCode? GenderCode { get; set; } - public required string? AddressLine1 { get; set; } - public required string? AddressLine2 { get; set; } - public required string? AddressLine3 { get; set; } - public required string? City { get; set; } - public required string? Postcode { get; set; } - public required string? Country { get; set; } + public required Gender? Gender { get; init; } + public required string? AddressLine1 { get; init; } + public required string? AddressLine2 { get; init; } + public required string? AddressLine3 { get; init; } + public required string? City { get; init; } + public required string? Postcode { get; init; } + public required string? Country { get; init; } } public class CreateTrnRequestHandler( @@ -150,7 +150,7 @@ await dbContext.TpsEmployments StatedMiddleName = command.MiddleName ?? "", StatedLastName = command.LastName, DateOfBirth = command.DateOfBirth, - Gender = command.GenderCode ?? Contact_GenderCode.Notavailable, + Gender = command.Gender?.ConvertToContact_GenderCode() ?? Contact_GenderCode.Notavailable, EmailAddress = emailAddress, NationalInsuranceNumber = NationalInsuranceNumberHelper.Normalize(command.NationalInsuranceNumber), PotentialDuplicates = potentialDuplicates.Select(d => (Duplicate: d, HasActiveAlert: resultsWithActiveAlerts.Contains(d.ContactId))).ToArray(), diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/Controllers/TrnRequestsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/Controllers/TrnRequestsController.cs index 09f1f7c5b..0139a2ad3 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/Controllers/TrnRequestsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240307/Controllers/TrnRequestsController.cs @@ -44,7 +44,7 @@ public async Task CreateTrnRequestAsync( AddressLine3 = null, City = null, Postcode = null, - GenderCode = null, + Gender = null, Country = null }; diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Responses/GetTeacherResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Responses/GetTeacherResponse.cs index 22acf33f4..c43d5ad74 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Responses/GetTeacherResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240416/Responses/GetTeacherResponse.cs @@ -1,7 +1,163 @@ +using System.Text.Json.Serialization; +using AutoMapper.Configuration.Annotations; +using Optional; +using TeachingRecordSystem.Api.Infrastructure.Mapping; using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; namespace TeachingRecordSystem.Api.V3.V20240416.Responses; [AutoMap(typeof(GetPersonResult))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponse))] -public partial record GetTeacherResponse; +public record GetTeacherResponse +{ + public required string Trn { get; init; } + public required string FirstName { get; init; } + public required string MiddleName { get; init; } + public required string LastName { get; init; } + public required DateOnly DateOfBirth { get; init; } + 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; } + public required Option> MandatoryQualifications { get; init; } + public required Option> HigherEducationQualifications { get; init; } + public required Option> Sanctions { get; init; } + public required Option> Alerts { get; init; } + public required Option> PreviousNames { get; init; } + public required Option AllowIdSignInWithProhibitions { get; init; } +} + +[AutoMap(typeof(Implementation.Dtos.QtsInfo))] +public record GetTeacherResponseQts +{ + 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 +{ + 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; } + public required DateOnly? EndDate { get; init; } + public required DqtInductionStatus? Status { get; init; } + public required string? StatusDescription { get; init; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public required string? CertificateUrl { get; init; } + public required IReadOnlyCollection Periods { get; init; } +} + +[AutoMap(typeof(GetPersonResultDqtInductionPeriod))] +public record GetTeacherResponseInductionPeriod +{ + public required DateOnly? StartDate { get; init; } + public required DateOnly? EndDate { get; init; } + public required int? Terms { get; init; } + public required GetTeacherResponseInductionPeriodAppropriateBody? AppropriateBody { get; init; } +} + +[AutoMap(typeof(GetPersonResultInductionPeriodAppropriateBody))] +public record GetTeacherResponseInductionPeriodAppropriateBody +{ + public required string Name { get; init; } +} + +[AutoMap(typeof(GetPersonResultInitialTeacherTraining))] +public record GetTeacherResponseInitialTeacherTraining +{ + [ValueConverter(typeof(UnwrapFromOptionValueConverter))] + public required GetTeacherResponseInitialTeacherTrainingQualification? Qualification { get; init; } + [ValueConverter(typeof(UnwrapFromOptionValueConverter))] + public required DateOnly? StartDate { get; init; } + [ValueConverter(typeof(UnwrapFromOptionValueConverter))] + public required DateOnly? EndDate { get; init; } + [ValueConverter(typeof(UnwrapFromOptionValueConverter))] + public required IttProgrammeType? ProgrammeType { get; init; } + [ValueConverter(typeof(UnwrapFromOptionValueConverter))] + public required string? ProgrammeTypeDescription { get; init; } + [ValueConverter(typeof(UnwrapFromOptionValueConverter))] + public required IttOutcome? Result { get; init; } + [ValueConverter(typeof(UnwrapFromOptionValueConverter))] + public required GetTeacherResponseInitialTeacherTrainingAgeRange? AgeRange { get; init; } + public required GetTeacherResponseInitialTeacherTrainingProvider? Provider { get; init; } + [ValueConverter(typeof(UnwrapFromOptionValueConverter, IReadOnlyCollection>))] + 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; } + public required string Name { get; init; } +} + +[AutoMap(typeof(GetPersonResultNpqQualification))] +public record GetTeacherResponseNpqQualification +{ + public required DateOnly Awarded { get; init; } + public required GetTeacherResponseNpqQualificationType Type { get; init; } + public required string CertificateUrl { get; init; } +} + +[AutoMap(typeof(GetPersonResultNpqQualificationType))] +public record GetTeacherResponseNpqQualificationType +{ + public required NpqQualificationType Code { get; init; } + public required string Name { get; init; } +} + +[AutoMap(typeof(GetPersonResultMandatoryQualification))] +public record GetTeacherResponseMandatoryQualification +{ + public required DateOnly Awarded { get; init; } + public required string Specialism { get; init; } +} + +[AutoMap(typeof(GetPersonResultHigherEducationQualification))] +public record GetTeacherResponseHigherEducationQualification +{ + public required string? Name { get; init; } + public required DateOnly? Awarded { get; init; } + public required IReadOnlyCollection Subjects { get; init; } +} + +[AutoMap(typeof(GetPersonResultHigherEducationQualificationSubject))] +public record GetTeacherResponseHigherEducationQualificationSubject +{ + public required string Code { get; init; } + public required string Name { get; init; } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/TrnRequestsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/TrnRequestsController.cs index 8743410a2..dc0195440 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/TrnRequestsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Controllers/TrnRequestsController.cs @@ -44,7 +44,7 @@ public async Task CreateTrnRequestAsync( AddressLine3 = null, City = null, Postcode = null, - GenderCode = null, + Gender = null, Country = null }; var result = await handler.HandleAsync(command); diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateDateOfBirthChangeResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateDateOfBirthChangeResponse.cs index 3ab247313..8e7584aa4 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateDateOfBirthChangeResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateDateOfBirthChangeResponse.cs @@ -3,5 +3,7 @@ namespace TeachingRecordSystem.Api.V3.V20240606.Responses; [AutoMap(typeof(CreateDateOfBirthChangeRequestResult))] -[GenerateVersionedDto(typeof(V20240412.Responses.CreateDateOfBirthChangeResponse))] -public partial record CreateDateOfBirthChangeResponse; +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 538f92ef8..00e02e519 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateNameChangeResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/CreateNameChangeResponse.cs @@ -3,5 +3,7 @@ namespace TeachingRecordSystem.Api.V3.V20240606.Responses; [AutoMap(typeof(CreateNameChangeRequestResult))] -[GenerateVersionedDto(typeof(V20240412.Responses.CreateNameChangeResponse))] -public partial record CreateNameChangeResponse; +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 749fb979b..6c98b479d 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/FindPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/FindPersonResponse.cs @@ -1,15 +1,24 @@ using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Api.V3.V20240606.Requests; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; namespace TeachingRecordSystem.Api.V3.V20240606.Responses; -[GenerateVersionedDto(typeof(V20240101.Responses.FindTeachersResponse), excludeMembers: ["Query", "Results"])] -public partial record FindPersonResponse +public record FindPersonResponse { + public required int Total { get; init; } public required FindPersonRequest Query { get; init; } public required IReadOnlyCollection Results { get; init; } } [AutoMap(typeof(FindPersonsResultItem))] -[GenerateVersionedDto(typeof(V20240101.Responses.FindTeachersResponseResult))] -public partial record FindPersonResponseResult; +public record FindPersonResponseResult +{ + public required string Trn { get; init; } + public required DateOnly DateOfBirth { get; init; } + public required string FirstName { get; init; } + public required string MiddleName { get; init; } + public required string LastName { get; init; } + public required IReadOnlyCollection Sanctions { get; init; } + public required IReadOnlyCollection PreviousNames { 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 22126382e..092c0a17c 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/GetPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/GetPersonResponse.cs @@ -1,3 +1,4 @@ +using System.Text.Json.Serialization; using AutoMapper.Configuration.Annotations; using Optional; using TeachingRecordSystem.Api.Infrastructure.Mapping; @@ -7,7 +8,7 @@ namespace TeachingRecordSystem.Api.V3.V20240606.Responses; [AutoMap(typeof(GetPersonResult))] -public partial record GetPersonResponse +public record GetPersonResponse { public required string Trn { get; init; } public required string FirstName { get; init; } @@ -17,7 +18,7 @@ public partial record GetPersonResponse public required string? NationalInsuranceNumber { get; init; } public required Option PendingNameChange { get; init; } public required Option PendingDateOfBirthChange { get; init; } - public required string? EmailAddress { get; set; } + public required string? EmailAddress { get; init; } public required GetPersonResponseQts? Qts { get; init; } public required GetPersonResponseEyts? Eyts { get; init; } [SourceMember(nameof(GetPersonResult.DqtInduction))] @@ -33,37 +34,63 @@ public partial record GetPersonResponse } [AutoMap(typeof(Implementation.Dtos.QtsInfo))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseQts))] -public partial record GetPersonResponseQts; +public record GetPersonResponseQts +{ + public required DateOnly? Awarded { get; init; } + public required string CertificateUrl { get; init; } + public required string? StatusDescription { get; init; } +} [AutoMap(typeof(Implementation.Dtos.EytsInfo))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseEyts))] -public partial record GetPersonResponseEyts; +public record GetPersonResponseEyts +{ + public required DateOnly? Awarded { get; init; } + public required string CertificateUrl { get; init; } + public required string? StatusDescription { get; init; } +} [AutoMap(typeof(GetPersonResultDqtInduction))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseInduction), excludeMembers: ["Periods"])] -public partial record GetPersonResponseInduction +public record GetPersonResponseInduction { + public required DateOnly? StartDate { get; init; } + public required DateOnly? EndDate { get; init; } + public required DqtInductionStatus? Status { get; init; } + public required string? StatusDescription { get; init; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public required string? CertificateUrl { get; init; } public required IReadOnlyCollection Periods { get; init; } } [AutoMap(typeof(GetPersonResultDqtInductionPeriod))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseInductionPeriod), excludeMembers: ["AppropriateBody"])] -public partial record GetPersonResponseInductionPeriod +public record GetPersonResponseInductionPeriod { + public required DateOnly? StartDate { get; init; } + public required DateOnly? EndDate { get; init; } + public required int? Terms { get; init; } public required GetPersonResponseInductionPeriodAppropriateBody? AppropriateBody { get; init; } } [AutoMap(typeof(GetPersonResultInductionPeriodAppropriateBody))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseInductionPeriodAppropriateBody))] -public partial record GetPersonResponseInductionPeriodAppropriateBody; +public record GetPersonResponseInductionPeriodAppropriateBody +{ + public required string Name { get; init; } +} [AutoMap(typeof(GetPersonResultInitialTeacherTraining))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseInitialTeacherTraining), excludeMembers: ["Qualification", "AgeRange", "Provider", "Subjects"])] -public partial record GetPersonResponseInitialTeacherTraining +public record GetPersonResponseInitialTeacherTraining { [ValueConverter(typeof(UnwrapFromOptionValueConverter))] public required GetPersonResponseInitialTeacherTrainingQualification? Qualification { get; init; } + [ValueConverter(typeof(UnwrapFromOptionValueConverter))] + public required DateOnly? StartDate { get; init; } + [ValueConverter(typeof(UnwrapFromOptionValueConverter))] + public required DateOnly? EndDate { get; init; } + [ValueConverter(typeof(UnwrapFromOptionValueConverter))] + public required IttProgrammeType? ProgrammeType { get; init; } + [ValueConverter(typeof(UnwrapFromOptionValueConverter))] + public required string? ProgrammeTypeDescription { get; init; } + [ValueConverter(typeof(UnwrapFromOptionValueConverter))] + public required IttOutcome? Result { get; init; } [ValueConverter(typeof(UnwrapFromOptionValueConverter))] public required GetPersonResponseInitialTeacherTrainingAgeRange? AgeRange { get; init; } public required GetPersonResponseInitialTeacherTrainingProvider? Provider { get; init; } @@ -72,43 +99,64 @@ public partial record GetPersonResponseInitialTeacherTraining } [AutoMap(typeof(GetPersonResultInitialTeacherTrainingQualification))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseInitialTeacherTrainingQualification))] -public partial record GetPersonResponseInitialTeacherTrainingQualification; +public record GetPersonResponseInitialTeacherTrainingQualification +{ + public required string Name { get; init; } +} [AutoMap(typeof(GetPersonResultInitialTeacherTrainingAgeRange))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseInitialTeacherTrainingAgeRange))] -public partial record GetPersonResponseInitialTeacherTrainingAgeRange; +public record GetPersonResponseInitialTeacherTrainingAgeRange +{ + public required string Description { get; init; } +} [AutoMap(typeof(GetPersonResultInitialTeacherTrainingProvider))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseInitialTeacherTrainingProvider))] -public partial record GetPersonResponseInitialTeacherTrainingProvider; +public record GetPersonResponseInitialTeacherTrainingProvider +{ + public required string Name { get; init; } + public required string Ukprn { get; init; } +} [AutoMap(typeof(GetPersonResultInitialTeacherTrainingSubject))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseInitialTeacherTrainingSubject))] -public partial record GetPersonResponseInitialTeacherTrainingSubject; +public record GetPersonResponseInitialTeacherTrainingSubject +{ + public required string Code { get; init; } + public required string Name { get; init; } +} [AutoMap(typeof(GetPersonResultNpqQualification))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseNpqQualification), excludeMembers: "Type")] -public partial record GetPersonResponseNpqQualification +public record GetPersonResponseNpqQualification { + public required DateOnly Awarded { get; init; } public required GetPersonResponseNpqQualificationType Type { get; init; } + public required string CertificateUrl { get; init; } } [AutoMap(typeof(GetPersonResultNpqQualificationType))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseNpqQualificationType))] -public partial record GetPersonResponseNpqQualificationType; +public record GetPersonResponseNpqQualificationType +{ + public required NpqQualificationType Code { get; init; } + public required string Name { get; init; } +} [AutoMap(typeof(GetPersonResultMandatoryQualification))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseMandatoryQualification))] -public partial record GetPersonResponseMandatoryQualification; +public record GetPersonResponseMandatoryQualification +{ + public required DateOnly Awarded { get; init; } + public required string Specialism { get; init; } +} [AutoMap(typeof(GetPersonResultHigherEducationQualification))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseHigherEducationQualification), excludeMembers: "Subjects")] -public partial record GetPersonResponseHigherEducationQualification +public record GetPersonResponseHigherEducationQualification { + public required string? Name { get; init; } + public required DateOnly? Awarded { get; init; } public required IReadOnlyCollection Subjects { get; init; } } [AutoMap(typeof(GetPersonResultHigherEducationQualificationSubject))] -[GenerateVersionedDto(typeof(V20240101.Responses.GetTeacherResponseHigherEducationQualificationSubject))] -public partial record GetPersonResponseHigherEducationQualificationSubject; +public record GetPersonResponseHigherEducationQualificationSubject +{ + public required string Code { get; init; } + public required string Name { get; init; } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonResponse.cs index 345f4c634..02e2a4e27 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonResponse.cs @@ -1,21 +1,28 @@ 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; namespace TeachingRecordSystem.Api.V3.V20240814.Responses; -[GenerateVersionedDto(typeof(V20240101.Responses.FindTeachersResponse), excludeMembers: ["Query", "Results"])] -public partial record FindPersonResponse +public record FindPersonResponse { + public required int Total { get; init; } public required FindPersonRequest Query { get; init; } public required IReadOnlyCollection Results { get; init; } } [AutoMap(typeof(FindPersonsResultItem))] -[GenerateVersionedDto(typeof(V20240101.Responses.FindTeachersResponseResult))] -public partial record FindPersonResponseResult +public record FindPersonResponseResult { + public required string Trn { get; init; } + public required DateOnly DateOfBirth { get; init; } + public required string FirstName { get; init; } + public required string MiddleName { get; init; } + 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; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonResponse.cs index 1eb06d1b1..945710e72 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonResponse.cs @@ -1,19 +1,31 @@ +using AutoMapper.Configuration.Annotations; using TeachingRecordSystem.Api.V3.Implementation.Operations; -using TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; -using FindPersonRequest = TeachingRecordSystem.Api.V3.V20240920.Requests.FindPersonRequest; +using TeachingRecordSystem.Api.V3.V20240920.Requests; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; +using Alert = TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos.Alert; namespace TeachingRecordSystem.Api.V3.V20240920.Responses; -[GenerateVersionedDto(typeof(V20240814.Responses.FindPersonResponse), excludeMembers: ["Query", "Results"])] -public partial record FindPersonResponse +public record FindPersonResponse { + public required int Total { get; init; } public required FindPersonRequest Query { get; init; } public required IReadOnlyCollection Results { get; init; } } [AutoMap(typeof(FindPersonsResultItem))] -[GenerateVersionedDto(typeof(V20240814.Responses.FindPersonResponseResult), excludeMembers: ["Sanctions"])] -public partial record FindPersonResponseResult +public record FindPersonResponseResult { + public required string Trn { get; init; } + public required DateOnly DateOfBirth { get; init; } + public required string FirstName { get; init; } + 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; } public required IReadOnlyCollection Alerts { 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 75ee4478e..0ee19b280 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonsResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/FindPersonsResponse.cs @@ -1,20 +1,31 @@ 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))] -[GenerateVersionedDto(typeof(V20240814.Responses.FindPersonsResponse), excludeMembers: ["Results"])] -public partial record FindPersonsResponse +public record FindPersonsResponse { + public required int Total { get; init; } [SourceMember(nameof(FindPersonsResult.Items))] public required IReadOnlyCollection Results { get; init; } } [AutoMap(typeof(FindPersonsResultItem))] -[GenerateVersionedDto(typeof(V20240814.Responses.FindPersonsResponseResult), excludeMembers: ["Sanctions"])] -public partial record FindPersonsResponseResult +public record FindPersonsResponseResult { + public required string Trn { get; init; } + public required DateOnly DateOfBirth { get; init; } + public required string FirstName { get; init; } + 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; } public required IReadOnlyCollection Alerts { 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 56f99a691..3d9a4e9ba 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/GetPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240920/Responses/GetPersonResponse.cs @@ -1,28 +1,67 @@ +using System.Text.Json.Serialization; using AutoMapper.Configuration.Annotations; using Optional; using TeachingRecordSystem.Api.V3.Implementation.Operations; -using TeachingRecordSystem.Api.V3.V20240606.Responses; using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; using TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; namespace TeachingRecordSystem.Api.V3.V20240920.Responses; [AutoMap(typeof(GetPersonResult))] -[GenerateVersionedDto(typeof(V20240606.Responses.GetPersonResponse), excludeMembers: ["Alerts", "Sanctions", "Induction", "InitialTeacherTraining"])] -public partial record GetPersonResponse +public record GetPersonResponse { - public required Option> Alerts { get; init; } + public required string Trn { get; init; } + public required string FirstName { get; init; } + public required string MiddleName { get; init; } + public required string LastName { get; init; } + public required DateOnly DateOfBirth { get; init; } + public required string? NationalInsuranceNumber { get; init; } + public required Option PendingNameChange { get; init; } + public required Option PendingDateOfBirthChange { get; init; } + 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; } + public required Option> MandatoryQualifications { get; init; } + public required Option> HigherEducationQualifications { get; init; } + public required Option> Sanctions { get; init; } + public required Option> Alerts { get; init; } + public required Option> PreviousNames { get; init; } + public required Option AllowIdSignInWithProhibitions { get; init; } +} + +[AutoMap(typeof(Implementation.Dtos.QtsInfo))] +public record GetPersonResponseQts +{ + 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 +{ + public required DateOnly? Awarded { get; init; } + public required string CertificateUrl { get; init; } + public required string? StatusDescription { get; init; } } [AutoMap(typeof(GetPersonResultDqtInduction))] -[GenerateVersionedDto(typeof(V20240606.Responses.GetPersonResponseInduction), excludeMembers: ["Periods"])] -public partial record GetPersonResponseInduction; +public record GetPersonResponseInduction +{ + public required DateOnly? StartDate { get; init; } + public required DateOnly? EndDate { get; init; } + public required TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos.DqtInductionStatus? Status { get; init; } + public required string? StatusDescription { get; init; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public required string? CertificateUrl { get; init; } +} [AutoMap(typeof(GetPersonResultInitialTeacherTraining))] -public partial record GetPersonResponseInitialTeacherTraining +public record GetPersonResponseInitialTeacherTraining { public required GetPersonResponseInitialTeacherTrainingProvider? Provider { get; init; } public required Option Qualification { get; init; } @@ -34,3 +73,66 @@ public partial record GetPersonResponseInitialTeacherTraining public required Option AgeRange { get; init; } public required Option> 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; } + public required string Name { get; init; } +} + +[AutoMap(typeof(GetPersonResultNpqQualification))] +public record GetPersonResponseNpqQualification +{ + public required DateOnly Awarded { get; init; } + public required GetPersonResponseNpqQualificationType Type { get; init; } + public required string CertificateUrl { get; init; } +} + +[AutoMap(typeof(GetPersonResultNpqQualificationType))] +public record GetPersonResponseNpqQualificationType +{ + public required NpqQualificationType Code { get; init; } + public required string Name { get; init; } +} + +[AutoMap(typeof(GetPersonResultMandatoryQualification))] +public record GetPersonResponseMandatoryQualification +{ + public required DateOnly Awarded { get; init; } + public required string Specialism { get; init; } +} + +[AutoMap(typeof(GetPersonResultHigherEducationQualification))] +public record GetPersonResponseHigherEducationQualification +{ + public required string? Name { get; init; } + public required DateOnly? Awarded { get; init; } + public required IReadOnlyCollection Subjects { get; init; } +} + +[AutoMap(typeof(GetPersonResultHigherEducationQualificationSubject))] +public record GetPersonResponseHigherEducationQualificationSubject +{ + public required string Code { get; init; } + public required string Name { get; init; } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/PersonController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/PersonController.cs index ef67df8c7..7f51d813a 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/PersonController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/PersonController.cs @@ -5,7 +5,7 @@ using TeachingRecordSystem.Api.Infrastructure.ModelBinding; using TeachingRecordSystem.Api.Infrastructure.Security; using TeachingRecordSystem.Api.V3.Implementation.Operations; -using TeachingRecordSystem.Api.V3.V20240920.Requests; +using TeachingRecordSystem.Api.V3.VNext.Requests; using TeachingRecordSystem.Api.V3.VNext.Responses; namespace TeachingRecordSystem.Api.V3.VNext.Controllers; diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/PersonsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/PersonsController.cs index 4d14eebc5..82d7d5931 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/PersonsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/PersonsController.cs @@ -4,12 +4,8 @@ using TeachingRecordSystem.Api.Infrastructure.ModelBinding; using TeachingRecordSystem.Api.Infrastructure.Security; using TeachingRecordSystem.Api.V3.Implementation.Operations; -using TeachingRecordSystem.Api.V3.V20240920.Requests; using TeachingRecordSystem.Api.V3.VNext.Requests; using TeachingRecordSystem.Api.V3.VNext.Responses; -using FindPersonResponse = TeachingRecordSystem.Api.V3.VNext.Responses.FindPersonResponse; -using FindPersonResponseResult = TeachingRecordSystem.Api.V3.VNext.Responses.FindPersonResponseResult; -using FindPersonsResponse = TeachingRecordSystem.Api.V3.VNext.Responses.FindPersonsResponse; namespace TeachingRecordSystem.Api.V3.VNext.Controllers; diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/TrnRequestsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/TrnRequestsController.cs index 27883fc82..12ca46d15 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/TrnRequestsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/TrnRequestsController.cs @@ -2,9 +2,9 @@ using Microsoft.AspNetCore.Mvc; using Swashbuckle.AspNetCore.Annotations; using TeachingRecordSystem.Api.Infrastructure.Security; -using TeachingRecordSystem.Api.V3.Implementation.Dtos; using TeachingRecordSystem.Api.V3.Implementation.Operations; using TeachingRecordSystem.Api.V3.VNext.Requests; +using TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos; using TrnRequestInfo = TeachingRecordSystem.Core.ApiSchema.V3.V20240606.Dtos.TrnRequestInfo; namespace TeachingRecordSystem.Api.V3.VNext.Controllers; @@ -44,7 +44,7 @@ public async Task CreateTrnRequestAsync( AddressLine1 = request.Person.Address?.AddressLine1, AddressLine2 = request.Person.Address?.AddressLine2, AddressLine3 = request.Person.Address?.AddressLine3, - GenderCode = request.Person.GenderCode.HasValue ? GenderExtensions.ConvertToContact_GenderCode(request.Person.GenderCode!.Value) : null, + Gender = request.Person.Gender is Gender gender ? mapper.Map(gender) : null, City = request.Person.Address?.City, Postcode = request.Person.Address?.Postcode, Country = request.Person.Address?.Country, diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/CreateTrnRequestRequest.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/CreateTrnRequestRequest.cs index 404eeae92..dd7b5100f 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/CreateTrnRequestRequest.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/CreateTrnRequestRequest.cs @@ -1,21 +1,29 @@ - -using TeachingRecordSystem.Api.V3.Implementation.Dtos; +using Swashbuckle.AspNetCore.Annotations; +using TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos; namespace TeachingRecordSystem.Api.V3.VNext.Requests; -[GenerateVersionedDto(typeof(V20240606.Requests.CreateTrnRequestRequest), excludeMembers: "Person")] -public partial record CreateTrnRequestRequest +public record CreateTrnRequestRequest { + [SwaggerSchema(description: + "A unique ID that represents this request. " + + "If a request has already been created with this ID then that existing record's result is returned.")] + public required string RequestId { get; init; } + public required CreateTrnRequestRequestPerson Person { get; init; } public bool IdentityVerified { get; init; } public string? OneLoginUserSubject { get; init; } - public required CreateTrnRequestRequestPerson Person { get; init; } } -[GenerateVersionedDto(typeof(V20240606.Requests.CreateTrnRequestRequestPerson))] -public partial record CreateTrnRequestRequestPerson +public record CreateTrnRequestRequestPerson { + public required string FirstName { get; init; } + public string? MiddleName { get; init; } + public required string LastName { get; init; } + public required DateOnly DateOfBirth { get; init; } + public IReadOnlyCollection? EmailAddresses { get; init; } + public string? NationalInsuranceNumber { get; init; } public CreateTrnRequestAddress? Address { get; init; } - public Gender? GenderCode { get; init; } + public Gender? Gender { get; init; } } public class CreateTrnRequestAddress diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/FindPersonRequest.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/FindPersonRequest.cs new file mode 100644 index 000000000..83f6d9a21 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/FindPersonRequest.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Mvc; + +namespace TeachingRecordSystem.Api.V3.VNext.Requests; + +public record FindPersonRequest +{ + [FromQuery(Name = "findBy")] + public FindPersonFindBy FindBy { get; init; } + [FromQuery(Name = "lastName")] + public string? LastName { get; init; } + [FromQuery(Name = "dateOfBirth")] + public DateOnly? DateOfBirth { get; init; } +} + +public enum FindPersonFindBy +{ + LastNameAndDateOfBirth = 1 +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/FindPersonsRequest.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/FindPersonsRequest.cs new file mode 100644 index 000000000..cbc1940d8 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/FindPersonsRequest.cs @@ -0,0 +1,12 @@ +namespace TeachingRecordSystem.Api.V3.VNext.Requests; + +public record FindPersonsRequest +{ + public required IReadOnlyCollection Persons { get; init; } +} + +public record FindPersonsRequestPerson +{ + public required string Trn { get; init; } + public required DateOnly DateOfBirth { get; init; } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/GetPersonRequestIncludes.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/GetPersonRequestIncludes.cs new file mode 100644 index 000000000..94c277778 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/GetPersonRequestIncludes.cs @@ -0,0 +1,24 @@ +using System.ComponentModel; + +namespace TeachingRecordSystem.Api.V3.VNext.Requests; + +[Flags] +[Description("Comma-separated list of data to include in response.")] +public enum GetPersonRequestIncludes +{ + None = 0, + + Induction = 1 << 0, + InitialTeacherTraining = 1 << 1, + NpqQualifications = 1 << 2, + MandatoryQualifications = 1 << 3, + PendingDetailChanges = 1 << 4, + HigherEducationQualifications = 1 << 5, + Alerts = 1 << 7, + PreviousNames = 1 << 8, + + [ExcludeFromSchema] + _AllowIdSignInWithProhibitions = 1 << 9, + + All = Induction | InitialTeacherTraining | NpqQualifications | MandatoryQualifications | PendingDetailChanges | HigherEducationQualifications | Alerts | PreviousNames +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonResponse.cs index c5a300c5b..5410ef52e 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonResponse.cs @@ -1,17 +1,30 @@ using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Api.V3.VNext.Requests; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos; +using TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos; using InductionStatus = TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos.InductionStatus; namespace TeachingRecordSystem.Api.V3.VNext.Responses; -[GenerateVersionedDto(typeof(V20240920.Responses.FindPersonResponse), excludeMembers: ["Results"])] -public partial record FindPersonResponse +public record FindPersonResponse { + public required int Total { get; init; } + public required FindPersonRequest Query { get; init; } public required IReadOnlyCollection Results { get; init; } } [AutoMap(typeof(FindPersonsResultItem))] -[GenerateVersionedDto(typeof(V20240920.Responses.FindPersonResponseResult), excludeMembers: ["InductionStatus"])] -public partial record FindPersonResponseResult +public record FindPersonResponseResult { + public required string Trn { get; init; } + public required DateOnly DateOfBirth { get; init; } + public required string FirstName { get; init; } + public required string MiddleName { get; init; } + public required string LastName { get; init; } + public required IReadOnlyCollection PreviousNames { get; init; } + public required QtsInfo? Qts { get; init; } + public required EytsInfo? Eyts { get; init; } + public required IReadOnlyCollection Alerts { get; init; } public required InductionStatus InductionStatus { get; init; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonsResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonsResponse.cs index 3a77e70ce..cdff9b5e0 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonsResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonsResponse.cs @@ -1,20 +1,31 @@ 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.VNext.Dtos.InductionStatus; +using NameInfo = TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos.NameInfo; namespace TeachingRecordSystem.Api.V3.VNext.Responses; [AutoMap(typeof(FindPersonsResult))] -[GenerateVersionedDto(typeof(V20240920.Responses.FindPersonsResponse), excludeMembers: ["Results"])] -public partial record FindPersonsResponse +public record FindPersonsResponse { + public required int Total { get; init; } [SourceMember(nameof(FindPersonsResult.Items))] public required IReadOnlyCollection Results { get; init; } } [AutoMap(typeof(FindPersonsResultItem))] -[GenerateVersionedDto(typeof(V20240920.Responses.FindPersonsResponseResult), excludeMembers: ["InductionStatus"])] -public partial record FindPersonsResponseResult +public record FindPersonsResponseResult { + public required string Trn { get; init; } + public required DateOnly DateOfBirth { get; init; } + public required string FirstName { get; init; } + public required string MiddleName { get; init; } + public required string LastName { get; init; } + public required IReadOnlyCollection PreviousNames { get; init; } + public required QtsInfo? Qts { get; init; } + public required EytsInfo? Eyts { get; init; } + public required IReadOnlyCollection Alerts { get; init; } public required InductionStatus InductionStatus { get; init; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/GetPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/GetPersonResponse.cs index 8f1e96b03..2b4e3f62b 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/GetPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/GetPersonResponse.cs @@ -1,18 +1,131 @@ 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.VNext.Dtos; namespace TeachingRecordSystem.Api.V3.VNext.Responses; [AutoMap(typeof(GetPersonResult))] -[GenerateVersionedDto(typeof(V20240920.Responses.GetPersonResponse), excludeMembers: ["Induction"])] -public partial record GetPersonResponse +public record GetPersonResponse { + public required string Trn { get; init; } + public required string FirstName { get; init; } + public required string MiddleName { get; init; } + public required string LastName { get; init; } + public required DateOnly DateOfBirth { get; init; } + public required string? NationalInsuranceNumber { get; init; } + public required Option PendingNameChange { get; init; } + public required Option PendingDateOfBirthChange { get; init; } + public required string? EmailAddress { get; init; } + public required GetPersonResponseQts? Qts { get; init; } + public required GetPersonResponseEyts? Eyts { get; init; } public required Option Induction { get; init; } + public required Option> InitialTeacherTraining { get; init; } + public required Option> NpqQualifications { get; init; } + public required Option> MandatoryQualifications { get; init; } + public required Option> HigherEducationQualifications { get; init; } + public required Option> Sanctions { get; init; } + public required Option> Alerts { get; init; } + public required Option> PreviousNames { get; init; } + public required Option AllowIdSignInWithProhibitions { get; init; } +} + +[AutoMap(typeof(Implementation.Dtos.QtsInfo))] +public record GetPersonResponseQts +{ + 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 +{ + public required DateOnly? Awarded { get; init; } + public required string CertificateUrl { get; init; } + public required string? StatusDescription { get; init; } +} + +[AutoMap(typeof(GetPersonResultInitialTeacherTraining))] +public record GetPersonResponseInitialTeacherTraining +{ + public required GetPersonResponseInitialTeacherTrainingProvider? Provider { get; init; } + public required Option Qualification { get; init; } + public required Option StartDate { get; init; } + public required Option EndDate { get; init; } + public required Option ProgrammeType { get; init; } + public required Option ProgrammeTypeDescription { get; init; } + public required Option Result { get; init; } + public required Option AgeRange { get; init; } + public required Option> 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; } + public required string Name { get; init; } +} + +[AutoMap(typeof(GetPersonResultNpqQualification))] +public record GetPersonResponseNpqQualification +{ + public required DateOnly Awarded { get; init; } + public required GetPersonResponseNpqQualificationType Type { get; init; } + public required string CertificateUrl { get; init; } +} + +[AutoMap(typeof(GetPersonResultNpqQualificationType))] +public record GetPersonResponseNpqQualificationType +{ + public required NpqQualificationType Code { get; init; } + public required string Name { get; init; } +} + +[AutoMap(typeof(GetPersonResultMandatoryQualification))] +public record GetPersonResponseMandatoryQualification +{ + public required DateOnly Awarded { get; init; } + public required string Specialism { get; init; } +} + +[AutoMap(typeof(GetPersonResultHigherEducationQualification))] +public record GetPersonResponseHigherEducationQualification +{ + public required string? Name { get; init; } + public required DateOnly? Awarded { get; init; } + public required IReadOnlyCollection Subjects { get; init; } +} + +[AutoMap(typeof(GetPersonResultHigherEducationQualificationSubject))] +public record GetPersonResponseHigherEducationQualificationSubject +{ + public required string Code { get; init; } + public required string Name { get; init; } } [AutoMap(typeof(GetPersonResultInduction))] -public partial record GetPersonResponseInduction : InductionInfo +public record GetPersonResponseInduction : InductionInfo { public required string? CertificateUrl { get; init; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Validators/CreateTrnRequestRequestValidator.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Validators/CreateTrnRequestRequestValidator.cs index dc7ac903f..39dd9c2cc 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Validators/CreateTrnRequestRequestValidator.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Validators/CreateTrnRequestRequestValidator.cs @@ -32,7 +32,7 @@ public CreateTrnRequestRequestValidator(IClock clock) .MaximumLength(AttributeConstraints.Contact.Address1_PostalCodeLength) .When(r => r.Person.Address != null); - RuleFor(r => r.Person.GenderCode) + RuleFor(r => r.Person.Gender) .IsInEnum(); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/ApiSchema/V3/VNext/Dtos/Gender.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/ApiSchema/V3/VNext/Dtos/Gender.cs new file mode 100644 index 000000000..b8d82fce1 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/ApiSchema/V3/VNext/Dtos/Gender.cs @@ -0,0 +1,8 @@ +namespace TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos; + +public enum Gender +{ + Male = 1, + Female = 2, + Other = 3 +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/CreateTrnRequestTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/CreateTrnRequestTests.cs index 083e0be4a..596b39e6e 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/CreateTrnRequestTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/CreateTrnRequestTests.cs @@ -113,7 +113,7 @@ public async Task Post_ValidAddressFields_PopulatesContactAddressFields() postcode = postcode, country = country, }, - genderCode = gender + gender = gender }, identityVerified = identityVerified, oneLoginUserSubject = oneLoginUserSubject @@ -177,7 +177,7 @@ public async Task Post_AddressFieldsExceedingMaxLengths_ReturnsBadRequest() postcode = postcode, country = country, }, - genderCode = gender + gender = gender }, identityVerified = identityVerified, oneLoginUserSubject = oneLoginUserSubject diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VersionReferenceTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VersionReferenceTests.cs new file mode 100644 index 000000000..a4ca46ac6 --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VersionReferenceTests.cs @@ -0,0 +1,69 @@ +using System.Reflection; +using Xunit.Sdk; + +namespace TeachingRecordSystem.Api.Tests.V3; + +public class VersionReferenceTests +{ + public static IEnumerable MinorVersions => VersionRegistry.AllV3MinorVersions.Select(v => new object[] { v }); + + [Theory] + [MemberData(nameof(MinorVersions))] + public void CheckInterVersionDependencies(string minorVersion) + { + var assemblies = AppDomain.CurrentDomain.GetAssemblies() + .Where(a => a.GetName().Name is "TeachingRecordSystem.Api"); + + var typesForVersion = assemblies + .SelectMany(GetTypesForVersion) + .ToArray(); + + var visited = new HashSet(); + + foreach (var type in typesForVersion) + { + VisitType(type); + } + + static string? GetVersionForType(Type type) + { + if (type.Namespace is null) + { + return null; + } + + var namespaceParts = type.Namespace.Split('.'); + return namespaceParts.FirstOrDefault(p => VersionRegistry.AllV3MinorVersions.Any(v => $"V{v}" == p))?.TrimStart('V'); + } + + IEnumerable GetTypesForVersion(Assembly assembly) => + assembly.GetTypes().Where(t => GetVersionForType(t) == minorVersion); + + void VisitType(Type type) + { + var name = type.FullName; + if (name is null || !visited.Add(name)) + { + return; + } + + var typeVersion = GetVersionForType(type); + if (typeVersion is not null && typeVersion != minorVersion && type.Namespace?.Contains("Core.ApiSchema") != true) + { + throw new XunitException( + $"Version {minorVersion} references a type in another version ({type.FullName})."); + } + + if (type.Namespace?.Contains("Implementation.Dtos") == true) + { + throw new XunitException( + $"Version {minorVersion} references an internal implementation type ({type.FullName})."); + } + + foreach (var property in type.GetProperties()) + { + VisitType(property.PropertyType); + } + } + } +}