Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Admin API for listing all tokens of an identity #999

Merged
merged 33 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
77191a0
feat: added an AdminApi TokensController (draft!)
ericbrunner Dec 18, 2024
a51db5f
feat: added bruno http file
ericbrunner Dec 18, 2024
91713ea
refactor: re-arranged / refactored to fit in solution structure
ericbrunner Dec 19, 2024
904d482
chore: fixed formatting
ericbrunner Dec 19, 2024
2809055
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
ericbrunner Dec 19, 2024
06667a4
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Dec 20, 2024
6d77772
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Dec 20, 2024
b248db6
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Dec 21, 2024
efc2848
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Dec 21, 2024
ee0ce56
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Dec 24, 2024
dee85b7
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Dec 27, 2024
b746f06
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Dec 31, 2024
407d4fc
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Jan 7, 2025
e24a11e
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Jan 7, 2025
6936da7
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Jan 7, 2025
c790ca1
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Jan 7, 2025
4e4b0a2
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Jan 8, 2025
1272160
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Jan 8, 2025
040d115
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Jan 8, 2025
69bfed8
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Jan 9, 2025
dbb82f3
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Jan 9, 2025
f56dfea
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Jan 11, 2025
ca2fe87
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Jan 14, 2025
0a0e999
Merge branch 'main' into ABL-440-admin-api-for-listing-all-tokens-of-…
mergify[bot] Jan 15, 2025
13d4236
fix: PR Remarks
ericbrunner Jan 15, 2025
1486f09
fix: whitespace formatting
ericbrunner Jan 15, 2025
5a4357a
test: added IntegrationTest "Listing all tokens of an identity that d…
ericbrunner Jan 15, 2025
ea167b8
test: added HTTP 200 OK Step
ericbrunner Jan 16, 2025
5ee270c
chore: some pr remarks fixed
ericbrunner Jan 16, 2025
f7631a9
chore: some pr remarks fixed
ericbrunner Jan 16, 2025
7d07662
test: change field name to match naming conventions
tnotheis Jan 17, 2025
a167a53
test: inline variable to improve assertion error message
tnotheis Jan 17, 2025
4668d95
fix: add Tokens projects to dockerfile of admin ui
tnotheis Jan 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@
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.Database;
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 Down Expand Up @@ -148,7 +152,7 @@ private static Func<ActionContext, IActionResult> InvalidModelStateResponseFacto
var responsePayload = new HttpResponseEnvelopeError(
HttpError.ForProduction(GenericApplicationErrors.Validation.InputCannotBeParsed().Code,
formattedMessage,
""));
"")); // TODO: add docs

return new BadRequestObjectResult(responsePayload);
};
Expand All @@ -175,4 +179,18 @@ public static IServiceCollection AddOData(this IServiceCollection services)

return services;
}

public static void AddPersistence(this IServiceCollection services)
{
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>();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
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;

Expand All @@ -15,17 +11,7 @@ public static IServiceCollection AddTokens(this IServiceCollection services, ICo

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>();

services.AddPersistence();
return services;
}
}
167 changes: 85 additions & 82 deletions Applications/AdminApi/src/AdminApi/appsettings.json
ericbrunner marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,91 +1,94 @@
{
"AllowedHosts": "*",
"Authentication": {
"JwtLifetimeInSeconds": 300
},
"Infrastructure": {
"EventBus": {
"SubscriptionClientName": "adminui"
}
},
"Modules": {
"Announcements": {
"Application": {
"Pagination": {
"DefaultPageSize": 50,
"MaxPageSize": 200
}
},
"Infrastructure": {
"SqlDatabase": {
"EnableHealthCheck": true
}
}
"AllowedHosts": "*",
"Authentication": {
"JwtLifetimeInSeconds": 300
},
"Challenges": {
"Infrastructure": {
"SqlDatabase": {
"EnableHealthCheck": true
}
}
},
"Quotas": {
"Application": {
"Pagination": {
"DefaultPageSize": 50,
"MaxPageSize": 200
}
},
"Infrastructure": {
"SqlDatabase": {
"EnableHealthCheck": true
"Infrastructure": {
"EventBus": {
"SubscriptionClientName": "adminui"
}
}
},
"Devices": {
"Application": {
"Pagination": {
"DefaultPageSize": 50,
"MaxPageSize": 200
"Modules": {
"Announcements": {
"Application": {
"Pagination": {
"DefaultPageSize": 50,
"MaxPageSize": 200
}
},
"Infrastructure": {
"SqlDatabase": {
"EnableHealthCheck": true
}
}
},
"Challenges": {
"Infrastructure": {
"SqlDatabase": {
"EnableHealthCheck": true
}
}
},
"Quotas": {
"Application": {
"Pagination": {
"DefaultPageSize": 50,
"MaxPageSize": 200
}
},
"Infrastructure": {
"SqlDatabase": {
"EnableHealthCheck": true
}
}
},
"Devices": {
"Application": {
"Pagination": {
"DefaultPageSize": 50,
"MaxPageSize": 200
}
},
"Infrastructure": {
"SqlDatabase": {
"EnableHealthCheck": true
}
}
},

"Tokens": {
"Application": {
"Pagination": {
"DefaultPageSize": 50,
"MaxPageSize": 200
}
},
"Infrastructure": {
"SqlDatabase": {
"EnableHealthCheck": true
}
}
}
},
"Infrastructure": {
"SqlDatabase": {
"EnableHealthCheck": true
}
}
},
"Tokens": {
"Application": {
"Pagination": {
"DefaultPageSize": 50,
"MaxPageSize": 200
}
},
"Infrastructure": {
"SqlDatabase": {
"EnableHealthCheck": true
}
}
}
},
"Logging": {
"MinimumLevel": {
"Default": "Warning",
"Override": {
"Backbone": "Information",
"Enmeshed": "Information",
"AdminApi": "Information",
"Microsoft": "Information"
}
},
"WriteTo": {
"Console": {
"Name": "Console",
"Args": {
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
"Logging": {
"MinimumLevel": {
"Default": "Warning",
"Override": {
"Backbone": "Information",
"Enmeshed": "Information",
"AdminApi": "Information",
"Microsoft": "Information"
}
},
"WriteTo": {
"Console": {
"Name": "Console",
"Args": {
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
}
}
}
}

}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@Integration
Feature: GET /Tokens?createdBy={identity-address}

Listing all tokens of an identity that doesn't have any tokens

Scenario: Get all Tokens for an identity with no tokens
Given an identity with no tokens
When a GET request is sent to the /Tokens endpoint with the identity's address
Then the response status code is 200 (OK)
And the response content is an empty array
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Backbone.AdminApi.Sdk.Endpoints.Identities.Types.Responses;
using Backbone.AdminApi.Sdk.Endpoints.Tokens.Response;
using Backbone.AdminApi.Sdk.Services;
using Backbone.AdminApi.Tests.Integration.Configuration;
using Backbone.AdminApi.Tests.Integration.Extensions;
using Backbone.BuildingBlocks.SDK.Endpoints.Common.Types;
using Microsoft.Extensions.Options;
using PaginationFilter = Backbone.BuildingBlocks.SDK.Endpoints.Common.Types.PaginationFilter;


namespace Backbone.AdminApi.Tests.Integration.StepDefinitions;

[Binding]
[Scope(Feature = "GET /Tokens?createdBy={identity-address}")]
internal class TokensStepDefinitions(HttpClientFactory factory, IOptions<HttpClientOptions> options) : BaseStepDefinitions(factory, options)
{
private ApiResponse<CreateIdentityResponse>? _createIdentityResponse;
ericbrunner marked this conversation as resolved.
Show resolved Hide resolved
private string _newIdentity = string.Empty;
ericbrunner marked this conversation as resolved.
Show resolved Hide resolved
private ApiResponse<ListTokensTestResponse> _tokensResult = null!;
ericbrunner marked this conversation as resolved.
Show resolved Hide resolved

[Given(@"an identity with no tokens")]
public async Task GivenAnIdentityWithNoTokens()
{
_createIdentityResponse = await IdentityCreationHelper.CreateIdentity(_client);

_createIdentityResponse.Should().BeASuccess();

_newIdentity = _createIdentityResponse.Result!.Address;
}


[When(@"a GET request is sent to the /Tokens endpoint with the identity's address")]
public async Task WhenAGETRequestIsSentToTheTokensEndpointWithTheIdentitysAddress()
{
_tokensResult = await _client.Tokens.ListTokensByIdentity(new PaginationFilter { PageNumber = 1, PageSize = 5 }, _newIdentity, CancellationToken.None);
}

[Then(@"the response status code is (\d+) \(.+\)")]
public void ThenTheResponseStatusCodeIs(int expectedStatusCode)
{
((int)_tokensResult!.Status).Should().Be(expectedStatusCode);
}


[Then(@"the response content is an empty array")]
public void ThenTheResponseContentIsAnEmptyArray()
{
var tokens = _tokensResult.Result!.Count;
tokens.Should().Be(0);
}
}
ericbrunner marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,13 @@ public class Validator : AbstractValidator<ListTokensByIdentityQuery>
public Validator()
{
RuleFor(q => q.CreatedBy)
.Cascade(CascadeMode.Stop)
.DetailedNotEmpty();

RuleFor(q => q.PaginationFilter.PageNumber)
.Cascade(CascadeMode.Stop)
.GreaterThanOrEqualTo(1)
.WithErrorCode(GenericApplicationErrors.Validation.InvalidPropertyValue().Code);

RuleFor(q => q.PaginationFilter.PageSize)
.Cascade(CascadeMode.Stop)
.GreaterThanOrEqualTo(1)
.WithErrorCode(GenericApplicationErrors.Validation.InvalidPropertyValue().Code);
}
Expand Down
1 change: 1 addition & 0 deletions Sdks/AdminApi.Sdk/src/AdminApi.Sdk.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
<ProjectReference Include="..\..\..\BuildingBlocks\src\BuildingBlocks.SDK\BuildingBlocks.SDK.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\src\Crypto\Crypto.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\src\Tooling\Tooling.csproj" />
<ProjectReference Include="..\..\..\Modules\Tokens\src\Tokens.Domain\Tokens.Domain.csproj" />
</ItemGroup>
</Project>
4 changes: 4 additions & 0 deletions Sdks/AdminApi.Sdk/src/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Backbone.AdminApi.Sdk.Endpoints.Metrics;
using Backbone.AdminApi.Sdk.Endpoints.Relationships;
using Backbone.AdminApi.Sdk.Endpoints.Tiers;
using Backbone.AdminApi.Sdk.Endpoints.Tokens;
using Backbone.BuildingBlocks.SDK.Endpoints.Common;
using Backbone.Tooling.JsonConverters;

Expand All @@ -34,6 +35,7 @@ private Client(HttpClient httpClient, string apiKey)
Tiers = new TiersEndpoint(endpointClient);
Challenges = new ChallengesEndpoint(endpointClient);
Messages = new MessagesEndpoint(endpointClient);
Tokens = new TokensEndpoint(endpointClient);
}

public ApiKeyValidationEndpoint ApiKeyValidation { get; }
Expand All @@ -46,6 +48,8 @@ private Client(HttpClient httpClient, string apiKey)
public ChallengesEndpoint Challenges { get; }
public MessagesEndpoint Messages { get; }

public TokensEndpoint Tokens { get; }

public static Client Create(string baseUrl, string apiKey)
{
return Create(new HttpClient { BaseAddress = new Uri(baseUrl) }, apiKey);
Expand Down
Loading
Loading