Skip to content

Commit

Permalink
refactor: re-arranged / refactored to fit in solution structure
Browse files Browse the repository at this point in the history
  • Loading branch information
ericbrunner committed Dec 19, 2024
1 parent a51db5f commit 91713ea
Show file tree
Hide file tree
Showing 21 changed files with 271 additions and 198 deletions.
8 changes: 4 additions & 4 deletions Applications/AdminApi/http/Tokens/List Tokens.bru
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ meta {
}

get {
url: {{baseUrl}}/Tokens
url: {{baseUrl}}/Tokens?createdBy=did:e:localhost:dids:c179861648989f28d189c9&PageNumber=1&PageSize=1
body: none
auth: inherit
}

params:query {
~ids: TOKsjPynl0FHYJzHnkIo
~PageNumber: 1
~PageSize: 1
createdBy: did:e:localhost:dids:c179861648989f28d189c9
PageNumber: 1
PageSize: 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.ComponentModel.DataAnnotations;
using Backbone.Modules.Tokens.Application;

namespace Backbone.AdminApi.Configuration;

public class TokensConfiguration
{
[Required]
public ApplicationOptions Application { get; set; } = new();

[Required]
public InfrastructureConfiguration Infrastructure { get; set; } = new();

public class InfrastructureConfiguration
{
[Required]
public SqlDatabaseConfiguration SqlDatabase { get; set; } = new();

public class SqlDatabaseConfiguration
{
[Required]
[MinLength(1)]
[RegularExpression("SqlServer|Postgres")]
public string Provider { get; set; } = string.Empty;

[Required]
[MinLength(1)]
public string ConnectionString { get; set; } = string.Empty;

[Required]
public bool EnableHealthCheck { get; set; } = true;
}
}
}
24 changes: 11 additions & 13 deletions Applications/AdminApi/src/AdminApi/Controllers/TokensController.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,36 @@
using Backbone.AdminApi.Configuration;
using Backbone.AdminApi.Queries.GetAllTokens;
using Backbone.BuildingBlocks.API.Mvc;
using Backbone.BuildingBlocks.API.Mvc;
using Backbone.BuildingBlocks.Application.Abstractions.Exceptions;
using Backbone.BuildingBlocks.Application.Pagination;
using Backbone.Modules.Tokens.Domain.Entities;
using Backbone.Modules.Tokens.Application;
using Backbone.Modules.Tokens.Application.Tokens.DTOs;
using Backbone.Modules.Tokens.Application.Tokens.Queries.ListTokensByIdentity;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

using ApplicationException = Backbone.BuildingBlocks.Application.Abstractions.Exceptions.ApplicationException;

namespace Backbone.AdminApi.Controllers;

[Route("api/v1/[controller]")]
[Authorize("ApiKey")]
public class TokensController(IMediator mediator, IOptions<AdminConfiguration> options) : ApiControllerBase(mediator)
public class TokensController(IMediator mediator, IOptions<ApplicationOptions> options) : ApiControllerBase(mediator)
{
// The Admin API has a new endpoint GET /Tokens?createdBy={identityAddress}, which returns all Tokens of created by the identity with the given address.
// All properties of the Token are returned.
[HttpGet]
[ProducesResponseType(typeof(List<Token>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetTokens([FromQuery] PaginationFilter paginationFilter, [FromQuery] string createdBy, CancellationToken cancellationToken)
[ProducesResponseType(typeof(List<TokenDTO>), StatusCodes.Status200OK)]
public async Task<IActionResult> ListTokensByIdentity([FromQuery] PaginationFilter paginationFilter, [FromQuery] string createdBy, CancellationToken cancellationToken)
{
if (paginationFilter.PageSize != null)
{
var maxPageSize = options.Value.Modules.Devices.Application.Pagination.MaxPageSize;
var maxPageSize = options.Value.Pagination.MaxPageSize;

if (paginationFilter.PageSize > maxPageSize)
{
throw new BuildingBlocks.Application.Abstractions.Exceptions.ApplicationException(GenericApplicationErrors.Validation.InvalidPageSize(maxPageSize));
throw new ApplicationException(GenericApplicationErrors.Validation.InvalidPageSize(maxPageSize));
}
}

var request = new GetTokensQuery(createdBy, paginationFilter);
var request = new ListTokensByIdentityQuery(createdBy, paginationFilter);
var pagedResult = await _mediator.Send(request, cancellationToken);

return Paged(pagedResult);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,9 @@
using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext;
using Backbone.Modules.Devices.Application.Devices.Commands.RegisterDevice;
using Backbone.Modules.Devices.Application.Devices.DTOs;
using Backbone.Modules.Tokens.Application.Infrastructure.Persistence.Repository;
using Backbone.Modules.Tokens.Infrastructure.Persistence;
using Backbone.Modules.Tokens.Infrastructure.Persistence.Repository;
using FluentValidation;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData;
using Microsoft.Extensions.Options;
using Microsoft.OData.ModelBuilder;

namespace Backbone.AdminApi.Extensions;
Expand All @@ -41,30 +37,7 @@ public static IServiceCollection AddCustomAspNetCore(this IServiceCollection ser
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
options.Filters.Add(new RedirectAntiforgeryValidationFailedResultFilter());
})
.ConfigureApiBehaviorOptions(options =>
{
options.InvalidModelStateResponseFactory = context =>
{
var firstPropertyWithError =
context.ModelState.First(p => p.Value is { Errors.Count: > 0 });
var nameOfPropertyWithError = firstPropertyWithError.Key;
var firstError = firstPropertyWithError.Value!.Errors.First();
var firstErrorMessage = !string.IsNullOrWhiteSpace(firstError.ErrorMessage)
? firstError.ErrorMessage
: firstError.Exception != null
? firstError.Exception.Message
: "";

var formattedMessage = string.IsNullOrEmpty(nameOfPropertyWithError)
? firstErrorMessage
: $"'{nameOfPropertyWithError}': {firstErrorMessage}";
context.HttpContext.Response.ContentType = "application/json";
var responsePayload = new HttpResponseEnvelopeError(
HttpError.ForProduction(GenericApplicationErrors.Validation.InputCannotBeParsed().Code, formattedMessage,
"")); // TODO: add docs
return new BadRequestObjectResult(responsePayload);
};
})
.ConfigureApiBehaviorOptions(options => options.InvalidModelStateResponseFactory = InvalidModelStateResponseFactory())
.AddJsonOptions(options =>
{
var jsonConverters =
Expand Down Expand Up @@ -155,6 +128,31 @@ public static IServiceCollection AddCustomAspNetCore(this IServiceCollection ser
return services;
}

private static Func<ActionContext, IActionResult> InvalidModelStateResponseFactory() => context =>
{
var (nameOfPropertyWithError, value) = context.ModelState.First(p => p.Value is { Errors.Count: > 0 });

var firstError = value!.Errors.First();
var firstErrorMessage = !string.IsNullOrWhiteSpace(firstError.ErrorMessage)
? firstError.ErrorMessage
: firstError.Exception != null
? firstError.Exception.Message
: "";

var formattedMessage = string.IsNullOrEmpty(nameOfPropertyWithError)
? firstErrorMessage
: $"'{nameOfPropertyWithError}': {firstErrorMessage}";

context.HttpContext.Response.ContentType = "application/json";

var responsePayload = new HttpResponseEnvelopeError(
HttpError.ForProduction(GenericApplicationErrors.Validation.InputCannotBeParsed().Code,
formattedMessage,
""));

return new BadRequestObjectResult(responsePayload);
};

private static object GetPropertyValue(object source, string propertyPath)
{
foreach (var property in propertyPath.Split('.').Select(s => source.GetType().GetProperty(s)))
Expand All @@ -177,19 +175,4 @@ public static IServiceCollection AddOData(this IServiceCollection services)

return services;
}

public static IServiceCollection AddRepositories(this IServiceCollection services)
{
var parsedConfiguration = services.BuildServiceProvider().GetRequiredService<IOptions<AdminConfiguration>>().Value;

services.AddPersistence(options =>
{
options.DbOptions.Provider = parsedConfiguration.Infrastructure.SqlDatabase.Provider;
options.DbOptions.DbConnectionString = parsedConfiguration.Infrastructure.SqlDatabase.ConnectionString;
});

services.AddTransient<ITokensRepository, TokensRepository>();

return services;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Backbone.AdminApi.Configuration;
using Backbone.Modules.Tokens.Application.Extensions;
using Backbone.Modules.Tokens.Application.Infrastructure.Persistence.Repository;
using Backbone.Modules.Tokens.Infrastructure.Persistence.Database;
using Backbone.Modules.Tokens.Infrastructure.Persistence.Repository;
using Microsoft.Extensions.Options;

namespace Backbone.AdminApi.Extensions;

public static class TokensServiceCollectionExtensions
{
public static IServiceCollection AddTokens(this IServiceCollection services, IConfiguration configuration)
{
services.AddApplication(configuration.GetSection("Application"));

services.ConfigureAndValidate<TokensConfiguration.InfrastructureConfiguration>(configuration.GetSection("Infrastructure").Bind);

var infrastructureConfiguration = services.BuildServiceProvider().GetRequiredService<IOptions<TokensConfiguration.InfrastructureConfiguration>>().Value;

services.AddDatabase(options =>
{
options.Provider = infrastructureConfiguration.SqlDatabase.Provider;
options.DbConnectionString = infrastructureConfiguration.SqlDatabase.ConnectionString;
});

// Note: Registration required. Only Modules have their used repositories registered in the DI container.
services.AddTransient<ITokensRepository, TokensRepository>();

return services;
}
}
4 changes: 1 addition & 3 deletions Applications/AdminApi/src/AdminApi/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ static void ConfigureServices(IServiceCollection services, IConfiguration config
services.AddCustomAspNetCore(parsedConfiguration)
.AddOData()
.AddCustomFluentValidation()
.AddRepositories()
.AddCustomIdentity(environment)
.AddDatabase(parsedConfiguration.Infrastructure.SqlDatabase)
.AddDevices(configuration.GetSection("Modules:Devices"))
.AddTokens(configuration.GetSection("Modules:Tokens"))
.AddQuotas(parsedConfiguration.Modules.Quotas)
.AddAnnouncements(parsedConfiguration.Modules.Announcements)
.AddChallenges(parsedConfiguration.Modules.Challenges)
Expand All @@ -130,8 +130,6 @@ static void ConfigureServices(IServiceCollection services, IConfiguration config

services.AddEventBus(parsedConfiguration.Infrastructure.EventBus);
services.AddPushNotifications(parsedConfiguration.Modules.Devices.Infrastructure.PushNotifications);

services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<Program>());
}

static void LoadConfiguration(WebApplicationBuilder webApplicationBuilder, string[] strings)
Expand Down

This file was deleted.

This file was deleted.

22 changes: 0 additions & 22 deletions Applications/AdminApi/src/AdminApi/Queries/GetAllTokens/Handler.cs

This file was deleted.

Loading

0 comments on commit 91713ea

Please sign in to comment.