-
-
Notifications
You must be signed in to change notification settings - Fork 118
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(dir): ✨🚧 WIP port query endpoints
- Loading branch information
1 parent
78749d6
commit c95d947
Showing
15 changed files
with
449 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using FilterLists.Directory.Application.Queries; | ||
using MediatR; | ||
|
||
namespace FilterLists.Directory.Api; | ||
|
||
internal static class Endpoints | ||
{ | ||
internal static void MapEndpoints(this WebApplication app) | ||
{ | ||
var lists = app.MapGroup("/lists"); | ||
|
||
lists.MapGet("/", | ||
(IMediator mediator, CancellationToken ct) => | ||
mediator.CreateStream(new GetLists.Request(), ct) | ||
); | ||
|
||
lists.MapGet("/{id:int}", | ||
async (int id, IMediator mediator, CancellationToken ct) => | ||
await mediator.Send(new GetListDetails.Request(id), ct) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,16 @@ | ||
using FilterLists.Directory.Api; | ||
using FilterLists.Directory.Application; | ||
|
||
var builder = WebApplication.CreateBuilder(args); | ||
|
||
// Add service defaults & Aspire components. | ||
builder.AddServiceDefaults(); | ||
|
||
// Add services to the container. | ||
builder.Services.AddProblemDetails(); | ||
builder.AddApplication(); | ||
|
||
var app = builder.Build(); | ||
|
||
// Configure the HTTP request pipeline. | ||
app.UseExceptionHandler(); | ||
|
||
var summaries = new[] | ||
{ | ||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" | ||
}; | ||
|
||
app.MapGet("/weatherforecast", () => | ||
{ | ||
var forecast = Enumerable.Range(1, 5).Select(index => | ||
new WeatherForecast | ||
( | ||
DateOnly.FromDateTime(DateTime.Now.AddDays(index)), | ||
Random.Shared.Next(-20, 55), | ||
summaries[Random.Shared.Next(summaries.Length)] | ||
)) | ||
.ToArray(); | ||
return forecast; | ||
}); | ||
|
||
app.MapEndpoints(); | ||
app.MapDefaultEndpoints(); | ||
|
||
app.Run(); | ||
|
||
internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) | ||
{ | ||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); | ||
} | ||
app.Run(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
services/Directory/FilterLists.Directory.Application/ConfigurationExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using FilterLists.Directory.Infrastructure; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
|
||
namespace FilterLists.Directory.Application; | ||
|
||
public static class ConfigurationExtensions | ||
{ | ||
public static void AddApplication(this IHostApplicationBuilder builder) | ||
{ | ||
builder.AddInfrastructure(); | ||
builder.Services.AddMediatR(cfg => | ||
{ | ||
cfg.RegisterServicesFromAssembly(typeof(ConfigurationExtensions).Assembly); | ||
}); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
...ices/Directory/FilterLists.Directory.Application/FilterLists.Directory.Application.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0"/> | ||
<PackageReference Include="MediatR" Version="12.2.0"/> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\FilterLists.Directory.Infrastructure\FilterLists.Directory.Infrastructure.csproj"/> | ||
</ItemGroup> | ||
|
||
</Project> |
253 changes: 253 additions & 0 deletions
253
services/Directory/FilterLists.Directory.Application/Queries/GetListDetails.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
using FilterLists.Directory.Infrastructure.Persistence.Queries.Context; | ||
using JetBrains.Annotations; | ||
using MediatR; | ||
using Microsoft.EntityFrameworkCore; | ||
|
||
namespace FilterLists.Directory.Application.Queries; | ||
|
||
public static class GetListDetails | ||
{ | ||
private static readonly Func<QueryDbContext, int, Task<ListDetailsVm>> Query = | ||
EF.CompileAsyncQuery((QueryDbContext ctx, int id) => | ||
ctx.FilterLists | ||
.Select(f => new ListDetailsVm | ||
{ | ||
Id = f.Id, | ||
Name = f.Name, | ||
Description = f.Description, | ||
LicenseId = f.LicenseId, | ||
SyntaxIds = f.FilterListSyntaxes | ||
.OrderBy(fs => fs.SyntaxId) | ||
.Select(fs => fs.SyntaxId), | ||
LanguageIds = f.FilterListLanguages | ||
.OrderBy(fl => fl.LanguageId) | ||
.Select(fl => fl.LanguageId), | ||
TagIds = f.FilterListTags | ||
.OrderBy(ft => ft.TagId) | ||
.Select(ft => ft.TagId), | ||
ViewUrls = f.ViewUrls | ||
.OrderBy(u => u.SegmentNumber) | ||
.ThenBy(u => u.Primariness) | ||
.Select(u => new ListDetailsVm.ViewUrlVm | ||
{ | ||
SegmentNumber = u.SegmentNumber, | ||
Primariness = u.Primariness, | ||
Url = u.Url | ||
}), | ||
HomeUrl = f.HomeUrl, | ||
OnionUrl = f.OnionUrl, | ||
PolicyUrl = f.PolicyUrl, | ||
SubmissionUrl = f.SubmissionUrl, | ||
IssuesUrl = f.IssuesUrl, | ||
ForumUrl = f.ForumUrl, | ||
ChatUrl = f.ChatUrl, | ||
EmailAddress = f.EmailAddress, | ||
DonateUrl = f.DonateUrl, | ||
MaintainerIds = f.FilterListMaintainers | ||
.OrderBy(fm => fm.MaintainerId) | ||
.Select(fm => fm.MaintainerId), | ||
UpstreamFilterListIds = f.UpstreamFilterLists | ||
.OrderBy(ff => ff.UpstreamFilterListId) | ||
.Select(ff => ff.UpstreamFilterListId), | ||
ForkFilterListIds = f.ForkFilterLists | ||
.OrderBy(ff => ff.ForkFilterListId) | ||
.Select(ff => ff.ForkFilterListId), | ||
IncludedInFilterListIds = f.IncludedInFilterLists | ||
.OrderBy(fm => fm.IncludedInFilterListId) | ||
.Select(fm => fm.IncludedInFilterListId), | ||
IncludesFilterListIds = f.IncludesFilterLists | ||
.OrderBy(fm => fm.IncludesFilterListId) | ||
.Select(fm => fm.IncludesFilterListId), | ||
DependencyFilterListIds = f.DependencyFilterLists | ||
.OrderBy(fd => fd.DependencyFilterListId) | ||
.Select(fd => fd.DependencyFilterListId), | ||
DependentFilterListIds = f.DependentFilterLists | ||
.OrderBy(fd => fd.DependentFilterListId) | ||
.Select(fd => fd.DependentFilterListId) | ||
}) | ||
.Single(f => f.Id == id)); | ||
|
||
public sealed record Request(int Id) : IRequest<ListDetailsVm>; | ||
|
||
internal sealed class Handler(QueryDbContext ctx) : IRequestHandler<Request, ListDetailsVm> | ||
{ | ||
public Task<ListDetailsVm> Handle(Request request, CancellationToken _) | ||
{ | ||
// TODO: handle Single() exceptions | ||
return Query(ctx, request.Id); | ||
} | ||
} | ||
|
||
[PublicAPI] | ||
public record ListDetailsVm | ||
{ | ||
/// <summary> | ||
/// The identifier. | ||
/// </summary> | ||
/// <example>301</example> | ||
public int Id { get; init; } | ||
|
||
/// <summary> | ||
/// The unique name in title case. | ||
/// </summary> | ||
/// <example>EasyList</example> | ||
public required string Name { get; init; } | ||
|
||
/// <summary> | ||
/// The brief description in English (preferably quoted from the project). | ||
/// </summary> | ||
/// <example> | ||
/// EasyList is the primary filter list that removes most adverts from international web pages, including unwanted | ||
/// frames, images, and objects. It is the most popular list used by many ad blockers and forms the basis of over a | ||
/// dozen combination and supplementary filter lists. | ||
/// </example> | ||
public string? Description { get; init; } | ||
|
||
/// <summary> | ||
/// The identifier of the License under which this FilterList is released. | ||
/// </summary> | ||
/// <example>4</example> | ||
public int LicenseId { get; init; } | ||
|
||
/// <summary> | ||
/// The identifiers of the Syntaxes implemented by this FilterList. | ||
/// </summary> | ||
/// <example>[ 3 ]</example> | ||
public IEnumerable<short> SyntaxIds { get; init; } = []; | ||
|
||
/// <summary> | ||
/// The identifiers of the Languages targeted by this FilterList. | ||
/// </summary> | ||
/// <example>[ 37 ]</example> | ||
public IEnumerable<short> LanguageIds { get; init; } = []; | ||
|
||
/// <summary> | ||
/// The identifiers of the Tags applied to this FilterList. | ||
/// </summary> | ||
/// <example>[ 2 ]</example> | ||
public IEnumerable<int> TagIds { get; init; } = []; | ||
|
||
/// <summary> | ||
/// The view URLs. | ||
/// </summary> | ||
public IEnumerable<ViewUrlVm> ViewUrls { get; init; } = []; | ||
|
||
/// <summary> | ||
/// The URL of the home page. | ||
/// </summary> | ||
/// <example>https://easylist.to/</example> | ||
public Uri? HomeUrl { get; init; } | ||
|
||
/// <summary> | ||
/// The URL of the Tor / Onion page. | ||
/// </summary> | ||
/// <example>null</example> | ||
public Uri? OnionUrl { get; init; } | ||
|
||
/// <summary> | ||
/// The URL of the policy/guidelines for the types of rules this FilterList includes. | ||
/// </summary> | ||
/// <example>null</example> | ||
public Uri? PolicyUrl { get; init; } | ||
|
||
/// <summary> | ||
/// The URL of the submission/contact form for adding rules to this FilterList. | ||
/// </summary> | ||
/// <example>null</example> | ||
public Uri? SubmissionUrl { get; init; } | ||
|
||
/// <summary> | ||
/// The URL of the GitHub Issues page. | ||
/// </summary> | ||
/// <example>https://github.com/easylist/easylist/issues</example> | ||
public Uri? IssuesUrl { get; init; } | ||
|
||
/// <summary> | ||
/// The URL of the forum page. | ||
/// </summary> | ||
/// <example>https://forums.lanik.us/viewforum.php?f=23</example> | ||
public Uri? ForumUrl { get; init; } | ||
|
||
/// <summary> | ||
/// The URL of the chat room. | ||
/// </summary> | ||
/// <example>null</example> | ||
public Uri? ChatUrl { get; init; } | ||
|
||
/// <summary> | ||
/// The email address at which the project can be contacted. | ||
/// </summary> | ||
/// <example>[email protected]</example> | ||
public string? EmailAddress { get; init; } | ||
|
||
/// <summary> | ||
/// The URL at which donations to the project can be made. | ||
/// </summary> | ||
/// <example>null</example> | ||
public Uri? DonateUrl { get; init; } | ||
|
||
/// <summary> | ||
/// The identifiers of the Maintainers of this FilterList. | ||
/// </summary> | ||
/// <example>[ 7 ]</example> | ||
public IEnumerable<int> MaintainerIds { get; init; } = []; | ||
|
||
/// <summary> | ||
/// The identifiers of the FilterLists from which this FilterList was forked. | ||
/// </summary> | ||
/// <example>[]</example> | ||
public IEnumerable<int> UpstreamFilterListIds { get; init; } = []; | ||
|
||
/// <summary> | ||
/// The identifiers of the FilterLists that have been forked from this FilterList. | ||
/// </summary> | ||
/// <example>[ 166, 565 ]</example> | ||
public IEnumerable<int> ForkFilterListIds { get; init; } = []; | ||
|
||
/// <summary> | ||
/// The identifiers of the FilterLists that include this FilterList. | ||
/// </summary> | ||
/// <example>[]</example> | ||
public IEnumerable<int> IncludedInFilterListIds { get; init; } = []; | ||
|
||
/// <summary> | ||
/// The identifiers of the FilterLists that this FilterList includes. | ||
/// </summary> | ||
/// <example>[ 11, 13, 168 ]</example> | ||
public IEnumerable<int> IncludesFilterListIds { get; init; } = []; | ||
|
||
/// <summary> | ||
/// The identifiers of the FilterLists that this FilterList depends upon. | ||
/// </summary> | ||
/// <example>[]</example> | ||
public IEnumerable<int> DependencyFilterListIds { get; init; } = []; | ||
|
||
/// <summary> | ||
/// The identifiers of the FilterLists dependent upon this FilterList. | ||
/// </summary> | ||
/// <example>[]</example> | ||
public IEnumerable<int> DependentFilterListIds { get; init; } = []; | ||
|
||
[PublicAPI] | ||
public record ViewUrlVm | ||
{ | ||
/// <summary> | ||
/// The segment number of the URL for the FilterList (for multi-part lists). | ||
/// </summary> | ||
/// <example>1</example> | ||
public short SegmentNumber { get; init; } | ||
|
||
/// <summary> | ||
/// How primary the URL is for the FilterList segment (1 is original, 2+ is a mirror; unique per SegmentNumber) | ||
/// </summary> | ||
/// <example>1</example> | ||
public short Primariness { get; init; } | ||
|
||
/// <summary> | ||
/// The view URL. | ||
/// </summary> | ||
/// <example>https://easylist.to/easylist/easylist.txt</example> | ||
public required Uri Url { get; init; } | ||
} | ||
} | ||
} |
Oops, something went wrong.