Skip to content

Commit

Permalink
feat(apps): create endpoint to fetch activeAppRoleDetails (#622)
Browse files Browse the repository at this point in the history
* create endpoint to fetch activeAppRoleDetails
Ref : #573
---------
Co-authored-by: Norbert Truchsess <[email protected]>
  • Loading branch information
VPrasannaK94 authored Apr 11, 2024
1 parent 07832c1 commit 2f9ab33
Show file tree
Hide file tree
Showing 9 changed files with 235 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
using Org.Eclipse.TractusX.Portal.Backend.Framework.DateTimeProvider;
using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling;
using Org.Eclipse.TractusX.Portal.Backend.Framework.IO;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Web;
using Org.Eclipse.TractusX.Portal.Backend.Notifications.Library;
using Org.Eclipse.TractusX.Portal.Backend.Offers.Library.Service;
Expand Down Expand Up @@ -362,4 +363,19 @@ public async Task DeleteActiveAppDocumentAsync(Guid appId, Guid documentId)
/// <inheritdoc />
public async Task CreateActiveAppDocumentAsync(Guid appId, DocumentTypeId documentTypeId, IFormFile document, CancellationToken cancellationToken) =>
await _offerDocumentService.UploadDocumentAsync(appId, documentTypeId, document, OfferTypeId.APP, _settings.UploadActiveAppDocumentTypeIds, OfferStatusId.ACTIVE, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);

/// <inheritdoc />
public async Task<IEnumerable<ActiveAppRoleDetails>> GetActiveAppRolesAsync(Guid appId, string? languageShortName)
{
var (isValid, isActive, roleDetails) = await _portalRepositories.GetInstance<IUserRolesRepository>().GetActiveAppRolesAsync(appId, OfferTypeId.APP, languageShortName, Constants.DefaultLanguage).ConfigureAwait(ConfigureAwaitOptions.None);
if (!isValid)
{
throw new NotFoundException($"App {appId} does not exist");
}
if (!isActive)
{
throw new ConflictException($"App {appId} is not Active");
}
return roleDetails ?? throw new UnexpectedConditionException("roleDetails should never be null here");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,11 @@ public interface IAppChangeBusinessLogic
/// <param name="document"></param>
/// <param name="cancellationToken"></param>
Task CreateActiveAppDocumentAsync(Guid appId, DocumentTypeId documentTypeId, IFormFile document, CancellationToken cancellationToken);

/// <summary>
/// Gets user roles for an active app id
/// </summary>
/// <param name="appId">Id of the offer</param>
/// <param name="languageShortName"></param>
Task<IEnumerable<ActiveAppRoleDetails>> GetActiveAppRolesAsync(Guid appId, string? languageShortName);
}
18 changes: 18 additions & 0 deletions src/marketplace/Apps.Service/Controllers/AppChangeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,4 +256,22 @@ public async Task<NoContentResult> CreateActiveAppDocumentAsync([FromRoute] Guid
await _businessLogic.CreateActiveAppDocumentAsync(appId, documentTypeId, document, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
return NoContent();
}

/// <summary>
/// Gets the client roles for the given active app.
/// </summary>
/// <param name="appId" example="D3B1ECA2-6148-4008-9E6C-C1C2AEA5C645">Id of the app which roles should be returned.</param>
/// <param name="languageShortName">OPTIONAL: The language short name.</param>
/// <returns>Returns the client roles for the given active app.</returns>
/// <remarks>Example: GET: /api/apps/AppChange/D3B1ECA2-6148-4008-9E6C-C1C2AEA5C645/roles</remarks>
/// <response code="200">Returns the client roles.</response>
/// <response code="400">The language does not exist.</response>
/// <response code="404">The app was not found.</response>
[HttpGet]
[Authorize(Roles = "view_client_roles")]
[Authorize(Policy = PolicyTypes.ValidCompany)]
[Route("{appId}/roles")]
[ProducesResponseType(typeof(IEnumerable<ActiveAppRoleDetails>), StatusCodes.Status200OK)]
public Task<IEnumerable<ActiveAppRoleDetails>> GetActiveAppRolesAsync([FromRoute] Guid appId, [FromQuery] string? languageShortName = null) =>
_businessLogic.GetActiveAppRolesAsync(appId, languageShortName);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/********************************************************************************
* Copyright (c) 2021, 2023 BMW Group AG
* Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
Expand Down Expand Up @@ -29,3 +28,12 @@ public record OfferRoleInfo(
public record OfferRoleInfos(
[property: JsonPropertyName("offerId")] Guid OfferId,
[property: JsonPropertyName("roles")] IEnumerable<OfferRoleInfo> RoleInfos);

public record ActiveAppRoleDetails(
[property: JsonPropertyName("role")] string Role,
[property: JsonPropertyName("descriptions")] IEnumerable<ActiveAppUserRoleDescription> Descriptions);

public record ActiveAppUserRoleDescription(
[property: JsonPropertyName("languageCode")] string LanguageCode,
[property: JsonPropertyName("description")] string Description);

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums;

namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories;

Expand Down Expand Up @@ -70,4 +71,12 @@ public interface IUserRolesRepository

IAsyncEnumerable<(Guid CompanyUserId, IEnumerable<Guid> UserRoleIds)> GetUserWithUserRolesForApplicationId(Guid applicationId, IEnumerable<Guid> userRoleIds);
IAsyncEnumerable<Guid> GetRolesForClient(string technicalUserProfileClient);

/// <summary>
/// Gets userRoles for an offerId
/// </summary>
/// <param name="offerId"></param>
/// <param name="languageShortName"></param>
/// <returns></returns>
Task<(bool IsValid, bool IsActive, IEnumerable<ActiveAppRoleDetails>? AppRoleDetails)> GetActiveAppRolesAsync(Guid offerId, OfferTypeId offerTypeId, string? languageShortName, string defaultLanguageShortName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -275,4 +275,30 @@ public IAsyncEnumerable<Guid> GetRolesForClient(string technicalUserProfileClien
.Where(instance => technicalUserProfileClient == instance.IamClient!.ClientClientId)
.SelectMany(instance => instance.App!.UserRoles.Select(role => role.Id))
.ToAsyncEnumerable();

/// <inheritdoc />
public Task<(bool IsValid, bool IsActive, IEnumerable<ActiveAppRoleDetails>? AppRoleDetails)> GetActiveAppRolesAsync(Guid offerId, OfferTypeId offerTypeId, string? languageShortName, string defaultLanguageShortName) =>
_dbContext.Offers
.AsNoTracking()
.Where(offer => offer!.Id == offerId && offer.OfferTypeId == offerTypeId)
.Select(offer => new
{
Active = offer.OfferStatusId == OfferStatusId.ACTIVE,
Roles = offer.UserRoles
})
.Select(x => new ValueTuple<bool, bool, IEnumerable<ActiveAppRoleDetails>?>(
true,
x.Active,
x.Active
? x.Roles.Select(role =>
new ActiveAppRoleDetails(
role.UserRoleText,
role.UserRoleDescriptions.Where(description =>
(languageShortName != null && description.LanguageShortName == languageShortName) ||
description.LanguageShortName == defaultLanguageShortName)
.Select(description => new ActiveAppUserRoleDescription(
description.LanguageShortName,
description.Description))))
: null))
.SingleOrDefaultAsync();
}
Original file line number Diff line number Diff line change
Expand Up @@ -1147,4 +1147,77 @@ public async Task CreateActiveAppDocumentAsync_ReturnsExpected()

#endregion

#region GetActiveAppRoles

[Fact]
public async Task GetActiveAppRolesAsync_Throws_NotFoundException()
{
// Arrange
var appId = _fixture.Create<Guid>();
var activeAppRoleDetails = default((bool, bool, IEnumerable<ActiveAppRoleDetails>));
A.CallTo(() => _userRolesRepository.GetActiveAppRolesAsync(A<Guid>._, A<OfferTypeId>._, A<string>._, A<string>._))
.Returns(activeAppRoleDetails);

// Act
Task Act() => _sut.GetActiveAppRolesAsync(appId, null);

// Assert
var result = await Assert.ThrowsAsync<NotFoundException>(Act);
result.Message.Should().Be($"App {appId} does not exist");
A.CallTo(() => _userRolesRepository.GetActiveAppRolesAsync(appId, OfferTypeId.APP, null, "en"))
.MustHaveHappenedOnceExactly();
}

[Fact]
public async Task GetActiveAppRolesAsync_Throws_ConflictException()
{
// Arrange
var appId = _fixture.Create<Guid>();
var activeAppRoleDetails = (true, false, _fixture.CreateMany<ActiveAppRoleDetails>());
A.CallTo(() => _userRolesRepository.GetActiveAppRolesAsync(A<Guid>._, A<OfferTypeId>._, A<string>._, A<string>._))
.Returns(activeAppRoleDetails);

// Act
Task Act() => _sut.GetActiveAppRolesAsync(appId, "de");

// Assert
var result = await Assert.ThrowsAsync<ConflictException>(Act);
result.Message.Should().Be($"App {appId} is not Active");
A.CallTo(() => _userRolesRepository.GetActiveAppRolesAsync(appId, OfferTypeId.APP, "de", "en"))
.MustHaveHappenedOnceExactly();
}

[Fact]
public async Task GetActiveAppRolesAsync_ReturnsExpected()
{
// Arrange
var appId = _fixture.Create<Guid>();
var userRole1 = new ActiveAppRoleDetails("TestRole1", [
new ActiveAppUserRoleDescription("en", "TestRole1 description")
]);
var userRole2 = new ActiveAppRoleDetails("TestRole2", [
new ActiveAppUserRoleDescription("en", "TestRole2 description")
]);
var activeAppRoleDetails = (true, true, new[] {
userRole1,
userRole2
});

A.CallTo(() => _userRolesRepository.GetActiveAppRolesAsync(A<Guid>._, A<OfferTypeId>._, A<string>._, A<string>._))
.Returns(activeAppRoleDetails);

// Act
var result = await _sut.GetActiveAppRolesAsync(appId, "de");

// Assert
result.Should().HaveCount(2)
.And.Satisfy(
x => x.Role == "TestRole1" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole1 description",
x => x.Role == "TestRole2" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole2 description");
A.CallTo(() => _userRolesRepository.GetActiveAppRolesAsync(appId, OfferTypeId.APP, "de", "en"))
.MustHaveHappenedOnceExactly();
}

#endregion

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
using AutoFixture;
using FakeItEasy;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Org.Eclipse.TractusX.Portal.Backend.Apps.Service.BusinessLogic;
using Org.Eclipse.TractusX.Portal.Backend.Apps.Service.ViewModels;
Expand All @@ -29,6 +28,7 @@
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Identities;
using Org.Eclipse.TractusX.Portal.Backend.Tests.Shared;
using Org.Eclipse.TractusX.Portal.Backend.Tests.Shared.Extensions;
using System.Collections.Immutable;
using Xunit;

namespace Org.Eclipse.TractusX.Portal.Backend.Apps.Service.Controllers.Tests;
Expand Down Expand Up @@ -193,4 +193,25 @@ public async Task CreateActiveAppDocumentAsync_ReturnsExpected()
// Assert
A.CallTo(() => _logic.CreateActiveAppDocumentAsync(appId, documentTypeId, file, CancellationToken.None)).MustHaveHappened();
}

[Fact]
public async Task GetActiveAppRolesAsync_ReturnsExpected()
{
// Arrange
var appId = _fixture.Create<Guid>();
var language = _fixture.Create<string>();
var activeAppRoleDetails = _fixture.CreateMany<ActiveAppRoleDetails>(5).ToImmutableArray();

A.CallTo(() => _logic.GetActiveAppRolesAsync(A<Guid>._, A<string>._))
.Returns(activeAppRoleDetails);

// Act
var result = await _controller.GetActiveAppRolesAsync(appId, language);

// Assert
A.CallTo(() => _logic.GetActiveAppRolesAsync(appId, language))
.MustHaveHappenedOnceExactly();
result.Should().HaveSameCount(activeAppRoleDetails)
.And.ContainInOrder(activeAppRoleDetails);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Tests.Setup;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums;
using Xunit.Extensions.AssemblyFixture;

namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Tests;
Expand Down Expand Up @@ -167,10 +168,10 @@ public async Task GetUserRoleDataUntrackedAsync_WithNotMatchingClient_ReturnsEmp
{
// Arrange
var userRoleConfig = new[]{
new UserRoleConfig("not-existing-client", new []
{
new UserRoleConfig("not-existing-client",
[
"Company Admin"
})};
])};
var sut = await CreateSut();

// Act
Expand All @@ -182,6 +183,57 @@ public async Task GetUserRoleDataUntrackedAsync_WithNotMatchingClient_ReturnsEmp

#endregion

#region GetActiveAppRoles

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

// Act
var data = await sut.GetActiveAppRolesAsync(new Guid("deadbeef-dead-beef-dead-beefdeadbeef"), OfferTypeId.APP, "de", Constants.DefaultLanguage);

// Assert
data.IsValid.Should().BeFalse();
data.IsActive.Should().BeFalse();
data.AppRoleDetails.Should().BeNull();
}

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

// Act
var data = await sut.GetActiveAppRolesAsync(new Guid("99C5FD12-8085-4DE2-ABFD-215E1EE4BAA7"), OfferTypeId.APP, "de", Constants.DefaultLanguage);

// Assert
data.IsValid.Should().BeTrue();
data.IsActive.Should().BeFalse();
data.AppRoleDetails.Should().BeNull();
}

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

// Act
var data = await sut.GetActiveAppRolesAsync(new Guid("ac1cf001-7fbc-1f2f-817f-bce05744000b"), OfferTypeId.APP, "de", Constants.DefaultLanguage);

// Assert
data.IsValid.Should().BeTrue();
data.IsActive.Should().BeTrue();
data.AppRoleDetails.Should().HaveCount(2)
.And.Satisfy(
x => x.Role == "EarthCommerce.AdministratorRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en"),
x => x.Role == "EarthCommerce.Advanced.BuyerRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en"));
}

#endregion
private async Task<IUserRolesRepository> CreateSut()
{
var context = await _dbTestDbFixture.GetPortalDbContext();
Expand Down

0 comments on commit 2f9ab33

Please sign in to comment.