Skip to content

Commit

Permalink
feat: Internal issuer component enhance get credential endpoint by su…
Browse files Browse the repository at this point in the history
…pporting filters
  • Loading branch information
leandro-cavalcante committed Nov 12, 2024
1 parent dd4d7ea commit 0060508
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 15 deletions.
13 changes: 12 additions & 1 deletion docs/api/issuer-service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ paths:
tags:
- 'Org.Eclipse.TractusX.SsiCredentialIssuer.Service, Version=1.2.0.0, Culture=neutral, PublicKeyToken=null'
summary: Gets all use case frameworks and the participation status of the acting company
description: 'Example: GET: api/issuer/useCaseParticipation'
description: 'Example: GET: api/issuer/useCaseParticipation<br><h3>Available values:</h3> All, Active, Expired'
parameters:
- name: status
in: query
schema:
type: string
responses:
'200':
description: OK
Expand All @@ -30,6 +35,12 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: Conflict
content:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Org.Eclipse.TractusX.SsiCredentialIssuer.DBAccess.Models;

public enum StatusType
{
Active,
Expired,
All
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,19 @@ public class CompanySsiDetailsRepository(IssuerDbContext context)
: ICompanySsiDetailsRepository
{
/// <inheritdoc />
public IAsyncEnumerable<UseCaseParticipationData> GetUseCaseParticipationForCompany(string bpnl, DateTimeOffset minExpiry) =>
public IAsyncEnumerable<UseCaseParticipationData> GetUseCaseParticipationForCompany(string bpnl, DateTimeOffset minExpiry, StatusType? statusType) =>
context.VerifiedCredentialTypes
.Where(t => t.VerifiedCredentialTypeAssignedKind!.VerifiedCredentialTypeKindId == VerifiedCredentialTypeKindId.FRAMEWORK)
.Select(t => new
{
t.VerifiedCredentialTypeAssignedUseCase!.UseCase,
TypeId = t.Id,
ExternalTypeDetails = t.VerifiedCredentialTypeAssignedExternalType!.VerifiedCredentialExternalType!.VerifiedCredentialExternalTypeDetailVersions
.Where(x => !statusType.HasValue || statusType == StatusType.All
|| (statusType == StatusType.Active
&& (x.Expiry > minExpiry))
|| (statusType == StatusType.Expired && x.Expiry <= DateTimeOffset.UtcNow)
)
})
.Select(x => new UseCaseParticipationData(
x.UseCase!.Name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ public interface ICompanySsiDetailsRepository
/// </summary>
/// <param name="bpnl">Bpnl of the company</param>
/// <param name="minExpiry">The minimum datetime the expiry date should have</param>
/// <param name="statusType">the status type on how the credentials should be filtered</param>
/// <returns>AsyncEnumerable of UseCaseParticipation</returns>
IAsyncEnumerable<UseCaseParticipationData> GetUseCaseParticipationForCompany(string bpnl, DateTimeOffset minExpiry);
IAsyncEnumerable<UseCaseParticipationData> GetUseCaseParticipationForCompany(string bpnl, DateTimeOffset minExpiry, StatusType? statusType);

/// <summary>
/// Gets the company credential details for the given company id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace Org.Eclipse.TractusX.SsiCredentialIssuer.Service.BusinessLogic;

public interface IIssuerBusinessLogic
{
IAsyncEnumerable<UseCaseParticipationData> GetUseCaseParticipationAsync();
IAsyncEnumerable<UseCaseParticipationData> GetUseCaseParticipationAsync(string? status);

IAsyncEnumerable<CertificateParticipationData> GetSsiCertificatesAsync();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,22 @@ public IssuerBusinessLogic(
}

/// <inheritdoc />
public IAsyncEnumerable<UseCaseParticipationData> GetUseCaseParticipationAsync() =>
_repositories
public IAsyncEnumerable<UseCaseParticipationData> GetUseCaseParticipationAsync(string? status)
{
StatusType? statusTypeResult = null;
if (!string.IsNullOrEmpty(status))
{
if (!(Enum.TryParse<StatusType>(status, ignoreCase: true, out var statusType) || !Enum.IsDefined(typeof(StatusType), statusType)))
{
throw new ArgumentException($"Status value {status} is not valid; please use Active, Expired or All");
}
statusTypeResult = statusType;
}

return _repositories
.GetInstance<ICompanySsiDetailsRepository>()
.GetUseCaseParticipationForCompany(_identity.Bpnl, _dateTimeProvider.OffsetNow);
.GetUseCaseParticipationForCompany(_identity.Bpnl, _dateTimeProvider.OffsetNow, statusTypeResult);
}

/// <inheritdoc />
public IAsyncEnumerable<CertificateParticipationData> GetSsiCertificatesAsync() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,18 @@ public static RouteGroupBuilder MapIssuerApi(this RouteGroupBuilder group)
{
var issuer = group.MapGroup("/issuer");

issuer.MapGet("useCaseParticipation", (IIssuerBusinessLogic logic) => logic.GetUseCaseParticipationAsync())
issuer.MapGet("useCaseParticipation", (IIssuerBusinessLogic logic,
[FromQuery(Name = "status")] string? status) => logic.GetUseCaseParticipationAsync(status))
.WithSwaggerDescription("Gets all use case frameworks and the participation status of the acting company",
"Example: GET: api/issuer/useCaseParticipation")
"Example: GET: api/issuer/useCaseParticipation<br><h3>Available values:</h3> All, Active, Expired")
.RequireAuthorization(r =>
{
r.RequireRole("view_use_case_participation");
r.AddRequirements(new MandatoryIdentityClaimRequirement(PolicyTypeId.ValidBpn));
})
.WithDefaultResponses()
.Produces(StatusCodes.Status200OK, typeof(IEnumerable<UseCaseParticipationData>), Constants.JsonContentType)
.Produces(StatusCodes.Status400BadRequest, typeof(ErrorResponse), Constants.JsonContentType)
.Produces(StatusCodes.Status409Conflict, typeof(ErrorResponse), Constants.JsonContentType);

issuer.MapGet("certificates", (IIssuerBusinessLogic logic) => logic.GetSsiCertificatesAsync())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using FluentAssertions;
using Microsoft.EntityFrameworkCore;
using Org.Eclipse.TractusX.SsiCredentialIssuer.DbAccess.Tests.Setup;
using Org.Eclipse.TractusX.SsiCredentialIssuer.DBAccess.Models;
using Org.Eclipse.TractusX.SsiCredentialIssuer.DBAccess.Repositories;
using Org.Eclipse.TractusX.SsiCredentialIssuer.Entities;
using Org.Eclipse.TractusX.SsiCredentialIssuer.Entities.Entities;
Expand Down Expand Up @@ -49,14 +50,16 @@ public CompanySsiDetailsRepositoryTests(TestDbFixture testDbFixture)

#region GetDetailsForCompany

[Fact]
public async Task GetDetailsForCompany_WithValidData_ReturnsExpected()
[Theory]
[InlineData(null)]
[InlineData(StatusType.All)]
public async Task GetDetailsForCompany_WithValidData_And_StatusType_ReturnsExpected(StatusType? statusType)
{
// Arrange
var sut = await CreateSut();

// Act
var result = await sut.GetUseCaseParticipationForCompany(ValidBpnl, DateTimeOffset.MinValue).ToListAsync();
var result = await sut.GetUseCaseParticipationForCompany(ValidBpnl, DateTimeOffset.MinValue, statusType).ToListAsync();

// Assert
result.Should().HaveCount(10);
Expand Down Expand Up @@ -84,7 +87,7 @@ public async Task GetDetailsForCompany_WithExpiryFilter_ReturnsExpected()
var sut = await CreateSut();

// Act
var result = await sut.GetUseCaseParticipationForCompany(ValidBpnl, dt).ToListAsync();
var result = await sut.GetUseCaseParticipationForCompany(ValidBpnl, dt, null).ToListAsync();

// Assert
result.Should().HaveCount(10);
Expand All @@ -104,6 +107,56 @@ public async Task GetDetailsForCompany_WithExpiryFilter_ReturnsExpected()
x => x.ExternalDetailData.Version == "3.0" && !x.SsiDetailData.Any());
}

[Fact]
public async Task GetAllExternalTypeDetailDataWithValidData_WithValidData_and_StatusType_Active_ReturnsExpected()
{
// Arrange
var (sut, context) = await CreateSutWithContext();

Check warning

Code scanning / CodeQL

Useless assignment to local variable Warning test

This assignment to
context
is useless, since its value is never read.

//Act

var result = await sut.GetUseCaseParticipationForCompany(ValidBpnl, DateTimeOffset.UtcNow, StatusType.Active).ToListAsync();

// Assert
result.Should().HaveCount(10);
result.SelectMany(x => x.VerifiedCredentials)
.Select(x => x.ExternalDetailData)
.Should().HaveCount(1);
}

[Fact]
public async Task GetAllExternalTypeDetailDataWithValidData_and_StatusType_All_ReturnsExpected()
{
// Arrange
var sut = await CreateSut();

//Act

var result = await sut.GetUseCaseParticipationForCompany(ValidBpnl, DateTimeOffset.UtcNow, StatusType.All).ToListAsync();

// Assert
result.Should().HaveCount(10);
result.SelectMany(x => x.VerifiedCredentials)
.Select(x => x.ExternalDetailData)
.Should().HaveCount(11);
}

[Fact]
public async Task GetAllExternalTypeDetailDataWithValidData_WithValidData_and_StatusType_Expired_ReturnsExpected()
{
// Arrange
var (sut, context) = await CreateSutWithContext();

Check warning

Code scanning / CodeQL

Useless assignment to local variable Warning test

This assignment to
context
is useless, since its value is never read.
//Act

var result = await sut.GetUseCaseParticipationForCompany(ValidBpnl, DateTimeOffset.UtcNow, StatusType.Expired).ToListAsync();

// Assert
result.Should().HaveCount(10);
result.SelectMany(x => x.VerifiedCredentials)
.Select(x => x.ExternalDetailData)
.Should().HaveCount(10);
}

#endregion

#region GetAllCredentialDetails
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public async Task GetUseCaseParticipationAsync_ReturnsExpected()
Setup_GetUseCaseParticipationAsync();

// Act
var result = await _sut.GetUseCaseParticipationAsync().ToListAsync();
var result = await _sut.GetUseCaseParticipationAsync(null).ToListAsync();

// Assert
result.Should().HaveCount(5);
Expand Down Expand Up @@ -163,6 +163,93 @@ public async Task GetCredentialsForBpn_ReturnsExpected()
result.Should().HaveCount(5);
}

[Fact]
public async Task GetUseCaseParticipationAsync_WithValidStatus_ReturnsExpectedResults()
{
// Arrange
var status = "Active";
var now = DateTimeOffset.Now;
var verifiedCredentials = _fixture.Build<CompanySsiExternalTypeDetailData>()
.With(x => x.SsiDetailData, _fixture.CreateMany<CompanySsiDetailData>(1))
.CreateMany(5);
var expectedData = new List<UseCaseParticipationData>
{
new UseCaseParticipationData("Test", "Test", VerifiedCredentialTypeId.TRACEABILITY_FRAMEWORK, verifiedCredentials)
}.ToAsyncEnumerable();

A.CallTo(() => _dateTimeProvider.OffsetNow).Returns(now);
A.CallTo(() => _companySsiDetailsRepository.GetUseCaseParticipationForCompany(_identity.Bpnl, now, StatusType.Active))
.Returns(expectedData);

// Act
var result = await _sut.GetUseCaseParticipationAsync(status).ToListAsync();

// Assert
result.Should().BeEquivalentTo(expectedData.ToEnumerable());
}

[Fact]
public async Task GetUseCaseParticipationAsync_WithInvalidStatus_ThrowsArgumentException()
{
// Arrange
var status = "InvalidStatus";

// Act
Func<Task> act = async () => await _sut.GetUseCaseParticipationAsync(status).ToListAsync();

// Assert
await act.Should().ThrowAsync<ArgumentException>()
.WithMessage("Status value InvalidStatus is not valid; please use Active, Expired or All");
}

[Fact]
public async Task GetUseCaseParticipationAsync_WithNullStatus_ReturnsExpectedResults()
{
// Arrange
var now = DateTimeOffset.Now;
var verifiedCredentials = _fixture.Build<CompanySsiExternalTypeDetailData>()
.With(x => x.SsiDetailData, _fixture.CreateMany<CompanySsiDetailData>(1))
.CreateMany(5);
var expectedData = new List<UseCaseParticipationData>
{
new UseCaseParticipationData("Test", "Test", VerifiedCredentialTypeId.TRACEABILITY_FRAMEWORK, verifiedCredentials)
}.ToAsyncEnumerable();

A.CallTo(() => _dateTimeProvider.OffsetNow).Returns(now);
A.CallTo(() => _companySsiDetailsRepository.GetUseCaseParticipationForCompany(_identity.Bpnl, now, null))
.Returns(expectedData);

// Act
var result = await _sut.GetUseCaseParticipationAsync(null).ToListAsync();

// Assert
result.Should().BeEquivalentTo(expectedData.ToEnumerable());
}

[Fact]
public async Task GetUseCaseParticipationAsync_WithAllStatus_ReturnsExpectedResults()
{
// Arrange
var now = DateTimeOffset.Now;
var verifiedCredentials = _fixture.Build<CompanySsiExternalTypeDetailData>()
.With(x => x.SsiDetailData, _fixture.CreateMany<CompanySsiDetailData>(1))
.CreateMany(5);
var expectedData = new List<UseCaseParticipationData>
{
new UseCaseParticipationData("Test", "Test", VerifiedCredentialTypeId.TRACEABILITY_FRAMEWORK, verifiedCredentials)
}.ToAsyncEnumerable();

A.CallTo(() => _dateTimeProvider.OffsetNow).Returns(now);
A.CallTo(() => _companySsiDetailsRepository.GetUseCaseParticipationForCompany(_identity.Bpnl, now, StatusType.All))
.Returns(expectedData);

// Act
var result = await _sut.GetUseCaseParticipationAsync("All").ToListAsync();

// Assert
result.Should().BeEquivalentTo(expectedData.ToEnumerable());
}

#endregion

#region ApproveCredential
Expand Down Expand Up @@ -1081,7 +1168,7 @@ private void Setup_GetUseCaseParticipationAsync()
var verifiedCredentials = _fixture.Build<CompanySsiExternalTypeDetailData>()
.With(x => x.SsiDetailData, _fixture.CreateMany<CompanySsiDetailData>(1))
.CreateMany(5);
A.CallTo(() => _companySsiDetailsRepository.GetUseCaseParticipationForCompany(Bpnl, A<DateTimeOffset>._))
A.CallTo(() => _companySsiDetailsRepository.GetUseCaseParticipationForCompany(Bpnl, A<DateTimeOffset>._, null))
.Returns(_fixture.Build<UseCaseParticipationData>().With(x => x.VerifiedCredentials, verifiedCredentials).CreateMany(5).ToAsyncEnumerable());
}

Expand Down

0 comments on commit 0060508

Please sign in to comment.