Skip to content

Commit

Permalink
fix(e2e): adjust end to end tests (#321)
Browse files Browse the repository at this point in the history
* fix: clearinghouse endToEnd test
* fix: adjust GetAssignedAndMatchingCoreOfferRoles
* chore: adjust bpdm test
* feat(e2e): adjust upload document logic
* fix role-deletion now also deleting non-assignable roles.
Refs: CPLP-3328
---------
Co-authored-by: Norbert Truchsess <[email protected]>
Reviewed-by: Norbert Truchsess <[email protected]>
  • Loading branch information
Phil91 authored Jan 8, 2024
1 parent 7790690 commit e4435b7
Show file tree
Hide file tree
Showing 20 changed files with 213 additions and 184 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Async;
using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Linq;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models;
Expand All @@ -29,6 +30,7 @@
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Identities;
using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library;
using System.Collections.Immutable;
using System.Text.Json;

namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.BusinessLogic;
Expand Down Expand Up @@ -82,14 +84,14 @@ public Task<IEnumerable<UserRoleWithId>> ModifyCoreOfferUserRolesAsync(Guid offe
offerId, companyUserId, roles, companyId,
data =>
{
var userName = $"{data.firstname} {data.lastname}";
var userName = $"{data.Firstname} {data.Lastname}";
return (JsonSerializer.Serialize(new
{
OfferId = data.offerId,
CoreOfferName = data.offerName,
OfferId = data.OfferId,
CoreOfferName = data.OfferName,
Username = string.IsNullOrWhiteSpace(userName) ? "User" : userName,
RemovedRoles = string.Join(",", data.removedRoles),
AddedRoles = string.Join(",", data.addedRoles)
RemovedRoles = string.Join(",", data.RemovedRoles),
AddedRoles = string.Join(",", data.AddedRoles)
}, _options), NotificationTypeId.ROLE_UPDATE_CORE_OFFER);
});
}
Expand All @@ -99,18 +101,18 @@ public Task<IEnumerable<UserRoleWithId>> ModifyAppUserRolesAsync(Guid appId, Gui
() => _portalRepositories.GetInstance<IUserRepository>()
.GetAppAssignedIamClientUserDataUntrackedAsync(appId, companyUserId, _identityData.CompanyId),
(Guid companyUserId, IEnumerable<string> roles, Guid offerId) => _portalRepositories.GetInstance<IUserRolesRepository>()
.GetAssignedAndMatchingAppRoles(companyUserId, roles, offerId),
.GetAssignedAndMatchingAppRoles(companyUserId, roles, offerId).Select(x => new UserRoleModificationData(x.UserRoleText, x.RoleId, x.IsAssigned, true)),
appId, companyUserId, roles, _identityData.CompanyId,
data =>
{
var userName = $"{data.firstname} {data.lastname}";
var userName = $"{data.Firstname} {data.Lastname}";
return (JsonSerializer.Serialize(new
{
OfferId = data.offerId,
AppName = data.offerName,
OfferId = data.OfferId,
AppName = data.OfferName,
Username = string.IsNullOrWhiteSpace(userName) ? "User" : userName,
RemovedRoles = string.Join(",", data.removedRoles),
AddedRoles = string.Join(",", data.addedRoles)
RemovedRoles = string.Join(",", data.RemovedRoles),
AddedRoles = string.Join(",", data.AddedRoles)
}, _options), NotificationTypeId.ROLE_UPDATE_APP_OFFER);
});

Expand All @@ -120,14 +122,14 @@ public Task<IEnumerable<UserRoleWithId>> ModifyUserRoleAsync(Guid appId, UserRol
() => _portalRepositories.GetInstance<IUserRepository>()
.GetAppAssignedIamClientUserDataUntrackedAsync(appId, userRoleInfo.CompanyUserId, _identityData.CompanyId),
(Guid companyUserId, IEnumerable<string> roles, Guid offerId) => _portalRepositories.GetInstance<IUserRolesRepository>()
.GetAssignedAndMatchingAppRoles(companyUserId, roles, offerId),
.GetAssignedAndMatchingAppRoles(companyUserId, roles, offerId).Select(x => new UserRoleModificationData(x.UserRoleText, x.RoleId, x.IsAssigned, true)),
appId, userRoleInfo.CompanyUserId, userRoleInfo.Roles, _identityData.CompanyId, null);

private async Task<IEnumerable<UserRoleWithId>> ModifyUserRolesInternal(
Func<Task<OfferIamUserData?>> getIamUserData,
Func<Guid, IEnumerable<string>, Guid, IAsyncEnumerable<UserRoleModificationData>> getUserRoleModificationData,
Guid offerId, Guid companyUserId, IEnumerable<string> roles, Guid adminCompanyId,
Func<(Guid offerId, string offerName, string? firstname, string? lastname, IEnumerable<string> removedRoles, IEnumerable<string> addedRoles), (string content, NotificationTypeId notificationTypeId)>? getNotificationData)
Func<(Guid OfferId, string OfferName, string? Firstname, string? Lastname, IEnumerable<string> RemovedRoles, IEnumerable<string> AddedRoles), (string Content, NotificationTypeId NotificationTypeId)>? getNotificationData)
{
var result = await getIamUserData().ConfigureAwait(false);
if (result == default)
Expand Down Expand Up @@ -158,19 +160,19 @@ private async Task<IEnumerable<UserRoleWithId>> ModifyUserRolesInternal(

var iamUserId = await _provisioningManager.GetUserByUserName(companyUserId.ToString()).ConfigureAwait(false) ?? throw new ConflictException($"user {companyUserId} is not associated with any iamUser");

var distinctRoles = roles.Where(role => !string.IsNullOrWhiteSpace(role)).Distinct().ToList();
var distinctRoles = roles.Where(role => !string.IsNullOrWhiteSpace(role)).Distinct().ToImmutableList();
var existingRoles = await getUserRoleModificationData(companyUserId, distinctRoles, offerId).ToListAsync().ConfigureAwait(false);
var nonExistingRoles = distinctRoles.Except(existingRoles.Select(r => r.CompanyUserRoleText));
if (nonExistingRoles.Any())
{
throw new ControllerArgumentException($"Invalid roles {string.Join(",", nonExistingRoles)}", nameof(roles));
}
var rolesToAdd = existingRoles.Where(role => !role.IsAssignedToUser);
var rolesToDelete = existingRoles.Where(x => x.IsAssignedToUser).ExceptBy(distinctRoles, role => role.CompanyUserRoleText);
existingRoles.DuplicatesBy(x => x.CompanyUserRoleText).IfAny(
duplicateRoles => throw new ConflictException($"roles {string.Join(",", $"{duplicateRoles.Select(role => $"[{role.CompanyUserRoleText}, {role.CompanyUserRoleId}]")}")} are ambigous"));

distinctRoles.Except(existingRoles.Where(r => r.IsAssignable).Select(r => r.CompanyUserRoleText)).IfAny(
nonExistingRoles => throw new ControllerArgumentException($"Invalid roles {string.Join(",", nonExistingRoles)}", nameof(roles)));

var rolesToAdd = existingRoles.Where(role => !role.IsAssigned && role.IsAssignable);
var rolesToDelete = existingRoles.Where(role => role.IsAssigned).ExceptBy(distinctRoles, role => role.CompanyUserRoleText).ToImmutableList();

var rolesNotAdded = rolesToAdd.Any()
? rolesToAdd.Except(await AddRoles(companyUserId, result.IamClientIds, rolesToAdd, iamUserId).ConfigureAwait(false))
: Enumerable.Empty<UserRoleModificationData>();
var rolesAdded = await AddRoles(companyUserId, result.IamClientIds, rolesToAdd, iamUserId).ConfigureAwait(false);
var rolesNotAdded = rolesToAdd.ExceptBy(rolesAdded.Select(role => role.CompanyUserRoleId), role => role.CompanyUserRoleId);

if (rolesToDelete.Any())
{
Expand All @@ -185,14 +187,14 @@ private async Task<IEnumerable<UserRoleWithId>> ModifyUserRolesInternal(
result.Firstname,
result.Lastname,
rolesToDelete.Select(x => x.CompanyUserRoleText),
rolesToAdd.Select(x => x.CompanyUserRoleText)
rolesAdded.Select(x => x.CompanyUserRoleText)
);
var notificationData = getNotificationData(data);
_portalRepositories.GetInstance<INotificationRepository>().CreateNotification(companyUserId,
notificationData.notificationTypeId, false,
notificationData.NotificationTypeId, false,
notification =>
{
notification.Content = notificationData.content;
notification.Content = notificationData.Content;
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ public record ParticipantDetails(
[property: JsonPropertyName("countryAlpha2Code")] string CountryAlpha2Code
);

public record UniqueIdData(string Type, string Value);
public record UniqueIdData([property: JsonPropertyName("type")] string Type, [property: JsonPropertyName("value")] string Value);
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 All @@ -22,4 +21,4 @@ namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models;

public record UserRoleWithId(string CompanyUserRoleText, Guid CompanyUserRoleId);

public record UserRoleModificationData(string CompanyUserRoleText, Guid CompanyUserRoleId, bool IsAssignedToUser);
public record UserRoleModificationData(string CompanyUserRoleText, Guid CompanyUserRoleId, bool IsAssigned, bool IsAssignable);
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ public interface IUserRolesRepository
/// <returns>Returns a list of user role ids</returns>
IAsyncEnumerable<string> GetUserRolesForOfferIdAsync(Guid offerId);

IAsyncEnumerable<UserRoleModificationData> GetAssignedAndMatchingAppRoles(Guid companyUserId, IEnumerable<string> userRoles, Guid offerId);
IAsyncEnumerable<UserRoleModificationData> GetAssignedAndMatchingCoreOfferRoles(Guid companyUserId, IEnumerable<string> userRoles, Guid offerId);
IAsyncEnumerable<(string UserRoleText, Guid RoleId, bool IsAssigned)> GetAssignedAndMatchingAppRoles(Guid identityId, IEnumerable<string> userRoles, Guid offerId);
IAsyncEnumerable<UserRoleModificationData> GetAssignedAndMatchingCoreOfferRoles(Guid identityId, IEnumerable<string> userRoles, Guid offerId);

/// <summary>
/// Get user name data by assinged roles
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,32 +97,44 @@ public async IAsyncEnumerable<Guid> GetUserRoleIdsUntrackedAsync(IEnumerable<Use
}
}

public IAsyncEnumerable<UserRoleModificationData> GetAssignedAndMatchingAppRoles(Guid companyUserId, IEnumerable<string> userRoles, Guid offerId) =>
public IAsyncEnumerable<(string UserRoleText, Guid RoleId, bool IsAssigned)> GetAssignedAndMatchingAppRoles(Guid identityId, IEnumerable<string> userRoles, Guid offerId) =>
_dbContext.UserRoles
.AsNoTracking()
.Where(role =>
role.OfferId == offerId &&
(userRoles.Contains(role.UserRoleText) ||
role.IdentityAssignedRoles.Select(u => u.Identity!).Any(user => user.Id == companyUserId)))
.Select(userRole => new UserRoleModificationData(
userRole.UserRoleText,
userRole.Id,
userRole.IdentityAssignedRoles.Select(u => u.Identity!).Any(user => user.Id == companyUserId)
.Where(role => role.OfferId == offerId)
.Select(role => new
{
Role = role,
IsAssigned = role.IdentityAssignedRoles.Any(iar => iar.IdentityId == identityId)
})
.Where(x =>
userRoles.Contains(x.Role.UserRoleText) ||
x.IsAssigned)
.Select(x => new ValueTuple<string, Guid, bool>(
x.Role.UserRoleText,
x.Role.Id,
x.IsAssigned
))
.ToAsyncEnumerable();

public IAsyncEnumerable<UserRoleModificationData> GetAssignedAndMatchingCoreOfferRoles(Guid companyUserId, IEnumerable<string> userRoles, Guid offerId) =>
public IAsyncEnumerable<UserRoleModificationData> GetAssignedAndMatchingCoreOfferRoles(Guid identityId, IEnumerable<string> userRoles, Guid offerId) =>
_dbContext.UserRoles
.AsNoTracking()
.Where(role =>
role.OfferId == offerId &&
role.UserRoleCollections.Any(collection => collection.CompanyRoleAssignedRoleCollection!.CompanyRole!.CompanyAssignedRoles.Any(assigned => assigned.Company!.Identities.Any(user => user.Id == companyUserId))) &&
(userRoles.Contains(role.UserRoleText) ||
role.IdentityAssignedRoles.Select(u => u.Identity!).Any(user => user.Id == companyUserId)))
.Select(userRole => new UserRoleModificationData(
userRole.UserRoleText,
userRole.Id,
userRole.IdentityAssignedRoles.Select(u => u.Identity!).Any(user => user.Id == companyUserId)
.Where(role => role.OfferId == offerId)
.Select(role => new
{
Role = role,
IsAssigned = role.IdentityAssignedRoles.Any(iar => iar.IdentityId == identityId),
IsAssignable = role.UserRoleCollections.Any(collection => collection.CompanyRoleAssignedRoleCollection!.CompanyRole!.CompanyAssignedRoles.Any(assigned => assigned.Company!.Identities.Any(identity => identity.Id == identityId)))
})
.Where(x =>
userRoles.Contains(x.Role.UserRoleText) ||
x.IsAssigned ||
x.IsAssignable)
.Select(x => new UserRoleModificationData(
x.Role.UserRoleText,
x.Role.Id,
x.IsAssigned,
x.IsAssignable
))
.ToAsyncEnumerable();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public interface IRegistrationBusinessLogic
{
Task<CompanyBpdmDetailData> GetCompanyBpdmDetailDataByBusinessPartnerNumber(string businessPartnerNumber, string token, CancellationToken cancellationToken);
IAsyncEnumerable<string> GetClientRolesCompositeAsync();
Task<int> UploadDocumentAsync(Guid applicationId, IFormFile document, DocumentTypeId documentTypeId, CancellationToken cancellationToken);
Task UploadDocumentAsync(Guid applicationId, IFormFile document, DocumentTypeId documentTypeId, CancellationToken cancellationToken);

/// <summary>
/// Gets the file content from the persistence store for the given user
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ private async Task<CompanyBpdmDetailData> GetCompanyBpdmDetailDataByBusinessPart
}
}

public async Task<int> UploadDocumentAsync(Guid applicationId, IFormFile document, DocumentTypeId documentTypeId, CancellationToken cancellationToken)
public async Task UploadDocumentAsync(Guid applicationId, IFormFile document, DocumentTypeId documentTypeId, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(document.FileName))
{
Expand All @@ -167,6 +167,7 @@ public async Task<int> UploadDocumentAsync(Guid applicationId, IFormFile documen
{
throw new ForbiddenException($"The users company is not assigned with application {applicationId}");
}

_portalRepositories.GetInstance<IApplicationRepository>().AttachAndModifyCompanyApplication(applicationId, application =>
{
application.DateLastChanged = _dateTimeProvider.OffsetNow;
Expand All @@ -178,7 +179,8 @@ public async Task<int> UploadDocumentAsync(Guid applicationId, IFormFile documen
{
doc.CompanyUserId = _identityData.IdentityId;
});
return await _portalRepositories.SaveAsync().ConfigureAwait(false);

await _portalRepositories.SaveAsync().ConfigureAwait(false);
}

public async Task<(string FileName, byte[] Content, string MediaType)> GetDocumentContentAsync(Guid documentId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public Task<CompanyBpdmDetailData> GetCompanyBpdmDetailDataAsync([FromRoute] str
/// <param name="cancellationToken">CancellationToken (provided by controller)</param>
/// <returns></returns>
/// <remarks>Example: Post: /api/registration/application/{applicationId}/documentType/{documentTypeId}/documents</remarks>
/// <response code="200">Successfully uploaded the document</response>
/// <response code="204">Successfully uploaded the document</response>
/// <response code="403">The user is not assigned with the CompanyApplication.</response>
/// <response code="415">Only PDF files are supported.</response>
/// <response code="400">Input is incorrect.</response>
Expand All @@ -90,12 +90,16 @@ public Task<CompanyBpdmDetailData> GetCompanyBpdmDetailDataAsync([FromRoute] str
[Consumes("multipart/form-data")]
[Route("application/{applicationId}/documentType/{documentTypeId}/documents")]
[RequestFormLimits(ValueLengthLimit = 819200, MultipartBodyLengthLimit = 819200)]
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status403Forbidden)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status415UnsupportedMediaType)]
public Task<int> UploadDocumentAsync([FromRoute] Guid applicationId, [FromRoute] DocumentTypeId documentTypeId, [FromForm(Name = "document")] IFormFile document, CancellationToken cancellationToken) =>
_registrationBusinessLogic.UploadDocumentAsync(applicationId, document, documentTypeId, cancellationToken);
public async Task<NoContentResult> UploadDocumentAsync([FromRoute] Guid applicationId, [FromRoute] DocumentTypeId documentTypeId, [FromForm(Name = "document")] IFormFile document, CancellationToken cancellationToken)
{
await _registrationBusinessLogic.UploadDocumentAsync(applicationId, document, documentTypeId,
cancellationToken).ConfigureAwait(false);
return NoContent();
}

/// <summary>
/// Gets a specific document by its id
Expand Down
Loading

0 comments on commit e4435b7

Please sign in to comment.