From a7028c41bc47166b21a70d1263714e90975f3090 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Tue, 16 May 2023 12:07:24 +0000 Subject: [PATCH] feat(user): adding admin details for GetOwnUserDetails (#32) * Endpoint GET: api/administration/user/ownUser is being enhanced by adding into the response body the users company administratorsAdd details of admin-users. Ref: CPLP2598 --------- Co-authored-by: VPrasannaK94 Reviewed-By: Norbert Truchsess --- .../BusinessLogic/IUserBusinessLogic.cs | 2 +- .../BusinessLogic/UserBusinessLogic.cs | 6 +- .../BusinessLogic/UserSettings.cs | 6 ++ .../Controllers/UserController.cs | 4 +- .../Models/CompanyUserDetails.cs | 35 ++++++++++-- .../Repositories/IUserRepository.cs | 2 +- .../Repositories/UserRepository.cs | 12 ++-- .../BusinessLogic/UserBusinessLogicTests.cs | 55 +++++++++++++++++-- .../Controllers/UserControllerTest.cs | 18 ++++++ .../appsettings.IntegrationTests.json | 6 ++ .../company_user_assigned_roles.test.json | 10 ++++ .../Seeder/Data/user_roles.test.json | 13 +++++ .../UserRepositoryTests.cs | 30 ++++++++++ 13 files changed, 179 insertions(+), 20 deletions(-) diff --git a/src/administration/Administration.Service/BusinessLogic/IUserBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/IUserBusinessLogic.cs index bc6d532d1a..e4fd397414 100644 --- a/src/administration/Administration.Service/BusinessLogic/IUserBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/IUserBusinessLogic.cs @@ -37,7 +37,7 @@ public interface IUserBusinessLogic Task GetOwnCompanyUserDetailsAsync(Guid companyUserId, string iamUserId); Task AddOwnCompanyUsersBusinessPartnerNumbersAsync(Guid companyUserId, IEnumerable businessPartnerNumbers, string adminUserId); Task AddOwnCompanyUsersBusinessPartnerNumberAsync(Guid companyUserId, string businessPartnerNumber, string adminUserId); - Task GetOwnUserDetails(string iamUserId); + Task GetOwnUserDetails(string iamUserId); Task UpdateOwnUserDetails(Guid companyUserId, OwnCompanyUserEditableDetails ownCompanyUserEditableDetails, string iamUserId); /// diff --git a/src/administration/Administration.Service/BusinessLogic/UserBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/UserBusinessLogic.cs index aaa9caa9d2..ae1411a8f5 100644 --- a/src/administration/Administration.Service/BusinessLogic/UserBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/UserBusinessLogic.cs @@ -311,9 +311,11 @@ public async Task AddOwnCompanyUsersBusinessPartnerNumbersAsync(Guid compan public Task AddOwnCompanyUsersBusinessPartnerNumberAsync(Guid companyUserId, string businessPartnerNumber, string adminUserId) => AddOwnCompanyUsersBusinessPartnerNumbersAsync(companyUserId, Enumerable.Repeat(businessPartnerNumber, 1), adminUserId); - public async Task GetOwnUserDetails(string iamUserId) + public async Task GetOwnUserDetails(string iamUserId) { - var details = await _portalRepositories.GetInstance().GetUserDetailsUntrackedAsync(iamUserId).ConfigureAwait(false); + var userRoleIds = await _portalRepositories.GetInstance() + .GetUserRoleIdsUntrackedAsync(_settings.UserAdminRoles).ToListAsync().ConfigureAwait(false); + var details = await _portalRepositories.GetInstance().GetUserDetailsUntrackedAsync(iamUserId, userRoleIds).ConfigureAwait(false); if (details == null) { throw new NotFoundException($"no company-user data found for user {iamUserId}"); diff --git a/src/administration/Administration.Service/BusinessLogic/UserSettings.cs b/src/administration/Administration.Service/BusinessLogic/UserSettings.cs index bdd6556af6..27382bf95f 100644 --- a/src/administration/Administration.Service/BusinessLogic/UserSettings.cs +++ b/src/administration/Administration.Service/BusinessLogic/UserSettings.cs @@ -42,6 +42,12 @@ public UserSettings() /// [Required] public IEnumerable CompanyUserStatusIds { get; set; } = null!; + + /// + /// Company User Status Id + /// + [Required] + public IDictionary> UserAdminRoles { get; set; } = null!; } public class UserSetting diff --git a/src/administration/Administration.Service/Controllers/UserController.cs b/src/administration/Administration.Service/Controllers/UserController.cs index 98bb84606e..2e1cf39a5d 100644 --- a/src/administration/Administration.Service/Controllers/UserController.cs +++ b/src/administration/Administration.Service/Controllers/UserController.cs @@ -388,9 +388,9 @@ public IAsyncEnumerable GetClientRolesAsync([FromRoute] Guid appId, [HttpGet] [Authorize(Roles = "view_own_user_account")] [Route("ownUser")] - [ProducesResponseType(typeof(CompanyUserDetails), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(CompanyOwnUserDetails), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)] - public Task GetOwnUserDetails() => + public Task GetOwnUserDetails() => this.WithIamUserId(iamUserId => _logic.GetOwnUserDetails(iamUserId)); /// diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserDetails.cs b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserDetails.cs index 4fdda6667b..04a2264d78 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserDetails.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserDetails.cs @@ -24,12 +24,12 @@ namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; public record CompanyUserDetails( - [property: JsonPropertyName("companyUserId")] Guid companyUserId, - [property: JsonPropertyName("created")] DateTimeOffset createdAt, - [property: JsonPropertyName("bpn")] IEnumerable businessPartnerNumbers, - [property: JsonPropertyName("company")] string companyName, - [property: JsonPropertyName("status")] CompanyUserStatusId companyUserStatusId, - [property: JsonPropertyName("assignedRoles")] IEnumerable assignedRoles) + [property: JsonPropertyName("companyUserId")] Guid Company2UserId, + [property: JsonPropertyName("created")] DateTimeOffset CreatedAt, + [property: JsonPropertyName("bpn")] IEnumerable BusinessPartnerNumbers, + [property: JsonPropertyName("company")] string CompanyName, + [property: JsonPropertyName("status")] CompanyUserStatusId CompanyUserStatusId, + [property: JsonPropertyName("assignedRoles")] IEnumerable AssignedRoles) { [JsonPropertyName("firstName")] public string? FirstName { get; set; } @@ -41,6 +41,29 @@ public record CompanyUserDetails( public string? Email { get; set; } } +public record CompanyOwnUserDetails( + [property: JsonPropertyName("companyUserId")] Guid CompanyUserId, + [property: JsonPropertyName("created")] DateTimeOffset CreatedAt, + [property: JsonPropertyName("bpn")] IEnumerable BusinessPartnerNumbers, + [property: JsonPropertyName("company")] string CompanyName, + [property: JsonPropertyName("status")] CompanyUserStatusId CompanyUserStatusId, + [property: JsonPropertyName("assignedRoles")] IEnumerable AssignedRoles, + [property: JsonPropertyName("admin")] IEnumerable AdminDetails) +{ + [JsonPropertyName("firstName")] + public string? FirstName { get; set; } + + [JsonPropertyName("lastName")] + public string? LastName { get; set; } + + [JsonPropertyName("email")] + public string? Email { get; set; } +} + +public record CompanyUserAdminDetails( + [property: JsonPropertyName("id")] Guid CompanyUserId, + [property: JsonPropertyName("email")] string? Email); + public record CompanyUserAssignedRoleDetails( [property: JsonPropertyName("appId")] Guid OfferId, [property: JsonPropertyName("roles")] IEnumerable UserRoles); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IUserRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IUserRepository.cs index 0367a68c61..068f2878c4 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IUserRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IUserRepository.cs @@ -54,7 +54,7 @@ public interface IUserRepository /// Returns the id of the CompanyUser Task GetCompanyUserIdForIamUserUntrackedAsync(string userId); - Task GetUserDetailsUntrackedAsync(string iamUserId); + Task GetUserDetailsUntrackedAsync(string iamUserId, IEnumerable userRoleIds); Task GetUserWithCompanyIdpAsync(string iamUserId); Task GetCompanyUserIdForUserApplicationUntrackedAsync(Guid applicationId, string iamUserId); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRepository.cs index 167997e7e8..9971698080 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRepository.cs @@ -226,11 +226,12 @@ public Task GetCompanyIdForIamUserUntrackedAsync(string iamUserId) => iamUser.CompanyUser.Company!.CompanyAssignedRoles.SelectMany(car => car.CompanyRole!.CompanyRoleAssignedRoleCollection!.UserRoleCollection!.UserRoles.Where(ur => ur.Offer!.AppInstances.Any(ai => ai.IamClient!.ClientClientId == technicalUserClientId)).Select(ur => ur.Id)).Distinct())) .SingleOrDefaultAsync(); - public Task GetUserDetailsUntrackedAsync(string iamUserId) => + public Task GetUserDetailsUntrackedAsync(string iamUserId, IEnumerable userRoleIds) => _dbContext.CompanyUsers .AsNoTracking() + .AsSplitQuery() .Where(companyUser => companyUser.IamUser!.UserEntityId == iamUserId) - .Select(companyUser => new CompanyUserDetails( + .Select(companyUser => new CompanyOwnUserDetails( companyUser.Id, companyUser.DateCreated, companyUser.CompanyUserAssignedBusinessPartners.Select(assignedPartner => @@ -244,8 +245,11 @@ public Task GetCompanyIdForIamUserUntrackedAsync(string iamUserId) => app.Offer!.UserRoles .Where(role => role.CompanyUsers.Any(user => user.Id == companyUser.Id)) .Select(role => role.UserRoleText) - )) - ) + )), + companyUser.Company.CompanyUsers.Where(user => user.UserRoles.Any(role => userRoleIds.Contains(role.Id))) + .Select(admin => new CompanyUserAdminDetails( + admin.Id, + admin.Email))) { FirstName = companyUser.Firstname, LastName = companyUser.Lastname, diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs index d8120fffb3..96a4237c3d 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs @@ -113,6 +113,10 @@ public UserBusinessLogicTests() } }; _error = _fixture.Create(); + + A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRepository); + A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRolesRepository); + A.CallTo(() => _portalRepositories.GetInstance()).Returns(_notificationRepository); } #region CreateOwnCompanyUsersAsync @@ -1323,7 +1327,53 @@ public async Task GetOwnCompanyAppUsersAsync_WithValidData_ThrowsForbiddenExcept } #endregion - + + #region GetOwnUserDetails + + [Fact] + public async Task GetOwnUserDetails_ReturnsExpected() + { + // Arrange + var companyOwnUserDetails = _fixture.Create(); + var iamUserId = _fixture.Create().ToString(); + var userRoleIds = new [] { _fixture.Create(), _fixture.Create()}; + + A.CallTo(() => _userRolesRepository.GetUserRoleIdsUntrackedAsync(A>>._)) + .Returns(userRoleIds.ToAsyncEnumerable()); + A.CallTo(() => _userRepository.GetUserDetailsUntrackedAsync(A._, A>._)) + .Returns(companyOwnUserDetails); + var sut = new UserBusinessLogic(_provisioningManager, null!, null!, _portalRepositories, null!, _logger, _options); + + // Act + var result = await sut.GetOwnUserDetails(iamUserId).ConfigureAwait(false); + + // Assert + A.CallTo(() => _userRolesRepository.GetUserRoleIdsUntrackedAsync(A>> + .That.IsSameSequenceAs(_options.Value.UserAdminRoles))).MustHaveHappenedOnceExactly(); + A.CallTo(() => _userRepository.GetUserDetailsUntrackedAsync(iamUserId, A>.That.IsSameSequenceAs(userRoleIds))).MustHaveHappenedOnceExactly(); + result.Should().Be(companyOwnUserDetails); + } + + [Fact] + public async Task GetOwnUserDetails_ThrowsNotFoundException() + { + // Arrange + var iamUserId = _fixture.Create().ToString(); + + A.CallTo(() => _userRepository.GetUserDetailsUntrackedAsync(iamUserId,A>._)) + .Returns((CompanyOwnUserDetails) default!); + var sut = new UserBusinessLogic(_provisioningManager, null!, null!, _portalRepositories, null!, _logger, _options); + + // Act + async Task Act() => await sut.GetOwnUserDetails(iamUserId).ConfigureAwait(false); + + // Assert + var error = await Assert.ThrowsAsync(Act).ConfigureAwait(false); + error.Message.Should().Be($"no company-user data found for user {iamUserId}"); + } + + #endregion + #region Setup private void SetupFakesForUserCreation(bool isBulkUserCreation) @@ -1465,9 +1515,6 @@ private void SetupFakesForUserRoleModification(List? notifications } _fixture.Inject(_provisioningManager); - A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRepository); - A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRolesRepository); - A.CallTo(() => _portalRepositories.GetInstance()).Returns(_notificationRepository); } private UserCreationInfo CreateUserCreationInfo() => diff --git a/tests/administration/Administration.Service.Tests/Controllers/UserControllerTest.cs b/tests/administration/Administration.Service.Tests/Controllers/UserControllerTest.cs index bf8c10115e..c2c85ec33b 100644 --- a/tests/administration/Administration.Service.Tests/Controllers/UserControllerTest.cs +++ b/tests/administration/Administration.Service.Tests/Controllers/UserControllerTest.cs @@ -34,9 +34,11 @@ public class UserControllerTest private readonly IUserBusinessLogic _logic; private readonly IUserRolesBusinessLogic _rolesLogic; private readonly UserController _controller; + private readonly Fixture _fixture; public UserControllerTest() { + _fixture = new Fixture(); _logic = A.Fake(); _rolesLogic = A.Fake(); var logger = A.Fake>(); @@ -62,4 +64,20 @@ public async Task ModifyUserRolesAsync_WithValidData_ReturnsExpectedResult() Assert.IsType>(result); result.Should().BeEmpty(); } + + [Fact] + public async Task GetOwnUserDetails_ReturnsExpectedResult() + { + // Arrange + var data = _fixture.Create(); + A.CallTo(() => _logic.GetOwnUserDetails(IamUserId)) + .Returns(data); + + // Act + var result = await this._controller.GetOwnUserDetails().ConfigureAwait(false); + + // Assert + A.CallTo(() => _logic.GetOwnUserDetails(IamUserId)).MustHaveHappenedOnceExactly(); + result.Should().Be(data); + } } diff --git a/tests/administration/Administration.Service.Tests/appsettings.IntegrationTests.json b/tests/administration/Administration.Service.Tests/appsettings.IntegrationTests.json index 4154897956..04b834c13c 100644 --- a/tests/administration/Administration.Service.Tests/appsettings.IntegrationTests.json +++ b/tests/administration/Administration.Service.Tests/appsettings.IntegrationTests.json @@ -263,6 +263,12 @@ "Portal": { "KeycloakClientID": "test", "BasePortalAddress": "https://test-portal.azurewebsites.net" + }, + "UserAdminRoles": { + "Cl2-CX-Portal": [ + "Company Admin", + "IT Admin" + ] } }, "ApplicationChecklist": { diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/company_user_assigned_roles.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/company_user_assigned_roles.test.json index 9903b29d20..e12f556ffc 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/company_user_assigned_roles.test.json +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/company_user_assigned_roles.test.json @@ -43,5 +43,15 @@ "company_user_id": "ac1cf001-7fbc-1f2f-817f-bce058020006", "user_role_id": "aabcdfeb-6669-4c74-89f0-19cda090873e", "last_editor_id": null + }, + { + "company_user_id": "ac1cf001-7fbc-1f2f-817f-bce058019992", + "user_role_id": "efc20368-9e82-46ff-b88f-6495b9810254", + "last_editor_id": null + }, + { + "company_user_id": "ac1cf001-7fbc-1f2f-817f-bce058019993", + "user_role_id": "efc20368-9e82-46ff-b88f-6495b9810254", + "last_editor_id": null } ] \ No newline at end of file diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/user_roles.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/user_roles.test.json index 555aaebef0..f3ef88ddcd 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/user_roles.test.json +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/user_roles.test.json @@ -16,5 +16,18 @@ "user_role": "test", "offer_id": "a16e73b9-5277-4b69-9f8d-3b227495dfea", "last_editor_id": null + }, + { + "id": "efc20368-9e82-46ff-b88f-6495b9810254", + "user_role": "Company Admin", + "offer_id": "a16e73b9-5277-4b69-9f8d-3b227495dfea", + "last_editor_id": null + } + , + { + "id": "efc20368-9e82-46ff-b88f-6495b9810255", + "user_role": "IT Admin", + "offer_id": "a16e73b9-5277-4b69-9f8d-3b227495dfea", + "last_editor_id": null } ] diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRepositoryTests.cs index f415a78e19..befc61d40c 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRepositoryTests.cs @@ -447,6 +447,36 @@ public async Task GetCoreOfferAssignedIamClientUserDataUntrackedAsync_ReturnsExp #endregion + #region GetUserDetails + + [Fact] + public async Task GetUserDetailsUntrackedAsync_ReturnsExpected() + { + // Arrange + var sut = await CreateSut().ConfigureAwait(false); + var userRoleIds = new []{ + new Guid("efc20368-9e82-46ff-b88f-6495b9810255"), + new Guid("efc20368-9e82-46ff-b88f-6495b9810254")}; + + // Act + var result = await sut.GetUserDetailsUntrackedAsync("e5e403d5-3bd9-48f6-8931-7c0c717c3f40", userRoleIds).ConfigureAwait(false); + + // Assert + result.Should().NotBeNull(); + result!.CompanyName.Should().Be("Security Company"); + result.CompanyUserId.Should().Be("ac1cf001-7fbc-1f2f-817f-bce058019992"); + result.Email.Should().Be("julia.jeroch@bmw.de"); + result.FirstName.Should().Be("Test User"); + result.BusinessPartnerNumbers.Should().BeEmpty(); + result.AdminDetails.Should().NotBeEmpty() + .And.HaveCount(2) + .And.Satisfy( + x => x.CompanyUserId == new Guid("ac1cf001-7fbc-1f2f-817f-bce058019992") && x.Email == "julia.jeroch@bmw.de", + x => x.CompanyUserId == new Guid("ac1cf001-7fbc-1f2f-817f-bce058019993") && x.Email == "julia.jeroch@bmw.de"); + } + + #endregion + private async Task CreateSut() { var context = await _dbTestDbFixture.GetPortalDbContext().ConfigureAwait(false);