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

[SELC-6304] feat: added checks on product phases and roles #504

Merged
merged 1 commit into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -11,14 +11,18 @@
import it.pagopa.selfcare.dashboard.connector.model.product.mapper.ProductMapper;
import it.pagopa.selfcare.dashboard.connector.model.user.*;
import it.pagopa.selfcare.dashboard.core.exception.InvalidOnboardingStatusException;
import it.pagopa.selfcare.dashboard.core.exception.InvalidProductRoleException;
import it.pagopa.selfcare.onboarding.common.PartyRole;
import it.pagopa.selfcare.product.entity.PHASE_ADDITION_ALLOWED;
import it.pagopa.selfcare.product.entity.Product;
import it.pagopa.selfcare.product.entity.ProductRole;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;
import java.util.stream.Collectors;


@Slf4j
Expand Down Expand Up @@ -136,7 +140,8 @@ public String createUsers(String institutionId, String productId, UserToCreate u
log.trace("createOrUpdateUserByFiscalCode start");
log.debug("createOrUpdateUserByFiscalCode userDto = {}", userDto);
Institution institution = verifyOnboardingStatus(institutionId, productId);
List<CreateUserDto.Role> role = retrieveRole(productId, userDto.getProductRoles(), userDto.getRole());
Product product = verifyProductPhasesAndRoles(productId, institution.getInstitutionType(), userDto.getRole(), userDto.getProductRoles());
List<CreateUserDto.Role> role = retrieveRole(product, userDto.getProductRoles(), userDto.getRole());
String userId = userApiConnector.createOrUpdateUserByFiscalCode(institution, productId, userDto, role);
log.trace("createOrUpdateUserByFiscalCode end");
return userId;
Expand All @@ -148,7 +153,8 @@ public void addUserProductRoles(String institutionId, String productId, String u
log.debug("createOrUpdateUserByUserId userId = {}", userId);
Institution institution = verifyOnboardingStatus(institutionId, productId);
PartyRole partyRole = Optional.ofNullable(role).map(PartyRole::valueOf).orElse(null);
List<CreateUserDto.Role> roleDto = retrieveRole(productId, productRoles, partyRole);
Product product = verifyProductPhasesAndRoles(productId, institution.getInstitutionType(), partyRole, productRoles);
List<CreateUserDto.Role> roleDto = retrieveRole(product, productRoles, partyRole);
userApiConnector.createOrUpdateUserByUserId(institution, productId, userId, roleDto);
log.trace("createOrUpdateUserByUserId end");
}
Expand All @@ -163,14 +169,46 @@ private Institution verifyOnboardingStatus(String institutionId, String productI
else return institution;
}

/**
* <p>Get the product and verify if his phasesAdditionAllowed field allow to add users directly from dashboard with the specified partyRole and productRoles
* or throw an exception.</p>
*
* <p>Dashboard can add the user directly if the phasesAdditionAllowed contains the "dashboard" string else additional steps
* needs to be performed by the user (ex: sign additional documentation) and an onboarding procedure is required</p>
*
* <p>All the productRoles must be present in the roles of the ProductRoleInfo</p>
*
* @param productId product id
* @param institutionType institution type
* @param partyRole role to use
* @param productRoles a set of productRoles
* @return the product
* @throws InvalidProductRoleException if dashboard can not add the user directly with the partyRole specified
*/
private Product verifyProductPhasesAndRoles(String productId, String institutionType, PartyRole partyRole, Set<String> productRoles) {
final Product product = productsConnector.getProduct(productId);
return Optional.ofNullable(partyRole)
// If partyRole is present ==> get the ProductRoleInfo
.map(pr -> product.getRoleMappings(institutionType).get(pr))
// Check if phasesAdditionAllowed contains the "dashboard" string
.filter(pri -> pri.getPhasesAdditionAllowed().stream().anyMatch(PHASE_ADDITION_ALLOWED.DASHBOARD.value::equals))
// Obtain a set of validRoles from the product role info
.map(pri -> pri.getRoles().stream().map(ProductRole::getCode).collect(Collectors.toSet()))
// Check if all the productRoles in input are validRoles
.filter(validRoles -> validRoles.containsAll(productRoles))
// If all the previous filters are successful ==> Return the product
.map(i -> product)
// If any of the previous filters fail ==> throw exception
.orElseThrow(() -> new InvalidProductRoleException("The product doesn't allow adding users directly with these role and productRoles"));
}

/**
* This method is used to retrieve a list of roles for a given product.
* It maps each product role to a CreateUserDto.Role object, which includes the label and party role.
* To retrieve the party role, it uses the roleMappings of the product filtering by a white list of party roles (Only SUB_DELEGATE and OPERATOR are allowed
* as Role to be assigned to a user in add Users ProductRoles operation).
*/
private List<CreateUserDto.Role> retrieveRole(String productId, Set<String> productRoles, PartyRole partyRole) {
Product product = productsConnector.getProduct(productId);
private List<CreateUserDto.Role> retrieveRole(Product product, Set<String> productRoles, PartyRole partyRole) {
return productRoles.stream().map(productRole -> {
CreateUserDto.Role role = new CreateUserDto.Role();
role.setProductRole(productRole);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import it.pagopa.selfcare.dashboard.connector.model.institution.RelationshipState;
import it.pagopa.selfcare.dashboard.connector.model.user.*;
import it.pagopa.selfcare.dashboard.core.exception.InvalidOnboardingStatusException;
import it.pagopa.selfcare.dashboard.core.exception.InvalidProductRoleException;
import it.pagopa.selfcare.onboarding.common.PartyRole;
import it.pagopa.selfcare.product.entity.PHASE_ADDITION_ALLOWED;
import it.pagopa.selfcare.product.entity.Product;
Expand Down Expand Up @@ -289,7 +290,7 @@ void addUserProductRoles_ok() {
final String productId = "productId";
final String userId = "userId";
Set<String> productRoles = new HashSet<>(List.of("operator"));
String role = "MANAGER";
String role = "OPERATOR";
Product product = getProduct();

Institution institution = new Institution();
Expand All @@ -301,10 +302,7 @@ void addUserProductRoles_ok() {
CreateUserDto.Role roleDto = new CreateUserDto.Role();
roleDto.setProductRole("operator");
roleDto.setLabel("operator");
roleDto.setPartyRole(PartyRole.MANAGER);

when(msCoreConnectorMock.getInstitution(institutionId)).thenReturn(institution);
when(productsConnectorMock.getProduct(productId)).thenReturn(product);
roleDto.setPartyRole(OPERATOR);

when(msCoreConnectorMock.getInstitution(institutionId)).thenReturn(institution);
when(productsConnectorMock.getProduct(productId)).thenReturn(product);
Expand Down Expand Up @@ -365,6 +363,97 @@ void addUserProductRoles_invalidOnboardingStatus() {
verifyNoInteractions(userApiConnectorMock);
}

@Test
void addUserProductRolesWithInvalidPartyRole() {
final String institutionId = "institutionId";
final String productId = "productId";
final String userId = "userId";
final Set<String> productRoles = Set.of("operator");
final Product product = getProduct();

final Institution institution = new Institution();
final OnboardedProduct onboardedProduct = new OnboardedProduct();
onboardedProduct.setProductId(productId);
onboardedProduct.setStatus(RelationshipState.ACTIVE);
institution.setOnboarding(List.of(onboardedProduct));

when(msCoreConnectorMock.getInstitution(institutionId)).thenReturn(institution);
when(productsConnectorMock.getProduct(productId)).thenReturn(product);

assertThrows(InvalidProductRoleException.class,
() -> userV2ServiceImpl.addUserProductRoles(institutionId, productId, userId, productRoles, null),
"The product doesn't allow adding users directly with these role and productRoles");

assertThrows(InvalidProductRoleException.class,
() -> userV2ServiceImpl.addUserProductRoles(institutionId, productId, userId, productRoles, "MANAGER"),
"The product doesn't allow adding users directly with these role and productRoles");
}

@Test
void addUserProductRolesWithInvalidPhasesAdditionAllowed() {
final String institutionId = "institutionId";
final String productId = "productId";
final String userId = "userId";
final Set<String> productRoles = Set.of("manager");
final String role = "MANAGER";

final Product product = getProduct();
final ProductRoleInfo productRoleInfoManager = new ProductRoleInfo();
productRoleInfoManager.setPhasesAdditionAllowed(List.of(PHASE_ADDITION_ALLOWED.DASHBOARD_ASYNC.value, PHASE_ADDITION_ALLOWED.ONBOARDING.value));
final ProductRole pr = new ProductRole();
pr.setCode("manager");
pr.setLabel("manager");
productRoleInfoManager.setRoles(List.of(pr));
product.setRoleMappings(Map.of(MANAGER, productRoleInfoManager));

final Institution institution = new Institution();
final OnboardedProduct onboardedProduct = new OnboardedProduct();
onboardedProduct.setProductId(productId);
onboardedProduct.setStatus(RelationshipState.ACTIVE);
institution.setOnboarding(List.of(onboardedProduct));

when(msCoreConnectorMock.getInstitution(institutionId)).thenReturn(institution);
when(productsConnectorMock.getProduct(productId)).thenReturn(product);

assertThrows(InvalidProductRoleException.class,
() -> userV2ServiceImpl.addUserProductRoles(institutionId, productId, userId, productRoles, role),
"The product doesn't allow adding users directly with these role and productRoles");
}

@Test
void addUserProductRolesWithInvalidProductRoles() {
final String institutionId = "institutionId";
final String productId = "productId";
final String userId = "userId";
final Set<String> productRoles = Set.of("operator2", "operator0", "operator1");
final String role = "OPERATOR";

final Product product = getProduct();
final ProductRoleInfo productRoleInfoOperator = new ProductRoleInfo();
productRoleInfoOperator.setPhasesAdditionAllowed(List.of(PHASE_ADDITION_ALLOWED.DASHBOARD_ASYNC.value, PHASE_ADDITION_ALLOWED.DASHBOARD.value));
final ProductRole pr1 = new ProductRole();
pr1.setCode("operator1");
pr1.setLabel("operator1");
final ProductRole pr2 = new ProductRole();
pr2.setCode("operator2");
pr2.setLabel("operator2");
productRoleInfoOperator.setRoles(List.of(pr1, pr2));
product.setRoleMappings(Map.of(PartyRole.OPERATOR, productRoleInfoOperator));

final Institution institution = new Institution();
final OnboardedProduct onboardedProduct = new OnboardedProduct();
onboardedProduct.setProductId(productId);
onboardedProduct.setStatus(RelationshipState.ACTIVE);
institution.setOnboarding(List.of(onboardedProduct));

when(msCoreConnectorMock.getInstitution(institutionId)).thenReturn(institution);
when(productsConnectorMock.getProduct(productId)).thenReturn(product);

assertThrows(InvalidProductRoleException.class,
() -> userV2ServiceImpl.addUserProductRoles(institutionId, productId, userId, productRoles, role),
"The product doesn't allow adding users directly with these role and productRoles");
}

@Test
void createUsersByFiscalCode() {

Expand All @@ -374,7 +463,7 @@ void createUsersByFiscalCode() {
UserToCreate userToCreate = new UserToCreate();
HashSet<String> productRoles = new HashSet<>();
productRoles.add(productRole);
userToCreate.setRole(PartyRole.MANAGER);
userToCreate.setRole(OPERATOR);
userToCreate.setProductRoles(productRoles);

Product product = getProduct();
Expand All @@ -389,7 +478,7 @@ void createUsersByFiscalCode() {
CreateUserDto.Role roleDto = new CreateUserDto.Role();
roleDto.setProductRole("operator");
roleDto.setLabel("operator");
roleDto.setPartyRole(MANAGER);
roleDto.setPartyRole(OPERATOR);


when(productsConnectorMock.getProduct(productId)).thenReturn(product);
Expand Down Expand Up @@ -418,7 +507,7 @@ void createUsersByFiscalCodeWithPartyROle() {
UserToCreate userToCreate = new UserToCreate();
HashSet<String> productRoles = new HashSet<>();
productRoles.add(productRole);
userToCreate.setRole(PartyRole.MANAGER);
userToCreate.setRole(OPERATOR);
userToCreate.setProductRoles(productRoles);

Product product = getProduct();
Expand All @@ -432,7 +521,7 @@ void createUsersByFiscalCodeWithPartyROle() {
CreateUserDto.Role roleDto = new CreateUserDto.Role();
roleDto.setProductRole("operator");
roleDto.setLabel("operator");
roleDto.setPartyRole(PartyRole.MANAGER);
roleDto.setPartyRole(OPERATOR);

when(productsConnectorMock.getProduct(productId)).thenReturn(product);

Expand Down Expand Up @@ -470,6 +559,98 @@ void createUsersByFiscalCodeWithOnboardingNotActive() {
verifyNoMoreInteractions(userApiConnectorMock);
}

@Test
void createUsersByFiscalCodeWithInvalidPartyRole() {
final String institutionId = "institutionId";
final String productId = "productId";
final UserToCreate userToCreate = new UserToCreate();
final Set<String> productRoles = Set.of("manager");
userToCreate.setRole(MANAGER);
userToCreate.setProductRoles(productRoles);

final Product product = getProduct();

final Institution institution = new Institution();
final OnboardedProduct onboardedProduct = new OnboardedProduct();
onboardedProduct.setProductId(productId);
onboardedProduct.setStatus(RelationshipState.ACTIVE);
institution.setOnboarding(List.of(onboardedProduct));

when(productsConnectorMock.getProduct(productId)).thenReturn(product);
when(msCoreConnectorMock.getInstitution(institutionId)).thenReturn(institution);

assertThrows(InvalidProductRoleException.class,
() -> userV2ServiceImpl.createUsers(institutionId, productId, userToCreate),
"The product doesn't allow adding users directly with these role and productRoles");
}

@Test
void createUsersByFiscalCodeWithInvalidPhasesAdditionAllowed() {
final String institutionId = "institutionId";
final String productId = "productId";
final UserToCreate userToCreate = new UserToCreate();
final Set<String> productRoles = Set.of("manager");
userToCreate.setRole(MANAGER);
userToCreate.setProductRoles(productRoles);

final Product product = getProduct();
final ProductRoleInfo productRoleInfoManager = new ProductRoleInfo();
productRoleInfoManager.setPhasesAdditionAllowed(List.of(PHASE_ADDITION_ALLOWED.DASHBOARD_ASYNC.value, PHASE_ADDITION_ALLOWED.ONBOARDING.value));
final ProductRole pr = new ProductRole();
pr.setCode("manager");
pr.setLabel("manager");
productRoleInfoManager.setRoles(List.of(pr));
product.setRoleMappings(Map.of(MANAGER, productRoleInfoManager));

final Institution institution = new Institution();
final OnboardedProduct onboardedProduct = new OnboardedProduct();
onboardedProduct.setProductId(productId);
onboardedProduct.setStatus(RelationshipState.ACTIVE);
institution.setOnboarding(List.of(onboardedProduct));

when(productsConnectorMock.getProduct(productId)).thenReturn(product);
when(msCoreConnectorMock.getInstitution(institutionId)).thenReturn(institution);

assertThrows(InvalidProductRoleException.class,
() -> userV2ServiceImpl.createUsers(institutionId, productId, userToCreate),
"The product doesn't allow adding users directly with these role and productRoles");
}

@Test
void createUsersByFiscalCodeWithInvalidProductRoles() {
final String institutionId = "institutionId";
final String productId = "productId";
final UserToCreate userToCreate = new UserToCreate();
final Set<String> productRoles = Set.of("operator2", "operator0", "operator1");
userToCreate.setRole(OPERATOR);
userToCreate.setProductRoles(productRoles);

final Product product = getProduct();
final ProductRoleInfo productRoleInfoOperator = new ProductRoleInfo();
productRoleInfoOperator.setPhasesAdditionAllowed(List.of(PHASE_ADDITION_ALLOWED.DASHBOARD_ASYNC.value, PHASE_ADDITION_ALLOWED.DASHBOARD.value));
final ProductRole pr1 = new ProductRole();
pr1.setCode("operator1");
pr1.setLabel("operator1");
final ProductRole pr2 = new ProductRole();
pr2.setCode("operator2");
pr2.setLabel("operator2");
productRoleInfoOperator.setRoles(List.of(pr1, pr2));
product.setRoleMappings(Map.of(PartyRole.OPERATOR, productRoleInfoOperator));

final Institution institution = new Institution();
final OnboardedProduct onboardedProduct = new OnboardedProduct();
onboardedProduct.setProductId(productId);
onboardedProduct.setStatus(RelationshipState.ACTIVE);
institution.setOnboarding(List.of(onboardedProduct));

when(productsConnectorMock.getProduct(productId)).thenReturn(product);
when(msCoreConnectorMock.getInstitution(institutionId)).thenReturn(institution);

assertThrows(InvalidProductRoleException.class,
() -> userV2ServiceImpl.createUsers(institutionId, productId, userToCreate),
"The product doesn't allow adding users directly with these role and productRoles");
}

private static Product getProduct() {
Product product = new Product();
Map<PartyRole, it.pagopa.selfcare.product.entity.ProductRoleInfo> map = new EnumMap<>(PartyRole.class);
Expand Down
Loading