diff --git a/libs/onboarding-sdk-azure-storage/pom.xml b/libs/onboarding-sdk-azure-storage/pom.xml index f928ebd1c..57bc353df 100644 --- a/libs/onboarding-sdk-azure-storage/pom.xml +++ b/libs/onboarding-sdk-azure-storage/pom.xml @@ -6,7 +6,7 @@ it.pagopa.selfcare onboarding-sdk-pom - 0.1.4 + 0.1.5 ../onboarding-sdk-pom diff --git a/libs/onboarding-sdk-common/pom.xml b/libs/onboarding-sdk-common/pom.xml index f317f8ee1..2d8d6492e 100644 --- a/libs/onboarding-sdk-common/pom.xml +++ b/libs/onboarding-sdk-common/pom.xml @@ -4,7 +4,7 @@ it.pagopa.selfcare onboarding-sdk-pom - 0.1.4 + 0.1.5 ../onboarding-sdk-pom onboarding-sdk-common diff --git a/libs/onboarding-sdk-crypto/pom.xml b/libs/onboarding-sdk-crypto/pom.xml index 2e0756775..ca4ebf8e2 100644 --- a/libs/onboarding-sdk-crypto/pom.xml +++ b/libs/onboarding-sdk-crypto/pom.xml @@ -4,7 +4,7 @@ it.pagopa.selfcare onboarding-sdk-pom - 0.1.4 + 0.1.5 ../onboarding-sdk-pom onboarding-sdk-crypto diff --git a/libs/onboarding-sdk-pom/pom.xml b/libs/onboarding-sdk-pom/pom.xml index 17302dc41..d4c8c7ef1 100644 --- a/libs/onboarding-sdk-pom/pom.xml +++ b/libs/onboarding-sdk-pom/pom.xml @@ -6,7 +6,7 @@ onboarding-sdk-pom pom onboarding-sdk-pom - 0.1.4 + 0.1.5 17 diff --git a/libs/onboarding-sdk-product/pom.xml b/libs/onboarding-sdk-product/pom.xml index 9e8037771..c40172f62 100644 --- a/libs/onboarding-sdk-product/pom.xml +++ b/libs/onboarding-sdk-product/pom.xml @@ -4,7 +4,7 @@ it.pagopa.selfcare onboarding-sdk-pom - 0.1.4 + 0.1.5 ../onboarding-sdk-pom onboarding-sdk-product @@ -49,6 +49,10 @@ 8.6.6 test + + org.apache.commons + commons-lang3 + diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductService.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductService.java index 56ead812b..f0959af09 100644 --- a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductService.java +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductService.java @@ -4,6 +4,7 @@ import it.pagopa.selfcare.onboarding.common.InstitutionType; import it.pagopa.selfcare.onboarding.common.PartyRole; import it.pagopa.selfcare.product.entity.Product; +import it.pagopa.selfcare.product.entity.ProductRole; import it.pagopa.selfcare.product.entity.ProductRoleInfo; import java.util.List; @@ -19,4 +20,6 @@ public interface ProductService { void fillContractTemplatePathAndVersion(Product product, InstitutionType institutionType); Product getProductIsValid(String productId); + + ProductRole validateProductRole(String productId, String productRole, PartyRole role); } diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceCacheable.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceCacheable.java index 11a3043b3..fd7d2bd00 100644 --- a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceCacheable.java +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceCacheable.java @@ -6,6 +6,7 @@ import it.pagopa.selfcare.onboarding.common.InstitutionType; import it.pagopa.selfcare.onboarding.common.PartyRole; import it.pagopa.selfcare.product.entity.Product; +import it.pagopa.selfcare.product.entity.ProductRole; import it.pagopa.selfcare.product.entity.ProductRoleInfo; import java.time.LocalDateTime; @@ -73,4 +74,10 @@ public Product getProductIsValid(String productId) { refreshProduct(); return productService.getProductIsValid(productId); } + + @Override + public ProductRole validateProductRole(String productId, String productRole, PartyRole role) { + refreshProduct(); + return productService.validateProductRole(productId, productRole, role); + } } diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceDefault.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceDefault.java index add7cd8b3..16928b850 100644 --- a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceDefault.java +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceDefault.java @@ -9,6 +9,7 @@ import it.pagopa.selfcare.onboarding.common.InstitutionType; import it.pagopa.selfcare.onboarding.common.PartyRole; import it.pagopa.selfcare.product.entity.Product; +import it.pagopa.selfcare.product.entity.ProductRole; import it.pagopa.selfcare.product.entity.ProductRoleInfo; import it.pagopa.selfcare.product.entity.ProductStatus; import it.pagopa.selfcare.product.exception.InvalidRoleMappingException; @@ -39,14 +40,17 @@ public ProductServiceDefault(String productString, ObjectMapper mapper) throws J } private Map constructProductsMap(String productString, ObjectMapper mapper) throws JsonProcessingException { - List productList = mapper.readValue(productString, new TypeReference>(){}); - if(Objects.isNull(productList) || productList.isEmpty()) throw new ProductNotFoundException("json string is empty!"); + List productList = mapper.readValue(productString, new TypeReference>() { + }); + if (Objects.isNull(productList) || productList.isEmpty()) + throw new ProductNotFoundException("json string is empty!"); return productList.stream() .collect(Collectors.toMap(Product::getId, Function.identity())); } /** * Returns the list of PagoPA products tree which are not INACTIVE + * * @param rootOnly if true only product that has parent is null are returned * @return List of PagoPA products */ @@ -54,11 +58,11 @@ private Map constructProductsMap(String productString, ObjectMa public List getProducts(boolean rootOnly, boolean valid) { return rootOnly - ? productsMap.values().stream() + ? productsMap.values().stream() .filter(product -> Objects.isNull(product.getParentId())) .filter(product -> !valid || !statusIsNotValid(product.getStatus())) .collect(Collectors.toList()) - : productsMap.values().stream() + : productsMap.values().stream() .filter(product -> !valid || !statusIsNotValid(product.getStatus())) .collect(Collectors.toList()); } @@ -66,19 +70,20 @@ public List getProducts(boolean rootOnly, boolean valid) { /** * Utility method for validating role mappings that contains associations between Selfcare role and Product role. * Each Selfcare role must be only one Product role except OPERATOR. + * * @param roleMappings - * @throws IllegalArgumentException roleMappings is null or empty + * @throws IllegalArgumentException roleMappings is null or empty * @throws InvalidRoleMappingException Selfcare role have more than one Product role */ @Override public void validateRoleMappings(Map roleMappings) { - if(Objects.isNull(roleMappings) || roleMappings.isEmpty()) + if (Objects.isNull(roleMappings) || roleMappings.isEmpty()) throw new IllegalArgumentException("A product role mappings is required"); roleMappings.forEach((partyRole, productRoleInfo) -> { - if(Objects.isNull(productRoleInfo)) + if (Objects.isNull(productRoleInfo)) throw new IllegalArgumentException("A product role info is required"); - if(Objects.isNull(productRoleInfo.getRoles()) || productRoleInfo.getRoles().isEmpty()) + if (Objects.isNull(productRoleInfo.getRoles()) || productRoleInfo.getRoles().isEmpty()) throw new IllegalArgumentException("At least one Product role are required"); if (productRoleInfo.getRoles().size() > 1 && !PartyRole.OPERATOR.equals(partyRole)) { throw new InvalidRoleMappingException(String.format("Only '%s' Party-role can have more than one Product-role, %s", @@ -91,11 +96,11 @@ public void validateRoleMappings(Map roleM /** * Return a product by productId without any filter * retrieving data from institutionContractMappings map + * * @param productId * @return Product * @throws IllegalArgumentException if @param id is null * @throws ProductNotFoundException if product is not found - * */ @Override public Product getProduct(String productId) { @@ -104,7 +109,7 @@ public Product getProduct(String productId) { private Product getProduct(String productId, boolean filterValid) { - if(Objects.isNull(productId)) { + if (Objects.isNull(productId)) { throw new IllegalArgumentException(REQUIRED_PRODUCT_ID_MESSAGE); } Product product = Optional.ofNullable(productsMap.get(productId)) @@ -130,7 +135,8 @@ private Product getProduct(String productId, boolean filterValid) { * Fills contractTemplatePath and ContractTemplateVersion based on @param institutionType. * If institutionContractMappings contains institutionType, it take value from that setting inside * contractTemplatePath and contractTemplateVersion of product - * @param product Product + * + * @param product Product * @param institutionType InstitutionType */ @Override @@ -144,6 +150,7 @@ public void fillContractTemplatePathAndVersion(Product product, InstitutionType /** * Returns the information for a single product if it has not PHASE_OUT,INACTIVE status and its parent has not PHASE_OUT,INACTIVE status + * * @param productId * @return Product if it is valid or null if it has PHASE_OUT,INACTIVE status * @throws IllegalArgumentException product id is null @@ -154,6 +161,38 @@ public Product getProductIsValid(String productId) { return getProduct(productId, true); } + /** + * The validateProductRole function is used to validate a product role searching for it within the role map for a specific product + * given productId. It returns founded ProductRole object filtered by productRole code + */ + @Override + public ProductRole validateProductRole(String productId, String productRole, PartyRole role) { + if (role == null) { + throw new IllegalArgumentException("Role is mandatory to check productRole"); + } + + Product product = getProduct(productId); + return Optional.ofNullable(product.getRoleMappings()) + .map(partyRoleProductRoleInfoMap -> getProductRole(productRole, role, product)) + .orElseThrow(() -> new IllegalArgumentException(String.format("RoleMappings map for product %s not found", productId))); + } + + /** + * The getProductRole function takes a productRole, role, and product as parameters. + * It returns the ProductRole object that matches the given role and product. + */ + private static ProductRole getProductRole(String productRole, PartyRole role, Product product) { + ProductRoleInfo productRoleInfo = product.getRoleMappings().get(role); + if (productRoleInfo == null) { + throw new IllegalArgumentException(String.format("Role %s not found", role)); + } + return Optional.ofNullable(productRoleInfo.getRoles()) + .map(productRoles -> productRoles.stream().filter(prodRole -> prodRole.getCode().equals(productRole)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(String.format("ProductRole %s not found for role %s", productRole, role)))) + .orElseThrow(() -> new IllegalArgumentException(String.format("Roles of ProductRoleInfo related to role %s not found", role))); + } + private static boolean statusIsNotValid(ProductStatus status) { return List.of(ProductStatus.INACTIVE, ProductStatus.PHASE_OUT).contains(status); } diff --git a/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceCacheableTest.java b/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceCacheableTest.java index 68509b120..3199c31a8 100644 --- a/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceCacheableTest.java +++ b/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceCacheableTest.java @@ -1,6 +1,7 @@ package it.pagopa.selfcare.product.service; import com.azure.storage.blob.models.BlobProperties; +import com.fasterxml.jackson.core.JsonProcessingException; import it.pagopa.selfcare.azurestorage.AzureBlobClient; import it.pagopa.selfcare.onboarding.common.PartyRole; import it.pagopa.selfcare.product.entity.Product; @@ -26,6 +27,11 @@ class ProductServiceCacheableTest { "{\"id\":\"prod-test\", \"parentId\":\"prod-test-parent\",\"status\":\"ACTIVE\"}," + "{\"id\":\"prod-inactive\",\"status\":\"INACTIVE\"}]"; + final private String PRODUCT_JSON_STRING_WITH_ROLEMAPPING = "[{\"id\":\"prod-test-parent\",\"status\":\"ACTIVE\"}," + + "{\"id\":\"prod-test\", \"parentId\":\"prod-test-parent\",\"status\":\"ACTIVE\", \"roleMappings\" : {\"MANAGER\":{\"roles\":[{\"code\":\"operatore\"}]}}}," + + "{\"id\":\"prod-inactive\",\"status\":\"INACTIVE\"}]"; + + final private String PRODUCT_JSON_STRING_EMPTY = "[]"; @Test @@ -176,6 +182,37 @@ void getProduct_notFoundInactive() { assertThrows(ProductNotFoundException.class, executable); } + @Test + void validateProductRoleWithoutRole() { + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING, filePath); + assertThrows(IllegalArgumentException.class, () -> productServiceCacheable.validateProductRole("prod-test", "productRole", null)); + } + + + @Test + void validateProductRoleOk() { + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING_WITH_ROLEMAPPING, filePath); + assertDoesNotThrow(() -> productServiceCacheable.validateProductRole("prod-test", "operatore", PartyRole.MANAGER)); + } + + + @Test + void validateProductRoleWithProductRoleMappingNotFound() { + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING_WITH_ROLEMAPPING, filePath); + assertThrows(IllegalArgumentException.class, () -> productServiceCacheable.validateProductRole("prod-test", "productRole", PartyRole.DELEGATE)); + } + + + @Test + void validateProductRoleOkWithProductRoleNotFound() { + final String filePath = "filePath"; + ProductServiceCacheable productServiceCacheable = mockProductService(PRODUCT_JSON_STRING_WITH_ROLEMAPPING, filePath); + assertThrows(IllegalArgumentException.class, () -> productServiceCacheable.validateProductRole("prod-test", "amministratore", PartyRole.MANAGER)); + } + private ProductServiceCacheable mockProductService(String productJson, String filePath) { AzureBlobClient azureBlobClient = mock(AzureBlobClient.class); BlobProperties blobPropertiesMock = mock(BlobProperties.class); diff --git a/libs/onboarding-sdk-product/src/test/java/ProductServiceDefaultTest.java b/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceDefaultTest.java similarity index 76% rename from libs/onboarding-sdk-product/src/test/java/ProductServiceDefaultTest.java rename to libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceDefaultTest.java index 84438221a..ce1b11631 100644 --- a/libs/onboarding-sdk-product/src/test/java/ProductServiceDefaultTest.java +++ b/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceDefaultTest.java @@ -1,3 +1,5 @@ +package it.pagopa.selfcare.product.service; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import it.pagopa.selfcare.onboarding.common.PartyRole; @@ -21,6 +23,10 @@ public class ProductServiceDefaultTest { "{\"id\":\"prod-test\", \"parentId\":\"prod-test-parent\",\"status\":\"ACTIVE\"}," + "{\"id\":\"prod-inactive\",\"status\":\"INACTIVE\"}]"; + final private String PRODUCT_JSON_STRING_WITH_ROLEMAPPING = "[{\"id\":\"prod-test-parent\",\"status\":\"ACTIVE\"}," + + "{\"id\":\"prod-test\", \"parentId\":\"prod-test-parent\",\"status\":\"ACTIVE\", \"roleMappings\" : {\"MANAGER\":{\"roles\":[{\"code\":\"operatore\"}]}}}," + + "{\"id\":\"prod-inactive\",\"status\":\"INACTIVE\"}]"; + @Test void productServiceDefault_shouldThrowProductNotFoundExceptionIfJsonIsEmpty() { assertThrows(ProductNotFoundException.class, () -> new ProductServiceDefault(PRODUCT_JSON_STRING_EMPTY)); @@ -113,4 +119,31 @@ void getProductValid_shouldThrowProductNotFoundExceptionIfProductInactive() thro ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); assertThrows(ProductNotFoundException.class, () -> productService.getProductIsValid("prod-inactive")); } + + @Test + void validateProductRoleWithoutRole() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + assertThrows(IllegalArgumentException.class, () -> productService.validateProductRole("prod-test", "productRole", null)); + } + + + @Test + void validateProductRoleOk() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING_WITH_ROLEMAPPING); + assertDoesNotThrow(() -> productService.validateProductRole("prod-test", "operatore", PartyRole.MANAGER)); + } + + + @Test + void validateProductRoleWithProductRoleMappingNotFound() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING_WITH_ROLEMAPPING); + assertThrows(IllegalArgumentException.class, () -> productService.validateProductRole("prod-test", "productRole", PartyRole.DELEGATE)); + } + + + @Test + void validateProductRoleOkWithProductRoleNotFound() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING_WITH_ROLEMAPPING); + assertThrows(IllegalArgumentException.class, () -> productService.validateProductRole("prod-test", "amministratore", PartyRole.MANAGER)); + } } diff --git a/test-coverage/pom.xml b/test-coverage/pom.xml index 69e980397..c9339991c 100644 --- a/test-coverage/pom.xml +++ b/test-coverage/pom.xml @@ -77,22 +77,22 @@ it.pagopa.selfcare onboarding-sdk-product - 0.1.4 + 0.1.5 it.pagopa.selfcare onboarding-sdk-common - 0.1.4 + 0.1.5 it.pagopa.selfcare onboarding-sdk-azure-storage - 0.1.4 + 0.1.5 it.pagopa.selfcare onboarding-sdk-crypto - 0.1.4 + 0.1.5