This commit is contained in:
Zeeshaun
2026-03-17 10:03:23 -05:00
parent 1a0702a79a
commit bd1a9744ad
139 changed files with 5388 additions and 0 deletions
@@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Threading.Tasks;
using Serilog;
using LCU.Library.Internal.ArchiverApiLib.Repositories;
using LCU.Library.Internal.ArchiverApiModel.Entities;
using LCU.Library.Internal.Exceptions;
namespace LCU.Api.Internal.ArchiverApi.Services;
public class ApplicationMappingService : IApplicationMappingService
{
private readonly IApplicationMappingRepository _applicationMappingRepository;
private readonly IUnitOfWork _unitOfWork;
public ApplicationMappingService(IUnitOfWork unitOfWork,
IApplicationMappingRepository applicationMappingRepository)
{
_unitOfWork = unitOfWork;
_applicationMappingRepository = applicationMappingRepository;
}
public async Task<IEnumerable<ApplicationMapping>> GetAsync()
{
try
{
return await _applicationMappingRepository.ListAsync();
}
catch (Exception exception)
{
Log.Error(exception, "Failure retrieving application mappings.");
throw new ServiceException("Failure retrieving application mappings.");
}
}
public async Task<ApplicationMapping> GetByIdAsync(int id)
{
try
{
var applicationMapping = await _applicationMappingRepository.FindByIdAsync(id);
ArgumentNullException.ThrowIfNull(applicationMapping);
return applicationMapping;
}
catch (Exception exception)
{
Log.Error(exception, $"Failure retrieving application mapping with id {id}.");
throw new ServiceException($"Failure retrieving application mapping with id {id}.");
}
}
public async Task<IEnumerable<ApplicationMapping>> GetByIdentifierAsync(string identifier)
{
try
{
var applicationMapping = await _applicationMappingRepository.FindByIdentifierAsync(identifier);
ArgumentNullException.ThrowIfNull(applicationMapping);
return applicationMapping;
}
catch (Exception exception)
{
Log.Error(exception, $"Failure retrieving application mapping with id {identifier}.");
throw new ServiceException($"Failure retrieving application mapping with id {identifier}.");
}
}
public async Task<ApplicationMapping> SaveAsync(ApplicationMapping applicationMapping)
{
try
{
var result = await _applicationMappingRepository.AddAsync(applicationMapping);
await _unitOfWork.CompleteAsync();
return result;
}
catch (Exception exception)
{
Log.Error(exception, "Failure saving application mapping");
throw new ServiceException("Failure saving application mapping");
}
}
public ApplicationMapping Update(ApplicationMapping applicationMapping)
{
try
{
var existing = GetByIdAsync(applicationMapping.ApplicationMappingId).Result;
ArgumentNullException.ThrowIfNull(existing);
existing.Identifier = applicationMapping.Identifier;
existing.DesignatedName = applicationMapping.DesignatedName;
existing.ApplicationOverrideName = applicationMapping.ApplicationOverrideName;
existing.ParameterMappings = applicationMapping.ParameterMappings;
_applicationMappingRepository.Update(existing);
_unitOfWork.Complete();
return existing;
}
catch (SqlException sqlException)
{
Log.Error(sqlException, "SQL Failure updating application mapping");
throw new ServiceException("SQL Failure updating application mapping");
}
catch (Exception exception)
{
Log.Error(exception, "Failure updating application mapping");
throw new ServiceException("Failure updating application mapping");
}
}
public void DeleteAsync(int applicationMappingId)
{
try
{
var applicationMapping = _applicationMappingRepository.FindByIdAsync(applicationMappingId).Result;
ArgumentNullException.ThrowIfNull(applicationMapping);
_applicationMappingRepository.Remove(applicationMapping);
_unitOfWork.Complete();
}
catch (SqlException sqlException)
{
Log.Error(sqlException, $"SQL failure removing application mapping. ApplicationMappingId: {applicationMappingId}");
throw new ServiceException($"SQL failure removing application mapping. ApplicationMappingId: {applicationMappingId}");
}
catch (Exception exception)
{
Log.Error(exception, $"Failure removing application mapping. ApplicationMappingId: {applicationMappingId}");
throw new ServiceException($"Failure removing application mapping. ApplicationMappingId: {applicationMappingId}");
}
}
}
@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using Serilog;
using Newtonsoft.Json;
using LCU.Api.Internal.MaidBotLib.Models;
using LCU.Library.Internal.ApiResponse.Models;
using LCU.Library.Internal.ApiResponse.Services;
using LCU.Library.Internal.ArchiverApiModel.Models;
namespace LCU.Api.Internal.ArchiverApi.Services;
public class ArchiveCompletionService : IArchiveCompletionService
{
private readonly IFileOperationsService _fileOperationsService;
private readonly INotificationService _notificationService;
public ArchiveCompletionService(IFileOperationsService fileOperationsService,
INotificationService notificationService)
{
_fileOperationsService = fileOperationsService;
_notificationService = notificationService;
}
public void HandleReportArchiveCompletedRequest(Response response)
{
try
{
var payLoadString = response.ResponsePayload;
var archiveResponsePayload = JsonConvert.DeserializeObject<ArchiveResponsePayload>(payLoadString);
var archiveRequestResponse = archiveResponsePayload.ArchiveRequestResponse;
archiveRequestResponse.IsSuccessful = response.Successful;
archiveRequestResponse.MessageStack.AddRange(response.ResponseStack);
var requestResult = PopulateErrorDetailsAndRequestResponse(archiveResponsePayload, archiveRequestResponse);
QueueReturnResponse.QueueResponse(archiveResponsePayload.ArchiveRequest,
requestResult.archiveRequestResponse.IsSuccessful,
requestResult.archiveRequestResponse.MessageStack);
var errorsSent = _notificationService.SendErrorEmailAsync(requestResult.errorDetails).Result;
if (!errorsSent)
{
Log.ForContext(nameof(PropertyEnum.Group),
nameof(GroupEnum.ITDevelopment))
.Error($"Failure to send error details for {requestResult.errorDetails.Count} errors.");
throw new Exception($"Failure to send error details for {requestResult.errorDetails.Count} errors.");
}
}
catch (Exception exception)
{
Log.Error(exception, $"Error while archiving reports. " +
$"Message:{exception.Message}");
}
}
public (List<ErrorDetail> errorDetails, ArchiveRequestResponse archiveRequestResponse) PopulateErrorDetailsAndRequestResponse(ArchiveResponsePayload archiveResponsePayload,
ArchiveRequestResponse archiveRequestResponse)
{
var errorDetails = new List<ErrorDetail>();
foreach (var request in archiveResponsePayload.BulkOperationRequest.OperationRequests)
{
var errorMessage = "";
try
{
//If file still exist move did not occur.
var fileExists = _fileOperationsService.ValidateFileExists(request.Source).Result;
if (fileExists)
{
errorMessage = $"File {request.SourceFile} was not archived to the path of {request.Destination} ";
archiveRequestResponse.IsSuccessful = false;
archiveRequestResponse.MessageStack.Add(errorMessage);
}
}
catch (Exception exception)
{
var loggingMessage = $"Exception thrown while looking for the file at path {request.Source}.";
errorMessage = $"{loggingMessage}. Message: {exception.Message}";
Log.Error(exception, loggingMessage);
}
if (!string.IsNullOrEmpty(errorMessage))
{
var newErrorDetail = new ErrorDetail()
{
FileLocation = request.SourcePath,
Filename = request.FinalSourceFile,
Destination = request.Destination,
Description = errorMessage
};
errorDetails.Add(newErrorDetail);
}
}
return (errorDetails, archiveRequestResponse);
}
}
@@ -0,0 +1,284 @@
using System;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using Serilog;
using Newtonsoft.Json;
using LCU.Library.Internal.ApiResponse.Models;
using LCU.Library.Internal.FileOperationsModels.Models.NameSettings;
using LCU.Library.Internal.FileOperationsModels.Models;
using LCU.Api.Internal.ArchiverApi.Configuration;
using LCU.Api.Internal.MaidBotLib.Models;
using LCU.Library.Internal.ApiResponse.Services;
using LCU.Library.Internal.ArchiverApiModel.Models;
using LCU.Library.Internal.LcuMassTransitModels;
namespace LCU.Api.Internal.ArchiverApi.Services;
public class ArchiverService : IArchiverService
{
private readonly ArchiverApiConfig _ArchiverApiConfig;
private readonly IReportService _reportService;
private readonly IFileOperationsService _fileOperationsService;
private readonly ConnectionConfiguration _connectionConfiguration;
private readonly ReceiveEndpointConfiguration _receiveEndpointsConfiguration;
private const string NameRegexStartTag = "{Regex0}";
private const string NameRegexStart = "^(" + RegexStartCaseInsenstive;
private const string NameRegexEndTag = "{Regex1}";
private const string NameRegexEnd = RegexStopCaseInsenstive + ")";
private const string AnyWordAndPeriodRegexTag = "{Regex2}";
private const string AnyWordAndPeriodRegex = "\\w*\\.";
private const string ExtensionRegexTag = "{Regex3}";
private const string ExtensionRegexStart = "(";
private const string ExtensionRegexEnd = ")$";
private const string RegexPipe = "|";
private const string RegexStartCaseInsenstive = "(?i)";
private const string RegexStopCaseInsenstive = "(?-i)";
public ArchiverService(ArchiverApiConfig ArchiverApiConfig,
IReportService reportService,
IFileOperationsService fileOperationsService,
ConnectionConfiguration connectionConfiguration,
ReceiveEndpointConfigurations receiveEndpointsConfiguration)
{
_ArchiverApiConfig = ArchiverApiConfig;
_reportService = reportService;
_fileOperationsService = fileOperationsService;
_connectionConfiguration = connectionConfiguration;
_receiveEndpointsConfiguration = receiveEndpointsConfiguration.ResponseReceiveEndpoint;
}
public void ExecuteRequest(ArchiveRequest archiveRequest)
{
try
{
var archiveResult = HandleArchiveRequest(archiveRequest);
if (!archiveResult.archiveRequestResponse.IsSuccessful)
{
var errorMessage = String.Join("; ", archiveResult.archiveRequestResponse.MessageStack.ToArray());
Log.Error($"Archive Request was not successful. MessaggeStack:{errorMessage}");
}
//Happy path we queue return response later in ArchivecompletionService after the BulkOperations has been preformed.
if (archiveResult.queueReturnResponse)
{
QueueReturnResponse.QueueResponse(archiveRequest,
archiveResult.archiveRequestResponse.IsSuccessful,
archiveResult.archiveRequestResponse.MessageStack);
}
}
catch (Exception exception)
{
Log.ForContext(nameof(PropertyEnum.Group),
nameof(GroupEnum.ITDevelopment))
.Error(exception, $"Error while archiving reports. Look into failed ArchiveRequest. " +
$"ArchiveRequest: {JsonConvert.SerializeObject(archiveRequest)}");
}
}
public (ArchiveRequestResponse archiveRequestResponse, bool queueReturnResponse) HandleArchiveRequest(ArchiveRequest archiveRequest)
{
var archiveRequestResponse = new ArchiveRequestResponse();
try
{
var reports = _reportService.GetReportsToArchiveAsync(archiveRequest).Result;
if (!reports.Any())
{
Log.Information("No reports to bulk move.");
archiveRequestResponse.MessageStack.Add("No application histories retrieved from DNA database to move.");
archiveRequestResponse.IsSuccessful = archiveRequest.SucceedIfEmpty;
return (archiveRequestResponse, true);
}
var bulkOperationRequest = BuildBulkOperationRequest(reports, archiveRequest);
if (!bulkOperationRequest.OperationRequests.Any())
{
Log.Information("There are no files to bulk move.");
archiveRequestResponse.MessageStack.Add("There are no files to bulk move.");
archiveRequestResponse.IsSuccessful = archiveRequest.SucceedIfEmpty;
return (archiveRequestResponse, true);
}
bulkOperationRequest = SetUpResponse(bulkOperationRequest, archiveRequest, archiveRequestResponse);
_fileOperationsService.SendBulkOperationsAsync(bulkOperationRequest);
}
catch (Exception exception)
{
archiveRequestResponse.IsSuccessful = false;
var anyIdentifiers = archiveRequest.ArchiveIdentifiers != null && archiveRequest.ArchiveIdentifiers.Any();
var identifiers = anyIdentifiers ? String.Join(", ", archiveRequest.ArchiveIdentifiers.ToArray()) : "";
archiveRequestResponse.MessageStack.Add($"Failure to execute archive request. " +
$"EffectiveDate: [{archiveRequest.EffectiveDate}], " +
$"DaysFromDate: [{archiveRequest.DaysFromDate}], " +
$"ArchiveDestinationBase: [{archiveRequest.ArchiveDestinationBase}], " +
$"Identifiers: [{identifiers}], " +
$"Exception: {exception} ");
}
return (archiveRequestResponse, !archiveRequestResponse.IsSuccessful);
}
public BulkOperationRequest<MoveFileRequest> BuildBulkOperationRequest(IEnumerable<Report> reports, ArchiveRequest archiveRequest)
{
try
{
var bulkOperationRequest = new BulkOperationRequest<MoveFileRequest>();
bulkOperationRequest.OperationRequests = new List<MoveFileRequest>();
var extensionRegex = new RegexSetting()
{
Tag = ExtensionRegexTag,
Regex = BuildExtensionRegexString(archiveRequest)
};
var anyWordAndPeriodRegex = new RegexSetting()
{
Tag = AnyWordAndPeriodRegexTag,
Regex = AnyWordAndPeriodRegex
};
foreach (var report in reports)
{
var nameSettings = SetUpNameSettings(report);
nameSettings.RegexSettings.Add(anyWordAndPeriodRegex);
nameSettings.RegexSettings.Add(extensionRegex);
var dynamicallyNamedRequests = CreateOperationRequests(report, nameSettings, archiveRequest);
bulkOperationRequest.OperationRequests.AddRange(dynamicallyNamedRequests);
}
return bulkOperationRequest;
}
catch (AggregateException exception)
{
throw new AggregateException($"Error while attempting to build bulk operation request. " +
$"Exception Message: {exception.Message}");
}
catch (Exception exception)
{
throw new Exception($"Error while attempting to build bulk operation request. " +
$"Exception Message: {exception.Message}");
}
}
public string BuildExtensionRegexString(ArchiveRequest archiveRequest)
{
var regexStringBuilder = new StringBuilder();
regexStringBuilder.Append(ExtensionRegexStart);
for (int index = 0; index < archiveRequest.AllowedExensions.Count; ++index)
{
var pipe = index == archiveRequest.AllowedExensions.Count ? "" : RegexPipe;
regexStringBuilder.Append(RegexStartCaseInsenstive +
archiveRequest.AllowedExensions[index] +
RegexStopCaseInsenstive +
pipe);
}
regexStringBuilder.Append(ExtensionRegexEnd);
return regexStringBuilder.ToString();
}
public List<MoveFileRequest> CreateOperationRequests(Report report, DynamicNameSetting nameSettings, ArchiveRequest archiveRequest)
{
var fileName = report.HasRegexMapping ? report.DisplayReportName : report.FinalReportName;
DateTime effectiveDate = archiveRequest.EffectiveDate == null ? DateTime.MinValue : (DateTime)archiveRequest.EffectiveDate;
var reportPath = $"{_ArchiverApiConfig.DnaBasePath}\\" +
$"{effectiveDate.ToString(_ArchiverApiConfig.ReportPathDateFormat)}\\" +
$"{report.QueueNumber}";
var sourceFile = $"{NameRegexStartTag}{fileName}{NameRegexEndTag}{AnyWordAndPeriodRegexTag}{ExtensionRegexTag}";
var files = _fileOperationsService.BuildDynamicFileListAsync(reportPath, sourceFile, nameSettings).Result;
var dynamicallyNamedRequests = new List<MoveFileRequest>();
foreach (var file in files)
{
var request = new MoveFileRequest()
{
SourcePath = reportPath,
SourceFile = file,
DestinationPath = archiveRequest.ArchiveDestinationBase,
FileNameSetting = nameSettings
};
SetDestinationName(report, request, archiveRequest);
dynamicallyNamedRequests.Add(request);
}
return dynamicallyNamedRequests;
}
public void SetDestinationName(Report report, MoveFileRequest request, ArchiveRequest archiveRequest)
{
var extention = archiveRequest.AllowedExensions
.FirstOrDefault(fe => request.SourceFile.Contains($".{fe}", StringComparison.OrdinalIgnoreCase));
if (extention != null)
{
request.DestinationName = report.BuildDestinationName(request.FinalSourceFile, extention);
}
}
public DynamicNameSetting SetUpNameSettings(Report report) {
var nameSettings = new DynamicNameSetting();
nameSettings.RegexSettings = new List<RegexSetting>()
{
new RegexSetting()
{
Tag = NameRegexStartTag,
Regex = NameRegexStart
},
new RegexSetting()
{
Tag = NameRegexEndTag,
Regex = NameRegexEnd
}
};
if (report.ApplicationMapping == null)
{
return nameSettings;
};
foreach (var regex in report.ApplicationMapping.RegexMappings)
{
nameSettings.RegexSettings.Add(new RegexSetting()
{
Tag = regex.Tag,
Regex = regex.Regex,
});
}
return nameSettings;
}
public BulkOperationRequest<MoveFileRequest> SetUpResponse(BulkOperationRequest<MoveFileRequest> bulkOperationRequest,
ArchiveRequest archiveRequest,
ArchiveRequestResponse archiveRequestResponse)
{
var archiveResponsePayload = new ArchiveResponsePayload()
{
ArchiveRequest = archiveRequest,
BulkOperationRequest = bulkOperationRequest,
ArchiveRequestResponse = archiveRequestResponse
};
var responseItem = new ResponseItem
{
ReturnQueueConsumerConfig = new QueueConsumerConfig()
{
ExchangeName = _receiveEndpointsConfiguration.ReceiveEndpoint
},
ReturnQueueConnectionConfig = new QueueConnectionConfig()
{
Url = _connectionConfiguration.HostUrl,
Username = _connectionConfiguration.UserName,
Password = _connectionConfiguration.Password
},
ResponsePayload = JsonConvert.SerializeObject(archiveResponsePayload)
};
bulkOperationRequest.ResponseItems = new List<ResponseItem>()
{
responseItem
};
return bulkOperationRequest;
}
}
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Text;
using Newtonsoft.Json;
using LCU.Api.Internal.ArchiverApi.Configuration;
using LCU.Library.Internal.ArchiverApi.Utilities;
using LCU.Library.Internal.ArchiverApiModel.Models;
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.CoreRequests;
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.ApplicationHistories;
namespace LCU.Api.Internal.ArchiverApi.Services;
public class CoreApiWrapperService : ICoreApiWrapperService
{
private readonly ArchiverApiConfig _ArchiverApiConfig;
public CoreApiWrapperService(ArchiverApiConfig ArchiverApiConfig)
{
_ArchiverApiConfig = ArchiverApiConfig;
}
public async Task<IEnumerable<ApplicationHistory>> GetApplicationHistories(ArchiveRequest archiveRequest)
{
try
{
var applicationHistoryRequest = new ApplicationHistoryRequest()
{
ApplicationNumbers = archiveRequest.ArchiveIdentifiers,
EffectiveDate = archiveRequest.EffectiveDate.ToString()
};
var url = SetUpUrl(applicationHistoryRequest);
var client = HttpUtilities.GetClient(url);
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
if (!response.IsSuccessStatusCode)
{
throw new Exception($"Issue retrieving Application History from Core Api Wrapper. " +
$"Request: {JsonConvert.SerializeObject(applicationHistoryRequest)}");
}
var stringResponse = await response.Content.ReadAsStringAsync();
var applicationHistories = JsonConvert.DeserializeObject<List<ApplicationHistory>>(stringResponse);
return applicationHistories;
}
catch (Exception exception)
{
throw new Exception($"Failure to get application histories. Exception Message: {exception.Message}");
}
}
public string SetUpUrl(ApplicationHistoryRequest applicationHistoryRequest)
{
var endpointBuilder = new StringBuilder();
endpointBuilder.Append(_ArchiverApiConfig.CoreApiWrapperGetApplicationHistory);
var propertyCounter = 0;
var propertyName = nameof(applicationHistoryRequest.ApplicationNumbers);
HttpUtilities.AppendListOfValuesToEndpoint(endpointBuilder, propertyCounter, applicationHistoryRequest.ApplicationNumbers, propertyName);
endpointBuilder.Append($"&{nameof(applicationHistoryRequest.EffectiveDate)}={applicationHistoryRequest.EffectiveDate}");
return endpointBuilder.ToString();
}
}
@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Net.Http;
using System.Text;
using Newtonsoft.Json;
using LCU.Library.Internal.FileOperationsModels.Models.NameSettings;
using LCU.Library.Internal.ArchiverApi.Utilities;
using LCU.Library.Internal.FileOperationsModels.Models;
using LCU.Api.Internal.ArchiverApi.Configuration;
namespace LCU.Api.Internal.ArchiverApi.Services;
public class FileOperationsService : IFileOperationsService
{
private readonly ArchiverApiConfig _ArchiverApiConfig;
public FileOperationsService(ArchiverApiConfig ArchiverApiConfig)
{
_ArchiverApiConfig = ArchiverApiConfig;
}
public void SendBulkOperationsAsync(BulkOperationRequest<MoveFileRequest> bulkOperationRequest)
{
try
{
var encoded = JsonConvert.SerializeObject(bulkOperationRequest);
var client = HttpUtilities.GetClient(_ArchiverApiConfig.FileOperationApiBulkMoveFile);
var content = new StringContent(encoded, Encoding.UTF8, "application/json");
HttpResponseMessage response = client.PostAsync(_ArchiverApiConfig.FileOperationApiBulkMoveFile, content).Result;
response.EnsureSuccessStatusCode();
if (!response.IsSuccessStatusCode)
{
throw new Exception($"IsSuccessStatusCode: {response.IsSuccessStatusCode}");
}
}
catch (Exception ex)
{
throw new Exception($"Failure to use the Bulk Operations. Message{ex.Message}");
}
}
public async Task<List<string>> BuildDynamicFileListAsync(string path, string file, DynamicNameSetting dynamicNameSetting)
{
try
{
var dynamicFileListRequest = new DynamicFileListRequest()
{
Path = path,
Filename = file,
DynamicFileSettings = dynamicNameSetting
};
var encoded = JsonConvert.SerializeObject(dynamicFileListRequest);
var client = HttpUtilities.GetClient(_ArchiverApiConfig.FileOperationApiBuildDynamicFileList);
var content = new StringContent(encoded, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(_ArchiverApiConfig.FileOperationApiBuildDynamicFileList, content);
if (!response.IsSuccessStatusCode)
{
throw new Exception($"IsSuccessStatusCode: {response.IsSuccessStatusCode}");
}
var stringResponse = await response.Content.ReadAsStringAsync();
var fileList = JsonConvert.DeserializeObject<List<string>>(stringResponse);
return fileList;
}
catch (Exception exception)
{
throw new Exception($"Unable to build dynamic list of files. Exception Message: {exception}");
}
}
public async Task<bool> ValidateFileExists(string sourceFilePath)
{
try
{
var encoded = JsonConvert.SerializeObject(sourceFilePath);
var client = HttpUtilities.GetClient(_ArchiverApiConfig.FileOperationApiValidateFileExists);
var content = new StringContent(encoded, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(_ArchiverApiConfig.FileOperationApiValidateFileExists, content);
if (!response.IsSuccessStatusCode)
{
throw new Exception($"IsSuccessStatusCode: {response.IsSuccessStatusCode}");
}
var stringResponse = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<bool>(stringResponse);
return result;
}
catch (Exception exception)
{
throw new Exception($"Failure to validate files exist. " +
$"Exception Message:{exception.Message}");
}
}
}
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using LCU.Library.Internal.ArchiverApiModel.Entities;
namespace LCU.Api.Internal.ArchiverApi.Services;
public interface IApplicationMappingService
{
Task<IEnumerable<ApplicationMapping>> GetAsync();
Task<ApplicationMapping> GetByIdAsync(int id);
Task<IEnumerable<ApplicationMapping>> GetByIdentifierAsync(string identifier);
Task<ApplicationMapping> SaveAsync(ApplicationMapping applicationMapping);
ApplicationMapping Update(ApplicationMapping applicationMapping);
void DeleteAsync(int applicationMappingId);
}
@@ -0,0 +1,7 @@
using LCU.Library.Internal.ApiResponse.Models;
namespace LCU.Api.Internal.ArchiverApi.Services;
public interface IArchiveCompletionService
{
void HandleReportArchiveCompletedRequest(Response response);
}
@@ -0,0 +1,15 @@
using System.Collections.Generic;
using LCU.Library.Internal.FileOperationsModels.Models;
using LCU.Library.Internal.FileOperationsModels.Models.NameSettings;
using LCU.Library.Internal.ArchiverApiModel.Models;
namespace LCU.Api.Internal.ArchiverApi.Services;
public interface IArchiverService
{
void ExecuteRequest(ArchiveRequest archiveRequest);
(ArchiveRequestResponse archiveRequestResponse, bool queueReturnResponse) HandleArchiveRequest(ArchiveRequest archiveRequest);
BulkOperationRequest<MoveFileRequest> BuildBulkOperationRequest(IEnumerable<Report> reports, ArchiveRequest archiveRequest);
string BuildExtensionRegexString(ArchiveRequest archiveRequest);
List<MoveFileRequest> CreateOperationRequests(Report report, DynamicNameSetting nameSettings, ArchiveRequest archiveRequest);
void SetDestinationName(Report report, MoveFileRequest request, ArchiveRequest archiveRequest);
}
@@ -0,0 +1,12 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using LCU.Library.Internal.ArchiverApiModel.Models;
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.ApplicationHistories;
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.CoreRequests;
namespace LCU.Api.Internal.ArchiverApi.Services;
public interface ICoreApiWrapperService
{
Task<IEnumerable<ApplicationHistory>> GetApplicationHistories(ArchiveRequest archiveRequest);
string SetUpUrl(ApplicationHistoryRequest applicationHistoryRequest);
}
@@ -0,0 +1,12 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using LCU.Library.Internal.FileOperationsModels.Models;
using LCU.Library.Internal.FileOperationsModels.Models.NameSettings;
namespace LCU.Api.Internal.ArchiverApi.Services;
public interface IFileOperationsService
{
void SendBulkOperationsAsync(BulkOperationRequest<MoveFileRequest> bulkOperationRequest);
Task<List<string>> BuildDynamicFileListAsync(string path, string file, DynamicNameSetting dynamicNameSetting);
Task<bool> ValidateFileExists(string sourceFilePath);
}
@@ -0,0 +1,12 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using LCU.Library.Internal.ArchiverApiModel.Models;
namespace LCU.Api.Internal.ArchiverApi.Services;
public interface INotificationService
{
Task<bool> SendEmailAsync(List<string> recipients, string subject, string emailTemplate);
Task<bool> SendErrorEmailAsync(List<ErrorDetail> errorDetails);
string CreateErrorRow(ErrorDetail errorDetail, string basePath);
string CreateErrorMonitoringEmail(string errorRows, string basePath);
}
@@ -0,0 +1,7 @@
using LCU.Library.Internal.ArchiverApiModel.Models;
namespace LCU.Api.Internal.ArchiverApi.Services;
public interface IQueueArchiverService
{
void QueueArchiver(ArchiveRequest archiveRequest);
}
@@ -0,0 +1,15 @@
using LCU.Library.Internal.ArchiverApiModel.Entities;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LCU.Api.Internal.ArchiverApi.Services;
public interface IRegexMappingService
{
Task<IEnumerable<RegexMapping>> GetAsync();
Task<RegexMapping> GetByApplicationMappingIdAsync(int id);
Task<RegexMapping> SaveAsync(RegexMapping regexMapping);
RegexMapping Update(RegexMapping regexMapping);
void DeleteAsync(int regexMappingId);
public Task<RegexMapping> GetByRegexMappingIdAsync(int id);
}
@@ -0,0 +1,9 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using LCU.Library.Internal.ArchiverApiModel.Models;
namespace LCU.Api.Internal.ArchiverApi.Services;
public interface IReportService
{
Task<IEnumerable<Report>> GetReportsToArchiveAsync(ArchiveRequest archiveRequest);
}
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Serilog;
using LCU.Api.Internal.ArchiverApi.Configuration;
using LCU.API.Internal.NotificationsApiLib.Models;
using LCU.Library.Internal.ArchiverApi.Utilities;
using LCU.Library.Internal.ArchiverApiModel.Models;
namespace LCU.Api.Internal.ArchiverApi.Services;
public class NotificationService : INotificationService
{
private readonly ArchiverApiConfig _ArchiverApiConfig;
private const string TableRowsTag = "{TableRows}";
public NotificationService(ArchiverApiConfig ArchiverApiConfig)
{
_ArchiverApiConfig = ArchiverApiConfig;
}
public async Task<bool> SendEmailAsync(List<string> recipients, string subject, string emailTemplate)
{
try
{
var emailRequest = new EmailRequest
{
Recipient = recipients,
Subject = subject,
Body = emailTemplate
};
var encoded = JsonConvert.SerializeObject(emailRequest);
var client = HttpUtilities.GetClient(_ArchiverApiConfig.NotificationApiEmail);
var content = new StringContent(encoded, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(_ArchiverApiConfig.NotificationApiEmail, content);
response.EnsureSuccessStatusCode();
return response.IsSuccessStatusCode;
}
catch (Exception ex)
{
Log.Error(ex, $"Failure to send email from Archiver Api");
return false;
}
}
public async Task<bool> SendErrorEmailAsync(List<ErrorDetail> errorDetails)
{
if (!errorDetails.Any())
{
return true;
}
var basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory);
string rowsOfErrors = "";
foreach (var errorDetail in errorDetails)
{
rowsOfErrors += CreateErrorRow(errorDetail, basePath);
}
var emailTemplate = CreateErrorMonitoringEmail(rowsOfErrors, basePath);
var successfullySent = await SendEmailAsync(_ArchiverApiConfig.ErrorRecipients,
_ArchiverApiConfig.ErrorMonitoringSubject,
emailTemplate);
return successfullySent;
}
public string CreateErrorRow(ErrorDetail errorDetail, string basePath)
{
var errorRowReader = new StreamReader($"{basePath}{_ArchiverApiConfig.ErrorRowTemplate}");
string errorRowOutput = errorRowReader.ReadToEnd();
foreach (var property in errorDetail.GetType().GetProperties())
{
string value = property.GetValue(errorDetail) == null ?
string.Empty :
property.GetValue(errorDetail).ToString();
errorRowOutput = errorRowOutput.Replace($"{{{property.Name}}}", value);
}
return errorRowOutput;
}
public string CreateErrorMonitoringEmail(string errorRows, string basePath)
{
var errorMonitoringReader = new StreamReader($"{basePath}{_ArchiverApiConfig.ErrorMonitoringTemplate}");
string errorMonitoringOutput = errorMonitoringReader.ReadToEnd();
return errorMonitoringOutput.Replace(TableRowsTag, errorRows);
}
}
@@ -0,0 +1,44 @@
using System;
using Serilog;
using MassTransit;
using TimeZoneConverter;
using LCU.Library.Internal.ArchiverApiModel.Models;
using LCU.Api.Internal.ArchiverApi.Configuration;
using LCU.Library.Internal.LcuMassTransitModels;
using LCU.Library.Internal.Exceptions;
namespace LCU.Api.Internal.ArchiverApi.Services;
public class QueueArchiverService : IQueueArchiverService
{
private readonly ISendEndpoint _sendEndpoint;
private readonly ReceiveEndpointConfiguration _receiveEndpointsConfiguration;
private readonly ArchiverApiConfig _archiverApiConfig;
public QueueArchiverService(IBusControl busControl,
ReceiveEndpointConfigurations receiveEndpointsConfiguration,
ArchiverApiConfig archiverApiConfig)
{
_receiveEndpointsConfiguration = receiveEndpointsConfiguration.ArchiverReceiveEndpoint;
_archiverApiConfig = archiverApiConfig;
_sendEndpoint = busControl.GetSendEndpoint(_receiveEndpointsConfiguration.ReceiveEndpointUri).Result;
}
public void QueueArchiver(ArchiveRequest archiveRequest)
{
try
{
var dateToConvert = archiveRequest.EffectiveDate == null ?
DateTime.Now.AddDays(archiveRequest.DaysFromDate) :
Convert.ToDateTime(archiveRequest.EffectiveDate).AddDays(archiveRequest.DaysFromDate);
var assumedTimezone = TZConvert.GetTimeZoneInfo(_archiverApiConfig.TimeZone);
archiveRequest.EffectiveDate = TimeZoneInfo.ConvertTime(dateToConvert, assumedTimezone).Date;
_sendEndpoint.Send(archiveRequest);
}
catch (Exception ex)
{
Log.Error(ex, $"Failed to queue archive request with effective date. Effective Date: {archiveRequest.EffectiveDate}");
throw new ServiceException($"Failed to queue archive request with effective date. Effective Date: {archiveRequest.EffectiveDate}");
}
}
}
@@ -0,0 +1,150 @@
using LCU.Library.Internal.ArchiverApiLib.Repositories;
using LCU.Library.Internal.ArchiverApiModel.Entities;
using System.Data.SqlClient;
using LCU.Library.Internal.Exceptions;
using Serilog;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LCU.Api.Internal.ArchiverApi.Services;
public class RegexMappingService : IRegexMappingService
{
private readonly IRegexMappingRepository _regexMappingRepository;
private readonly IUnitOfWork _unitOfWork;
public RegexMappingService(IUnitOfWork unitOfWork,
IRegexMappingRepository regexMappingRepository)
{
_unitOfWork = unitOfWork;
_regexMappingRepository = regexMappingRepository;
}
public void DeleteAsync(int regexMappingId)
{
try
{
var regexMapping = _regexMappingRepository.FindByRegexMappingIdAsync(regexMappingId).Result;
ArgumentNullException.ThrowIfNull(regexMapping);
_regexMappingRepository.Remove(regexMapping);
_unitOfWork.Complete();
}
catch (SqlException sqlException)
{
Log.Error(sqlException, $"SQL failure removing regex mapping. RegexMappingId: {regexMappingId}");
throw new ServiceException($"SQL failure removing regex mapping. RegexMappingId: {regexMappingId}");
}
catch (Exception exception)
{
Log.Error(exception, $"Failure removing regex mapping. RegexMappingId: {regexMappingId}");
throw new ServiceException($"Failure removing regex mapping. RegexMappingId: {regexMappingId}");
}
}
public async Task<IEnumerable<RegexMapping>> GetAsync()
{
try
{
return await _regexMappingRepository.ListAsync();
}
catch (Exception exception)
{
Log.Error(exception, "Failure retrieving regex mappings.");
throw new ServiceException("Failure retrieving regex mappings.");
}
}
public async Task<RegexMapping> GetByApplicationMappingIdAsync(int id)
{
try
{
var regexMapping = await _regexMappingRepository.FindByApplicationMappingIdAsync(id);
ArgumentNullException.ThrowIfNull(regexMapping);
return regexMapping;
}
catch (Exception exception)
{
Log.Error(exception, $"Failure retrieving regex mapping with id {id}.");
throw new ServiceException($"Failure retrieving regex mapping with id {id}.");
}
}
public async Task<RegexMapping> GetByRegexMappingIdAsync(int id)
{
try
{
var regexMapping = await _regexMappingRepository.FindByRegexMappingIdAsync(id);
ArgumentNullException.ThrowIfNull(regexMapping);
return regexMapping;
}
catch (Exception exception)
{
Log.Error(exception, $"Failure retrieving regex mapping with id {id}.");
throw new ServiceException($"Failure retrieving regex mapping with id {id}.");
}
}
public async Task<RegexMapping> SaveAsync(RegexMapping regexMapping)
{
try
{
if (CheckTagInvalid(regexMapping.Tag))
{
throw new Exception("Invalid Tag: "+regexMapping.Tag);
}
var result = await _regexMappingRepository.AddAsync(regexMapping);
await _unitOfWork.CompleteAsync();
return result;
}
catch (Exception exception)
{
Log.Error(exception, "Failure saving regex mapping");
throw new ServiceException("Failure saving regex mapping");
}
}
public RegexMapping Update(RegexMapping regexMapping)
{
try
{
if (CheckTagInvalid(regexMapping.Tag))
{
throw new Exception("Invalid Tag: "+regexMapping.Tag);
}
var existing = GetByRegexMappingIdAsync(regexMapping.RegexMappingId).Result;
ArgumentNullException.ThrowIfNull(existing);
existing.ApplicationMappingId = regexMapping.ApplicationMappingId;
existing.Regex = regexMapping.Regex;
existing.Tag = regexMapping.Tag;
_regexMappingRepository.Update(existing);
_unitOfWork.Complete();
return existing;
}
catch (SqlException sqlException)
{
Log.Error(sqlException, "SQL Failure updating regex mapping");
throw new ServiceException("SQL Failure updating regex mapping");
}
catch (Exception exception)
{
Log.Error(exception, "Failure updating regex mapping");
throw new ServiceException("Failure updating regex mapping");
}
}
private bool CheckTagInvalid(string tag)
{
var endIndex = tag.IndexOf('}');
var sub = tag.Substring(0, 6);
if (tag.Substring(0,6) == "{Regex" && endIndex >= 7)
{
var tagNumber = Int32.Parse(tag.Substring(6, endIndex - 6));
return tagNumber >= 0 && tagNumber <= 3;
}
return true;
}
}
@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using LCU.Library.Internal.ArchiverApiModel.Models;
using LCU.Library.Internal.ArchiverApiModel.Entities;
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.ApplicationHistories;
namespace LCU.Api.Internal.ArchiverApi.Services;
public class ReportService : IReportService
{
private readonly ICoreApiWrapperService _coreApiWrapperService;
private readonly IApplicationMappingService _applicationMappingService;
private readonly IRegexMappingService _regexMappingService;
public ReportService(ICoreApiWrapperService coreApiWrapperService,
IApplicationMappingService applicationMappingService,
IRegexMappingService regexMappingService)
{
_coreApiWrapperService = coreApiWrapperService;
_applicationMappingService = applicationMappingService;
_regexMappingService = regexMappingService;
}
public async Task<IEnumerable<Report>> GetReportsToArchiveAsync(ArchiveRequest archiveRequest)
{
try
{
var applicationHistories = await _coreApiWrapperService.GetApplicationHistories(archiveRequest);
var reports = new List<Report>();
foreach (var applicationHistory in applicationHistories)
{
var applicationMappings = await _applicationMappingService.GetByIdentifierAsync(applicationHistory.ApplicationNumber.ToString());
var report = new Report()
{
ReportName = applicationHistory.ApplicationName,
QueueNumber = applicationHistory.QueueNumber.ToString(),
StopDateTime = applicationHistory.StopDateTime,
ApplicationMapping = DeteriminApplicationMapping(applicationMappings.ToList(), applicationHistory),
};
reports.Add(report);
}
return reports;
}
catch (Exception exception)
{
throw new Exception($"Error while trying to get reports ready for archiving. " +
$"Message: {exception.Message}");
}
}
public ApplicationMapping DeteriminApplicationMapping(List<ApplicationMapping> applicationMappings, ApplicationHistory applicationHistory)
{
var applicationMapping = DeteriminApplicationMappingWithoutParameters(applicationMappings);
if(applicationMapping != null)
{
return applicationMapping;
}
applicationMapping = DeteriminApplicationMappingByParameters(applicationMappings, applicationHistory);
return applicationMapping;
}
public ApplicationMapping DeteriminApplicationMappingWithoutParameters(List<ApplicationMapping> possibleApplicationMappings)
{
var onlyASingleApplicationMapping = possibleApplicationMappings.Count == 1;
if (onlyASingleApplicationMapping)
{
var singleApplicationMapping = possibleApplicationMappings.First();
if (singleApplicationMapping.ParameterMappings == null ||
!singleApplicationMapping.ParameterMappings.Any())
{
return singleApplicationMapping;
}
}
return null;
}
public ApplicationMapping DeteriminApplicationMappingByParameters(List<ApplicationMapping> possibleApplicationMappings, ApplicationHistory applicationHistory)
{
foreach (var applicationMapping in possibleApplicationMappings)
{
bool containsAllParameter = false;
foreach (var parameterMapping in applicationMapping.ParameterMappings)
{
containsAllParameter = applicationHistory.QueueApplicationParameters.Any(qap => qap.ParameterCode == parameterMapping.ParameterCode &&
qap.ParameterValue == parameterMapping.ParameterValue);
if (!containsAllParameter)
{
break;
}
}
if (containsAllParameter)
{
return applicationMapping;
}
}
return null;
}
}