diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 0000000..e69de29
diff --git a/EstateReportingAPI.BusinessLogic/EstateReportingAPI.BusinessLogic.csproj b/EstateReportingAPI.BusinessLogic/EstateReportingAPI.BusinessLogic.csproj
index 0d65c0a..00be78f 100644
--- a/EstateReportingAPI.BusinessLogic/EstateReportingAPI.BusinessLogic.csproj
+++ b/EstateReportingAPI.BusinessLogic/EstateReportingAPI.BusinessLogic.csproj
@@ -8,10 +8,10 @@
-
+
-
+
diff --git a/EstateReportingAPI.BusinessLogic/Queries/FileImportLogQueries.cs b/EstateReportingAPI.BusinessLogic/Queries/FileImportLogQueries.cs
index 360d553..7ff5b68 100644
--- a/EstateReportingAPI.BusinessLogic/Queries/FileImportLogQueries.cs
+++ b/EstateReportingAPI.BusinessLogic/Queries/FileImportLogQueries.cs
@@ -10,4 +10,10 @@ public record FileImportLogQueries
{
public record GetFileImportLogListQuery(Guid EstateId, Guid? MerchantId, DateTime StartDate, DateTime EndDate) : IRequest>>;
public record GetFileImportLogQuery(Guid EstateId, Guid? MerchantId, Guid FileImportLogId) : IRequest>;
+}
+
+[ExcludeFromCodeCoverage]
+public record FileProfileConfigurationQueries
+{
+ public record GetFileProfileConfigurationListQuery(Guid EstateId) : IRequest>>;
}
\ No newline at end of file
diff --git a/EstateReportingAPI.BusinessLogic/ReportingManager.cs b/EstateReportingAPI.BusinessLogic/ReportingManager.cs
index 3b9986c..9723b15 100644
--- a/EstateReportingAPI.BusinessLogic/ReportingManager.cs
+++ b/EstateReportingAPI.BusinessLogic/ReportingManager.cs
@@ -8,13 +8,11 @@
namespace EstateReportingAPI.BusinessLogic;
-using Azure;
using Microsoft.EntityFrameworkCore;
using Models;
using Shared.EntityFramework;
using Shared.Results;
using System;
-using System.ClientModel.Primitives;
using System.Linq;
using System.Threading;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
@@ -65,6 +63,8 @@ Task>> GetFileImportLogList(FileImportLogQueries.GetF
CancellationToken cancellationToken);
Task> GetFileImportLog(FileImportLogQueries.GetFileImportLogQuery request,
CancellationToken cancellationToken);
+ Task>> GetFileProfileConfigurationList(FileProfileConfigurationQueries.GetFileProfileConfigurationListQuery request,
+ CancellationToken cancellationToken);
}
public class ReportingManager : IReportingManager {
@@ -1522,6 +1522,34 @@ join fl in context.FileLines on f.FileId equals fl.FileId
return Result.Success(fileImportLogs);
}
+ public async Task>> GetFileProfileConfigurationList(FileProfileConfigurationQueries.GetFileProfileConfigurationListQuery request,
+ CancellationToken cancellationToken) {
+ using ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString());
+ await using EstateManagementContext context = resolvedContext.Context;
+
+ var query = from c in context.FileProfileConfigurations
+ join h in context.FileFormatHandlers on c.FileFormatHandlerId equals h.FileFormatHandlerId
+ join r in context.RequestTypes on c.RequestTypeId equals r.RequestTypeId
+ join o in context.Operators on c.OperatorId equals o.OperatorId
+ select new FileProfileConfiguration
+ {
+ FileProfileId = c.FileProfileId,
+ Name = c.Name,
+ ListeningDirectory = c.ListeningDirectory,
+ RequestType = r.Name,
+ OperatorName = o.Name,
+ LineTerminator = c.LineTerminator,
+ FileFormatHandler = h.Name
+ };
+
+ Result> result = await ExecuteQuerySafeToList(query, cancellationToken, "Error retrieving file import logs");
+
+ if (result.IsFailed)
+ return ResultHelpers.CreateFailure(result);
+
+ return Result.Success(result.Data);
+ }
+
private async Task GetSettlementSummary(IQueryable query,
CancellationToken cancellationToken) {
// Get the settleed fees summary
diff --git a/EstateReportingAPI.BusinessLogic/RequestHandlers/FileImportLogRequestHandler.cs b/EstateReportingAPI.BusinessLogic/RequestHandlers/FileImportLogRequestHandler.cs
index 888c723..68d2a53 100644
--- a/EstateReportingAPI.BusinessLogic/RequestHandlers/FileImportLogRequestHandler.cs
+++ b/EstateReportingAPI.BusinessLogic/RequestHandlers/FileImportLogRequestHandler.cs
@@ -23,4 +23,20 @@ public async Task> Handle(FileImportLogQueries.GetFileImpo
{
return await this.Manager.GetFileImportLog(request, cancellationToken);
}
+}
+
+public class FileProfileConfigurationRequestHandler : IRequestHandler>>
+
+{
+ private readonly IReportingManager Manager;
+ public FileProfileConfigurationRequestHandler(IReportingManager manager)
+ {
+ this.Manager = manager;
+ }
+
+ public async Task>> Handle(FileProfileConfigurationQueries.GetFileProfileConfigurationListQuery request,
+ CancellationToken cancellationToken)
+ {
+ return await this.Manager.GetFileProfileConfigurationList(request, cancellationToken);
+ }
}
\ No newline at end of file
diff --git a/EstateReportingAPI.DataTrasferObjects/FileProfileConfiguration.cs b/EstateReportingAPI.DataTrasferObjects/FileProfileConfiguration.cs
new file mode 100644
index 0000000..7d4ab54
--- /dev/null
+++ b/EstateReportingAPI.DataTrasferObjects/FileProfileConfiguration.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace EstateReportingAPI.DataTransferObjects;
+
+public class FileProfileConfiguration
+{
+ public Guid FileProfileId { get; set; }
+ public string Name { get; set; }
+ public string ListeningDirectory { get; set; }
+ public string RequestType { get; set; }
+ public string OperatorName { get; set; }
+ public string LineTerminator { get; set; }
+ public string FileFormatHandler { get; set; }
+}
\ No newline at end of file
diff --git a/EstateReportingAPI.IntegrationTests/DatabaseHelper.cs b/EstateReportingAPI.IntegrationTests/DatabaseHelper.cs
index bf7b5b5..baf8f0a 100644
--- a/EstateReportingAPI.IntegrationTests/DatabaseHelper.cs
+++ b/EstateReportingAPI.IntegrationTests/DatabaseHelper.cs
@@ -28,6 +28,7 @@
using DbFile = TransactionProcessor.Database.Entities.File;
using FileLine = TransactionProcessor.Database.Entities.FileLine;
using EstateSecurityUser = TransactionProcessor.Database.Entities.EstateSecurityUser;
+using FileProfileConfiguration = TransactionProcessor.Database.Entities.FileProfileConfiguration;
namespace EstateReportingAPI.IntegrationTests;
@@ -103,6 +104,48 @@ public async Task AddFileLine(Guid fileId, int lineNumber, string data, string s
await this.Context.SaveChangesAsync(CancellationToken.None);
}
+ public async Task AddFileFormatHandler(string name)
+ {
+ Guid id = Guid.NewGuid();
+ FileFormatHandler h = new() { FileFormatHandlerId = id, Name = name };
+
+ await this.Context.AddAsync(h);
+ await this.Context.SaveChangesAsync(CancellationToken.None);
+
+ return id;
+ }
+
+ public async Task AddRequestType(string name)
+ {
+ Guid id = Guid.NewGuid();
+ RequestType r = new() { RequestTypeId = id, Name = name };
+
+ await this.Context.AddAsync(r);
+ await this.Context.SaveChangesAsync(CancellationToken.None);
+
+ return id;
+ }
+
+ public async Task AddFileProfileConfiguration(Guid fileProfileId,
+ string name,
+ string listeningDirectory,
+ Guid fileFormatHandlerId,
+ Guid requestTypeId,
+ Guid operatorId,
+ string lineTerminator) {
+ FileProfileConfiguration configuration = new() {
+ Name = name,
+ FileFormatHandlerId = fileFormatHandlerId,
+ FileProfileId = fileProfileId,
+ LineTerminator = lineTerminator,
+ ListeningDirectory = listeningDirectory,
+ OperatorId = operatorId,
+ RequestTypeId = requestTypeId
+ };
+ await this.Context.AddAsync(configuration);
+ await this.Context.SaveChangesAsync(CancellationToken.None);
+ }
+
public async Task DeleteAllMerchants(){
List merchants = await this.Context.Merchants.ToListAsync();
this.Context.RemoveRange(merchants);
diff --git a/EstateReportingAPI.IntegrationTests/EstateReportingAPI.IntegrationTests.csproj b/EstateReportingAPI.IntegrationTests/EstateReportingAPI.IntegrationTests.csproj
index 1990fb4..b07a0fd 100644
--- a/EstateReportingAPI.IntegrationTests/EstateReportingAPI.IntegrationTests.csproj
+++ b/EstateReportingAPI.IntegrationTests/EstateReportingAPI.IntegrationTests.csproj
@@ -8,9 +8,9 @@
-
+
-
+
diff --git a/EstateReportingAPI.IntegrationTests/FileProfileConfigurationEndpointTests.cs b/EstateReportingAPI.IntegrationTests/FileProfileConfigurationEndpointTests.cs
new file mode 100644
index 0000000..bdb7e50
--- /dev/null
+++ b/EstateReportingAPI.IntegrationTests/FileProfileConfigurationEndpointTests.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using EstateReportingAPI.DataTransferObjects;
+using Microsoft.EntityFrameworkCore;
+using System.Linq;
+using Shouldly;
+using Xunit;
+
+namespace EstateReportingAPI.IntegrationTests
+{
+ public class FileProfileConfigurationEndpointTests : ControllerTestsBase
+ {
+ private const string BaseRoute = "api/fileprofiles";
+
+ [Fact]
+ public async Task FileProfileConfiguration_Get_NoData_ReturnsEmptyList()
+ {
+ // ensure estate exists
+ await this.helper.AddEstate("Test Estate", "Ref1");
+
+ var result = await this.CreateAndSendHttpRequestMessage>($"{BaseRoute}", CancellationToken.None);
+ result.IsSuccess.ShouldBeTrue();
+ var list = result.Data;
+ list.ShouldNotBeNull();
+ list.Count.ShouldBe(0);
+ }
+
+ [Fact]
+ public async Task FileProfileConfiguration_Get_ReturnsInsertedData()
+ {
+ // setup estate and operator
+ await this.helper.AddEstate("Test Estate", "Ref1");
+ var operatorId = await this.helper.AddOperator("Test Estate", "Test Operator");
+
+ // insert supporting rows and a profile using helper methods
+ Guid profileId = Guid.NewGuid();
+ string handlerName = $"TestHandler-{this.TestId}";
+ string requestName = $"TestRequest-{this.TestId}";
+ string profileName = $"TestProfile-{this.TestId}";
+
+ Guid handlerId = await this.helper.AddFileFormatHandler(handlerName);
+ Guid requestId = await this.helper.AddRequestType(requestName);
+
+ await this.helper.AddFileProfileConfiguration(profileId, profileName, "C:\\listen", handlerId, requestId, operatorId, "\\n");
+
+ var result = await this.CreateAndSendHttpRequestMessage>($"{BaseRoute}", CancellationToken.None);
+ result.IsSuccess.ShouldBeTrue();
+ var list = result.Data;
+ list.ShouldNotBeNull();
+ list.Count.ShouldBeGreaterThan(0);
+
+ var match = list.SingleOrDefault(f => f.FileProfileId == profileId);
+ match.ShouldNotBeNull();
+ match.Name.ShouldBe(profileName);
+ }
+
+ protected override Task ClearStandingData()
+ {
+ return Task.CompletedTask;
+ }
+
+ protected override Task SetupStandingData()
+ {
+ // tests will create their own standing data as needed
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/EstateReportingAPI.Models/FileProfileConfiguration.cs b/EstateReportingAPI.Models/FileProfileConfiguration.cs
new file mode 100644
index 0000000..c46905e
--- /dev/null
+++ b/EstateReportingAPI.Models/FileProfileConfiguration.cs
@@ -0,0 +1,12 @@
+namespace EstateReportingAPI.Models;
+
+public class FileProfileConfiguration
+{
+ public Guid FileProfileId { get; set; }
+ public string Name { get; set; } = string.Empty;
+ public string ListeningDirectory { get; set; } = string.Empty;
+ public string RequestType { get; set; } = string.Empty;
+ public string OperatorName { get; set; } = string.Empty;
+ public string LineTerminator { get; set; } = string.Empty;
+ public string FileFormatHandler { get; set; } = string.Empty;
+}
\ No newline at end of file
diff --git a/EstateReportingAPI.Tests/EstateReportingAPI.Tests.csproj b/EstateReportingAPI.Tests/EstateReportingAPI.Tests.csproj
index f4c0bf1..33343ca 100644
--- a/EstateReportingAPI.Tests/EstateReportingAPI.Tests.csproj
+++ b/EstateReportingAPI.Tests/EstateReportingAPI.Tests.csproj
@@ -7,12 +7,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -20,7 +20,7 @@
-
+
all
diff --git a/EstateReportingAPI/Bootstrapper/MiddlewareRegistry.cs b/EstateReportingAPI/Bootstrapper/MiddlewareRegistry.cs
index 98741d7..0223c3d 100644
--- a/EstateReportingAPI/Bootstrapper/MiddlewareRegistry.cs
+++ b/EstateReportingAPI/Bootstrapper/MiddlewareRegistry.cs
@@ -20,7 +20,6 @@ public class MiddlewareRegistry : ServiceRegistry{
public MiddlewareRegistry()
{
this.ConfigureHealthChecks();
- //this.ConfigureSwagger();
this.ConfigureAuthentication();
this.ConfigureControllers();
this.ConfigureMiddlewareLogging();
@@ -50,34 +49,7 @@ private void ConfigureHealthChecks(){
tags: new[] { "db", "sql", "sqlserver" });
}
}
-
- private void ConfigureSwagger(){
- this.AddSwaggerGen(c => {
- c.SwaggerDoc("v1",
- new OpenApiInfo{
- Title = "Estate Reporting API",
- Version = "1.0",
- Description = "A REST Api to manage all aspects of reporting for an estate (merchants, operators and contracts).",
- Contact = new OpenApiContact{
- Name = "Stuart Ferguson",
- Email = "golfhandicapping@btinternet.com"
- }
- });
- // add a custom operation filter which sets default values
-
- c.ExampleFilters();
-
- //Locate the XML files being generated by ASP.NET...
- var directory = new DirectoryInfo(AppContext.BaseDirectory);
- var xmlFiles = directory.GetFiles("*.xml");
-
- //... and tell Swagger to use those XML comments.
- foreach (FileInfo fileInfo in xmlFiles){
- c.IncludeXmlComments(fileInfo.FullName);
- }
- });
- }
-
+
private void ConfigureAuthentication(){
String? inTestMode = Environment.GetEnvironmentVariable("InTestMode");
if (String.Compare(inTestMode, Boolean.TrueString, StringComparison.InvariantCultureIgnoreCase) != 0){
diff --git a/EstateReportingAPI/Endpoints/FileImportLogEndpoints.cs b/EstateReportingAPI/Endpoints/FileImportLogEndpoints.cs
index 5a7b086..e43cc89 100644
--- a/EstateReportingAPI/Endpoints/FileImportLogEndpoints.cs
+++ b/EstateReportingAPI/Endpoints/FileImportLogEndpoints.cs
@@ -23,4 +23,22 @@ public static void MapFileImportLogEndpoints(this IEndpointRouteBuilder app)
group.MapGet("/{fileimportlogid}", FileImportHandler.GetFileImportLog).WithStandardProduces();
}
+}
+
+public static class FileProfileConfigurationEndpoints
+{
+ private const string BaseRoute = "api/fileprofiles";
+
+ public static void MapFileProfileConfigurationEndpoints(this IEndpointRouteBuilder app)
+ {
+ RouteGroupBuilder group = app.MapGroup(BaseRoute).WithTags("File Profile Configurations");
+
+ Boolean disableAuthorisation = ConfigurationReader.GetValueOrDefault("AppSettings", "DisableAuthorisation", false);
+ if (disableAuthorisation == false)
+ {
+ group = group.RequireAuthorization();
+ }
+
+ group.MapGet("/", FileProfileConfigurationHandler.GetFileProfileConfigurationList).WithStandardProduces>();
+ }
}
\ No newline at end of file
diff --git a/EstateReportingAPI/EstateReportingAPI.csproj b/EstateReportingAPI/EstateReportingAPI.csproj
index a7e6c2e..f86bcb2 100644
--- a/EstateReportingAPI/EstateReportingAPI.csproj
+++ b/EstateReportingAPI/EstateReportingAPI.csproj
@@ -36,7 +36,7 @@
-
+
diff --git a/EstateReportingAPI/Handlers/FileImportHandler.cs b/EstateReportingAPI/Handlers/FileImportHandler.cs
index ab46325..d4a9ff1 100644
--- a/EstateReportingAPI/Handlers/FileImportHandler.cs
+++ b/EstateReportingAPI/Handlers/FileImportHandler.cs
@@ -7,6 +7,28 @@
namespace EstateReportingAPI.Handlers;
+public static class FileProfileConfigurationHandler
+{
+ public static async Task GetFileProfileConfigurationList([FromHeader] Guid estateId,
+ IMediator mediator,
+ CancellationToken cancellationToken)
+ {
+ FileProfileConfigurationQueries.GetFileProfileConfigurationListQuery query = new(estateId);
+ Result> result = await mediator.Send(query, cancellationToken);
+
+ return ResponseFactory.FromResult(result, r => r.Select(m => new DataTransferObjects.FileProfileConfiguration()
+ {
+ FileFormatHandler = m.FileFormatHandler,
+ FileProfileId = m.FileProfileId,
+ LineTerminator = m.LineTerminator,
+ ListeningDirectory = m.ListeningDirectory,
+ Name = m.Name,
+ OperatorName = m.OperatorName,
+ RequestType = m.RequestType
+ }).ToList());
+ }
+}
+
public static class FileImportHandler
{
public static async Task GetFileImportLogList([FromHeader] Guid estateId,
diff --git a/EstateReportingAPI/Startup.cs b/EstateReportingAPI/Startup.cs
index 86a09bf..d41e4fe 100644
--- a/EstateReportingAPI/Startup.cs
+++ b/EstateReportingAPI/Startup.cs
@@ -72,6 +72,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerF
endpoints.MapTransactionEndpoints();
endpoints.MapSettlementEndpoints();
endpoints.MapFileImportLogEndpoints();
+ endpoints.MapFileProfileConfigurationEndpoints();
endpoints.MapHealthChecks("health", new HealthCheckOptions()
{
@@ -84,9 +85,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerF
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
});
- //app.UseSwagger();
-
- //app.UseSwaggerUI();
}
}
}
\ No newline at end of file