diff --git a/services/Directory/FilterLists.Directory.Application/Commands/CreateList.cs b/services/Directory/FilterLists.Directory.Application/Commands/CreateList.cs index ecbe86f0b..ed2dfcc3e 100644 --- a/services/Directory/FilterLists.Directory.Application/Commands/CreateList.cs +++ b/services/Directory/FilterLists.Directory.Application/Commands/CreateList.cs @@ -182,11 +182,30 @@ public record FilterListViewUrl internal class Validator : AbstractValidator { - public Validator() + public Validator(IValidator urlValidator) { RuleFor(c => c.LicenseId) .GreaterThan(0) .When(c => c.LicenseId != null); + RuleForEach(c => c.ViewUrls.Select(u => u.Url)) + .SetValidator(urlValidator) + .OverridePropertyName(nameof(Command.ViewUrls)); + RuleFor(c => c.HomeUrl) + .SetValidator(urlValidator); + RuleFor(c => c.OnionUrl) + .SetValidator(urlValidator); + RuleFor(c => c.PolicyUrl) + .SetValidator(urlValidator); + RuleFor(c => c.SubmissionUrl) + .SetValidator(urlValidator); + RuleFor(c => c.IssuesUrl) + .SetValidator(urlValidator); + RuleFor(c => c.ForumUrl) + .SetValidator(urlValidator); + RuleFor(c => c.ChatUrl) + .SetValidator(urlValidator); + RuleFor(c => c.DonateUrl) + .SetValidator(urlValidator); } } diff --git a/services/Directory/FilterLists.Directory.Application/ConfigurationExtensions.cs b/services/Directory/FilterLists.Directory.Application/ConfigurationExtensions.cs index e8e5e8b03..e6afd2d00 100644 --- a/services/Directory/FilterLists.Directory.Application/ConfigurationExtensions.cs +++ b/services/Directory/FilterLists.Directory.Application/ConfigurationExtensions.cs @@ -1,4 +1,5 @@ -using FilterLists.Directory.Infrastructure; +using FilterLists.Directory.Application.Validators; +using FilterLists.Directory.Infrastructure; using FluentValidation; using MediatR; using Microsoft.AspNetCore.Builder; @@ -17,11 +18,12 @@ public static IHostBuilder ConfigureApplication(this IHostBuilder hostBuilder) public static void AddApplication(this IServiceCollection services, IConfiguration configuration) { - services.AddMediatR(typeof(ConfigurationExtensions).Assembly); - services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidatorPipelineBehavior<,>)); + services.AddInfrastructure(configuration); + services.AddHttpClient(); services.AddValidatorsFromAssembly(typeof(ConfigurationExtensions).Assembly, includeInternalTypes: true); services.AddAutoMapper(typeof(ConfigurationExtensions).Assembly); - services.AddInfrastructure(configuration); + services.AddMediatR(typeof(ConfigurationExtensions).Assembly); + services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidatorPipelineBehavior<,>)); } public static void UseApplication(this IApplicationBuilder app) diff --git a/services/Directory/FilterLists.Directory.Application/Validators/UrlValidator.cs b/services/Directory/FilterLists.Directory.Application/Validators/UrlValidator.cs new file mode 100644 index 000000000..8fb077b55 --- /dev/null +++ b/services/Directory/FilterLists.Directory.Application/Validators/UrlValidator.cs @@ -0,0 +1,38 @@ +using FluentValidation; + +namespace FilterLists.Directory.Application.Validators; + +internal class UriValidator : AbstractValidator +{ + public UriValidator(IHttpClientFactory httpClientFactory) + { + RuleFor(u => u) + .Cascade(CascadeMode.Stop) + .Must(u => Uri.TryCreate(u?.OriginalString, UriKind.Absolute, out _)) + .WithMessage(u => $"Malformed absolute URL {u?.OriginalString}.") + .CustomAsync( + async (u, context, token) => + { + var response = default(HttpResponseMessage?); + try + { + response = await httpClientFactory.CreateClient() + .GetAsync(u, HttpCompletionOption.ResponseHeadersRead, token); + } + catch (HttpRequestException ex) + { + context.AddFailure($"Error accessing URL {u?.OriginalString}. {ex.Message}"); + } + catch (InvalidOperationException ex) + { + context.AddFailure($"Error accessing URL {u?.OriginalString}. {ex.Message}"); + } + + if (response?.IsSuccessStatusCode != true) + { + context.AddFailure($"Error accessing URL {u?.OriginalString}. {response?.StatusCode}"); + } + }) + .When(u => u is not null); + } +} diff --git a/services/Directory/FilterLists.Directory.Application/ValidatorPipelineBahavior.cs b/services/Directory/FilterLists.Directory.Application/Validators/ValidatorPipelineBehavior.cs similarity index 92% rename from services/Directory/FilterLists.Directory.Application/ValidatorPipelineBahavior.cs rename to services/Directory/FilterLists.Directory.Application/Validators/ValidatorPipelineBehavior.cs index 74a3bccae..d58fcada0 100644 --- a/services/Directory/FilterLists.Directory.Application/ValidatorPipelineBahavior.cs +++ b/services/Directory/FilterLists.Directory.Application/Validators/ValidatorPipelineBehavior.cs @@ -1,7 +1,7 @@ using FluentValidation; using MediatR; -namespace FilterLists.Directory.Application; +namespace FilterLists.Directory.Application.Validators; internal class ValidatorPipelineBehavior : IPipelineBehavior where TRequest : notnull