diff --git a/services/.editorconfig b/services/.editorconfig index e71640ae5..e96a17379 100644 --- a/services/.editorconfig +++ b/services/.editorconfig @@ -138,4 +138,7 @@ visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public dotnet_diagnostic.CS1591.severity = silent #https://github.com/JosefPihrt/Roslynator/blob/master/docs/Options.md -roslynator.RCS1090.invert = true \ No newline at end of file +roslynator.RCS1090.invert = true + +#https://github.com/SonarSource/sonar-dotnet/issues/4731 +dotnet_diagnostic.S3903.severity = silent \ No newline at end of file diff --git a/services/Archival/FilterLists.Archival.Api/Controllers/ErrorController.cs b/services/Archival/FilterLists.Archival.Api/Controllers/ErrorController.cs index ac5c8d714..d3a148b7d 100644 --- a/services/Archival/FilterLists.Archival.Api/Controllers/ErrorController.cs +++ b/services/Archival/FilterLists.Archival.Api/Controllers/ErrorController.cs @@ -1,29 +1,28 @@ using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; -namespace FilterLists.Archival.Api.Controllers +namespace FilterLists.Archival.Api.Controllers; + +[ApiController] +[ApiExplorerSettings(IgnoreApi = true)] +// TODO: de-duplicate into SharedKernel +public class ErrorController : ControllerBase { - [ApiController] - [ApiExplorerSettings(IgnoreApi = true)] - // TODO: de-duplicate into SharedKernel - public class ErrorController : ControllerBase + [Route("/error-local-development")] + public IActionResult ErrorLocalDevelopment([FromServices] IWebHostEnvironment webHostEnvironment) { - [Route("/error-local-development")] - public IActionResult ErrorLocalDevelopment([FromServices] IWebHostEnvironment webHostEnvironment) + if (webHostEnvironment.EnvironmentName != "Development") { - if (webHostEnvironment.EnvironmentName != "Development") - { - throw new InvalidOperationException("This shouldn't be invoked in non-development environments."); - } - - var context = HttpContext.Features.Get(); - return Problem(context?.Error.StackTrace, title: context?.Error.Message); + throw new InvalidOperationException("This shouldn't be invoked in non-development environments."); } - [Route("/error")] - public IActionResult Error() - { - return Problem(); - } + var context = HttpContext.Features.Get(); + return Problem(context?.Error.StackTrace, title: context?.Error.Message); + } + + [Route("/error")] + public IActionResult Error() + { + return Problem(); } } diff --git a/services/Archival/FilterLists.Archival.Api/Controllers/PingController.cs b/services/Archival/FilterLists.Archival.Api/Controllers/PingController.cs index d812a6716..a4160e2e6 100644 --- a/services/Archival/FilterLists.Archival.Api/Controllers/PingController.cs +++ b/services/Archival/FilterLists.Archival.Api/Controllers/PingController.cs @@ -1,21 +1,20 @@ using Microsoft.AspNetCore.Mvc; -namespace FilterLists.Archival.Api.Controllers +namespace FilterLists.Archival.Api.Controllers; + +[ApiController] +[Route("[controller]")] +[Produces("application/json")] +public class PingController : ControllerBase { - [ApiController] - [Route("[controller]")] - [Produces("application/json")] - public class PingController : ControllerBase + /// + /// A sample endpoint. + /// + /// Pong. + [HttpGet] + [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] + public ActionResult Ping() { - /// - /// A sample endpoint. - /// - /// Pong. - [HttpGet] - [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] - public ActionResult Ping() - { - return "pong"; - } + return "pong"; } } diff --git a/services/Archival/FilterLists.Archival.Api/Program.cs b/services/Archival/FilterLists.Archival.Api/Program.cs index ce9b52d06..49b9e3e29 100644 --- a/services/Archival/FilterLists.Archival.Api/Program.cs +++ b/services/Archival/FilterLists.Archival.Api/Program.cs @@ -1,22 +1,21 @@ using FilterLists.Archival.Application; using FilterLists.SharedKernel.Logging; -namespace FilterLists.Archival.Api -{ - public static class Program - { - // TODO: migrate to new hosting model https://docs.microsoft.com/en-us/aspnet/core/migration/50-to-60?view=aspnetcore-6.0&tabs=visual-studio#new-hosting-model - public static async Task Main(string[] args) - { - var host = CreateHostBuilder(args).Build(); - await host.TryRunWithLoggingAsync(); - } +namespace FilterLists.Archival.Api; - public static IHostBuilder CreateHostBuilder(string[] args) - { - return Host.CreateDefaultBuilder(args) - .UseApplication() - .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); - } +public static class Program +{ + // TODO: migrate to new hosting model https://docs.microsoft.com/en-us/aspnet/core/migration/50-to-60?view=aspnetcore-6.0&tabs=visual-studio#new-hosting-model + public static async Task Main(string[] args) + { + var host = CreateHostBuilder(args).Build(); + await host.TryRunWithLoggingAsync(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) + { + return Host.CreateDefaultBuilder(args) + .UseApplication() + .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); } } diff --git a/services/Archival/FilterLists.Archival.Api/Startup.cs b/services/Archival/FilterLists.Archival.Api/Startup.cs index 2a8ee6e9a..73e32f850 100644 --- a/services/Archival/FilterLists.Archival.Api/Startup.cs +++ b/services/Archival/FilterLists.Archival.Api/Startup.cs @@ -1,33 +1,32 @@ using System.Text.Json.Serialization; using FilterLists.Archival.Application; -namespace FilterLists.Archival.Api +namespace FilterLists.Archival.Api; + +internal class Startup { - internal class Startup + public Startup(IConfiguration configuration) { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } + Configuration = configuration; + } - public IConfiguration Configuration { get; } + public IConfiguration Configuration { get; } - public void ConfigureServices(IServiceCollection services) - { - services.AddRouting(o => o.LowercaseUrls = true); - services.AddControllers().AddJsonOptions(o => - o.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull); - services.AddSwaggerGen(); - services.AddApplicationServices(Configuration); - } + public void ConfigureServices(IServiceCollection services) + { + services.AddRouting(o => o.LowercaseUrls = true); + services.AddControllers().AddJsonOptions(o => + o.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull); + services.AddSwaggerGen(); + services.AddApplicationServices(Configuration); + } - public static void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - app.UseApplication(); - app.UseExceptionHandler(env.IsDevelopment() ? "/error-local-development" : "/error"); - app.UseRouting(); - app.UseEndpoints(e => e.MapControllers()); - app.UseSwagger(); - } + public static void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseApplication(); + app.UseExceptionHandler(env.IsDevelopment() ? "/error-local-development" : "/error"); + app.UseRouting(); + app.UseEndpoints(e => e.MapControllers()); + app.UseSwagger(); } } diff --git a/services/Archival/FilterLists.Archival.Api/SwaggerExtensions.cs b/services/Archival/FilterLists.Archival.Api/SwaggerExtensions.cs index 660083eb2..a46ef700e 100644 --- a/services/Archival/FilterLists.Archival.Api/SwaggerExtensions.cs +++ b/services/Archival/FilterLists.Archival.Api/SwaggerExtensions.cs @@ -1,45 +1,44 @@ using System.Reflection; using Microsoft.OpenApi.Models; -namespace FilterLists.Archival.Api +namespace FilterLists.Archival.Api; + +internal static class SwaggerExtensions { - internal static class SwaggerExtensions + public static void AddSwaggerGen(this IServiceCollection services) { - public static void AddSwaggerGen(this IServiceCollection services) + services.AddSwaggerGen(o => { - services.AddSwaggerGen(o => + o.SwaggerDoc("v1", new OpenApiInfo { - o.SwaggerDoc("v1", new OpenApiInfo + Title = "FilterLists Archival API", + Description = + "An ASP.NET Core API archiving and serving copies of FilterLists for mirrors and analysis.", + Version = "v1", + //TermsOfService = "", + Contact = new OpenApiContact { Name = "FilterLists", Url = new Uri("https://filterlists.com") }, + License = new OpenApiLicense { - Title = "FilterLists Archival API", - Description = - "An ASP.NET Core API archiving and serving copies of FilterLists for mirrors and analysis.", - Version = "v1", - //TermsOfService = "", - Contact = new OpenApiContact { Name = "FilterLists", Url = new Uri("https://filterlists.com") }, - License = new OpenApiLicense - { - Name = "MIT License", - Url = new Uri("https://github.com/collinbarrett/FilterLists/blob/master/LICENSE") - } - }); - - var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; - var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - o.IncludeXmlComments(xmlPath); + Name = "MIT License", + Url = new Uri("https://github.com/collinbarrett/FilterLists/blob/master/LICENSE") + } }); - } - public static void UseSwagger(this IApplicationBuilder app) + var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + o.IncludeXmlComments(xmlPath); + }); + } + + public static void UseSwagger(this IApplicationBuilder app) + { + app.UseSwagger(o => { - app.UseSwagger(o => + o.RouteTemplate = "{documentName}/swagger.json"; + o.PreSerializeFilters.Add((swaggerDoc, httpReq) => swaggerDoc.Servers = new List { - o.RouteTemplate = "{documentName}/swagger.json"; - o.PreSerializeFilters.Add((swaggerDoc, httpReq) => swaggerDoc.Servers = new List - { - new() { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}/api/archival" } - }); + new() { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}/api/archival" } }); - } + }); } } diff --git a/services/Archival/FilterLists.Archival.Application/Commands/ArchiveList.cs b/services/Archival/FilterLists.Archival.Application/Commands/ArchiveList.cs index 450113f91..57e355f9d 100644 --- a/services/Archival/FilterLists.Archival.Application/Commands/ArchiveList.cs +++ b/services/Archival/FilterLists.Archival.Application/Commands/ArchiveList.cs @@ -6,93 +6,92 @@ using MediatR; using Microsoft.Extensions.Logging; -namespace FilterLists.Archival.Application.Commands -{ - public static class ArchiveList - { - public class Command : IRequest - { - public Command(int listId) - { - ListId = listId; - } +namespace FilterLists.Archival.Application.Commands; - public int ListId { get; } +public static class ArchiveList +{ + public class Command : IRequest + { + public Command(int listId) + { + ListId = listId; } - public class Handler : IRequestHandler + public int ListId { get; } + } + + public class Handler : IRequestHandler + { + private readonly IHttpContentClient _client; + private readonly IDirectoryApi _directory; + private readonly ILogger _logger; + private readonly IListArchiveRepository _repo; + + public Handler( + IHttpContentClient httpContentClient, + IDirectoryApi directoryApi, + ILogger logger, + IListArchiveRepository listArchiveRepository) { - private readonly IHttpContentClient _client; - private readonly IDirectoryApi _directory; - private readonly ILogger _logger; - private readonly IListArchiveRepository _repo; + _client = httpContentClient; + _directory = directoryApi; + _logger = logger; + _repo = listArchiveRepository; + } - public Handler( - IHttpContentClient httpContentClient, - IDirectoryApi directoryApi, - ILogger logger, - IListArchiveRepository listArchiveRepository) + public async Task Handle(Command request, CancellationToken cancellationToken) + { + _logger.LogInformation("Archiving list {ListId}", request.ListId); + + var segmentUrls = (await GetSegmentUrlsAsync(request.ListId, cancellationToken)).ToList(); + if (segmentUrls.Count > 0) { - _client = httpContentClient; - _directory = directoryApi; - _logger = logger; - _repo = listArchiveRepository; + var list = GetList(request.ListId, segmentUrls, cancellationToken); + await _repo.AddAsync(list, cancellationToken); + _repo.Commit(); + + _logger.LogInformation( + "Archived segment(s) {@SegmentNumbers} of list {ListId}", + segmentUrls.Select(s => s.SegmentNumber), + request.ListId); + } + else + { + _logger.LogWarning("List {ListId} has no URLs to archive", request.ListId); } - public async Task Handle(Command request, CancellationToken cancellationToken) - { - _logger.LogInformation("Archiving list {ListId}", request.ListId); + return Unit.Value; + } - var segmentUrls = (await GetSegmentUrlsAsync(request.ListId, cancellationToken)).ToList(); - if (segmentUrls.Count > 0) + private async Task> GetSegmentUrlsAsync( + int listId, + CancellationToken cancellationToken) + { + var listDetails = await _directory.GetListDetailsAsync(listId, cancellationToken); + return listDetails.ViewUrls? + .GroupBy(u => u.SegmentNumber, (_, ue) => ue.OrderBy(u => u.Primariness).First()) ?? + new List(); + } + + private ListArchive GetList( + int listId, + IEnumerable segmentUrls, + CancellationToken cancellationToken) + { + var segmentsAsync = GetSegmentsAsync(segmentUrls, cancellationToken); + return new ListArchive(listId, segmentsAsync); + } + + private async IAsyncEnumerable GetSegmentsAsync( + IEnumerable segmentUrls, + [EnumeratorCancellation] CancellationToken cancellationToken) + { + foreach (var segment in segmentUrls) + { + var content = await _client.GetContentAsync(segment.Url, cancellationToken); + if (content != Stream.Null) { - var list = GetList(request.ListId, segmentUrls, cancellationToken); - await _repo.AddAsync(list, cancellationToken); - _repo.Commit(); - - _logger.LogInformation( - "Archived segment(s) {@SegmentNumbers} of list {ListId}", - segmentUrls.Select(s => s.SegmentNumber), - request.ListId); - } - else - { - _logger.LogWarning("List {ListId} has no URLs to archive", request.ListId); - } - - return Unit.Value; - } - - private async Task> GetSegmentUrlsAsync( - int listId, - CancellationToken cancellationToken) - { - var listDetails = await _directory.GetListDetailsAsync(listId, cancellationToken); - return listDetails.ViewUrls? - .GroupBy(u => u.SegmentNumber, (_, ue) => ue.OrderBy(u => u.Primariness).First()) ?? - new List(); - } - - private ListArchive GetList( - int listId, - IEnumerable segmentUrls, - CancellationToken cancellationToken) - { - var segmentsAsync = GetSegmentsAsync(segmentUrls, cancellationToken); - return new ListArchive(listId, segmentsAsync); - } - - private async IAsyncEnumerable GetSegmentsAsync( - IEnumerable segmentUrls, - [EnumeratorCancellation] CancellationToken cancellationToken) - { - foreach (var segment in segmentUrls) - { - var content = await _client.GetContentAsync(segment.Url, cancellationToken); - if (content != Stream.Null) - { - yield return new ListArchiveSegment(segment.Url, content); - } + yield return new ListArchiveSegment(segment.Url, content); } } } diff --git a/services/Archival/FilterLists.Archival.Application/Commands/EnqueueArchiveAllLists.cs b/services/Archival/FilterLists.Archival.Application/Commands/EnqueueArchiveAllLists.cs index a7674148b..9a52fd112 100644 --- a/services/Archival/FilterLists.Archival.Application/Commands/EnqueueArchiveAllLists.cs +++ b/services/Archival/FilterLists.Archival.Application/Commands/EnqueueArchiveAllLists.cs @@ -3,51 +3,50 @@ using MediatR; using Microsoft.Extensions.Logging; -namespace FilterLists.Archival.Application.Commands +namespace FilterLists.Archival.Application.Commands; + +public static class EnqueueArchiveAllLists { - public static class EnqueueArchiveAllLists + public class Command : IRequest { - public class Command : IRequest + } + + public class Handler : IRequestHandler + { + private readonly IDirectoryApi _directory; + private readonly ILogger _logger; + + public Handler(IDirectoryApi directory, ILogger logger) { + _directory = directory; + _logger = logger; } - public class Handler : IRequestHandler + public async Task Handle(Command request, CancellationToken cancellationToken) { - private readonly IDirectoryApi _directory; - private readonly ILogger _logger; + var r = new Random(); + var lists = (await _directory.GetListsAsync(cancellationToken)).OrderBy(_ => r.Next()).ToList(); - public Handler(IDirectoryApi directory, ILogger logger) - { - _directory = directory; - _logger = logger; - } - - public async Task Handle(Command request, CancellationToken cancellationToken) - { - var r = new Random(); - var lists = (await _directory.GetListsAsync(cancellationToken)).OrderBy(_ => r.Next()).ToList(); - - int archiveCount; - TimeSpan spacing; + int archiveCount; + TimeSpan spacing; #if DEBUG - archiveCount = 0; - spacing = TimeSpan.FromSeconds(5); + archiveCount = 0; + spacing = TimeSpan.FromSeconds(5); #else archiveCount = 0; //archiveCount = lists.Count; spacing = TimeSpan.FromSeconds((double)86400 / lists.Count); #endif - _logger.LogInformation("Enqueuing archival of {ArchiveCount} lists spaced {Spacing} seconds apart.", - archiveCount, spacing.Seconds); + _logger.LogInformation("Enqueuing archival of {ArchiveCount} lists spaced {Spacing} seconds apart.", + archiveCount, spacing.Seconds); - for (var i = 0; i < archiveCount; i++) - { - new ArchiveList.Command(lists[i].Id).ScheduleBackgroundJob(i * spacing); - } - - return Unit.Value; + for (var i = 0; i < archiveCount; i++) + { + new ArchiveList.Command(lists[i].Id).ScheduleBackgroundJob(i * spacing); } + + return Unit.Value; } } } diff --git a/services/Archival/FilterLists.Archival.Application/ConfigurationExtensions.cs b/services/Archival/FilterLists.Archival.Application/ConfigurationExtensions.cs index 8c3216252..4b874ac65 100644 --- a/services/Archival/FilterLists.Archival.Application/ConfigurationExtensions.cs +++ b/services/Archival/FilterLists.Archival.Application/ConfigurationExtensions.cs @@ -8,35 +8,34 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace FilterLists.Archival.Application +namespace FilterLists.Archival.Application; + +public static class ConfigurationExtensions { - public static class ConfigurationExtensions + public static IHostBuilder UseApplication(this IHostBuilder hostBuilder) { - public static IHostBuilder UseApplication(this IHostBuilder hostBuilder) - { - return hostBuilder.UseInfrastructure(); - } + return hostBuilder.UseInfrastructure(); + } - public static void AddApplicationServices(this IServiceCollection services, IConfiguration configuration) - { - services.AddMediatR(typeof(ConfigurationExtensions).Assembly); - services.AddInfrastructureServices(configuration); - } + public static void AddApplicationServices(this IServiceCollection services, IConfiguration configuration) + { + services.AddMediatR(typeof(ConfigurationExtensions).Assembly); + services.AddInfrastructureServices(configuration); + } - public static void UseApplication(this IApplicationBuilder app) - { - app.UseInfrastructure(); - ScheduleArchival(); - } + public static void UseApplication(this IApplicationBuilder app) + { + app.UseInfrastructure(); + ScheduleArchival(); + } - private static void ScheduleArchival() - { + private static void ScheduleArchival() + { #if DEBUG - JobStorage.Current?.GetMonitoringApi()?.PurgeJobs(); - new EnqueueArchiveAllLists.Command().EnqueueBackgroundJob(); + JobStorage.Current?.GetMonitoringApi()?.PurgeJobs(); + new EnqueueArchiveAllLists.Command().EnqueueBackgroundJob(); #else new EnqueueArchiveAllLists.Command().AddOrUpdateRecurringJob(Cron.Daily); #endif - } } } diff --git a/services/Archival/FilterLists.Archival.Domain/Extensions/UriExtension.cs b/services/Archival/FilterLists.Archival.Domain/Extensions/UriExtension.cs index 07cda533a..2a512b00a 100644 --- a/services/Archival/FilterLists.Archival.Domain/Extensions/UriExtension.cs +++ b/services/Archival/FilterLists.Archival.Domain/Extensions/UriExtension.cs @@ -1,17 +1,16 @@ -namespace FilterLists.Archival.Domain.Extensions +namespace FilterLists.Archival.Domain.Extensions; + +internal static class UriExtension { - internal static class UriExtension + private static readonly Uri DummyBaseUri = new("http://localhost"); + + public static string GetFileExtension(this Uri uri) { - private static readonly Uri DummyBaseUri = new("http://localhost"); - - public static string GetFileExtension(this Uri uri) + if (!uri.IsAbsoluteUri) { - if (!uri.IsAbsoluteUri) - { - uri = new Uri(DummyBaseUri, uri); - } - - return Path.GetExtension(uri.LocalPath); + uri = new Uri(DummyBaseUri, uri); } + + return Path.GetExtension(uri.LocalPath); } } diff --git a/services/Archival/FilterLists.Archival.Domain/ListArchives/IListArchiveRepository.cs b/services/Archival/FilterLists.Archival.Domain/ListArchives/IListArchiveRepository.cs index 196ab9989..b52974799 100644 --- a/services/Archival/FilterLists.Archival.Domain/ListArchives/IListArchiveRepository.cs +++ b/services/Archival/FilterLists.Archival.Domain/ListArchives/IListArchiveRepository.cs @@ -1,9 +1,8 @@ using FilterLists.Archival.Domain.SeedWork; -namespace FilterLists.Archival.Domain.ListArchives +namespace FilterLists.Archival.Domain.ListArchives; + +public interface IListArchiveRepository : IUnitOfWork { - public interface IListArchiveRepository : IUnitOfWork - { - Task AddAsync(ListArchive listArchive, CancellationToken cancellationToken); - } + Task AddAsync(ListArchive listArchive, CancellationToken cancellationToken); } diff --git a/services/Archival/FilterLists.Archival.Domain/ListArchives/ListArchive.cs b/services/Archival/FilterLists.Archival.Domain/ListArchives/ListArchive.cs index 03083fe58..a057489ce 100644 --- a/services/Archival/FilterLists.Archival.Domain/ListArchives/ListArchive.cs +++ b/services/Archival/FilterLists.Archival.Domain/ListArchives/ListArchive.cs @@ -1,15 +1,14 @@ -namespace FilterLists.Archival.Domain.ListArchives +namespace FilterLists.Archival.Domain.ListArchives; + +public class ListArchive { - public class ListArchive + public ListArchive(int id, IAsyncEnumerable segments) { - public ListArchive(int id, IAsyncEnumerable segments) - { - Id = id; - Segments = segments; - } - - public int Id { get; } - - public IAsyncEnumerable Segments { get; } + Id = id; + Segments = segments; } + + public int Id { get; } + + public IAsyncEnumerable Segments { get; } } diff --git a/services/Archival/FilterLists.Archival.Domain/ListArchives/ListArchiveSegment.cs b/services/Archival/FilterLists.Archival.Domain/ListArchives/ListArchiveSegment.cs index 1b0a0869b..05e002ce7 100644 --- a/services/Archival/FilterLists.Archival.Domain/ListArchives/ListArchiveSegment.cs +++ b/services/Archival/FilterLists.Archival.Domain/ListArchives/ListArchiveSegment.cs @@ -1,15 +1,14 @@ -namespace FilterLists.Archival.Domain.ListArchives +namespace FilterLists.Archival.Domain.ListArchives; + +public class ListArchiveSegment { - public class ListArchiveSegment + public ListArchiveSegment(Uri sourceUri, Stream content) { - public ListArchiveSegment(Uri sourceUri, Stream content) - { - Extension = ListFileExtension.FromUri(sourceUri); - Content = content; - } - - public ListFileExtension Extension { get; } - - public Stream Content { get; } + Extension = ListFileExtension.FromUri(sourceUri); + Content = content; } + + public ListFileExtension Extension { get; } + + public Stream Content { get; } } diff --git a/services/Archival/FilterLists.Archival.Domain/ListArchives/ListFileExtension.cs b/services/Archival/FilterLists.Archival.Domain/ListArchives/ListFileExtension.cs index c22181b1c..4d98c0792 100644 --- a/services/Archival/FilterLists.Archival.Domain/ListArchives/ListFileExtension.cs +++ b/services/Archival/FilterLists.Archival.Domain/ListArchives/ListFileExtension.cs @@ -1,64 +1,63 @@ using FilterLists.Archival.Domain.Extensions; using FilterLists.Archival.Domain.SeedWork; -namespace FilterLists.Archival.Domain.ListArchives +namespace FilterLists.Archival.Domain.ListArchives; + +public sealed class ListFileExtension : ValueObject { - public sealed class ListFileExtension : ValueObject + private static readonly IDictionary Info = + new Dictionary + { + { string.Empty, (true, false) }, + { ".txt", (true, false) }, + { ".7z", (false, false) }, + { ".action", (true, true) }, // Privoxy + { ".all", (true, false) }, + { ".aspx", (true, false) }, + { ".bat", (true, true) }, + { ".blacklist", (true, false) }, + { ".cidr", (true, true) }, + { ".conf", (true, true) }, // dnsmasq / Unbound / BIND + { ".csv", (true, true) }, + { ".dat", (true, true) }, // Halite for Windows + { ".deny", (true, true) }, + { ".gz", (false, false) }, + { ".hosts", (true, true) }, + { ".ips", (true, false) }, + { ".ipset", (true, true) }, // Firehol + { ".json", (true, true) }, + { ".list", (true, false) }, + { ".lsrules", (true, true) }, // Little Snitch + { ".md", (true, true) }, + { ".netset", (true, true) }, // Firehol + { ".p2p", (true, true) }, // Peer Guardian + { ".php", (true, false) }, + { ".raw", (true, false) }, + { ".rpz", (true, true) }, // Response Policy Zone + { ".tpl", (true, true) }, // Internet Explorer + { ".uBl", (true, false) }, + { ".zip", (false, false) }, + { ".zone", (true, false) } + }; + + private ListFileExtension(string value) { - private static readonly IDictionary Info = - new Dictionary - { - { string.Empty, (true, false) }, - { ".txt", (true, false) }, - { ".7z", (false, false) }, - { ".action", (true, true) }, // Privoxy - { ".all", (true, false) }, - { ".aspx", (true, false) }, - { ".bat", (true, true) }, - { ".blacklist", (true, false) }, - { ".cidr", (true, true) }, - { ".conf", (true, true) }, // dnsmasq / Unbound / BIND - { ".csv", (true, true) }, - { ".dat", (true, true) }, // Halite for Windows - { ".deny", (true, true) }, - { ".gz", (false, false) }, - { ".hosts", (true, true) }, - { ".ips", (true, false) }, - { ".ipset", (true, true) }, // Firehol - { ".json", (true, true) }, - { ".list", (true, false) }, - { ".lsrules", (true, true) }, // Little Snitch - { ".md", (true, true) }, - { ".netset", (true, true) }, // Firehol - { ".p2p", (true, true) }, // Peer Guardian - { ".php", (true, false) }, - { ".raw", (true, false) }, - { ".rpz", (true, true) }, // Response Policy Zone - { ".tpl", (true, true) }, // Internet Explorer - { ".uBl", (true, false) }, - { ".zip", (false, false) }, - { ".zone", (true, false) } - }; + Value = value; + } - private ListFileExtension(string value) - { - Value = value; - } + public string Value { get; } - public string Value { get; } + public bool IsPlainText => Info[Value].IsPlainText; - public bool IsPlainText => Info[Value].IsPlainText; + public bool IsMeaningfulToConsumer => Info[Value].IsMeaningfulToConsumer; - public bool IsMeaningfulToConsumer => Info[Value].IsMeaningfulToConsumer; + public static ListFileExtension FromUri(Uri uri) + { + return new ListFileExtension(uri.GetFileExtension()); + } - public static ListFileExtension FromUri(Uri uri) - { - return new ListFileExtension(uri.GetFileExtension()); - } - - protected override IEnumerable GetEqualityComponents() - { - return new[] { Value }; - } + protected override IEnumerable GetEqualityComponents() + { + return new[] { Value }; } } diff --git a/services/Archival/FilterLists.Archival.Domain/SeedWork/IUnitOfWork.cs b/services/Archival/FilterLists.Archival.Domain/SeedWork/IUnitOfWork.cs index 67aebb8f5..0dcebe9c8 100644 --- a/services/Archival/FilterLists.Archival.Domain/SeedWork/IUnitOfWork.cs +++ b/services/Archival/FilterLists.Archival.Domain/SeedWork/IUnitOfWork.cs @@ -1,7 +1,6 @@ -namespace FilterLists.Archival.Domain.SeedWork +namespace FilterLists.Archival.Domain.SeedWork; + +public interface IUnitOfWork : IDisposable { - public interface IUnitOfWork : IDisposable - { - void Commit(); - } + void Commit(); } diff --git a/services/Archival/FilterLists.Archival.Domain/SeedWork/ValueObject.cs b/services/Archival/FilterLists.Archival.Domain/SeedWork/ValueObject.cs index 1a5aeef8b..d2a7512b6 100644 --- a/services/Archival/FilterLists.Archival.Domain/SeedWork/ValueObject.cs +++ b/services/Archival/FilterLists.Archival.Domain/SeedWork/ValueObject.cs @@ -1,57 +1,56 @@ -namespace FilterLists.Archival.Domain.SeedWork +namespace FilterLists.Archival.Domain.SeedWork; + +/// https://enterprisecraftsmanship.com/posts/value-object-better-implementation/ +public abstract class ValueObject { - /// https://enterprisecraftsmanship.com/posts/value-object-better-implementation/ - public abstract class ValueObject + protected abstract IEnumerable GetEqualityComponents(); + + public override bool Equals(object? obj) { - protected abstract IEnumerable GetEqualityComponents(); - - public override bool Equals(object? obj) + if (obj == null) { - if (obj == null) - { - return false; - } - - if (GetType() != obj.GetType()) - { - return false; - } - - var valueObject = (ValueObject)obj; - - return GetEqualityComponents().SequenceEqual(valueObject.GetEqualityComponents()); + return false; } - public override int GetHashCode() + if (GetType() != obj.GetType()) { - return GetEqualityComponents() - .Aggregate(1, (current, obj) => + return false; + } + + var valueObject = (ValueObject)obj; + + return GetEqualityComponents().SequenceEqual(valueObject.GetEqualityComponents()); + } + + public override int GetHashCode() + { + return GetEqualityComponents() + .Aggregate(1, (current, obj) => + { + unchecked { - unchecked - { - return (current * 23) + (obj?.GetHashCode() ?? 0); - } - }); - } + return (current * 23) + (obj?.GetHashCode() ?? 0); + } + }); + } - public static bool operator ==(ValueObject? a, ValueObject? b) + public static bool operator ==(ValueObject? a, ValueObject? b) + { + if (ReferenceEquals(a, null) && ReferenceEquals(b, null)) { - if (ReferenceEquals(a, null) && ReferenceEquals(b, null)) - { - return true; - } - - if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) - { - return false; - } - - return a.Equals(b); + return true; } - public static bool operator !=(ValueObject? a, ValueObject? b) + if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) { - return !(a == b); + return false; } + + return a.Equals(b); + } + + public static bool operator !=(ValueObject? a, ValueObject? b) + { + return !(a == b); } } diff --git a/services/Archival/FilterLists.Archival.Infrastructure/Clients/ConfigurationExtensions.cs b/services/Archival/FilterLists.Archival.Infrastructure/Clients/ConfigurationExtensions.cs index b0a545457..086493783 100644 --- a/services/Archival/FilterLists.Archival.Infrastructure/Clients/ConfigurationExtensions.cs +++ b/services/Archival/FilterLists.Archival.Infrastructure/Clients/ConfigurationExtensions.cs @@ -1,17 +1,16 @@ using Microsoft.Extensions.DependencyInjection; using Polly; -namespace FilterLists.Archival.Infrastructure.Clients +namespace FilterLists.Archival.Infrastructure.Clients; + +internal static class ConfigurationExtensions { - internal static class ConfigurationExtensions + public static void AddClients(this IServiceCollection services) { - public static void AddClients(this IServiceCollection services) - { - services.AddHttpClient() - .AddTransientHttpErrorPolicy(b => b.WaitAndRetryAsync(new[] - { - TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10) - })); - } + services.AddHttpClient() + .AddTransientHttpErrorPolicy(b => b.WaitAndRetryAsync(new[] + { + TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10) + })); } } diff --git a/services/Archival/FilterLists.Archival.Infrastructure/Clients/IHttpContentClient.cs b/services/Archival/FilterLists.Archival.Infrastructure/Clients/IHttpContentClient.cs index dee40447c..e56ba7f5d 100644 --- a/services/Archival/FilterLists.Archival.Infrastructure/Clients/IHttpContentClient.cs +++ b/services/Archival/FilterLists.Archival.Infrastructure/Clients/IHttpContentClient.cs @@ -1,48 +1,47 @@ using Microsoft.Extensions.Logging; -namespace FilterLists.Archival.Infrastructure.Clients +namespace FilterLists.Archival.Infrastructure.Clients; + +public interface IHttpContentClient : IDisposable { - public interface IHttpContentClient : IDisposable + Task GetContentAsync(Uri url, CancellationToken cancellationToken); +} + +internal sealed class HttpContentClient : IHttpContentClient +{ + private readonly HttpClient _httpClient; + private readonly ICollection _httpResponseMessages = new HashSet(); + private readonly ILogger _logger; + + public HttpContentClient(HttpClient httpClient, ILogger logger) { - Task GetContentAsync(Uri url, CancellationToken cancellationToken); + _httpClient = httpClient; + _httpClient.DefaultRequestHeaders.Add("User-Agent", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36"); + _logger = logger; } - internal sealed class HttpContentClient : IHttpContentClient + public async Task GetContentAsync(Uri url, CancellationToken cancellationToken) { - private readonly HttpClient _httpClient; - private readonly ICollection _httpResponseMessages = new HashSet(); - private readonly ILogger _logger; - - public HttpContentClient(HttpClient httpClient, ILogger logger) + var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancellationToken); + _httpResponseMessages.Add(response); + try { - _httpClient = httpClient; - _httpClient.DefaultRequestHeaders.Add("User-Agent", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36"); - _logger = logger; + response.EnsureSuccessStatusCode(); + return await response.Content.ReadAsStreamAsync(cancellationToken); } - - public async Task GetContentAsync(Uri url, CancellationToken cancellationToken) + catch (HttpRequestException ex) { - var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancellationToken); - _httpResponseMessages.Add(response); - try - { - response.EnsureSuccessStatusCode(); - return await response.Content.ReadAsStreamAsync(cancellationToken); - } - catch (HttpRequestException ex) - { - _logger.LogError(ex, "Failed to get content from {Url}", url); - return Stream.Null; - } + _logger.LogError(ex, "Failed to get content from {Url}", url); + return Stream.Null; } + } - public void Dispose() + public void Dispose() + { + foreach (var message in _httpResponseMessages) { - foreach (var message in _httpResponseMessages) - { - message.Dispose(); - } + message.Dispose(); } } } diff --git a/services/Archival/FilterLists.Archival.Infrastructure/ConfigurationExtensions.cs b/services/Archival/FilterLists.Archival.Infrastructure/ConfigurationExtensions.cs index 875947439..077bded0c 100644 --- a/services/Archival/FilterLists.Archival.Infrastructure/ConfigurationExtensions.cs +++ b/services/Archival/FilterLists.Archival.Infrastructure/ConfigurationExtensions.cs @@ -8,28 +8,27 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace FilterLists.Archival.Infrastructure +namespace FilterLists.Archival.Infrastructure; + +public static class ConfigurationExtensions { - public static class ConfigurationExtensions + public static IHostBuilder UseInfrastructure(this IHostBuilder hostBuilder) { - public static IHostBuilder UseInfrastructure(this IHostBuilder hostBuilder) - { - return hostBuilder.UseLogging(); - } + return hostBuilder.UseLogging(); + } - public static void AddInfrastructureServices(this IServiceCollection services, IConfiguration configuration) - { - services.AddSharedKernelLogging(configuration); - services.AddSchedulingServices(configuration); - services.AddDirectoryApiClient(configuration); - services.AddClients(); - services.AddPersistenceServices(configuration); - } + public static void AddInfrastructureServices(this IServiceCollection services, IConfiguration configuration) + { + services.AddSharedKernelLogging(configuration); + services.AddSchedulingServices(configuration); + services.AddDirectoryApiClient(configuration); + services.AddClients(); + services.AddPersistenceServices(configuration); + } - public static void UseInfrastructure(this IApplicationBuilder app) - { - app.UseLogging(); - app.UseScheduling(); - } + public static void UseInfrastructure(this IApplicationBuilder app) + { + app.UseLogging(); + app.UseScheduling(); } } diff --git a/services/Archival/FilterLists.Archival.Infrastructure/Options/GitOptions.cs b/services/Archival/FilterLists.Archival.Infrastructure/Options/GitOptions.cs index dec71053f..e4e57f4b1 100644 --- a/services/Archival/FilterLists.Archival.Infrastructure/Options/GitOptions.cs +++ b/services/Archival/FilterLists.Archival.Infrastructure/Options/GitOptions.cs @@ -1,11 +1,10 @@ -namespace FilterLists.Archival.Infrastructure.Options -{ - internal class GitOptions - { - public const string Key = "Git"; +namespace FilterLists.Archival.Infrastructure.Options; - public string RepositoryPath { get; init; } = null!; - public string UserName { get; init; } = null!; - public string UserEmail { get; init; } = null!; - } +internal class GitOptions +{ + public const string Key = "Git"; + + public string RepositoryPath { get; init; } = null!; + public string UserName { get; init; } = null!; + public string UserEmail { get; init; } = null!; } diff --git a/services/Archival/FilterLists.Archival.Infrastructure/Persistence/ConfigurationExtensions.cs b/services/Archival/FilterLists.Archival.Infrastructure/Persistence/ConfigurationExtensions.cs index 2d7b2b1b2..f270eee08 100644 --- a/services/Archival/FilterLists.Archival.Infrastructure/Persistence/ConfigurationExtensions.cs +++ b/services/Archival/FilterLists.Archival.Infrastructure/Persistence/ConfigurationExtensions.cs @@ -4,24 +4,23 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -namespace FilterLists.Archival.Infrastructure.Persistence -{ - internal static class ConfigurationExtensions - { - public static void AddPersistenceServices(this IServiceCollection services, IConfiguration configuration) - { - services.Configure(configuration.GetSection(GitOptions.Key)); - services.AddTransient(_ => - { - var gitOptions = configuration.GetSection(GitOptions.Key).Get(); - if (!Repository.IsValid(gitOptions.RepositoryPath)) - { - Repository.Init(gitOptions.RepositoryPath); - } +namespace FilterLists.Archival.Infrastructure.Persistence; - return new Repository(gitOptions.RepositoryPath); - }); - services.AddTransient(); - } +internal static class ConfigurationExtensions +{ + public static void AddPersistenceServices(this IServiceCollection services, IConfiguration configuration) + { + services.Configure(configuration.GetSection(GitOptions.Key)); + services.AddTransient(_ => + { + var gitOptions = configuration.GetSection(GitOptions.Key).Get(); + if (!Repository.IsValid(gitOptions.RepositoryPath)) + { + Repository.Init(gitOptions.RepositoryPath); + } + + return new Repository(gitOptions.RepositoryPath); + }); + services.AddTransient(); } } diff --git a/services/Archival/FilterLists.Archival.Infrastructure/Persistence/FileWriteStrategies/IStreamToPlainTextConversionStrategy.cs b/services/Archival/FilterLists.Archival.Infrastructure/Persistence/FileWriteStrategies/IStreamToPlainTextConversionStrategy.cs index 691f954b3..fa3626390 100644 --- a/services/Archival/FilterLists.Archival.Infrastructure/Persistence/FileWriteStrategies/IStreamToPlainTextConversionStrategy.cs +++ b/services/Archival/FilterLists.Archival.Infrastructure/Persistence/FileWriteStrategies/IStreamToPlainTextConversionStrategy.cs @@ -1,9 +1,8 @@ using FilterLists.Archival.Domain.ListArchives; -namespace FilterLists.Archival.Infrastructure.Persistence.FileWriteStrategies +namespace FilterLists.Archival.Infrastructure.Persistence.FileWriteStrategies; + +internal interface IStreamToPlainTextConversionStrategy { - internal interface IStreamToPlainTextConversionStrategy - { - Stream Convert(ListArchiveSegment listArchiveSegment, CancellationToken cancellationToken); - } + Stream Convert(ListArchiveSegment listArchiveSegment, CancellationToken cancellationToken); } diff --git a/services/Archival/FilterLists.Archival.Infrastructure/Persistence/FileWriteStrategies/PlainText.cs b/services/Archival/FilterLists.Archival.Infrastructure/Persistence/FileWriteStrategies/PlainText.cs index e3d3c1861..a59af1b45 100644 --- a/services/Archival/FilterLists.Archival.Infrastructure/Persistence/FileWriteStrategies/PlainText.cs +++ b/services/Archival/FilterLists.Archival.Infrastructure/Persistence/FileWriteStrategies/PlainText.cs @@ -1,12 +1,11 @@ using FilterLists.Archival.Domain.ListArchives; -namespace FilterLists.Archival.Infrastructure.Persistence.FileWriteStrategies +namespace FilterLists.Archival.Infrastructure.Persistence.FileWriteStrategies; + +internal class PlainText : IStreamToPlainTextConversionStrategy { - internal class PlainText : IStreamToPlainTextConversionStrategy + public Stream Convert(ListArchiveSegment listArchiveSegment, CancellationToken cancellationToken) { - public Stream Convert(ListArchiveSegment listArchiveSegment, CancellationToken cancellationToken) - { - return listArchiveSegment.Content; - } + return listArchiveSegment.Content; } } diff --git a/services/Archival/FilterLists.Archival.Infrastructure/Persistence/FileWriteStrategies/StreamToPlainTextConversionStrategyFactory.cs b/services/Archival/FilterLists.Archival.Infrastructure/Persistence/FileWriteStrategies/StreamToPlainTextConversionStrategyFactory.cs index 89823eee3..138ad2121 100644 --- a/services/Archival/FilterLists.Archival.Infrastructure/Persistence/FileWriteStrategies/StreamToPlainTextConversionStrategyFactory.cs +++ b/services/Archival/FilterLists.Archival.Infrastructure/Persistence/FileWriteStrategies/StreamToPlainTextConversionStrategyFactory.cs @@ -1,16 +1,15 @@ using FilterLists.Archival.Domain.ListArchives; -namespace FilterLists.Archival.Infrastructure.Persistence.FileWriteStrategies +namespace FilterLists.Archival.Infrastructure.Persistence.FileWriteStrategies; + +internal static class StreamToPlainTextConversionStrategyFactory { - internal static class StreamToPlainTextConversionStrategyFactory + public static TStrategy? GetStrategy(this ListArchiveSegment segment) + where TStrategy : class, IStreamToPlainTextConversionStrategy { - public static TStrategy? GetStrategy(this ListArchiveSegment segment) - where TStrategy : class, IStreamToPlainTextConversionStrategy - { - // TODO: implement non-plain text strategies - return segment.Extension.IsPlainText - ? new PlainText() as TStrategy - : default; - } + // TODO: implement non-plain text strategies + return segment.Extension.IsPlainText + ? new PlainText() as TStrategy + : default; } } diff --git a/services/Archival/FilterLists.Archival.Infrastructure/Persistence/GitListArchiveRepository.cs b/services/Archival/FilterLists.Archival.Infrastructure/Persistence/GitListArchiveRepository.cs index 96732db49..f64335c32 100644 --- a/services/Archival/FilterLists.Archival.Infrastructure/Persistence/GitListArchiveRepository.cs +++ b/services/Archival/FilterLists.Archival.Infrastructure/Persistence/GitListArchiveRepository.cs @@ -6,124 +6,123 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -namespace FilterLists.Archival.Infrastructure.Persistence +namespace FilterLists.Archival.Infrastructure.Persistence; + +internal sealed class GitListArchiveRepository : IListArchiveRepository { - internal sealed class GitListArchiveRepository : IListArchiveRepository + private readonly ILogger _logger; + private readonly GitOptions _options; + private readonly IRepository _repo; + private readonly ICollection _writtenFiles = new HashSet(); + + public GitListArchiveRepository( + ILogger logger, + IOptions gitOptions, + IRepository repository) { - private readonly ILogger _logger; - private readonly GitOptions _options; - private readonly IRepository _repo; - private readonly ICollection _writtenFiles = new HashSet(); + _logger = logger; + _options = gitOptions.Value; + _repo = repository; + } - public GitListArchiveRepository( - ILogger logger, - IOptions gitOptions, - IRepository repository) + public async Task AddAsync(ListArchive listArchive, CancellationToken cancellationToken) + { + var segmentNumber = 1; + await foreach (var segment in listArchive.Segments.WithCancellation(cancellationToken)) { - _logger = logger; - _options = gitOptions.Value; - _repo = repository; - } - - public async Task AddAsync(ListArchive listArchive, CancellationToken cancellationToken) - { - var segmentNumber = 1; - await foreach (var segment in listArchive.Segments.WithCancellation(cancellationToken)) + var strategy = segment.GetStrategy(); + if (strategy is default(IStreamToPlainTextConversionStrategy)) { - var strategy = segment.GetStrategy(); - if (strategy is default(IStreamToPlainTextConversionStrategy)) - { - _logger.LogWarning( - "No stream to plain text conversion strategy found for extension {Extension} for list {ListId}. Skipping list", - segment.Extension, - listArchive.Id); - return; - } - - var fileInfo = GetTargetFile(listArchive.Id, segmentNumber, segment.Extension); - if (fileInfo is default(FileInfo)) - { - _logger.LogWarning( - "Writing from non-plain text extension {Extension} for list {ListId} not yet supported. Skipping list", - segment.Extension, - listArchive.Id); - return; - } - - _writtenFiles.Add(fileInfo); - - _logger.LogInformation("Writing {FileName}", fileInfo.Name); - - await using var target = fileInfo.OpenWrite(); - await strategy.Convert(segment, cancellationToken).CopyToAsync(target, cancellationToken); - - _logger.LogInformation("Finished writing {FileName}", fileInfo.Name); - - segmentNumber++; - } - } - - public void Commit() - { - if (_writtenFiles.Count > 0) - { - var fileNames = _writtenFiles.Select(f => f.Name).ToList(); - var signature = new Signature(_options.UserName, _options.UserEmail, DateTime.UtcNow); - var message = - $"feat(archives): archive {fileNames.Count} file(s){Environment.NewLine}{string.Join(Environment.NewLine, fileNames)}"; - Commands.Stage(_repo, fileNames); - try - { - _repo.Commit(message, signature, signature); - } - catch (EmptyCommitException ex) - { - _logger.LogInformation(ex, "No changes to commit for {@FileNames}", fileNames); - } - - _logger.LogInformation("Committed {@FileNames}", fileNames); - } - else - { - _logger.LogInformation("No written files to commit"); - } - } - - public void Dispose() - { - foreach (var file in _writtenFiles) - { - if (File.Exists(file.Name)) - { - File.Delete(file.Name); - } + _logger.LogWarning( + "No stream to plain text conversion strategy found for extension {Extension} for list {ListId}. Skipping list", + segment.Extension, + listArchive.Id); + return; } - _repo.CheckoutPaths("HEAD", _writtenFiles.Select(f => f.Name)); - } - - private FileInfo? GetTargetFile(int listId, int segmentNumber, ListFileExtension extension) - { - string targetExtension; - if (extension.IsPlainText) + var fileInfo = GetTargetFile(listArchive.Id, segmentNumber, segment.Extension); + if (fileInfo is default(FileInfo)) { - targetExtension = extension.IsMeaningfulToConsumer ? extension.Value : ".txt"; - } - else - { - // TODO: implement - return default; + _logger.LogWarning( + "Writing from non-plain text extension {Extension} for list {ListId} not yet supported. Skipping list", + segment.Extension, + listArchive.Id); + return; } - var targetFileName = GetTargetFileNamePrefix(listId) + - (segmentNumber == 1 ? string.Empty : $"-{segmentNumber}") + - targetExtension; - return new FileInfo(Path.Combine(_options.RepositoryPath, targetFileName)); - } + _writtenFiles.Add(fileInfo); - private static string GetTargetFileNamePrefix(int listId) - { - return listId.ToString(CultureInfo.InvariantCulture).PadLeft(5, '0'); + _logger.LogInformation("Writing {FileName}", fileInfo.Name); + + await using var target = fileInfo.OpenWrite(); + await strategy.Convert(segment, cancellationToken).CopyToAsync(target, cancellationToken); + + _logger.LogInformation("Finished writing {FileName}", fileInfo.Name); + + segmentNumber++; } } + + public void Commit() + { + if (_writtenFiles.Count > 0) + { + var fileNames = _writtenFiles.Select(f => f.Name).ToList(); + var signature = new Signature(_options.UserName, _options.UserEmail, DateTime.UtcNow); + var message = + $"feat(archives): archive {fileNames.Count} file(s){Environment.NewLine}{string.Join(Environment.NewLine, fileNames)}"; + Commands.Stage(_repo, fileNames); + try + { + _repo.Commit(message, signature, signature); + } + catch (EmptyCommitException ex) + { + _logger.LogInformation(ex, "No changes to commit for {@FileNames}", fileNames); + } + + _logger.LogInformation("Committed {@FileNames}", fileNames); + } + else + { + _logger.LogInformation("No written files to commit"); + } + } + + public void Dispose() + { + foreach (var file in _writtenFiles) + { + if (File.Exists(file.Name)) + { + File.Delete(file.Name); + } + } + + _repo.CheckoutPaths("HEAD", _writtenFiles.Select(f => f.Name)); + } + + private FileInfo? GetTargetFile(int listId, int segmentNumber, ListFileExtension extension) + { + string targetExtension; + if (extension.IsPlainText) + { + targetExtension = extension.IsMeaningfulToConsumer ? extension.Value : ".txt"; + } + else + { + // TODO: implement + return default; + } + + var targetFileName = GetTargetFileNamePrefix(listId) + + (segmentNumber == 1 ? string.Empty : $"-{segmentNumber}") + + targetExtension; + return new FileInfo(Path.Combine(_options.RepositoryPath, targetFileName)); + } + + private static string GetTargetFileNamePrefix(int listId) + { + return listId.ToString(CultureInfo.InvariantCulture).PadLeft(5, '0'); + } } diff --git a/services/Archival/FilterLists.Archival.Infrastructure/Scheduling/ConfigurationExtensions.cs b/services/Archival/FilterLists.Archival.Infrastructure/Scheduling/ConfigurationExtensions.cs index 7fe6de9da..a2bab3d32 100644 --- a/services/Archival/FilterLists.Archival.Infrastructure/Scheduling/ConfigurationExtensions.cs +++ b/services/Archival/FilterLists.Archival.Infrastructure/Scheduling/ConfigurationExtensions.cs @@ -4,21 +4,20 @@ using Microsoft.Extensions.DependencyInjection; using StackExchange.Redis; -namespace FilterLists.Archival.Infrastructure.Scheduling +namespace FilterLists.Archival.Infrastructure.Scheduling; + +internal static class ConfigurationExtensions { - internal static class ConfigurationExtensions + private static ConnectionMultiplexer _redis = null!; + + public static void AddSchedulingServices(this IServiceCollection services, IConfiguration configuration) { - private static ConnectionMultiplexer _redis = null!; + _redis = ConnectionMultiplexer.Connect(configuration.GetConnectionString("SchedulingConnection")); + services.AddHangfire((_, globalConfiguration) => globalConfiguration.UseRedisStorage(_redis).UseMediatR()); + } - public static void AddSchedulingServices(this IServiceCollection services, IConfiguration configuration) - { - _redis = ConnectionMultiplexer.Connect(configuration.GetConnectionString("SchedulingConnection")); - services.AddHangfire((_, globalConfiguration) => globalConfiguration.UseRedisStorage(_redis).UseMediatR()); - } - - public static void UseScheduling(this IApplicationBuilder app) - { - app.UseHangfireServer(new BackgroundJobServerOptions { WorkerCount = Environment.ProcessorCount }); - } + public static void UseScheduling(this IApplicationBuilder app) + { + app.UseHangfireServer(new BackgroundJobServerOptions { WorkerCount = Environment.ProcessorCount }); } } diff --git a/services/Archival/FilterLists.Archival.Infrastructure/Scheduling/HangfireExtensions.cs b/services/Archival/FilterLists.Archival.Infrastructure/Scheduling/HangfireExtensions.cs index dbf3e2f8d..34c270327 100644 --- a/services/Archival/FilterLists.Archival.Infrastructure/Scheduling/HangfireExtensions.cs +++ b/services/Archival/FilterLists.Archival.Infrastructure/Scheduling/HangfireExtensions.cs @@ -1,26 +1,25 @@ using Hangfire; using Hangfire.Storage; -namespace FilterLists.Archival.Infrastructure.Scheduling -{ - public static class HangfireExtensions - { - // https://github.com/HangfireIO/Hangfire/issues/394#issuecomment-179924221 - public static void PurgeJobs(this IMonitoringApi monitoringApi) - { - var toDelete = new List(); - foreach (var queue in monitoringApi.Queues()) - { - for (var i = 0; i < Math.Ceiling(queue.Length / 1000d); i++) - { - toDelete.AddRange(monitoringApi.EnqueuedJobs(queue.Name, 1000 * i, 1000).Select(x => x.Key)); - } - } +namespace FilterLists.Archival.Infrastructure.Scheduling; - foreach (var jobId in toDelete) +public static class HangfireExtensions +{ + // https://github.com/HangfireIO/Hangfire/issues/394#issuecomment-179924221 + public static void PurgeJobs(this IMonitoringApi monitoringApi) + { + var toDelete = new List(); + foreach (var queue in monitoringApi.Queues()) + { + for (var i = 0; i < Math.Ceiling(queue.Length / 1000d); i++) { - BackgroundJob.Delete(jobId); + toDelete.AddRange(monitoringApi.EnqueuedJobs(queue.Name, 1000 * i, 1000).Select(x => x.Key)); } } + + foreach (var jobId in toDelete) + { + BackgroundJob.Delete(jobId); + } } } diff --git a/services/Archival/FilterLists.Archival.Infrastructure/Scheduling/ScheduleMediator.cs b/services/Archival/FilterLists.Archival.Infrastructure/Scheduling/ScheduleMediator.cs index 524164a52..f39245201 100644 --- a/services/Archival/FilterLists.Archival.Infrastructure/Scheduling/ScheduleMediator.cs +++ b/services/Archival/FilterLists.Archival.Infrastructure/Scheduling/ScheduleMediator.cs @@ -2,36 +2,35 @@ using MediatR; using Newtonsoft.Json; -namespace FilterLists.Archival.Infrastructure.Scheduling +namespace FilterLists.Archival.Infrastructure.Scheduling; + +public static class RequestExtensions { - public static class RequestExtensions + public static void EnqueueBackgroundJob(this IRequest request) { - public static void EnqueueBackgroundJob(this IRequest request) - { - // Hangfire replaces CancellationToken at runtime with its own. We just need any in the signature. - // https://docs.hangfire.io/en/latest/background-methods/using-cancellation-tokens.html#cancellationtoken - BackgroundJob.Enqueue(m => m.Send(request, CancellationToken.None)); - } - - public static void ScheduleBackgroundJob(this IRequest request, TimeSpan delay) - { - BackgroundJob.Schedule(m => m.Send(request, CancellationToken.None), delay); - } - - public static void AddOrUpdateRecurringJob(this IRequest request, Func cronExpression) - { - RecurringJob.AddOrUpdate(m => m.Send(request, CancellationToken.None), cronExpression); - } + // Hangfire replaces CancellationToken at runtime with its own. We just need any in the signature. + // https://docs.hangfire.io/en/latest/background-methods/using-cancellation-tokens.html#cancellationtoken + BackgroundJob.Enqueue(m => m.Send(request, CancellationToken.None)); } - internal static class HangfireExtension + public static void ScheduleBackgroundJob(this IRequest request, TimeSpan delay) { - public static IGlobalConfiguration UseMediatR(this IGlobalConfiguration globalConfiguration) - { - /// https://codeopinion.com/background-commands-mediatr-hangfire/ - GlobalConfiguration.Configuration.UseSerializerSettings( - new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects }); - return globalConfiguration; - } + BackgroundJob.Schedule(m => m.Send(request, CancellationToken.None), delay); + } + + public static void AddOrUpdateRecurringJob(this IRequest request, Func cronExpression) + { + RecurringJob.AddOrUpdate(m => m.Send(request, CancellationToken.None), cronExpression); + } +} + +internal static class HangfireExtension +{ + public static IGlobalConfiguration UseMediatR(this IGlobalConfiguration globalConfiguration) + { + /// https://codeopinion.com/background-commands-mediatr-hangfire/ + GlobalConfiguration.Configuration.UseSerializerSettings( + new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects }); + return globalConfiguration; } } diff --git a/services/Directory/FilterLists.Directory.Api.Contracts/ConfigurationExtensions.cs b/services/Directory/FilterLists.Directory.Api.Contracts/ConfigurationExtensions.cs index 72239648b..e9ab2d407 100644 --- a/services/Directory/FilterLists.Directory.Api.Contracts/ConfigurationExtensions.cs +++ b/services/Directory/FilterLists.Directory.Api.Contracts/ConfigurationExtensions.cs @@ -4,24 +4,23 @@ using Polly; using Refit; -namespace FilterLists.Directory.Api.Contracts +namespace FilterLists.Directory.Api.Contracts; + +public static class ConfigurationExtensions { - public static class ConfigurationExtensions + public static void AddDirectoryApiClient(this IServiceCollection services, IConfiguration configuration) { - public static void AddDirectoryApiClient(this IServiceCollection services, IConfiguration configuration) - { - // TODO: use SystemTextJsonContentSerializer() once less feature-limited - services.AddRefitClient() - .ConfigureHttpClient(c => + // TODO: use SystemTextJsonContentSerializer() once less feature-limited + services.AddRefitClient() + .ConfigureHttpClient(c => + { + var host = configuration.GetSection(ApiOptions.Key).Get().DirectoryHost; + c.BaseAddress = new UriBuilder("http", host).Uri; + }) + .AddTransientHttpErrorPolicy(b => + b.WaitAndRetryAsync(new[] { - var host = configuration.GetSection(ApiOptions.Key).Get().DirectoryHost; - c.BaseAddress = new UriBuilder("http", host).Uri; - }) - .AddTransientHttpErrorPolicy(b => - b.WaitAndRetryAsync(new[] - { - TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10) - })); - } + TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10) + })); } } diff --git a/services/Directory/FilterLists.Directory.Api.Contracts/IDirectoryApi.cs b/services/Directory/FilterLists.Directory.Api.Contracts/IDirectoryApi.cs index 3b6cdbb2b..63a7fb984 100644 --- a/services/Directory/FilterLists.Directory.Api.Contracts/IDirectoryApi.cs +++ b/services/Directory/FilterLists.Directory.Api.Contracts/IDirectoryApi.cs @@ -1,14 +1,13 @@ using FilterLists.Directory.Api.Contracts.Models; using Refit; -namespace FilterLists.Directory.Api.Contracts -{ - public interface IDirectoryApi - { - [Get("/lists")] - Task> GetListsAsync(CancellationToken cancellationToken); +namespace FilterLists.Directory.Api.Contracts; - [Get("/lists/{id}")] - Task GetListDetailsAsync(int id, CancellationToken cancellationToken); - } +public interface IDirectoryApi +{ + [Get("/lists")] + Task> GetListsAsync(CancellationToken cancellationToken); + + [Get("/lists/{id}")] + Task GetListDetailsAsync(int id, CancellationToken cancellationToken); } diff --git a/services/Directory/FilterLists.Directory.Api.Contracts/Models/ListDetailsVm.cs b/services/Directory/FilterLists.Directory.Api.Contracts/Models/ListDetailsVm.cs index bba9a1108..44327d79b 100644 --- a/services/Directory/FilterLists.Directory.Api.Contracts/Models/ListDetailsVm.cs +++ b/services/Directory/FilterLists.Directory.Api.Contracts/Models/ListDetailsVm.cs @@ -1,37 +1,36 @@ -namespace FilterLists.Directory.Api.Contracts.Models -{ - public class ListDetailsVm - { - public int Id { get; init; } - public string Name { get; init; } = null!; - public string? Description { get; init; } - public int? LicenseId { get; init; } - public IEnumerable? SyntaxIds { get; init; } - public IEnumerable? Iso6391s { get; init; } - public IEnumerable? TagIds { get; init; } - public IEnumerable? ViewUrls { get; init; } - public Uri? HomeUrl { get; init; } - public Uri? OnionUrl { get; init; } - public Uri? PolicyUrl { get; init; } - public Uri? SubmissionUrl { get; init; } - public Uri? IssuesUrl { get; init; } - public Uri? ForumUrl { get; init; } - public Uri? ChatUrl { get; init; } - public string? EmailAddress { get; init; } - public Uri? DonateUrl { get; init; } - public IEnumerable? MaintainerIds { get; init; } - public IEnumerable? UpstreamFilterListIds { get; init; } - public IEnumerable? ForkFilterListIds { get; init; } - public IEnumerable? IncludedInFilterListIds { get; init; } - public IEnumerable? IncludesFilterListIds { get; init; } - public IEnumerable? DependencyFilterListIds { get; init; } - public IEnumerable? DependentFilterListIds { get; init; } +namespace FilterLists.Directory.Api.Contracts.Models; - public class ViewUrlVm - { - public short SegmentNumber { get; init; } - public short Primariness { get; init; } - public Uri Url { get; init; } = null!; - } +public class ListDetailsVm +{ + public int Id { get; init; } + public string Name { get; init; } = null!; + public string? Description { get; init; } + public int? LicenseId { get; init; } + public IEnumerable? SyntaxIds { get; init; } + public IEnumerable? Iso6391s { get; init; } + public IEnumerable? TagIds { get; init; } + public IEnumerable? ViewUrls { get; init; } + public Uri? HomeUrl { get; init; } + public Uri? OnionUrl { get; init; } + public Uri? PolicyUrl { get; init; } + public Uri? SubmissionUrl { get; init; } + public Uri? IssuesUrl { get; init; } + public Uri? ForumUrl { get; init; } + public Uri? ChatUrl { get; init; } + public string? EmailAddress { get; init; } + public Uri? DonateUrl { get; init; } + public IEnumerable? MaintainerIds { get; init; } + public IEnumerable? UpstreamFilterListIds { get; init; } + public IEnumerable? ForkFilterListIds { get; init; } + public IEnumerable? IncludedInFilterListIds { get; init; } + public IEnumerable? IncludesFilterListIds { get; init; } + public IEnumerable? DependencyFilterListIds { get; init; } + public IEnumerable? DependentFilterListIds { get; init; } + + public class ViewUrlVm + { + public short SegmentNumber { get; init; } + public short Primariness { get; init; } + public Uri Url { get; init; } = null!; } } diff --git a/services/Directory/FilterLists.Directory.Api.Contracts/Models/ListVm.cs b/services/Directory/FilterLists.Directory.Api.Contracts/Models/ListVm.cs index bc6fef1fe..1fda98f36 100644 --- a/services/Directory/FilterLists.Directory.Api.Contracts/Models/ListVm.cs +++ b/services/Directory/FilterLists.Directory.Api.Contracts/Models/ListVm.cs @@ -1,15 +1,14 @@ -namespace FilterLists.Directory.Api.Contracts.Models +namespace FilterLists.Directory.Api.Contracts.Models; + +public class ListVm { - public class ListVm - { - public int Id { get; init; } - public string Name { get; init; } = null!; - public string? Description { get; init; } - public int? LicenseId { get; init; } - public IEnumerable? SyntaxIds { get; init; } - public IEnumerable? Iso6391s { get; init; } - public IEnumerable? TagIds { get; init; } - public Uri? PrimaryViewUrl { get; init; } - public IEnumerable? MaintainerIds { get; init; } - } + public int Id { get; init; } + public string Name { get; init; } = null!; + public string? Description { get; init; } + public int? LicenseId { get; init; } + public IEnumerable? SyntaxIds { get; init; } + public IEnumerable? Iso6391s { get; init; } + public IEnumerable? TagIds { get; init; } + public Uri? PrimaryViewUrl { get; init; } + public IEnumerable? MaintainerIds { get; init; } } diff --git a/services/Directory/FilterLists.Directory.Api.Contracts/Options/ApiOptions.cs b/services/Directory/FilterLists.Directory.Api.Contracts/Options/ApiOptions.cs index 67d00124b..4cfe70f53 100644 --- a/services/Directory/FilterLists.Directory.Api.Contracts/Options/ApiOptions.cs +++ b/services/Directory/FilterLists.Directory.Api.Contracts/Options/ApiOptions.cs @@ -1,9 +1,8 @@ -namespace FilterLists.Directory.Api.Contracts.Options -{ - internal class ApiOptions - { - public const string Key = "Api"; +namespace FilterLists.Directory.Api.Contracts.Options; - public string DirectoryHost { get; init; } = null!; - } +internal class ApiOptions +{ + public const string Key = "Api"; + + public string DirectoryHost { get; init; } = null!; } diff --git a/services/Directory/FilterLists.Directory.Api/Controllers/BaseController.cs b/services/Directory/FilterLists.Directory.Api/Controllers/BaseController.cs index ade29ae5e..1e470c010 100644 --- a/services/Directory/FilterLists.Directory.Api/Controllers/BaseController.cs +++ b/services/Directory/FilterLists.Directory.Api/Controllers/BaseController.cs @@ -2,34 +2,33 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; -namespace FilterLists.Directory.Api.Controllers +namespace FilterLists.Directory.Api.Controllers; + +[ApiController] +[Route("[controller]")] +[Produces("application/json")] +public abstract class BaseController : ControllerBase { - [ApiController] - [Route("[controller]")] - [Produces("application/json")] - public abstract class BaseController : ControllerBase + private readonly IMemoryCache _cache; + + protected BaseController(IMemoryCache cache) { - private readonly IMemoryCache _cache; + _cache = cache; + } - protected BaseController(IMemoryCache cache) + /// https://stackoverflow.com/a/52506210/2343739 + protected async Task CacheGetOrCreateAsync( + Func> actionAsync, + int? keySuffix = default, + TimeSpan? absoluteExpirationRelativeToNow = default, + [CallerMemberName] string key = default!) + { + var cacheKey = $"{GetType().Name}_{key}{(keySuffix is null ? string.Empty : $"_{keySuffix}")}"; + var result = await _cache.GetOrCreateAsync(cacheKey, entry => { - _cache = cache; - } - - /// https://stackoverflow.com/a/52506210/2343739 - protected async Task CacheGetOrCreateAsync( - Func> actionAsync, - int? keySuffix = default, - TimeSpan? absoluteExpirationRelativeToNow = default, - [CallerMemberName] string key = default!) - { - var cacheKey = $"{GetType().Name}_{key}{(keySuffix is null ? string.Empty : $"_{keySuffix}")}"; - var result = await _cache.GetOrCreateAsync(cacheKey, entry => - { - entry.AbsoluteExpirationRelativeToNow = absoluteExpirationRelativeToNow; - return actionAsync(); - }); - return result is null ? NotFound() : Ok(result); - } + entry.AbsoluteExpirationRelativeToNow = absoluteExpirationRelativeToNow; + return actionAsync(); + }); + return result is null ? NotFound() : Ok(result); } } diff --git a/services/Directory/FilterLists.Directory.Api/Controllers/ErrorController.cs b/services/Directory/FilterLists.Directory.Api/Controllers/ErrorController.cs index 814309fd7..a6b43bd6f 100644 --- a/services/Directory/FilterLists.Directory.Api/Controllers/ErrorController.cs +++ b/services/Directory/FilterLists.Directory.Api/Controllers/ErrorController.cs @@ -1,29 +1,28 @@ using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc; -namespace FilterLists.Directory.Api.Controllers +namespace FilterLists.Directory.Api.Controllers; + +[ApiController] +[ApiExplorerSettings(IgnoreApi = true)] +// TODO: de-duplicate into SharedKernel +public class ErrorController : ControllerBase { - [ApiController] - [ApiExplorerSettings(IgnoreApi = true)] - // TODO: de-duplicate into SharedKernel - public class ErrorController : ControllerBase + [Route("/error-local-development")] + public IActionResult ErrorLocalDevelopment([FromServices] IWebHostEnvironment webHostEnvironment) { - [Route("/error-local-development")] - public IActionResult ErrorLocalDevelopment([FromServices] IWebHostEnvironment webHostEnvironment) + if (webHostEnvironment.EnvironmentName != "Development") { - if (webHostEnvironment.EnvironmentName != "Development") - { - throw new InvalidOperationException("This shouldn't be invoked in non-development environments."); - } - - var context = HttpContext.Features.Get(); - return Problem(context?.Error.StackTrace, title: context?.Error.Message); + throw new InvalidOperationException("This shouldn't be invoked in non-development environments."); } - [Route("/error")] - public IActionResult Error() - { - return Problem(); - } + var context = HttpContext.Features.Get(); + return Problem(context?.Error.StackTrace, title: context?.Error.Message); + } + + [Route("/error")] + public IActionResult Error() + { + return Problem(); } } diff --git a/services/Directory/FilterLists.Directory.Api/Controllers/LanguagesController.cs b/services/Directory/FilterLists.Directory.Api/Controllers/LanguagesController.cs index fb5d19de5..7888d0eb4 100644 --- a/services/Directory/FilterLists.Directory.Api/Controllers/LanguagesController.cs +++ b/services/Directory/FilterLists.Directory.Api/Controllers/LanguagesController.cs @@ -3,27 +3,26 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; -namespace FilterLists.Directory.Api.Controllers +namespace FilterLists.Directory.Api.Controllers; + +public class LanguagesController : BaseController { - public class LanguagesController : BaseController + private readonly IMediator _mediator; + + public LanguagesController(IMemoryCache cache, IMediator mediator) : base(cache) { - private readonly IMediator _mediator; + _mediator = mediator; + } - public LanguagesController(IMemoryCache cache, IMediator mediator) : base(cache) - { - _mediator = mediator; - } - - /// - /// Gets the languages targeted by FilterLists. - /// - /// The cancellation token. - /// The languages targeted by FilterLists. - [HttpGet] - [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public Task Get(CancellationToken cancellationToken) - { - return CacheGetOrCreateAsync(() => _mediator.Send(new GetLanguages.Query(), cancellationToken)); - } + /// + /// Gets the languages targeted by FilterLists. + /// + /// The cancellation token. + /// The languages targeted by FilterLists. + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public Task Get(CancellationToken cancellationToken) + { + return CacheGetOrCreateAsync(() => _mediator.Send(new GetLanguages.Query(), cancellationToken)); } } diff --git a/services/Directory/FilterLists.Directory.Api/Controllers/LicensesController.cs b/services/Directory/FilterLists.Directory.Api/Controllers/LicensesController.cs index b8415b6de..e0f507610 100644 --- a/services/Directory/FilterLists.Directory.Api/Controllers/LicensesController.cs +++ b/services/Directory/FilterLists.Directory.Api/Controllers/LicensesController.cs @@ -3,27 +3,26 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; -namespace FilterLists.Directory.Api.Controllers +namespace FilterLists.Directory.Api.Controllers; + +public class LicensesController : BaseController { - public class LicensesController : BaseController + private readonly IMediator _mediator; + + public LicensesController(IMemoryCache cache, IMediator mediator) : base(cache) { - private readonly IMediator _mediator; + _mediator = mediator; + } - public LicensesController(IMemoryCache cache, IMediator mediator) : base(cache) - { - _mediator = mediator; - } - - /// - /// Gets the licenses applied to FilterLists. - /// - /// The cancellation token. - /// The licenses applied to FilterLists. - [HttpGet] - [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public Task Get(CancellationToken cancellationToken) - { - return CacheGetOrCreateAsync(() => _mediator.Send(new GetLicenses.Query(), cancellationToken)); - } + /// + /// Gets the licenses applied to FilterLists. + /// + /// The cancellation token. + /// The licenses applied to FilterLists. + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public Task Get(CancellationToken cancellationToken) + { + return CacheGetOrCreateAsync(() => _mediator.Send(new GetLicenses.Query(), cancellationToken)); } } diff --git a/services/Directory/FilterLists.Directory.Api/Controllers/ListsController.cs b/services/Directory/FilterLists.Directory.Api/Controllers/ListsController.cs index c067f161d..764b4d1a1 100644 --- a/services/Directory/FilterLists.Directory.Api/Controllers/ListsController.cs +++ b/services/Directory/FilterLists.Directory.Api/Controllers/ListsController.cs @@ -4,41 +4,40 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; -namespace FilterLists.Directory.Api.Controllers +namespace FilterLists.Directory.Api.Controllers; + +public class ListsController : BaseController { - public class ListsController : BaseController + private readonly IMediator _mediator; + + public ListsController(IMemoryCache cache, IMediator mediator) : base(cache) { - private readonly IMediator _mediator; + _mediator = mediator; + } - public ListsController(IMemoryCache cache, IMediator mediator) : base(cache) - { - _mediator = mediator; - } + /// + /// Gets the FilterLists.. + /// + /// The cancellation token. + /// The FilterLists. + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public Task Get(CancellationToken cancellationToken) + { + return CacheGetOrCreateAsync(() => _mediator.Send(new GetLists.Query(), cancellationToken)); + } - /// - /// Gets the FilterLists.. - /// - /// The cancellation token. - /// The FilterLists. - [HttpGet] - [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public Task Get(CancellationToken cancellationToken) - { - return CacheGetOrCreateAsync(() => _mediator.Send(new GetLists.Query(), cancellationToken)); - } - - /// - /// Gets the details of the FilterList. - /// - /// The identifier of the FilterList. - /// The cancellation token. - /// The details of the FilterList. - [HttpGet("{id:int}")] - [ProducesResponseType(typeof(ListDetailsVm), StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public Task GetDetails(int id, CancellationToken cancellationToken) - { - return CacheGetOrCreateAsync(() => _mediator.Send(new GetListDetails.Query(id), cancellationToken), id); - } + /// + /// Gets the details of the FilterList. + /// + /// The identifier of the FilterList. + /// The cancellation token. + /// The details of the FilterList. + [HttpGet("{id:int}")] + [ProducesResponseType(typeof(ListDetailsVm), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public Task GetDetails(int id, CancellationToken cancellationToken) + { + return CacheGetOrCreateAsync(() => _mediator.Send(new GetListDetails.Query(id), cancellationToken), id); } } diff --git a/services/Directory/FilterLists.Directory.Api/Controllers/MaintainersController.cs b/services/Directory/FilterLists.Directory.Api/Controllers/MaintainersController.cs index 9794324cc..57d367900 100644 --- a/services/Directory/FilterLists.Directory.Api/Controllers/MaintainersController.cs +++ b/services/Directory/FilterLists.Directory.Api/Controllers/MaintainersController.cs @@ -3,27 +3,26 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; -namespace FilterLists.Directory.Api.Controllers +namespace FilterLists.Directory.Api.Controllers; + +public class MaintainersController : BaseController { - public class MaintainersController : BaseController + private readonly IMediator _mediator; + + public MaintainersController(IMemoryCache cache, IMediator mediator) : base(cache) { - private readonly IMediator _mediator; + _mediator = mediator; + } - public MaintainersController(IMemoryCache cache, IMediator mediator) : base(cache) - { - _mediator = mediator; - } - - /// - /// Gets the maintainers of FilterLists. - /// - /// The cancellation token. - /// The maintainers of FilterLists. - [HttpGet] - [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public Task Get(CancellationToken cancellationToken) - { - return CacheGetOrCreateAsync(() => _mediator.Send(new GetMaintainers.Query(), cancellationToken)); - } + /// + /// Gets the maintainers of FilterLists. + /// + /// The cancellation token. + /// The maintainers of FilterLists. + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public Task Get(CancellationToken cancellationToken) + { + return CacheGetOrCreateAsync(() => _mediator.Send(new GetMaintainers.Query(), cancellationToken)); } } diff --git a/services/Directory/FilterLists.Directory.Api/Controllers/SoftwareController.cs b/services/Directory/FilterLists.Directory.Api/Controllers/SoftwareController.cs index f15327812..2c367b3cf 100644 --- a/services/Directory/FilterLists.Directory.Api/Controllers/SoftwareController.cs +++ b/services/Directory/FilterLists.Directory.Api/Controllers/SoftwareController.cs @@ -3,27 +3,26 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; -namespace FilterLists.Directory.Api.Controllers +namespace FilterLists.Directory.Api.Controllers; + +public class SoftwareController : BaseController { - public class SoftwareController : BaseController + private readonly IMediator _mediator; + + public SoftwareController(IMemoryCache cache, IMediator mediator) : base(cache) { - private readonly IMediator _mediator; + _mediator = mediator; + } - public SoftwareController(IMemoryCache cache, IMediator mediator) : base(cache) - { - _mediator = mediator; - } - - /// - /// Gets the software that subscribes to FilterLists. - /// - /// The cancellation token. - /// The software that subscribes to FilterLists. - [HttpGet] - [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public Task Get(CancellationToken cancellationToken) - { - return CacheGetOrCreateAsync(() => _mediator.Send(new GetSoftware.Query(), cancellationToken)); - } + /// + /// Gets the software that subscribes to FilterLists. + /// + /// The cancellation token. + /// The software that subscribes to FilterLists. + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public Task Get(CancellationToken cancellationToken) + { + return CacheGetOrCreateAsync(() => _mediator.Send(new GetSoftware.Query(), cancellationToken)); } } diff --git a/services/Directory/FilterLists.Directory.Api/Controllers/SyntaxesController.cs b/services/Directory/FilterLists.Directory.Api/Controllers/SyntaxesController.cs index 51840b552..2e885a21b 100644 --- a/services/Directory/FilterLists.Directory.Api/Controllers/SyntaxesController.cs +++ b/services/Directory/FilterLists.Directory.Api/Controllers/SyntaxesController.cs @@ -3,27 +3,26 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; -namespace FilterLists.Directory.Api.Controllers +namespace FilterLists.Directory.Api.Controllers; + +public class SyntaxesController : BaseController { - public class SyntaxesController : BaseController + private readonly IMediator _mediator; + + public SyntaxesController(IMemoryCache cache, IMediator mediator) : base(cache) { - private readonly IMediator _mediator; + _mediator = mediator; + } - public SyntaxesController(IMemoryCache cache, IMediator mediator) : base(cache) - { - _mediator = mediator; - } - - /// - /// Gets the syntaxes of FilterLists. - /// - /// The cancellation token. - /// The syntaxes of FilterLists. - [HttpGet] - [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public Task Get(CancellationToken cancellationToken) - { - return CacheGetOrCreateAsync(() => _mediator.Send(new GetSyntaxes.Query(), cancellationToken)); - } + /// + /// Gets the syntaxes of FilterLists. + /// + /// The cancellation token. + /// The syntaxes of FilterLists. + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public Task Get(CancellationToken cancellationToken) + { + return CacheGetOrCreateAsync(() => _mediator.Send(new GetSyntaxes.Query(), cancellationToken)); } } diff --git a/services/Directory/FilterLists.Directory.Api/Controllers/TagsController.cs b/services/Directory/FilterLists.Directory.Api/Controllers/TagsController.cs index 4a4269bff..38d7c1f8b 100644 --- a/services/Directory/FilterLists.Directory.Api/Controllers/TagsController.cs +++ b/services/Directory/FilterLists.Directory.Api/Controllers/TagsController.cs @@ -3,27 +3,26 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; -namespace FilterLists.Directory.Api.Controllers +namespace FilterLists.Directory.Api.Controllers; + +public class TagsController : BaseController { - public class TagsController : BaseController + private readonly IMediator _mediator; + + public TagsController(IMemoryCache cache, IMediator mediator) : base(cache) { - private readonly IMediator _mediator; + _mediator = mediator; + } - public TagsController(IMemoryCache cache, IMediator mediator) : base(cache) - { - _mediator = mediator; - } - - /// - /// Gets the tags of FilterLists. - /// - /// The cancellation token. - /// The tags of FilterLists. - [HttpGet] - [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public Task Get(CancellationToken cancellationToken) - { - return CacheGetOrCreateAsync(() => _mediator.Send(new GetTags.Query(), cancellationToken)); - } + /// + /// Gets the tags of FilterLists. + /// + /// The cancellation token. + /// The tags of FilterLists. + [HttpGet] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public Task Get(CancellationToken cancellationToken) + { + return CacheGetOrCreateAsync(() => _mediator.Send(new GetTags.Query(), cancellationToken)); } } diff --git a/services/Directory/FilterLists.Directory.Api/Program.cs b/services/Directory/FilterLists.Directory.Api/Program.cs index 59463e0b4..4166fb42c 100644 --- a/services/Directory/FilterLists.Directory.Api/Program.cs +++ b/services/Directory/FilterLists.Directory.Api/Program.cs @@ -2,22 +2,21 @@ using FilterLists.Directory.Infrastructure.Persistence; using FilterLists.SharedKernel.Logging; -namespace FilterLists.Directory.Api -{ - public static class Program - { - // TODO: migrate to new hosting model https://docs.microsoft.com/en-us/aspnet/core/migration/50-to-60?view=aspnetcore-6.0&tabs=visual-studio#new-hosting-model - public static async Task Main(string[] args) - { - var host = CreateHostBuilder(args).Build(); - await host.TryRunWithLoggingAsync(async () => await host.MigrateAsync()); - } +namespace FilterLists.Directory.Api; - public static IHostBuilder CreateHostBuilder(string[] args) - { - return Host.CreateDefaultBuilder(args) - .UseApplication() - .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); - } +public static class Program +{ + // TODO: migrate to new hosting model https://docs.microsoft.com/en-us/aspnet/core/migration/50-to-60?view=aspnetcore-6.0&tabs=visual-studio#new-hosting-model + public static async Task Main(string[] args) + { + var host = CreateHostBuilder(args).Build(); + await host.TryRunWithLoggingAsync(async () => await host.MigrateAsync()); + } + + public static IHostBuilder CreateHostBuilder(string[] args) + { + return Host.CreateDefaultBuilder(args) + .UseApplication() + .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); } } diff --git a/services/Directory/FilterLists.Directory.Api/Startup.cs b/services/Directory/FilterLists.Directory.Api/Startup.cs index 275adf83a..2b5001e2a 100644 --- a/services/Directory/FilterLists.Directory.Api/Startup.cs +++ b/services/Directory/FilterLists.Directory.Api/Startup.cs @@ -1,34 +1,33 @@ using System.Text.Json.Serialization; using FilterLists.Directory.Application; -namespace FilterLists.Directory.Api +namespace FilterLists.Directory.Api; + +internal class Startup { - internal class Startup + public Startup(IConfiguration configuration) { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } + Configuration = configuration; + } - public IConfiguration Configuration { get; } + public IConfiguration Configuration { get; } - public void ConfigureServices(IServiceCollection services) - { - services.AddMemoryCache(); - services.AddRouting(o => o.LowercaseUrls = true); - services.AddControllers().AddJsonOptions(o => - o.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull); - services.AddSwaggerGen(); - services.AddApplicationServices(Configuration); - } + public void ConfigureServices(IServiceCollection services) + { + services.AddMemoryCache(); + services.AddRouting(o => o.LowercaseUrls = true); + services.AddControllers().AddJsonOptions(o => + o.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull); + services.AddSwaggerGen(); + services.AddApplicationServices(Configuration); + } - public static void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - app.UseApplication(); - app.UseExceptionHandler(env.IsDevelopment() ? "/error-local-development" : "/error"); - app.UseRouting(); - app.UseEndpoints(e => e.MapControllers()); - app.UseSwagger(); - } + public static void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseApplication(); + app.UseExceptionHandler(env.IsDevelopment() ? "/error-local-development" : "/error"); + app.UseRouting(); + app.UseEndpoints(e => e.MapControllers()); + app.UseSwagger(); } } diff --git a/services/Directory/FilterLists.Directory.Api/SwaggerExtensions.cs b/services/Directory/FilterLists.Directory.Api/SwaggerExtensions.cs index 92097335e..ba68d1de4 100644 --- a/services/Directory/FilterLists.Directory.Api/SwaggerExtensions.cs +++ b/services/Directory/FilterLists.Directory.Api/SwaggerExtensions.cs @@ -1,44 +1,43 @@ using System.Reflection; using Microsoft.OpenApi.Models; -namespace FilterLists.Directory.Api +namespace FilterLists.Directory.Api; + +internal static class SwaggerExtensions { - internal static class SwaggerExtensions + public static void AddSwaggerGen(this IServiceCollection services) { - public static void AddSwaggerGen(this IServiceCollection services) + services.AddSwaggerGen(o => { - services.AddSwaggerGen(o => + o.SwaggerDoc("v1", new OpenApiInfo { - o.SwaggerDoc("v1", new OpenApiInfo + Title = "FilterLists Directory API", + Description = "An ASP.NET Core API serving the core FilterList information.", + Version = "v1", + //TermsOfService = "", + Contact = new OpenApiContact { Name = "FilterLists", Url = new Uri("https://filterlists.com") }, + License = new OpenApiLicense { - Title = "FilterLists Directory API", - Description = "An ASP.NET Core API serving the core FilterList information.", - Version = "v1", - //TermsOfService = "", - Contact = new OpenApiContact { Name = "FilterLists", Url = new Uri("https://filterlists.com") }, - License = new OpenApiLicense - { - Name = "MIT License", - Url = new Uri("https://github.com/collinbarrett/FilterLists/blob/master/LICENSE") - } - }); - - var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; - var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - o.IncludeXmlComments(xmlPath); + Name = "MIT License", + Url = new Uri("https://github.com/collinbarrett/FilterLists/blob/master/LICENSE") + } }); - } - public static void UseSwagger(this IApplicationBuilder app) + var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + o.IncludeXmlComments(xmlPath); + }); + } + + public static void UseSwagger(this IApplicationBuilder app) + { + app.UseSwagger(o => { - app.UseSwagger(o => + o.RouteTemplate = "{documentName}/swagger.json"; + o.PreSerializeFilters.Add((swaggerDoc, httpReq) => swaggerDoc.Servers = new List { - o.RouteTemplate = "{documentName}/swagger.json"; - o.PreSerializeFilters.Add((swaggerDoc, httpReq) => swaggerDoc.Servers = new List - { - new() { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}/api/directory" } - }); + new() { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}/api/directory" } }); - } + }); } } diff --git a/services/Directory/FilterLists.Directory.Application/ConfigurationExtensions.cs b/services/Directory/FilterLists.Directory.Application/ConfigurationExtensions.cs index a685f7e5c..a9fb4981e 100644 --- a/services/Directory/FilterLists.Directory.Application/ConfigurationExtensions.cs +++ b/services/Directory/FilterLists.Directory.Application/ConfigurationExtensions.cs @@ -5,25 +5,24 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace FilterLists.Directory.Application +namespace FilterLists.Directory.Application; + +public static class ConfigurationExtensions { - public static class ConfigurationExtensions + public static IHostBuilder UseApplication(this IHostBuilder hostBuilder) { - public static IHostBuilder UseApplication(this IHostBuilder hostBuilder) - { - return hostBuilder.UseInfrastructure(); - } + return hostBuilder.UseInfrastructure(); + } - public static void AddApplicationServices(this IServiceCollection services, IConfiguration configuration) - { - services.AddMediatR(typeof(ConfigurationExtensions).Assembly); - services.AddAutoMapper(typeof(ConfigurationExtensions).Assembly); - services.AddInfrastructureServices(configuration); - } + public static void AddApplicationServices(this IServiceCollection services, IConfiguration configuration) + { + services.AddMediatR(typeof(ConfigurationExtensions).Assembly); + services.AddAutoMapper(typeof(ConfigurationExtensions).Assembly); + services.AddInfrastructureServices(configuration); + } - public static void UseApplication(this IApplicationBuilder app) - { - app.UseInfrastructure(); - } + public static void UseApplication(this IApplicationBuilder app) + { + app.UseInfrastructure(); } } diff --git a/services/Directory/FilterLists.Directory.Application/Queries/GetLanguages.cs b/services/Directory/FilterLists.Directory.Application/Queries/GetLanguages.cs index 96d311b2f..3c7e365dd 100644 --- a/services/Directory/FilterLists.Directory.Application/Queries/GetLanguages.cs +++ b/services/Directory/FilterLists.Directory.Application/Queries/GetLanguages.cs @@ -5,54 +5,53 @@ using MediatR; using Microsoft.EntityFrameworkCore; -namespace FilterLists.Directory.Application.Queries +namespace FilterLists.Directory.Application.Queries; + +public static class GetLanguages { - public static class GetLanguages + public class Query : IRequest> { - public class Query : IRequest> + } + + internal class Handler : IRequestHandler> + { + private readonly IQueryContext _context; + private readonly IMapper _mapper; + + public Handler(IQueryContext context, IMapper mapper) { + _context = context; + _mapper = mapper; } - internal class Handler : IRequestHandler> + public async Task> Handle( + Query request, + CancellationToken cancellationToken) { - private readonly IQueryContext _context; - private readonly IMapper _mapper; - - public Handler(IQueryContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } - - public async Task> Handle( - Query request, - CancellationToken cancellationToken) - { - return await _context.Languages - .Where(l => l.FilterListLanguages.Any()) - .OrderBy(l => l.Iso6391) - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(cancellationToken); - } - } - - internal class LanguageVmProfile : Profile - { - public LanguageVmProfile() - { - CreateMap() - .ForMember(l => l.FilterListIds, - o => o.MapFrom(l => - l.FilterListLanguages.Select(fll => fll.FilterListId).OrderBy(flid => flid) - .AsEnumerable())); - } - } - - public class LanguageVm - { - public string Iso6391 { get; init; } = null!; - public string Name { get; init; } = null!; - public IEnumerable? FilterListIds { get; init; } + return await _context.Languages + .Where(l => l.FilterListLanguages.Any()) + .OrderBy(l => l.Iso6391) + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(cancellationToken); } } + + internal class LanguageVmProfile : Profile + { + public LanguageVmProfile() + { + CreateMap() + .ForMember(l => l.FilterListIds, + o => o.MapFrom(l => + l.FilterListLanguages.Select(fll => fll.FilterListId).OrderBy(flid => flid) + .AsEnumerable())); + } + } + + public class LanguageVm + { + public string Iso6391 { get; init; } = null!; + public string Name { get; init; } = null!; + public IEnumerable? FilterListIds { get; init; } + } } diff --git a/services/Directory/FilterLists.Directory.Application/Queries/GetLicenses.cs b/services/Directory/FilterLists.Directory.Application/Queries/GetLicenses.cs index 5396cacc4..2951c0061 100644 --- a/services/Directory/FilterLists.Directory.Application/Queries/GetLicenses.cs +++ b/services/Directory/FilterLists.Directory.Application/Queries/GetLicenses.cs @@ -5,56 +5,55 @@ using MediatR; using Microsoft.EntityFrameworkCore; -namespace FilterLists.Directory.Application.Queries +namespace FilterLists.Directory.Application.Queries; + +public static class GetLicenses { - public static class GetLicenses + public class Query : IRequest> { - public class Query : IRequest> + } + + internal class Handler : IRequestHandler> + { + private readonly IQueryContext _context; + private readonly IMapper _mapper; + + public Handler(IQueryContext context, IMapper mapper) { + _context = context; + _mapper = mapper; } - internal class Handler : IRequestHandler> + public async Task> Handle( + Query request, + CancellationToken cancellationToken) { - private readonly IQueryContext _context; - private readonly IMapper _mapper; - - public Handler(IQueryContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } - - public async Task> Handle( - Query request, - CancellationToken cancellationToken) - { - return await _context.Licenses - .OrderBy(l => l.Id) - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(cancellationToken); - } - } - - internal class LicenseVmProfile : Profile - { - public LicenseVmProfile() - { - CreateMap() - .ForMember(l => l.FilterListIds, - o => o.MapFrom(l => - l.FilterLists.Select(fl => fl.Id).OrderBy(flid => flid).AsEnumerable())); - } - } - - public class LicenseVm - { - public int Id { get; init; } - public string Name { get; init; } = null!; - public Uri? Url { get; init; } - public bool PermitsModification { get; init; } - public bool PermitsDistribution { get; init; } - public bool PermitsCommercialUse { get; init; } - public IEnumerable? FilterListIds { get; init; } + return await _context.Licenses + .OrderBy(l => l.Id) + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(cancellationToken); } } + + internal class LicenseVmProfile : Profile + { + public LicenseVmProfile() + { + CreateMap() + .ForMember(l => l.FilterListIds, + o => o.MapFrom(l => + l.FilterLists.Select(fl => fl.Id).OrderBy(flid => flid).AsEnumerable())); + } + } + + public class LicenseVm + { + public int Id { get; init; } + public string Name { get; init; } = null!; + public Uri? Url { get; init; } + public bool PermitsModification { get; init; } + public bool PermitsDistribution { get; init; } + public bool PermitsCommercialUse { get; init; } + public IEnumerable? FilterListIds { get; init; } + } } diff --git a/services/Directory/FilterLists.Directory.Application/Queries/GetListDetails.cs b/services/Directory/FilterLists.Directory.Application/Queries/GetListDetails.cs index 9674cd79d..5dfd317d8 100644 --- a/services/Directory/FilterLists.Directory.Application/Queries/GetListDetails.cs +++ b/services/Directory/FilterLists.Directory.Application/Queries/GetListDetails.cs @@ -6,89 +6,88 @@ using MediatR; using Microsoft.EntityFrameworkCore; -namespace FilterLists.Directory.Application.Queries +namespace FilterLists.Directory.Application.Queries; + +public static class GetListDetails { - public static class GetListDetails + public class Query : IRequest { - public class Query : IRequest + public Query(int id) { - public Query(int id) - { - Id = id; - } - - public int Id { get; } + Id = id; } - internal class Handler : IRequestHandler + public int Id { get; } + } + + internal class Handler : IRequestHandler + { + private readonly IQueryContext _context; + private readonly IMapper _mapper; + + public Handler(IQueryContext context, IMapper mapper) { - private readonly IQueryContext _context; - private readonly IMapper _mapper; - - public Handler(IQueryContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } - - public async Task Handle( - Query request, - CancellationToken cancellationToken) - { - return await _context.FilterLists - .ProjectTo(_mapper.ConfigurationProvider) - .SingleOrDefaultAsync(fl => fl.Id == request.Id, cancellationToken); - } + _context = context; + _mapper = mapper; } - internal class ListDetailsVmProfile : Profile + public async Task Handle( + Query request, + CancellationToken cancellationToken) { - public ListDetailsVmProfile() - { - CreateMap() - .ForMember(fl => fl.SyntaxIds, - o => o.MapFrom(fl => - fl.FilterListSyntaxes.Select(fls => fls.SyntaxId).OrderBy(sid => sid).AsEnumerable())) - .ForMember(fl => fl.Iso6391s, - o => o.MapFrom(fl => - fl.FilterListLanguages.Select(fls => fls.Iso6391).OrderBy(i => i).AsEnumerable())) - .ForMember(fl => fl.TagIds, - o => o.MapFrom(fl => - fl.FilterListTags.Select(flt => flt.TagId).OrderBy(tid => tid).AsEnumerable())) - .ForMember(fl => fl.ViewUrls, - o => o.MapFrom(fl => - fl.ViewUrls.OrderBy(u => u.SegmentNumber).ThenBy(u => u.Primariness).AsEnumerable())) - .ForMember(fl => fl.MaintainerIds, - o => o.MapFrom(fl => - fl.FilterListMaintainers.Select(flm => flm.MaintainerId).OrderBy(mid => mid) - .AsEnumerable())) - .ForMember(fl => fl.UpstreamFilterListIds, - o => o.MapFrom(fl => - fl.UpstreamFilterLists.Select(ufl => ufl.UpstreamFilterListId).OrderBy(flid => flid) - .AsEnumerable())) - .ForMember(fl => fl.ForkFilterListIds, - o => o.MapFrom(fl => - fl.ForkFilterLists.Select(ffl => ffl.ForkFilterListId).OrderBy(flid => flid) - .AsEnumerable())) - .ForMember(fl => fl.IncludedInFilterListIds, - o => o.MapFrom(fl => - fl.IncludedInFilterLists.Select(iifl => iifl.IncludedInFilterListId).OrderBy(flid => flid) - .AsEnumerable())) - .ForMember(fl => fl.IncludesFilterListIds, - o => o.MapFrom(fl => - fl.IncludesFilterLists.Select(ifl => ifl.IncludesFilterListId).OrderBy(flid => flid) - .AsEnumerable())) - .ForMember(fl => fl.DependencyFilterListIds, - o => o.MapFrom(fl => - fl.DependencyFilterLists.Select(dfl => dfl.DependencyFilterListId).OrderBy(flid => flid) - .AsEnumerable())) - .ForMember(fl => fl.DependentFilterListIds, - o => o.MapFrom(fl => - fl.DependentFilterLists.Select(dfl => dfl.DependentFilterListId).OrderBy(flid => flid) - .AsEnumerable())); + return await _context.FilterLists + .ProjectTo(_mapper.ConfigurationProvider) + .SingleOrDefaultAsync(fl => fl.Id == request.Id, cancellationToken); + } + } - CreateMap(); - } + internal class ListDetailsVmProfile : Profile + { + public ListDetailsVmProfile() + { + CreateMap() + .ForMember(fl => fl.SyntaxIds, + o => o.MapFrom(fl => + fl.FilterListSyntaxes.Select(fls => fls.SyntaxId).OrderBy(sid => sid).AsEnumerable())) + .ForMember(fl => fl.Iso6391s, + o => o.MapFrom(fl => + fl.FilterListLanguages.Select(fls => fls.Iso6391).OrderBy(i => i).AsEnumerable())) + .ForMember(fl => fl.TagIds, + o => o.MapFrom(fl => + fl.FilterListTags.Select(flt => flt.TagId).OrderBy(tid => tid).AsEnumerable())) + .ForMember(fl => fl.ViewUrls, + o => o.MapFrom(fl => + fl.ViewUrls.OrderBy(u => u.SegmentNumber).ThenBy(u => u.Primariness).AsEnumerable())) + .ForMember(fl => fl.MaintainerIds, + o => o.MapFrom(fl => + fl.FilterListMaintainers.Select(flm => flm.MaintainerId).OrderBy(mid => mid) + .AsEnumerable())) + .ForMember(fl => fl.UpstreamFilterListIds, + o => o.MapFrom(fl => + fl.UpstreamFilterLists.Select(ufl => ufl.UpstreamFilterListId).OrderBy(flid => flid) + .AsEnumerable())) + .ForMember(fl => fl.ForkFilterListIds, + o => o.MapFrom(fl => + fl.ForkFilterLists.Select(ffl => ffl.ForkFilterListId).OrderBy(flid => flid) + .AsEnumerable())) + .ForMember(fl => fl.IncludedInFilterListIds, + o => o.MapFrom(fl => + fl.IncludedInFilterLists.Select(iifl => iifl.IncludedInFilterListId).OrderBy(flid => flid) + .AsEnumerable())) + .ForMember(fl => fl.IncludesFilterListIds, + o => o.MapFrom(fl => + fl.IncludesFilterLists.Select(ifl => ifl.IncludesFilterListId).OrderBy(flid => flid) + .AsEnumerable())) + .ForMember(fl => fl.DependencyFilterListIds, + o => o.MapFrom(fl => + fl.DependencyFilterLists.Select(dfl => dfl.DependencyFilterListId).OrderBy(flid => flid) + .AsEnumerable())) + .ForMember(fl => fl.DependentFilterListIds, + o => o.MapFrom(fl => + fl.DependentFilterLists.Select(dfl => dfl.DependentFilterListId).OrderBy(flid => flid) + .AsEnumerable())); + + CreateMap(); } } } diff --git a/services/Directory/FilterLists.Directory.Application/Queries/GetLists.cs b/services/Directory/FilterLists.Directory.Application/Queries/GetLists.cs index 3c4effb4a..fc3f83f09 100644 --- a/services/Directory/FilterLists.Directory.Application/Queries/GetLists.cs +++ b/services/Directory/FilterLists.Directory.Application/Queries/GetLists.cs @@ -6,59 +6,58 @@ using MediatR; using Microsoft.EntityFrameworkCore; -namespace FilterLists.Directory.Application.Queries +namespace FilterLists.Directory.Application.Queries; + +public static class GetLists { - public static class GetLists + public class Query : IRequest> { - public class Query : IRequest> + } + + internal class Handler : IRequestHandler> + { + private readonly IQueryContext _context; + private readonly IMapper _mapper; + + public Handler(IQueryContext context, IMapper mapper) { + _context = context; + _mapper = mapper; } - internal class Handler : IRequestHandler> + public async Task> Handle( + Query request, + CancellationToken cancellationToken) { - private readonly IQueryContext _context; - private readonly IMapper _mapper; - - public Handler(IQueryContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } - - public async Task> Handle( - Query request, - CancellationToken cancellationToken) - { - return await _context.FilterLists - .OrderBy(fl => fl.Id) - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(cancellationToken); - } + return await _context.FilterLists + .OrderBy(fl => fl.Id) + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(cancellationToken); } + } - internal class ListVmProfile : Profile + internal class ListVmProfile : Profile + { + public ListVmProfile() { - public ListVmProfile() - { - CreateMap() - .ForMember(fl => fl.SyntaxIds, - o => o.MapFrom(fl => - fl.FilterListSyntaxes.Select(fls => fls.SyntaxId).OrderBy(sid => sid).AsEnumerable())) - .ForMember(fl => fl.Iso6391s, - o => o.MapFrom(fl => - fl.FilterListLanguages.Select(fls => fls.Iso6391).OrderBy(i => i).AsEnumerable())) - .ForMember(fl => fl.TagIds, - o => o.MapFrom(fl => - fl.FilterListTags.Select(flt => flt.TagId).OrderBy(tid => tid).AsEnumerable())) - .ForMember(fl => fl.PrimaryViewUrl, - o => o.MapFrom(fl => - fl.ViewUrls.OrderBy(u => u.SegmentNumber).ThenBy(u => u.Primariness).Select(u => u.Url) - .FirstOrDefault())) - .ForMember(fl => fl.MaintainerIds, - o => o.MapFrom(fl => - fl.FilterListMaintainers.Select(flm => flm.MaintainerId).OrderBy(mid => mid) - .AsEnumerable())); - } + CreateMap() + .ForMember(fl => fl.SyntaxIds, + o => o.MapFrom(fl => + fl.FilterListSyntaxes.Select(fls => fls.SyntaxId).OrderBy(sid => sid).AsEnumerable())) + .ForMember(fl => fl.Iso6391s, + o => o.MapFrom(fl => + fl.FilterListLanguages.Select(fls => fls.Iso6391).OrderBy(i => i).AsEnumerable())) + .ForMember(fl => fl.TagIds, + o => o.MapFrom(fl => + fl.FilterListTags.Select(flt => flt.TagId).OrderBy(tid => tid).AsEnumerable())) + .ForMember(fl => fl.PrimaryViewUrl, + o => o.MapFrom(fl => + fl.ViewUrls.OrderBy(u => u.SegmentNumber).ThenBy(u => u.Primariness).Select(u => u.Url) + .FirstOrDefault())) + .ForMember(fl => fl.MaintainerIds, + o => o.MapFrom(fl => + fl.FilterListMaintainers.Select(flm => flm.MaintainerId).OrderBy(mid => mid) + .AsEnumerable())); } } } diff --git a/services/Directory/FilterLists.Directory.Application/Queries/GetMaintainers.cs b/services/Directory/FilterLists.Directory.Application/Queries/GetMaintainers.cs index f72b13042..6d0154ab5 100644 --- a/services/Directory/FilterLists.Directory.Application/Queries/GetMaintainers.cs +++ b/services/Directory/FilterLists.Directory.Application/Queries/GetMaintainers.cs @@ -5,56 +5,55 @@ using MediatR; using Microsoft.EntityFrameworkCore; -namespace FilterLists.Directory.Application.Queries +namespace FilterLists.Directory.Application.Queries; + +public static class GetMaintainers { - public static class GetMaintainers + public class Query : IRequest> { - public class Query : IRequest> + } + + internal class Handler : IRequestHandler> + { + private readonly IQueryContext _context; + private readonly IMapper _mapper; + + public Handler(IQueryContext context, IMapper mapper) { + _context = context; + _mapper = mapper; } - internal class Handler : IRequestHandler> + public async Task> Handle( + Query request, + CancellationToken cancellationToken) { - private readonly IQueryContext _context; - private readonly IMapper _mapper; - - public Handler(IQueryContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } - - public async Task> Handle( - Query request, - CancellationToken cancellationToken) - { - return await _context.Maintainers - .OrderBy(m => m.Id) - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(cancellationToken); - } - } - - internal class MaintainerVmProfile : Profile - { - public MaintainerVmProfile() - { - CreateMap() - .ForMember(m => m.FilterListIds, - o => o.MapFrom(m => - m.FilterListMaintainers.Select(flm => flm.FilterListId).OrderBy(flid => flid) - .AsEnumerable())); - } - } - - public class MaintainerVm - { - public int Id { get; init; } - public string Name { get; init; } = null!; - public Uri? Url { get; init; } - public string? EmailAddress { get; init; } - public string? TwitterHandle { get; init; } - public IEnumerable? FilterListIds { get; init; } + return await _context.Maintainers + .OrderBy(m => m.Id) + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(cancellationToken); } } + + internal class MaintainerVmProfile : Profile + { + public MaintainerVmProfile() + { + CreateMap() + .ForMember(m => m.FilterListIds, + o => o.MapFrom(m => + m.FilterListMaintainers.Select(flm => flm.FilterListId).OrderBy(flid => flid) + .AsEnumerable())); + } + } + + public class MaintainerVm + { + public int Id { get; init; } + public string Name { get; init; } = null!; + public Uri? Url { get; init; } + public string? EmailAddress { get; init; } + public string? TwitterHandle { get; init; } + public IEnumerable? FilterListIds { get; init; } + } } diff --git a/services/Directory/FilterLists.Directory.Application/Queries/GetSoftware.cs b/services/Directory/FilterLists.Directory.Application/Queries/GetSoftware.cs index 5928d91ec..c8ee8f1cf 100644 --- a/services/Directory/FilterLists.Directory.Application/Queries/GetSoftware.cs +++ b/services/Directory/FilterLists.Directory.Application/Queries/GetSoftware.cs @@ -5,56 +5,55 @@ using MediatR; using Microsoft.EntityFrameworkCore; -namespace FilterLists.Directory.Application.Queries +namespace FilterLists.Directory.Application.Queries; + +public static class GetSoftware { - public static class GetSoftware + public class Query : IRequest> { - public class Query : IRequest> + } + + internal class Handler : IRequestHandler> + { + private readonly IQueryContext _context; + private readonly IMapper _mapper; + + public Handler(IQueryContext context, IMapper mapper) { + _context = context; + _mapper = mapper; } - internal class Handler : IRequestHandler> + public async Task> Handle( + Query request, + CancellationToken cancellationToken) { - private readonly IQueryContext _context; - private readonly IMapper _mapper; - - public Handler(IQueryContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } - - public async Task> Handle( - Query request, - CancellationToken cancellationToken) - { - return await _context.Software - .OrderBy(s => s.Id) - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(cancellationToken); - } - } - - internal class SoftwareVmProfile : Profile - { - public SoftwareVmProfile() - { - CreateMap() - .ForMember(s => s.SyntaxIds, - o => o.MapFrom(s => - s.SoftwareSyntaxes.Select(ss => ss.SyntaxId).OrderBy(sid => sid).AsEnumerable())); - } - } - - public class SoftwareVm - { - public int Id { get; init; } - public string Name { get; init; } = null!; - public string? Description { get; init; } - public Uri? HomeUrl { get; init; } - public Uri? DownloadUrl { get; init; } - public bool SupportsAbpUrlScheme { get; init; } - public IEnumerable? SyntaxIds { get; init; } + return await _context.Software + .OrderBy(s => s.Id) + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(cancellationToken); } } + + internal class SoftwareVmProfile : Profile + { + public SoftwareVmProfile() + { + CreateMap() + .ForMember(s => s.SyntaxIds, + o => o.MapFrom(s => + s.SoftwareSyntaxes.Select(ss => ss.SyntaxId).OrderBy(sid => sid).AsEnumerable())); + } + } + + public class SoftwareVm + { + public int Id { get; init; } + public string Name { get; init; } = null!; + public string? Description { get; init; } + public Uri? HomeUrl { get; init; } + public Uri? DownloadUrl { get; init; } + public bool SupportsAbpUrlScheme { get; init; } + public IEnumerable? SyntaxIds { get; init; } + } } diff --git a/services/Directory/FilterLists.Directory.Application/Queries/GetSyntaxes.cs b/services/Directory/FilterLists.Directory.Application/Queries/GetSyntaxes.cs index df5d1fe15..40db5cac6 100644 --- a/services/Directory/FilterLists.Directory.Application/Queries/GetSyntaxes.cs +++ b/services/Directory/FilterLists.Directory.Application/Queries/GetSyntaxes.cs @@ -5,58 +5,57 @@ using MediatR; using Microsoft.EntityFrameworkCore; -namespace FilterLists.Directory.Application.Queries +namespace FilterLists.Directory.Application.Queries; + +public static class GetSyntaxes { - public static class GetSyntaxes + public class Query : IRequest> { - public class Query : IRequest> + } + + internal class Handler : IRequestHandler> + { + private readonly IQueryContext _context; + private readonly IMapper _mapper; + + public Handler(IQueryContext context, IMapper mapper) { + _context = context; + _mapper = mapper; } - internal class Handler : IRequestHandler> + public async Task> Handle( + Query request, + CancellationToken cancellationToken) { - private readonly IQueryContext _context; - private readonly IMapper _mapper; - - public Handler(IQueryContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } - - public async Task> Handle( - Query request, - CancellationToken cancellationToken) - { - return await _context.Syntaxes - .OrderBy(s => s.Id) - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(cancellationToken); - } - } - - internal class SyntaxVmProfile : Profile - { - public SyntaxVmProfile() - { - CreateMap() - .ForMember(s => s.FilterListIds, - o => o.MapFrom(s => - s.FilterListSyntaxes.Select(sls => sls.FilterListId).OrderBy(flid => flid).AsEnumerable())) - .ForMember(s => s.SoftwareIds, - o => o.MapFrom(s => - s.SoftwareSyntaxes.Select(ss => ss.SoftwareId).OrderBy(sid => sid).AsEnumerable())); - } - } - - public class SyntaxVm - { - public int Id { get; init; } - public string Name { get; init; } = null!; - public string? Description { get; init; } - public Uri? Url { get; init; } - public IEnumerable? FilterListIds { get; init; } - public IEnumerable? SoftwareIds { get; init; } + return await _context.Syntaxes + .OrderBy(s => s.Id) + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(cancellationToken); } } + + internal class SyntaxVmProfile : Profile + { + public SyntaxVmProfile() + { + CreateMap() + .ForMember(s => s.FilterListIds, + o => o.MapFrom(s => + s.FilterListSyntaxes.Select(sls => sls.FilterListId).OrderBy(flid => flid).AsEnumerable())) + .ForMember(s => s.SoftwareIds, + o => o.MapFrom(s => + s.SoftwareSyntaxes.Select(ss => ss.SoftwareId).OrderBy(sid => sid).AsEnumerable())); + } + } + + public class SyntaxVm + { + public int Id { get; init; } + public string Name { get; init; } = null!; + public string? Description { get; init; } + public Uri? Url { get; init; } + public IEnumerable? FilterListIds { get; init; } + public IEnumerable? SoftwareIds { get; init; } + } } diff --git a/services/Directory/FilterLists.Directory.Application/Queries/GetTags.cs b/services/Directory/FilterLists.Directory.Application/Queries/GetTags.cs index 71ce784d7..3f3410deb 100644 --- a/services/Directory/FilterLists.Directory.Application/Queries/GetTags.cs +++ b/services/Directory/FilterLists.Directory.Application/Queries/GetTags.cs @@ -5,53 +5,52 @@ using MediatR; using Microsoft.EntityFrameworkCore; -namespace FilterLists.Directory.Application.Queries +namespace FilterLists.Directory.Application.Queries; + +public static class GetTags { - public static class GetTags + public class Query : IRequest> { - public class Query : IRequest> + } + + internal class Handler : IRequestHandler> + { + private readonly IQueryContext _context; + private readonly IMapper _mapper; + + public Handler(IQueryContext context, IMapper mapper) { + _context = context; + _mapper = mapper; } - internal class Handler : IRequestHandler> + public async Task> Handle( + Query request, + CancellationToken cancellationToken) { - private readonly IQueryContext _context; - private readonly IMapper _mapper; - - public Handler(IQueryContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } - - public async Task> Handle( - Query request, - CancellationToken cancellationToken) - { - return await _context.Tags - .OrderBy(t => t.Id) - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(cancellationToken); - } - } - - internal class TagVmProfile : Profile - { - public TagVmProfile() - { - CreateMap() - .ForMember(t => t.FilterListIds, - o => o.MapFrom(t => - t.FilterListTags.Select(flt => flt.FilterListId).OrderBy(flid => flid).AsEnumerable())); - } - } - - public class TagVm - { - public int Id { get; init; } - public string Name { get; init; } = null!; - public string? Description { get; init; } - public IEnumerable? FilterListIds { get; init; } + return await _context.Tags + .OrderBy(t => t.Id) + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(cancellationToken); } } + + internal class TagVmProfile : Profile + { + public TagVmProfile() + { + CreateMap() + .ForMember(t => t.FilterListIds, + o => o.MapFrom(t => + t.FilterListTags.Select(flt => flt.FilterListId).OrderBy(flid => flid).AsEnumerable())); + } + } + + public class TagVm + { + public int Id { get; init; } + public string Name { get; init; } = null!; + public string? Description { get; init; } + public IEnumerable? FilterListIds { get; init; } + } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure.Migrations.Tests/SeedQueryDbContextTest.cs b/services/Directory/FilterLists.Directory.Infrastructure.Migrations.Tests/SeedQueryDbContextTest.cs index 6bd660127..b21688cd8 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure.Migrations.Tests/SeedQueryDbContextTest.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure.Migrations.Tests/SeedQueryDbContextTest.cs @@ -3,25 +3,24 @@ using Microsoft.EntityFrameworkCore; using Xunit; -namespace FilterLists.Directory.Infrastructure.Migrations.Tests +namespace FilterLists.Directory.Infrastructure.Migrations.Tests; + +public class SeedQueryDbContextTest { - public class SeedQueryDbContextTest + [Fact] + public async Task Migrate_DoesNotThrowException() { - [Fact] - public async Task Migrate_DoesNotThrowException() + var exception = await Record.ExceptionAsync(async () => { - var exception = await Record.ExceptionAsync(async () => - { - var connString = Environment.GetEnvironmentVariable("ConnectionStrings__DirectoryConnection") ?? - throw new Exception(); - var options = new DbContextOptionsBuilder() - .UseNpgsql(connString, m => m.MigrationsAssembly(typeof(Initial).Assembly.GetName().Name)) - .EnableSensitiveDataLogging() - .Options; - await using var context = new QueryDbContext(options); - await context.Database.MigrateAsync(); - }); - Assert.Null(exception); - } + var connString = Environment.GetEnvironmentVariable("ConnectionStrings__DirectoryConnection") ?? + throw new Exception(); + var options = new DbContextOptionsBuilder() + .UseNpgsql(connString, m => m.MigrationsAssembly(typeof(Initial).Assembly.GetName().Name)) + .EnableSensitiveDataLogging() + .Options; + await using var context = new QueryDbContext(options); + await context.Database.MigrateAsync(); + }); + Assert.Null(exception); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/ConfigurationExtensions.cs b/services/Directory/FilterLists.Directory.Infrastructure/ConfigurationExtensions.cs index 33b9bfc26..1616dee26 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/ConfigurationExtensions.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/ConfigurationExtensions.cs @@ -6,29 +6,28 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace FilterLists.Directory.Infrastructure +namespace FilterLists.Directory.Infrastructure; + +public static class ConfigurationExtensions { - public static class ConfigurationExtensions + public static IHostBuilder UseInfrastructure(this IHostBuilder hostBuilder) { - public static IHostBuilder UseInfrastructure(this IHostBuilder hostBuilder) - { - return hostBuilder.UseLogging(); - } + return hostBuilder.UseLogging(); + } - public static void AddInfrastructureServices(this IServiceCollection services, IConfiguration configuration) + public static void AddInfrastructureServices(this IServiceCollection services, IConfiguration configuration) + { + services.AddSharedKernelLogging(configuration); + services.AddDbContextPool(o => { - services.AddSharedKernelLogging(configuration); - services.AddDbContextPool(o => - { - o.UseNpgsql(configuration.GetConnectionString("DirectoryConnection"), - po => po.MigrationsAssembly("FilterLists.Directory.Infrastructure.Migrations")); - }); - services.AddScoped(); - } + o.UseNpgsql(configuration.GetConnectionString("DirectoryConnection"), + po => po.MigrationsAssembly("FilterLists.Directory.Infrastructure.Migrations")); + }); + services.AddScoped(); + } - public static void UseInfrastructure(this IApplicationBuilder app) - { - app.UseLogging(); - } + public static void UseInfrastructure(this IApplicationBuilder app) + { + app.UseLogging(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/IQueryContext.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/IQueryContext.cs index a36abd6e8..607226e28 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/IQueryContext.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/IQueryContext.cs @@ -1,15 +1,14 @@ using FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Context +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Context; + +public interface IQueryContext { - public interface IQueryContext - { - IQueryable FilterLists { get; } - IQueryable Languages { get; } - IQueryable Licenses { get; } - IQueryable Maintainers { get; } - IQueryable Software { get; } - IQueryable Syntaxes { get; } - IQueryable Tags { get; } - } + IQueryable FilterLists { get; } + IQueryable Languages { get; } + IQueryable Licenses { get; } + IQueryable Maintainers { get; } + IQueryable Software { get; } + IQueryable Syntaxes { get; } + IQueryable Tags { get; } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/QueryContext.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/QueryContext.cs index 5aed830d9..ca9893c7d 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/QueryContext.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/QueryContext.cs @@ -1,28 +1,27 @@ using FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; using Microsoft.EntityFrameworkCore; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Context +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Context; + +internal class QueryContext : IQueryContext, IAsyncDisposable { - internal class QueryContext : IQueryContext, IAsyncDisposable + private readonly QueryDbContext _dbContext; + + public QueryContext(QueryDbContext dbContext) { - private readonly QueryDbContext _dbContext; - - public QueryContext(QueryDbContext dbContext) - { - _dbContext = dbContext; - } - - public async ValueTask DisposeAsync() - { - await _dbContext.DisposeAsync(); - } - - public IQueryable FilterLists => _dbContext.FilterLists.AsNoTracking(); - public IQueryable Languages => _dbContext.Languages.AsNoTracking(); - public IQueryable Licenses => _dbContext.Licenses.AsNoTracking(); - public IQueryable Maintainers => _dbContext.Maintainers.AsNoTracking(); - public IQueryable Software => _dbContext.Software.AsNoTracking(); - public IQueryable Syntaxes => _dbContext.Syntaxes.AsNoTracking(); - public IQueryable Tags => _dbContext.Tags.AsNoTracking(); + _dbContext = dbContext; } + + public async ValueTask DisposeAsync() + { + await _dbContext.DisposeAsync(); + } + + public IQueryable FilterLists => _dbContext.FilterLists.AsNoTracking(); + public IQueryable Languages => _dbContext.Languages.AsNoTracking(); + public IQueryable Licenses => _dbContext.Licenses.AsNoTracking(); + public IQueryable Maintainers => _dbContext.Maintainers.AsNoTracking(); + public IQueryable Software => _dbContext.Software.AsNoTracking(); + public IQueryable Syntaxes => _dbContext.Syntaxes.AsNoTracking(); + public IQueryable Tags => _dbContext.Tags.AsNoTracking(); } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/QueryDbContext.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/QueryDbContext.cs index a37ac3fa3..04b144d5d 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/QueryDbContext.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Context/QueryDbContext.cs @@ -1,37 +1,36 @@ using FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; using Microsoft.EntityFrameworkCore; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Context +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Context; + +public class QueryDbContext : DbContext { - public class QueryDbContext : DbContext + public QueryDbContext(DbContextOptions options) : base(options) { - public QueryDbContext(DbContextOptions options) : base(options) - { - } + } - public DbSet FilterLists => Set(); - public DbSet Languages => Set(); - public DbSet Licenses => Set(); - public DbSet Maintainers => Set(); - public DbSet Software => Set(); - public DbSet Syntaxes => Set(); - public DbSet Tags => Set(); + public DbSet FilterLists => Set(); + public DbSet Languages => Set(); + public DbSet Licenses => Set(); + public DbSet Maintainers => Set(); + public DbSet Software => Set(); + public DbSet Syntaxes => Set(); + public DbSet Tags => Set(); - public override int SaveChanges(bool acceptAllChangesOnSuccess) - { - throw new InvalidOperationException("This context is read-only."); - } + public override int SaveChanges(bool acceptAllChangesOnSuccess) + { + throw new InvalidOperationException("This context is read-only."); + } - public override Task SaveChangesAsync( - bool acceptAllChangesOnSuccess, - CancellationToken cancellationToken = default) - { - throw new InvalidOperationException("This context is read-only."); - } + public override Task SaveChangesAsync( + bool acceptAllChangesOnSuccess, + CancellationToken cancellationToken = default) + { + throw new InvalidOperationException("This context is read-only."); + } - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly); - } + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Dependent.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Dependent.cs index 39be9c67f..469f1b1bb 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Dependent.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Dependent.cs @@ -1,29 +1,28 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class Dependent - { - public int DependencyFilterListId { get; init; } - public FilterList DependencyFilterList { get; } = null!; - public int DependentFilterListId { get; init; } - public FilterList DependentFilterList { get; } = null!; - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class DependentTypeConfiguration : IEntityTypeConfiguration +public class Dependent +{ + public int DependencyFilterListId { get; init; } + public FilterList DependencyFilterList { get; } = null!; + public int DependentFilterListId { get; init; } + public FilterList DependentFilterList { get; } = null!; +} + +internal class DependentTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.ToTable(nameof(Dependent) + "s"); - builder.HasKey(d => new { d.DependencyFilterListId, d.DependentFilterListId }); - builder.HasOne(d => d.DependencyFilterList) - .WithMany(fl => fl.DependentFilterLists) - .HasForeignKey(d => d.DependencyFilterListId); - builder.HasOne(d => d.DependentFilterList) - .WithMany(fl => fl.DependencyFilterLists) - .HasForeignKey(d => d.DependentFilterListId); - builder.HasDataJsonFile(); - } + builder.ToTable(nameof(Dependent) + "s"); + builder.HasKey(d => new { d.DependencyFilterListId, d.DependentFilterListId }); + builder.HasOne(d => d.DependencyFilterList) + .WithMany(fl => fl.DependentFilterLists) + .HasForeignKey(d => d.DependencyFilterListId); + builder.HasOne(d => d.DependentFilterList) + .WithMany(fl => fl.DependencyFilterLists) + .HasForeignKey(d => d.DependentFilterListId); + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterList.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterList.cs index c60e219ca..edb07d107 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterList.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterList.cs @@ -1,42 +1,41 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class FilterList - { - public int Id { get; init; } - public string Name { get; init; } = null!; - public string? Description { get; init; } - public int? LicenseId { get; init; } - public License? License { get; } - public IReadOnlyCollection FilterListSyntaxes { get; } = new HashSet(); - public IReadOnlyCollection FilterListLanguages { get; } = new HashSet(); - public IReadOnlyCollection FilterListTags { get; } = new HashSet(); - public IReadOnlyCollection ViewUrls { get; } = new HashSet(); - public Uri? HomeUrl { get; init; } - public Uri? OnionUrl { get; init; } - public Uri? PolicyUrl { get; init; } - public Uri? SubmissionUrl { get; init; } - public Uri? IssuesUrl { get; init; } - public Uri? ForumUrl { get; init; } - public Uri? ChatUrl { get; init; } - public string? EmailAddress { get; init; } - public Uri? DonateUrl { get; init; } - public IReadOnlyCollection FilterListMaintainers { get; } = new HashSet(); - public IReadOnlyCollection UpstreamFilterLists { get; } = new HashSet(); - public IReadOnlyCollection ForkFilterLists { get; } = new HashSet(); - public IReadOnlyCollection IncludedInFilterLists { get; } = new HashSet(); - public IReadOnlyCollection IncludesFilterLists { get; } = new HashSet(); - public IReadOnlyCollection DependencyFilterLists { get; } = new HashSet(); - public IReadOnlyCollection DependentFilterLists { get; } = new HashSet(); - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class FilterListTypeConfiguration : IEntityTypeConfiguration +public class FilterList +{ + public int Id { get; init; } + public string Name { get; init; } = null!; + public string? Description { get; init; } + public int? LicenseId { get; init; } + public License? License { get; } + public IReadOnlyCollection FilterListSyntaxes { get; } = new HashSet(); + public IReadOnlyCollection FilterListLanguages { get; } = new HashSet(); + public IReadOnlyCollection FilterListTags { get; } = new HashSet(); + public IReadOnlyCollection ViewUrls { get; } = new HashSet(); + public Uri? HomeUrl { get; init; } + public Uri? OnionUrl { get; init; } + public Uri? PolicyUrl { get; init; } + public Uri? SubmissionUrl { get; init; } + public Uri? IssuesUrl { get; init; } + public Uri? ForumUrl { get; init; } + public Uri? ChatUrl { get; init; } + public string? EmailAddress { get; init; } + public Uri? DonateUrl { get; init; } + public IReadOnlyCollection FilterListMaintainers { get; } = new HashSet(); + public IReadOnlyCollection UpstreamFilterLists { get; } = new HashSet(); + public IReadOnlyCollection ForkFilterLists { get; } = new HashSet(); + public IReadOnlyCollection IncludedInFilterLists { get; } = new HashSet(); + public IReadOnlyCollection IncludesFilterLists { get; } = new HashSet(); + public IReadOnlyCollection DependencyFilterLists { get; } = new HashSet(); + public IReadOnlyCollection DependentFilterLists { get; } = new HashSet(); +} + +internal class FilterListTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.HasDataJsonFile(); - } + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListLanguage.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListLanguage.cs index 458b952fb..b0a53adb7 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListLanguage.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListLanguage.cs @@ -1,23 +1,22 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class FilterListLanguage - { - public int FilterListId { get; init; } - public FilterList FilterList { get; } = null!; - public string Iso6391 { get; init; } = null!; - public Language Language { get; } = null!; - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class FilterListLanguageTypeConfiguration : IEntityTypeConfiguration +public class FilterListLanguage +{ + public int FilterListId { get; init; } + public FilterList FilterList { get; } = null!; + public string Iso6391 { get; init; } = null!; + public Language Language { get; } = null!; +} + +internal class FilterListLanguageTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.ToTable(nameof(FilterListLanguage) + "s"); - builder.HasKey(fll => new { fll.FilterListId, fll.Iso6391 }); - builder.HasDataJsonFile(); - } + builder.ToTable(nameof(FilterListLanguage) + "s"); + builder.HasKey(fll => new { fll.FilterListId, fll.Iso6391 }); + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListMaintainer.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListMaintainer.cs index cabdc3c96..cdd3a703c 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListMaintainer.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListMaintainer.cs @@ -1,23 +1,22 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class FilterListMaintainer - { - public int FilterListId { get; init; } - public FilterList FilterList { get; } = null!; - public int MaintainerId { get; init; } - public Maintainer Maintainer { get; } = null!; - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class FilterListMaintainerTypeConfiguration : IEntityTypeConfiguration +public class FilterListMaintainer +{ + public int FilterListId { get; init; } + public FilterList FilterList { get; } = null!; + public int MaintainerId { get; init; } + public Maintainer Maintainer { get; } = null!; +} + +internal class FilterListMaintainerTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.ToTable(nameof(FilterListMaintainer) + "s"); - builder.HasKey(flm => new { flm.FilterListId, flm.MaintainerId }); - builder.HasDataJsonFile(); - } + builder.ToTable(nameof(FilterListMaintainer) + "s"); + builder.HasKey(flm => new { flm.FilterListId, flm.MaintainerId }); + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListSyntax.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListSyntax.cs index 4fbd1cb46..7497a2677 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListSyntax.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListSyntax.cs @@ -1,23 +1,22 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class FilterListSyntax - { - public int FilterListId { get; init; } - public FilterList FilterList { get; } = null!; - public int SyntaxId { get; init; } - public Syntax Syntax { get; } = null!; - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class FilterListSyntaxTypeConfiguration : IEntityTypeConfiguration +public class FilterListSyntax +{ + public int FilterListId { get; init; } + public FilterList FilterList { get; } = null!; + public int SyntaxId { get; init; } + public Syntax Syntax { get; } = null!; +} + +internal class FilterListSyntaxTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.ToTable(nameof(FilterListSyntax) + "es"); - builder.HasKey(fls => new { fls.FilterListId, fls.SyntaxId }); - builder.HasDataJsonFile(); - } + builder.ToTable(nameof(FilterListSyntax) + "es"); + builder.HasKey(fls => new { fls.FilterListId, fls.SyntaxId }); + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListTag.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListTag.cs index a72b725f8..2177e2ce9 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListTag.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListTag.cs @@ -1,23 +1,22 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class FilterListTag - { - public int FilterListId { get; init; } - public FilterList FilterList { get; } = null!; - public int TagId { get; init; } - public Tag Tag { get; } = null!; - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class FilterListTagTypeConfiguration : IEntityTypeConfiguration +public class FilterListTag +{ + public int FilterListId { get; init; } + public FilterList FilterList { get; } = null!; + public int TagId { get; init; } + public Tag Tag { get; } = null!; +} + +internal class FilterListTagTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.ToTable(nameof(FilterListTag) + "s"); - builder.HasKey(flt => new { flt.FilterListId, flt.TagId }); - builder.HasDataJsonFile(); - } + builder.ToTable(nameof(FilterListTag) + "s"); + builder.HasKey(flt => new { flt.FilterListId, flt.TagId }); + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListViewUrl.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListViewUrl.cs index 9c2f7e10c..f83b5f1ce 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListViewUrl.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/FilterListViewUrl.cs @@ -1,27 +1,26 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class FilterListViewUrl - { - public int Id { get; init; } - public int FilterListId { get; init; } - public FilterList FilterList { get; } = null!; - public short SegmentNumber { get; init; } - public short Primariness { get; init; } - public Uri Url { get; init; } = null!; - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class FilterListViewUrlConfiguration : IEntityTypeConfiguration +public class FilterListViewUrl +{ + public int Id { get; init; } + public int FilterListId { get; init; } + public FilterList FilterList { get; } = null!; + public short SegmentNumber { get; init; } + public short Primariness { get; init; } + public Uri Url { get; init; } = null!; +} + +internal class FilterListViewUrlConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.ToTable(nameof(FilterListViewUrl) + "s"); - builder.Property(u => u.SegmentNumber).HasDefaultValue(1); - builder.Property(u => u.Primariness).HasDefaultValue(1); - builder.HasIndex(u => new { u.FilterListId, u.SegmentNumber, u.Primariness }).IsUnique(); - builder.HasDataJsonFile(); - } + builder.ToTable(nameof(FilterListViewUrl) + "s"); + builder.Property(u => u.SegmentNumber).HasDefaultValue(1); + builder.Property(u => u.Primariness).HasDefaultValue(1); + builder.HasIndex(u => new { u.FilterListId, u.SegmentNumber, u.Primariness }).IsUnique(); + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Fork.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Fork.cs index 22349247f..d38613686 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Fork.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Fork.cs @@ -1,29 +1,28 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class Fork - { - public int UpstreamFilterListId { get; init; } - public FilterList UpstreamFilterList { get; } = null!; - public int ForkFilterListId { get; init; } - public FilterList ForkFilterList { get; } = null!; - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class ForkTypeConfiguration : IEntityTypeConfiguration +public class Fork +{ + public int UpstreamFilterListId { get; init; } + public FilterList UpstreamFilterList { get; } = null!; + public int ForkFilterListId { get; init; } + public FilterList ForkFilterList { get; } = null!; +} + +internal class ForkTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.ToTable(nameof(Fork) + "s"); - builder.HasKey(f => new { f.UpstreamFilterListId, f.ForkFilterListId }); - builder.HasOne(f => f.UpstreamFilterList) - .WithMany(fl => fl.ForkFilterLists) - .HasForeignKey(f => f.UpstreamFilterListId); - builder.HasOne(f => f.ForkFilterList) - .WithMany(fl => fl.UpstreamFilterLists) - .HasForeignKey(f => f.ForkFilterListId); - builder.HasDataJsonFile(); - } + builder.ToTable(nameof(Fork) + "s"); + builder.HasKey(f => new { f.UpstreamFilterListId, f.ForkFilterListId }); + builder.HasOne(f => f.UpstreamFilterList) + .WithMany(fl => fl.ForkFilterLists) + .HasForeignKey(f => f.UpstreamFilterListId); + builder.HasOne(f => f.ForkFilterList) + .WithMany(fl => fl.UpstreamFilterLists) + .HasForeignKey(f => f.ForkFilterListId); + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Language.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Language.cs index 9a84f2375..fc9899d98 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Language.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Language.cs @@ -1,24 +1,23 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class Language - { - public string Iso6391 { get; init; } = null!; - public string Name { get; init; } = null!; - public IReadOnlyCollection FilterListLanguages { get; } = new HashSet(); - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class LanguageTypeConfiguration : IEntityTypeConfiguration +public class Language +{ + public string Iso6391 { get; init; } = null!; + public string Name { get; init; } = null!; + public IReadOnlyCollection FilterListLanguages { get; } = new HashSet(); +} + +internal class LanguageTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.HasKey(l => l.Iso6391); - builder.Property(l => l.Iso6391) - .IsFixedLength() - .HasMaxLength(2); - builder.HasDataJsonFile(); - } + builder.HasKey(l => l.Iso6391); + builder.Property(l => l.Iso6391) + .IsFixedLength() + .HasMaxLength(2); + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/License.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/License.cs index 47b34461c..1a346d177 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/License.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/License.cs @@ -1,24 +1,23 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class License - { - public int Id { get; init; } - public string Name { get; init; } = null!; - public Uri? Url { get; init; } - public bool PermitsModification { get; init; } - public bool PermitsDistribution { get; init; } - public bool PermitsCommercialUse { get; init; } - public IReadOnlyCollection FilterLists { get; } = new HashSet(); - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class LicenseTypeConfiguration : IEntityTypeConfiguration +public class License +{ + public int Id { get; init; } + public string Name { get; init; } = null!; + public Uri? Url { get; init; } + public bool PermitsModification { get; init; } + public bool PermitsDistribution { get; init; } + public bool PermitsCommercialUse { get; init; } + public IReadOnlyCollection FilterLists { get; } = new HashSet(); +} + +internal class LicenseTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.HasDataJsonFile(); - } + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Maintainer.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Maintainer.cs index fdf7791d2..3bc34167b 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Maintainer.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Maintainer.cs @@ -1,23 +1,22 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class Maintainer - { - public int Id { get; init; } - public string Name { get; init; } = null!; - public Uri? Url { get; init; } - public string? EmailAddress { get; init; } - public string? TwitterHandle { get; init; } - public IReadOnlyCollection FilterListMaintainers { get; } = new HashSet(); - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class MaintainerTypeConfiguration : IEntityTypeConfiguration +public class Maintainer +{ + public int Id { get; init; } + public string Name { get; init; } = null!; + public Uri? Url { get; init; } + public string? EmailAddress { get; init; } + public string? TwitterHandle { get; init; } + public IReadOnlyCollection FilterListMaintainers { get; } = new HashSet(); +} + +internal class MaintainerTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.HasDataJsonFile(); - } + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Merge.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Merge.cs index 62a0a59c0..1f3248daf 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Merge.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Merge.cs @@ -1,29 +1,28 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class Merge - { - public int IncludedInFilterListId { get; init; } - public FilterList IncludedInFilterList { get; } = null!; - public int IncludesFilterListId { get; init; } - public FilterList IncludesFilterList { get; } = null!; - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class MergeTypeConfiguration : IEntityTypeConfiguration +public class Merge +{ + public int IncludedInFilterListId { get; init; } + public FilterList IncludedInFilterList { get; } = null!; + public int IncludesFilterListId { get; init; } + public FilterList IncludesFilterList { get; } = null!; +} + +internal class MergeTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.ToTable(nameof(Merge) + "s"); - builder.HasKey(m => new { m.IncludedInFilterListId, m.IncludesFilterListId }); - builder.HasOne(m => m.IncludedInFilterList) - .WithMany(fl => fl.IncludesFilterLists) - .HasForeignKey(m => m.IncludedInFilterListId); - builder.HasOne(m => m.IncludesFilterList) - .WithMany(fl => fl.IncludedInFilterLists) - .HasForeignKey(m => m.IncludesFilterListId); - builder.HasDataJsonFile(); - } + builder.ToTable(nameof(Merge) + "s"); + builder.HasKey(m => new { m.IncludedInFilterListId, m.IncludesFilterListId }); + builder.HasOne(m => m.IncludedInFilterList) + .WithMany(fl => fl.IncludesFilterLists) + .HasForeignKey(m => m.IncludedInFilterListId); + builder.HasOne(m => m.IncludesFilterList) + .WithMany(fl => fl.IncludedInFilterLists) + .HasForeignKey(m => m.IncludesFilterListId); + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Software.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Software.cs index 3cb91bdde..2e02da41a 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Software.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Software.cs @@ -1,24 +1,23 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class Software - { - public int Id { get; init; } - public string Name { get; init; } = null!; - public string? Description { get; init; } - public Uri? HomeUrl { get; init; } - public Uri? DownloadUrl { get; init; } - public bool SupportsAbpUrlScheme { get; init; } - public IReadOnlyCollection SoftwareSyntaxes { get; } = new HashSet(); - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class SoftwareTypeConfiguration : IEntityTypeConfiguration +public class Software +{ + public int Id { get; init; } + public string Name { get; init; } = null!; + public string? Description { get; init; } + public Uri? HomeUrl { get; init; } + public Uri? DownloadUrl { get; init; } + public bool SupportsAbpUrlScheme { get; init; } + public IReadOnlyCollection SoftwareSyntaxes { get; } = new HashSet(); +} + +internal class SoftwareTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.HasDataJsonFile(); - } + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/SoftwareSyntax.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/SoftwareSyntax.cs index 7245e27c9..1ebf4617b 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/SoftwareSyntax.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/SoftwareSyntax.cs @@ -1,23 +1,22 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class SoftwareSyntax - { - public int SoftwareId { get; init; } - public Software Software { get; } = null!; - public int SyntaxId { get; init; } - public Syntax Syntax { get; } = null!; - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class SoftwareSyntaxTypeConfiguration : IEntityTypeConfiguration +public class SoftwareSyntax +{ + public int SoftwareId { get; init; } + public Software Software { get; } = null!; + public int SyntaxId { get; init; } + public Syntax Syntax { get; } = null!; +} + +internal class SoftwareSyntaxTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.ToTable(nameof(SoftwareSyntax) + "es"); - builder.HasKey(ss => new { ss.SoftwareId, ss.SyntaxId }); - builder.HasDataJsonFile(); - } + builder.ToTable(nameof(SoftwareSyntax) + "es"); + builder.HasKey(ss => new { ss.SoftwareId, ss.SyntaxId }); + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Syntax.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Syntax.cs index a1b2cd419..926dd2554 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Syntax.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Syntax.cs @@ -1,23 +1,22 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class Syntax - { - public int Id { get; init; } - public string Name { get; init; } = null!; - public string? Description { get; init; } - public Uri? Url { get; init; } - public IReadOnlyCollection FilterListSyntaxes { get; } = new HashSet(); - public IReadOnlyCollection SoftwareSyntaxes { get; } = new HashSet(); - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class SyntaxTypeConfiguration : IEntityTypeConfiguration +public class Syntax +{ + public int Id { get; init; } + public string Name { get; init; } = null!; + public string? Description { get; init; } + public Uri? Url { get; init; } + public IReadOnlyCollection FilterListSyntaxes { get; } = new HashSet(); + public IReadOnlyCollection SoftwareSyntaxes { get; } = new HashSet(); +} + +internal class SyntaxTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.HasDataJsonFile(); - } + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Tag.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Tag.cs index 4bcb34694..b7fa326d9 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Tag.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/Queries/Entities/Tag.cs @@ -1,21 +1,20 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities -{ - public class Tag - { - public int Id { get; init; } - public string Name { get; init; } = null!; - public string? Description { get; init; } - public IReadOnlyCollection FilterListTags { get; } = new HashSet(); - } +namespace FilterLists.Directory.Infrastructure.Persistence.Queries.Entities; - internal class TagTypeConfiguration : IEntityTypeConfiguration +public class Tag +{ + public int Id { get; init; } + public string Name { get; init; } = null!; + public string? Description { get; init; } + public IReadOnlyCollection FilterListTags { get; } = new HashSet(); +} + +internal class TagTypeConfiguration : IEntityTypeConfiguration +{ + public virtual void Configure(EntityTypeBuilder builder) { - public virtual void Configure(EntityTypeBuilder builder) - { - builder.HasDataJsonFile(); - } + builder.HasDataJsonFile(); } } diff --git a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/SeedExtensions.cs b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/SeedExtensions.cs index c621b4f1b..cdc120944 100644 --- a/services/Directory/FilterLists.Directory.Infrastructure/Persistence/SeedExtensions.cs +++ b/services/Directory/FilterLists.Directory.Infrastructure/Persistence/SeedExtensions.cs @@ -5,36 +5,35 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace FilterLists.Directory.Infrastructure.Persistence +namespace FilterLists.Directory.Infrastructure.Persistence; + +public static class SeedExtension { - public static class SeedExtension + public static async Task MigrateAsync(this IHost host) { - public static async Task MigrateAsync(this IHost host) - { - using var scope = host.Services.CreateScope(); - var db = scope.ServiceProvider.GetRequiredService(); - await db.Database.MigrateAsync(); - } + using var scope = host.Services.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + await db.Database.MigrateAsync(); } +} - internal static class SeedConfigurationExtension +internal static class SeedConfigurationExtension +{ + public static void HasDataJsonFile(this EntityTypeBuilder entityTypeBuilder) { - public static void HasDataJsonFile(this EntityTypeBuilder entityTypeBuilder) + var path = Path.Combine("../data", $"{typeof(TEntity).Name}.json"); + if (!File.Exists(path)) { - var path = Path.Combine("../data", $"{typeof(TEntity).Name}.json"); - if (!File.Exists(path)) - { - return; - } + return; + } - var entitiesJson = File.ReadAllText(path); - var entities = JsonSerializer.Deserialize>(entitiesJson, - new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + var entitiesJson = File.ReadAllText(path); + var entities = JsonSerializer.Deserialize>(entitiesJson, + new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); - if (entities != null) - { - entityTypeBuilder.HasData((IEnumerable)entities); - } + if (entities != null) + { + entityTypeBuilder.HasData((IEnumerable)entities); } } } diff --git a/services/SharedKernel/FilterLists.SharedKernel.Logging/ConfigurationBuilder.cs b/services/SharedKernel/FilterLists.SharedKernel.Logging/ConfigurationBuilder.cs index 196a55a76..490f08273 100644 --- a/services/SharedKernel/FilterLists.SharedKernel.Logging/ConfigurationBuilder.cs +++ b/services/SharedKernel/FilterLists.SharedKernel.Logging/ConfigurationBuilder.cs @@ -1,16 +1,15 @@ using Serilog; using Serilog.Events; -namespace FilterLists.SharedKernel.Logging +namespace FilterLists.SharedKernel.Logging; + +internal static class ConfigurationBuilder { - internal static class ConfigurationBuilder - { - public static readonly LoggerConfiguration BaseLoggerConfiguration = - new LoggerConfiguration() - .MinimumLevel.Information() - .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) - .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information) - .Enrich.FromLogContext() - .WriteTo.Console(); - } + public static readonly LoggerConfiguration BaseLoggerConfiguration = + new LoggerConfiguration() + .MinimumLevel.Information() + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information) + .Enrich.FromLogContext() + .WriteTo.Console(); } diff --git a/services/SharedKernel/FilterLists.SharedKernel.Logging/ConfigurationExtensions.cs b/services/SharedKernel/FilterLists.SharedKernel.Logging/ConfigurationExtensions.cs index 828dc8c06..0a5b01b70 100644 --- a/services/SharedKernel/FilterLists.SharedKernel.Logging/ConfigurationExtensions.cs +++ b/services/SharedKernel/FilterLists.SharedKernel.Logging/ConfigurationExtensions.cs @@ -8,31 +8,30 @@ using Microsoft.Extensions.Hosting; using Serilog; -namespace FilterLists.SharedKernel.Logging +namespace FilterLists.SharedKernel.Logging; + +public static class ConfigurationExtensions { - public static class ConfigurationExtensions + public static IHostBuilder UseLogging(this IHostBuilder hostBuilder) { - public static IHostBuilder UseLogging(this IHostBuilder hostBuilder) - { - return hostBuilder.UseSerilog(); - } + return hostBuilder.UseSerilog(); + } - public static void AddSharedKernelLogging(this IServiceCollection services, IConfiguration configuration) + public static void AddSharedKernelLogging(this IServiceCollection services, IConfiguration configuration) + { + using var serverTelemetryChannel = new ServerTelemetryChannel { - using var serverTelemetryChannel = new ServerTelemetryChannel - { - StorageFolder = configuration.GetSection(ApplicationInsightsOptions.Key) - .Get() - .ServerTelemetryChannelStoragePath - }; - services.AddSingleton(typeof(ITelemetryChannel), serverTelemetryChannel); - TelemetryDebugWriter.IsTracingDisabled = true; - services.AddApplicationInsightsTelemetry(); - } + StorageFolder = configuration.GetSection(ApplicationInsightsOptions.Key) + .Get() + .ServerTelemetryChannelStoragePath + }; + services.AddSingleton(typeof(ITelemetryChannel), serverTelemetryChannel); + TelemetryDebugWriter.IsTracingDisabled = true; + services.AddApplicationInsightsTelemetry(); + } - public static void UseLogging(this IApplicationBuilder app) - { - app.UseSerilogRequestLogging(); - } + public static void UseLogging(this IApplicationBuilder app) + { + app.UseSerilogRequestLogging(); } } diff --git a/services/SharedKernel/FilterLists.SharedKernel.Logging/HostRunner.cs b/services/SharedKernel/FilterLists.SharedKernel.Logging/HostRunner.cs index 9f069fbcf..520a82c02 100644 --- a/services/SharedKernel/FilterLists.SharedKernel.Logging/HostRunner.cs +++ b/services/SharedKernel/FilterLists.SharedKernel.Logging/HostRunner.cs @@ -3,38 +3,37 @@ using Microsoft.Extensions.Hosting; using Serilog; -namespace FilterLists.SharedKernel.Logging +namespace FilterLists.SharedKernel.Logging; + +public static class HostRunner { - public static class HostRunner + public static async Task TryRunWithLoggingAsync(this IHost host, Func? runPreHostAsync = default) { - public static async Task TryRunWithLoggingAsync(this IHost host, Func? runPreHostAsync = default) + Log.Logger = ConfigurationBuilder.BaseLoggerConfiguration + .WriteTo.ApplicationInsights( + host.Services.GetRequiredService(), + TelemetryConverter.Traces) + .CreateLogger(); + + try { - Log.Logger = ConfigurationBuilder.BaseLoggerConfiguration - .WriteTo.ApplicationInsights( - host.Services.GetRequiredService(), - TelemetryConverter.Traces) - .CreateLogger(); + if (runPreHostAsync != null) + { + Log.Information("Initializing pre-host"); + await runPreHostAsync(); + } - try - { - if (runPreHostAsync != null) - { - Log.Information("Initializing pre-host"); - await runPreHostAsync(); - } - - Log.Information("Initializing host"); - await host.RunAsync(); - } - catch (Exception ex) - { - Log.Fatal(ex, "Host terminated unexpectedly"); - throw; - } - finally - { - Log.CloseAndFlush(); - } + Log.Information("Initializing host"); + await host.RunAsync(); + } + catch (Exception ex) + { + Log.Fatal(ex, "Host terminated unexpectedly"); + throw; + } + finally + { + Log.CloseAndFlush(); } } } diff --git a/services/SharedKernel/FilterLists.SharedKernel.Logging/Options/ApplicationInsightsOptions.cs b/services/SharedKernel/FilterLists.SharedKernel.Logging/Options/ApplicationInsightsOptions.cs index 2b7f5c4f3..f2f6c0eb4 100644 --- a/services/SharedKernel/FilterLists.SharedKernel.Logging/Options/ApplicationInsightsOptions.cs +++ b/services/SharedKernel/FilterLists.SharedKernel.Logging/Options/ApplicationInsightsOptions.cs @@ -1,9 +1,8 @@ -namespace FilterLists.SharedKernel.Logging.Options -{ - internal class ApplicationInsightsOptions - { - public const string Key = "ApplicationInsights"; +namespace FilterLists.SharedKernel.Logging.Options; - public string ServerTelemetryChannelStoragePath { get; init; } = null!; - } +internal class ApplicationInsightsOptions +{ + public const string Key = "ApplicationInsights"; + + public string ServerTelemetryChannelStoragePath { get; init; } = null!; }