adding
This commit is contained in:
+7
@@ -0,0 +1,7 @@
|
||||
namespace LCU.API.Internal.DocumentLib.Configurations;
|
||||
|
||||
public class BlobStorageConfiguration
|
||||
{
|
||||
public string ConnectionString { get; set; }
|
||||
public string ContainerName { get; set; }
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
namespace LCU.API.Internal.DocumentLib.Configurations;
|
||||
|
||||
public class DatabaseConfiguration
|
||||
{
|
||||
public string ConnectionString { get; set; }
|
||||
public string DatabaseName { get; set; }
|
||||
|
||||
public string DocumentContainerName { get; set; }
|
||||
|
||||
public string AuditContainerName { get; set; }
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.Configurations;
|
||||
public class NotificationApiConfiguration
|
||||
{
|
||||
public string Url { get; set; }
|
||||
public string Email { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public string EmailUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
return Url + Email;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using LCU.Library.Internal.DocumentModels.Requests;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.Containers;
|
||||
|
||||
[BsonKnownTypes(typeof(DocumentFieldAudit), typeof(DocumentActionAudit))]
|
||||
public abstract class DocumentAudit
|
||||
{
|
||||
protected DocumentAudit(Guid documentId, string source, DateTime date, string userId)
|
||||
{
|
||||
DocumentId = documentId;
|
||||
Source = source;
|
||||
Date = date;
|
||||
UserId = userId;
|
||||
}
|
||||
|
||||
public Guid DocumentId { get; set; }
|
||||
public string Source { get; set; }
|
||||
|
||||
[BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
|
||||
[BsonIgnoreExtraElements]
|
||||
public class DocumentFieldAudit : DocumentAudit
|
||||
{
|
||||
public DocumentFieldAudit(Guid documentId, string source, DateTime date, string userId, string field, object previousValue, object currentValue)
|
||||
: base(documentId, source, date, userId)
|
||||
{
|
||||
Field = field;
|
||||
PreviousValue = previousValue;
|
||||
CurrentValue = currentValue;
|
||||
}
|
||||
|
||||
public string Field { get; set; }
|
||||
public object PreviousValue { get; set; }
|
||||
public object CurrentValue { get; set; }
|
||||
}
|
||||
|
||||
[BsonIgnoreExtraElements]
|
||||
public class DocumentActionAudit : DocumentAudit
|
||||
{
|
||||
public DocumentActionAudit(Guid documentId, string source, DateTime date, string userId, DocumentAction action, string description)
|
||||
: base(documentId, source, date, userId)
|
||||
{
|
||||
Action = action;
|
||||
ActionDescription = description;
|
||||
}
|
||||
|
||||
public DocumentAction Action { get; set; }
|
||||
public string ActionDescription { get; set; }
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.IO;
|
||||
using MongoDB.Bson.Serialization.Conventions;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.Containers;
|
||||
|
||||
public class DocumentAuditDiscriminatorConvention : IDiscriminatorConvention
|
||||
{
|
||||
public static string Discriminator = StandardDiscriminatorConvention.Scalar.ElementName;
|
||||
public string ElementName => Discriminator;
|
||||
|
||||
public Type GetActualType(IBsonReader bsonReader, Type nominalType)
|
||||
{
|
||||
var bookmark = bsonReader.GetBookmark();
|
||||
|
||||
try
|
||||
{
|
||||
bsonReader.ReadStartDocument();
|
||||
|
||||
if (!bsonReader.FindElement(ElementName)) return typeof(DocumentFieldAudit);
|
||||
|
||||
return bsonReader.ReadString() switch
|
||||
{
|
||||
nameof(DocumentFieldAudit) => typeof(DocumentFieldAudit),
|
||||
nameof(DocumentActionAudit) => typeof(DocumentActionAudit),
|
||||
_ => throw new NotSupportedException()
|
||||
};
|
||||
}
|
||||
finally
|
||||
{
|
||||
bsonReader.ReturnToBookmark(bookmark);
|
||||
}
|
||||
}
|
||||
|
||||
public BsonValue GetDiscriminator(Type nominalType, Type actualType)
|
||||
{
|
||||
return actualType.Name;
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using MongoDB.Bson.Serialization;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using MongoDB.Bson.Serialization.Serializers;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.Containers;
|
||||
|
||||
[BsonIgnoreExtraElements]
|
||||
public class DocumentInformation
|
||||
{
|
||||
public Guid DocumentId { get; set; }
|
||||
public Guid? DocumentBlobId { get; set; }
|
||||
public Guid? TraceId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string Source { get; set; }
|
||||
|
||||
public string DataSource { get; set; }
|
||||
|
||||
[BsonSerializer(typeof(BigIntSerializer))]
|
||||
public BigInteger FileSize { get; set; }
|
||||
|
||||
public bool? ScanStatus { get; set; }
|
||||
|
||||
[BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
|
||||
public DateTime UploadDate { get; set; }
|
||||
|
||||
[BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
|
||||
public DateTime? LastModifiedDate { get; set; }
|
||||
|
||||
[BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
|
||||
public DateTime CreatedDate { get; set; }
|
||||
public string[] PersonNumbers { get; set; }
|
||||
public string[] OrganizationNumbers { get; set; }
|
||||
public string AccountNumber { get; set; }
|
||||
public Dictionary<string, string> Attributes { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class BigIntSerializer : SerializerBase<BigInteger>
|
||||
{
|
||||
public override BigInteger Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
|
||||
{
|
||||
var val = context.Reader.ReadString();
|
||||
return BigInteger.Parse(val);
|
||||
}
|
||||
|
||||
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, BigInteger value)
|
||||
{
|
||||
context.Writer.WriteString(value.ToString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Azure;
|
||||
using Azure.Storage.Blobs;
|
||||
using Azure.Storage.Blobs.Models;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.DataAccess;
|
||||
|
||||
public class BlobApiDao : IBlobApiDao
|
||||
{
|
||||
private readonly BlobContainerClient _client;
|
||||
|
||||
public BlobApiDao(IBlobStorageClient storageClient)
|
||||
{
|
||||
_client = storageClient.GetClient();
|
||||
}
|
||||
|
||||
public async Task<Guid> SaveDocumentToBlob(byte[] fileData)
|
||||
{
|
||||
var blobDocumentId = Guid.NewGuid();
|
||||
|
||||
using var stream = new MemoryStream(fileData, false);
|
||||
await _client.GetBlobClient(blobDocumentId.ToString()).UploadAsync(stream);
|
||||
return blobDocumentId;
|
||||
}
|
||||
|
||||
public async Task UpdateDocumentInBlob(Guid blobDocumentId, byte[] fileData)
|
||||
{
|
||||
using var stream = new MemoryStream(fileData, false);
|
||||
await _client.GetBlobClient(blobDocumentId.ToString()).UploadAsync(stream, true);
|
||||
}
|
||||
|
||||
public async Task<Response> RemoveDocumentFromBlob(Guid blobDocumentId)
|
||||
{
|
||||
return await _client.GetBlobClient(blobDocumentId.ToString())
|
||||
.DeleteAsync(DeleteSnapshotsOption.IncludeSnapshots);
|
||||
}
|
||||
|
||||
public async Task<Response<BlobDownloadStreamingResult>> GetDocumentFromBlob(Guid blobDocumentId)
|
||||
{
|
||||
return await _client.GetBlobClient(blobDocumentId.ToString()).DownloadStreamingAsync();
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
using Azure.Storage.Blobs;
|
||||
using LCU.API.Internal.DocumentLib.Configurations;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.DataAccess;
|
||||
|
||||
public class BlobStorageClient : IBlobStorageClient
|
||||
{
|
||||
private readonly BlobContainerClient _containerClient;
|
||||
|
||||
public BlobStorageClient(BlobStorageConfiguration config)
|
||||
{
|
||||
var serviceClient = new BlobServiceClient(config.ConnectionString);
|
||||
_containerClient = serviceClient.GetBlobContainerClient(config.ContainerName);
|
||||
}
|
||||
|
||||
public BlobContainerClient GetClient()
|
||||
{
|
||||
return _containerClient;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Azure;
|
||||
using Azure.Storage.Blobs.Models;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.DataAccess;
|
||||
|
||||
public interface IBlobApiDao
|
||||
{
|
||||
Task<Guid> SaveDocumentToBlob(byte[] fileData);
|
||||
Task UpdateDocumentInBlob(Guid blobDocumentId, byte[] fileData);
|
||||
Task<Response> RemoveDocumentFromBlob(Guid blobDocumentId);
|
||||
Task<Response<BlobDownloadStreamingResult>> GetDocumentFromBlob(Guid blobDocumentId);
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
using Azure.Storage.Blobs;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.DataAccess;
|
||||
|
||||
public interface IBlobStorageClient
|
||||
{
|
||||
BlobContainerClient GetClient();
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
using LCU.API.Internal.NotificationsApiLib.Models;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.DataAccess
|
||||
{
|
||||
public interface INotificationApiDao
|
||||
{
|
||||
Task SendEmailAsync(EmailRequest emailRequest);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
using LCU.API.Internal.DocumentLib.Configurations;
|
||||
using LCU.API.Internal.DocumentLib.Utilities;
|
||||
using LCU.API.Internal.NotificationsApiLib.Models;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.DataAccess
|
||||
{
|
||||
public class NotificationApiDao : INotificationApiDao
|
||||
{
|
||||
private readonly NotificationApiConfiguration _notificationApiConfiguration;
|
||||
public NotificationApiDao(NotificationApiConfiguration notificationApiConfiguration)
|
||||
{
|
||||
_notificationApiConfiguration = notificationApiConfiguration;
|
||||
}
|
||||
|
||||
public async Task SendEmailAsync(EmailRequest emailRequest)
|
||||
{
|
||||
await HttpUtilities.PostAsync<EmailRequest>(new Uri(_notificationApiConfiguration.EmailUrl),
|
||||
emailRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.Storage.Blobs" Version="12.13.0" />
|
||||
<PackageReference Include="LCU.API.Internal.NotificationsApiLib" Version="2.1.0" />
|
||||
<PackageReference Include="LCU.Library.Internal.Exceptions" Version="1.0.0" />
|
||||
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.30.1" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="2.20.0" />
|
||||
<PackageReference Include="Serilog" Version="2.11.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LCU.Library.Internal.DocumentModels\LCU.Library.Internal.DocumentModels.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,19 @@
|
||||
using LCU.API.Internal.DocumentLib.Configurations;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.Repositories;
|
||||
|
||||
public class DataClient : IDataClient
|
||||
{
|
||||
private readonly MongoClient _client;
|
||||
|
||||
public DataClient(DatabaseConfiguration config)
|
||||
{
|
||||
_client = new MongoClient(config.ConnectionString);
|
||||
}
|
||||
|
||||
public MongoClient GetClient()
|
||||
{
|
||||
return _client;
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using LCU.API.Internal.DocumentLib.Utilities;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.Repositories;
|
||||
|
||||
public class DocumentAuditRepository : IDocumentAuditRepository
|
||||
{
|
||||
private readonly IMongoCollection<DocumentAudit> _documentAudits;
|
||||
|
||||
public DocumentAuditRepository(IMongoCollectionFactory collectionFactory)
|
||||
{
|
||||
_documentAudits = collectionFactory.GetCollection<DocumentAudit>();
|
||||
}
|
||||
|
||||
public async Task<List<DocumentAudit>> GetDocumentAudits(params Guid[] documentIds)
|
||||
{
|
||||
return await (await _documentAudits.FindAsync(doc => documentIds.Contains(doc.DocumentId))).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<DocumentAudit>> SaveDocumentAudits(params DocumentAudit[] documentAudit)
|
||||
{
|
||||
await _documentAudits.InsertManyAsync(documentAudit);
|
||||
|
||||
return documentAudit;
|
||||
}
|
||||
}
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using LCU.API.Internal.DocumentLib.Utilities;
|
||||
using LCU.Library.Internal.DocumentIngestorModels.Models.Pagination;
|
||||
using LCU.Library.Internal.DocumentModels.Requests.Search;
|
||||
using Microsoft.Azure.Cosmos.Linq;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.Repositories;
|
||||
|
||||
public class DocumentInformationRepository : IDocumentInformationRepository
|
||||
{
|
||||
private readonly IMongoCollection<DocumentInformation> _documents;
|
||||
|
||||
public DocumentInformationRepository(IMongoCollectionFactory collectionFactory)
|
||||
{
|
||||
_documents = collectionFactory.GetCollection<DocumentInformation>();
|
||||
}
|
||||
|
||||
public async Task<DocumentInformation> GetDocumentInformation(Guid documentId)
|
||||
{
|
||||
return await _documents.Find(doc => doc.DocumentId == documentId)
|
||||
.SingleOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<List<DocumentInformation>> SearchDocumentInformation(DocumentInformationFilter filter, int? skip = null, int? take = null, List<SortableField>? sortDefinition = null)
|
||||
{
|
||||
var pipelineFilter = FilterFactory(filter);
|
||||
var sorter = Sorter<DocumentInformation>.GetSorter(sortDefinition);
|
||||
if (sorter != null) pipelineFilter = pipelineFilter.Sort(sorter);
|
||||
if (skip.HasValue) pipelineFilter = pipelineFilter.Skip(skip.Value);
|
||||
if (take.HasValue) pipelineFilter = pipelineFilter.Limit(take.Value);
|
||||
|
||||
var documentsInformation = await _documents.AggregateAsync(pipelineFilter);
|
||||
return await documentsInformation.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<long> CountDocuments(DocumentInformationFilter filter)
|
||||
{
|
||||
return (await _documents.AggregateAsync(FilterFactory(filter).Count())).Single().Count;
|
||||
}
|
||||
|
||||
public async Task<DocumentInformation> GetDocumentInformationByBlobId(Guid documentBlobId)
|
||||
{
|
||||
return await _documents
|
||||
.Find(doc => doc.DocumentBlobId == documentBlobId)
|
||||
.SingleOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<DocumentInformation> SaveDocumentInformation(DocumentInformation document)
|
||||
{
|
||||
await _documents.InsertOneAsync(document);
|
||||
return document;
|
||||
}
|
||||
|
||||
public async Task<DocumentInformation> UpdateDocumentInformation(Guid documentId, DocumentInformation newDocument)
|
||||
{
|
||||
await _documents.FindOneAndReplaceAsync(doc => doc.DocumentId == documentId, newDocument);
|
||||
return newDocument;
|
||||
}
|
||||
|
||||
public async Task<DocumentInformation> RemoveDocumentInformation(Guid documentId)
|
||||
{
|
||||
return await _documents.FindOneAndDeleteAsync(document => document.DocumentId == documentId);
|
||||
}
|
||||
|
||||
public async Task<List<Guid>> GetDocumentsForCleanup(GetDocumentCleanupRequest request)
|
||||
{
|
||||
IList<FilterDefinition<DocumentInformation>> filterConcat = new List<FilterDefinition<DocumentInformation>>();
|
||||
foreach(var documentCodeDetail in request.DocumentCodeDetailInfos)
|
||||
{
|
||||
var adjustedDate = DateTime.Now.AddMonths(documentCodeDetail.InternalRetentionMonths * -1);
|
||||
|
||||
var typeFilter = Builders<DocumentInformation>.Filter.Eq(x => x.Type, documentCodeDetail.DocumentCode);
|
||||
var dateFilter = Builders<DocumentInformation>.Filter.Lt(x => x.CreatedDate, adjustedDate);
|
||||
var groupFilter = Builders<DocumentInformation>.Filter.And(typeFilter, dateFilter);
|
||||
|
||||
filterConcat.Add(groupFilter);
|
||||
}
|
||||
|
||||
var filter = Builders<DocumentInformation>.Filter;
|
||||
var oneConcat = filter.Empty;
|
||||
oneConcat &= filter.Or(filterConcat);
|
||||
|
||||
var nullFilter = Builders<DocumentInformation>.Filter.Ne(x => x.DocumentBlobId, null);
|
||||
oneConcat &= filter.And(nullFilter);
|
||||
|
||||
var pipelineFilter = new EmptyPipelineDefinition<DocumentInformation>()
|
||||
.Match(oneConcat)
|
||||
.Limit(request.Limit);
|
||||
|
||||
var documentsInformation = await _documents.AggregateAsync(pipelineFilter);
|
||||
return (await documentsInformation.ToListAsync()).Select(document => document.DocumentId).ToList();
|
||||
}
|
||||
|
||||
private PipelineDefinition<DocumentInformation, DocumentInformation> FilterFactory(DocumentInformationFilter filter)
|
||||
{
|
||||
var builder = Builders<DocumentInformation>.Filter;
|
||||
IList<FilterDefinition<DocumentInformation>> stageOneFiltersAnd = new List<FilterDefinition<DocumentInformation>>();
|
||||
IList<FilterDefinition<DocumentInformation>> stageOneFiltersOr = new List<FilterDefinition<DocumentInformation>>();
|
||||
IList<FilterDefinition<DocumentInformation>> stageTwoFiltersAnd = new List<FilterDefinition<DocumentInformation>>();
|
||||
IList<FilterDefinition<DocumentInformation>> stageTwoFiltersOr = new List<FilterDefinition<DocumentInformation>>();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.Name))
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Eq("Name", filter.Name));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.Type))
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Eq("Type", filter.Type));
|
||||
}
|
||||
|
||||
if (filter.TypeContainsAny != null && filter.TypeContainsAny.Any())
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.In("Type", filter.TypeContainsAny));
|
||||
}
|
||||
|
||||
if (filter.ScanStatus != null)
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Eq("ScanStatus", filter.ScanStatus));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.Source))
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Eq("Source", filter.Source));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.DataSource))
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Eq("DataSource", filter.DataSource));
|
||||
}
|
||||
|
||||
if (filter.TraceId != null)
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Eq("TraceId", filter.TraceId));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.PersonNumbersEquals))
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Eq("PersonNumbers", filter.PersonNumbersEquals));
|
||||
}
|
||||
|
||||
if (filter.PersonNumbersContains != null && filter.PersonNumbersContains.Any())
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.All("PersonNumbers", filter.PersonNumbersContains));
|
||||
}
|
||||
|
||||
if (filter.PersonNumbersContainsAny != null && filter.PersonNumbersContainsAny.Any())
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.In("PersonNumbers", filter.PersonNumbersContainsAny));
|
||||
}
|
||||
|
||||
if (filter.OrganizationNumbersEquals != null && filter.OrganizationNumbersEquals.Any())
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Eq("OrganizationNumbers", filter.OrganizationNumbersEquals));
|
||||
}
|
||||
|
||||
if (filter.OrganizationNumbersContains != null && filter.OrganizationNumbersContains.Any())
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.All("OrganizationNumbers", filter.OrganizationNumbersContains));
|
||||
}
|
||||
|
||||
if (filter.OrganizationNumbersContainsAny != null && filter.OrganizationNumbersContainsAny.Any())
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.In("OrganizationNumbers", filter.OrganizationNumbersContainsAny));
|
||||
}
|
||||
|
||||
if (filter.AccountNumberEquals != null && filter.AccountNumberEquals.Any())
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Eq("AccountNumber", filter.AccountNumberEquals));
|
||||
}
|
||||
|
||||
if (filter.AccountNumberContainsAny != null && filter.AccountNumberContainsAny.Any())
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.In("AccountNumber", filter.AccountNumberContainsAny));
|
||||
}
|
||||
|
||||
if (filter.AttributesEquals != null && filter.AttributesEquals.Any())
|
||||
{
|
||||
foreach (var keyValuePair in filter.AttributesEquals)
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Eq($"Attributes.{keyValuePair.Key.Trim()}", keyValuePair.Value.Trim()));
|
||||
}
|
||||
}
|
||||
|
||||
if (filter.AttributesContains is not null)
|
||||
{
|
||||
foreach (var keyValuePair in filter.AttributesContains)
|
||||
{
|
||||
var queryExpr =
|
||||
new BsonRegularExpression(
|
||||
new Regex($"\\b({keyValuePair.Value.Trim()})\\b", RegexOptions.IgnoreCase));
|
||||
stageTwoFiltersAnd.Add(builder.Regex($"Attributes.{keyValuePair.Key.Trim()}", queryExpr));
|
||||
}
|
||||
}
|
||||
|
||||
if (filter.AttributesContainsAny is not null)
|
||||
{
|
||||
foreach (var keyValuePair in filter.AttributesContainsAny)
|
||||
{
|
||||
foreach (var value in keyValuePair.Value.Split(','))
|
||||
{
|
||||
var queryExpr = new BsonRegularExpression(new Regex($"^{value.Trim()}$", RegexOptions.IgnoreCase));
|
||||
stageTwoFiltersOr.Add(builder.Regex($"Attributes.{keyValuePair.Key.Trim()}", queryExpr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (filter.CreatedDateMinimum != null)
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Gte("CreatedDate", filter.CreatedDateMinimum));
|
||||
}
|
||||
|
||||
if (filter.CreatedDateMaximum != null)
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Lte("CreatedDate", filter.CreatedDateMaximum));
|
||||
}
|
||||
|
||||
if (filter.UploadDateMinimum != null)
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Gte("UploadDate", filter.UploadDateMinimum));
|
||||
}
|
||||
|
||||
if (filter.UploadDateMaximum != null)
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Lte("UploadDate", filter.UploadDateMaximum));
|
||||
}
|
||||
|
||||
if (filter.LastModifiedMinimum != null)
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Gte("LastModifiedDate", filter.LastModifiedMinimum));
|
||||
}
|
||||
|
||||
if (filter.LastModifiedDateMaximum != null)
|
||||
{
|
||||
stageOneFiltersAnd.Add(builder.Lte("LastModifiedDate", filter.LastModifiedDateMaximum));
|
||||
}
|
||||
|
||||
var stageOneFilterConcat = builder.Empty;
|
||||
if (stageOneFiltersAnd.Any())
|
||||
{
|
||||
stageOneFilterConcat &= builder.And(stageOneFiltersAnd);
|
||||
}
|
||||
if (stageOneFiltersOr.Any())
|
||||
{
|
||||
stageOneFilterConcat &= builder.Or(stageOneFiltersOr);
|
||||
}
|
||||
|
||||
var stageTwoFilterConcat = builder.Empty;
|
||||
if (stageTwoFiltersAnd.Any())
|
||||
{
|
||||
stageOneFilterConcat &= builder.And(stageTwoFiltersAnd);
|
||||
}
|
||||
if (stageTwoFiltersOr.Any())
|
||||
{
|
||||
stageTwoFilterConcat &= builder.Or(stageTwoFiltersOr);
|
||||
}
|
||||
|
||||
return new EmptyPipelineDefinition<DocumentInformation>()
|
||||
.Match(stageOneFilterConcat)
|
||||
.Match(stageTwoFilterConcat);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.Repositories;
|
||||
|
||||
public interface IDataClient
|
||||
{
|
||||
MongoClient GetClient();
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.Repositories;
|
||||
|
||||
public interface IDocumentAuditRepository
|
||||
{
|
||||
Task<List<DocumentAudit>> GetDocumentAudits(params Guid[] documentIds);
|
||||
Task<IEnumerable<DocumentAudit>> SaveDocumentAudits(params DocumentAudit[] documentAudit);
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using LCU.Library.Internal.DocumentIngestorModels.Models.Pagination;
|
||||
using LCU.Library.Internal.DocumentModels.Requests.Search;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.Repositories;
|
||||
|
||||
public interface IDocumentInformationRepository
|
||||
{
|
||||
Task<DocumentInformation> GetDocumentInformation(Guid documentId);
|
||||
Task<DocumentInformation> GetDocumentInformationByBlobId(Guid documentBlobId);
|
||||
Task<List<DocumentInformation>> SearchDocumentInformation(DocumentInformationFilter filter, int? skip = null, int? take = null, List<SortableField>? sortDefinition = null);
|
||||
Task<DocumentInformation> SaveDocumentInformation(DocumentInformation document);
|
||||
Task<DocumentInformation> UpdateDocumentInformation(Guid documentId, DocumentInformation newDocument);
|
||||
Task<DocumentInformation> RemoveDocumentInformation(Guid documentId);
|
||||
Task<long> CountDocuments(DocumentInformationFilter filter);
|
||||
Task<List<Guid>> GetDocumentsForCleanup(GetDocumentCleanupRequest request);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
using LCU.Library.Internal.Exceptions;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using JsonSerializer = System.Text.Json.JsonSerializer;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.Utilities;
|
||||
|
||||
public class HttpUtilities
|
||||
{
|
||||
public static HttpClient CreateClient(Uri uri)
|
||||
{
|
||||
var handler = new HttpClientHandler
|
||||
{
|
||||
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 |
|
||||
System.Security.Authentication.SslProtocols.Tls11 |
|
||||
System.Security.Authentication.SslProtocols.Tls,
|
||||
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
|
||||
};
|
||||
|
||||
var httpClient = new HttpClient(handler)
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(60),
|
||||
BaseAddress = uri
|
||||
};
|
||||
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
public static async Task PostAsync<TRequest>(Uri uri, TRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = CreateClient(uri);
|
||||
var jsonBody = JsonSerializer.Serialize(request);
|
||||
var content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
|
||||
var response = await client.PostAsync(uri, content);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new ServiceException($"StatusCode:{response.StatusCode}, " +
|
||||
$"Content: {response.Content.ReadAsStringAsync().Result}");
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Error(exception, "Failure during PostAsync.");
|
||||
throw new ServiceException($"Failure during Document Upload. Exception Message: {exception.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<TResponse> PostAsync<TRequest, TResponse>(Uri uri, TRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = CreateClient(uri);
|
||||
var jsonBody = JsonSerializer.Serialize(request);
|
||||
var content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
|
||||
var response = await client.PostAsync(uri, content);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new ServiceException($"StatusCode:{response.StatusCode}, " +
|
||||
$"Content: {response.Content.ReadAsStringAsync().Result}");
|
||||
}
|
||||
|
||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||
|
||||
return JsonSerializer.Deserialize<TResponse>(stringResponse, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Error(exception, "Failure during PostAsync.");
|
||||
throw new ServiceException($"Failure during PostAsync. Exception Message: {exception.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<TResponse> GetAsync<TResponse>(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
var client = CreateClient(uri);
|
||||
|
||||
var response = await client.GetAsync(uri);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new ServiceException($"StatusCode:{response.StatusCode}, " +
|
||||
$"Content: {response.Content.ReadAsStringAsync().Result}");
|
||||
}
|
||||
|
||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||
return JsonSerializer.Deserialize<TResponse>(stringResponse, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Error(exception, "Failure during GetAsync.");
|
||||
throw new ServiceException($"Failure during GetAsync. Exception Message: {exception.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.Utilities;
|
||||
|
||||
public interface IMongoCollectionFactory
|
||||
{
|
||||
IMongoCollection<T> GetCollection<T>();
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using LCU.API.Internal.DocumentLib.Configurations;
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using LCU.API.Internal.DocumentLib.Repositories;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace LCU.API.Internal.DocumentLib.Utilities;
|
||||
|
||||
public class MongoCollectionFactory : IMongoCollectionFactory
|
||||
{
|
||||
private readonly IDataClient _mongoDataClient;
|
||||
private readonly DatabaseConfiguration _config;
|
||||
|
||||
public MongoCollectionFactory(IDataClient mongoDataClient, DatabaseConfiguration config)
|
||||
{
|
||||
_mongoDataClient = mongoDataClient;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public IMongoCollection<T> GetCollection<T>()
|
||||
{
|
||||
return _mongoDataClient
|
||||
.GetClient()
|
||||
.GetDatabase(_config.DatabaseName)
|
||||
.GetCollection<T>(CollectionNameFor<T>());
|
||||
}
|
||||
|
||||
private string CollectionNameFor<T>()
|
||||
{
|
||||
return typeof(T) switch
|
||||
{
|
||||
var t when t == typeof(DocumentInformation) => _config.DocumentContainerName,
|
||||
var t when t == typeof(DocumentAudit) => _config.AuditContainerName,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user