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-3962] Added method to validate a productRole given productId a Role #120

Merged
merged 5 commits into from
Jan 25, 2024
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
2 changes: 1 addition & 1 deletion libs/onboarding-sdk-azure-storage/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>it.pagopa.selfcare</groupId>
<artifactId>onboarding-sdk-pom</artifactId>
<version>0.1.4</version>
<version>0.1.5</version>
<relativePath>../onboarding-sdk-pom</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion libs/onboarding-sdk-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>it.pagopa.selfcare</groupId>
<artifactId>onboarding-sdk-pom</artifactId>
<version>0.1.4</version>
<version>0.1.5</version>
<relativePath>../onboarding-sdk-pom</relativePath>
</parent>
<artifactId>onboarding-sdk-common</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion libs/onboarding-sdk-crypto/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>it.pagopa.selfcare</groupId>
<artifactId>onboarding-sdk-pom</artifactId>
<version>0.1.4</version>
<version>0.1.5</version>
<relativePath>../onboarding-sdk-pom</relativePath>
</parent>
<artifactId>onboarding-sdk-crypto</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion libs/onboarding-sdk-pom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<artifactId>onboarding-sdk-pom</artifactId>
<packaging>pom</packaging>
<name>onboarding-sdk-pom</name>
<version>0.1.4</version>
<version>0.1.5</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
Expand Down
6 changes: 5 additions & 1 deletion libs/onboarding-sdk-product/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>it.pagopa.selfcare</groupId>
<artifactId>onboarding-sdk-pom</artifactId>
<version>0.1.4</version>
<version>0.1.5</version>
<relativePath>../onboarding-sdk-pom</relativePath>
</parent>
<artifactId>onboarding-sdk-product</artifactId>
Expand Down Expand Up @@ -49,6 +49,10 @@
<version>8.6.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -39,46 +40,50 @@ public ProductServiceDefault(String productString, ObjectMapper mapper) throws J
}

private Map<String, Product> constructProductsMap(String productString, ObjectMapper mapper) throws JsonProcessingException {
List<Product> productList = mapper.readValue(productString, new TypeReference<List<Product>>(){});
if(Objects.isNull(productList) || productList.isEmpty()) throw new ProductNotFoundException("json string is empty!");
List<Product> productList = mapper.readValue(productString, new TypeReference<List<Product>>() {
});
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
*/
@Override
public List<Product> 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());
}

/**
* 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<PartyRole, ? extends ProductRoleInfo> 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",
Expand All @@ -91,11 +96,11 @@ public void validateRoleMappings(Map<PartyRole, ? extends ProductRoleInfo> 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) {
Expand All @@ -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))
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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);
flaminiaScarciofolo marked this conversation as resolved.
Show resolved Hide resolved
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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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));
Expand Down Expand Up @@ -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));
}
}
8 changes: 4 additions & 4 deletions test-coverage/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,22 @@
<dependency>
<groupId>it.pagopa.selfcare</groupId>
<artifactId>onboarding-sdk-product</artifactId>
<version>0.1.4</version>
<version>0.1.5</version>
</dependency>
<dependency>
<groupId>it.pagopa.selfcare</groupId>
<artifactId>onboarding-sdk-common</artifactId>
<version>0.1.4</version>
<version>0.1.5</version>
</dependency>
<dependency>
<groupId>it.pagopa.selfcare</groupId>
<artifactId>onboarding-sdk-azure-storage</artifactId>
<version>0.1.4</version>
<version>0.1.5</version>
</dependency>
<dependency>
<groupId>it.pagopa.selfcare</groupId>
<artifactId>onboarding-sdk-crypto</artifactId>
<version>0.1.4</version>
<version>0.1.5</version>
</dependency>
</dependencies>

Expand Down
Loading