diff --git a/apps/pom.xml b/apps/pom.xml index 1feb3e17..ed8cc65c 100644 --- a/apps/pom.xml +++ b/apps/pom.xml @@ -16,17 +16,17 @@ it.pagopa.selfcare onboarding-sdk-azure-storage - 0.1.4 + 0.1.6 it.pagopa.selfcare onboarding-sdk-common - 0.1.4 + 0.1.6 it.pagopa.selfcare onboarding-sdk-product - 0.1.4 + 0.1.6 diff --git a/apps/user-ms/src/main/java/it/pagopa/selfcare/user/controller/UserController.java b/apps/user-ms/src/main/java/it/pagopa/selfcare/user/controller/UserController.java index b940e2e1..2a18c1bd 100644 --- a/apps/user-ms/src/main/java/it/pagopa/selfcare/user/controller/UserController.java +++ b/apps/user-ms/src/main/java/it/pagopa/selfcare/user/controller/UserController.java @@ -54,5 +54,23 @@ public Uni getUserInfo(@PathParam(value = "id") String userId, return userService.retrievePerson(userId, productId, institutionId) .map(user -> userMapper.toUserResponse(user, institutionId)); } + + /** + * The deleteProducts function is used to delete logically the association institution and product. + * + * @param userId String + * @param institutionId String + * @param productId String + * + * @return A uni<void> + */ + @Operation(summary = "Delete logically the association institution and product") + @DELETE + @Path(value = "/{userId}/institutions/{institutionId}/products/{productId}") + public Uni deleteProducts(@PathParam(value = "userId") String userId, + @PathParam(value = "institutionId") String institutionId, + @PathParam(value = "productId") String productId) { + return userService.deleteUserInstitutionProduct(userId, institutionId, productId); + } } diff --git a/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserInstitutionService.java b/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserInstitutionService.java index fc3a1f83..3598429f 100644 --- a/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserInstitutionService.java +++ b/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserInstitutionService.java @@ -23,4 +23,6 @@ public interface UserInstitutionService { Multi findAllWithFilter(Map queryParameter); Uni retrieveFirstFilteredUserInstitution(Map queryParameter); + + Uni deleteUserInstitutionProduct(String userId, String institutionId, String productId); } diff --git a/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserInstitutionServiceDefault.java b/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserInstitutionServiceDefault.java index 9a4d6856..42adbeec 100644 --- a/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserInstitutionServiceDefault.java +++ b/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserInstitutionServiceDefault.java @@ -7,8 +7,11 @@ import it.pagopa.selfcare.user.controller.response.UserInstitutionResponse; import it.pagopa.selfcare.user.entity.OnboardedProduct; import it.pagopa.selfcare.user.entity.UserInstitution; +import it.pagopa.selfcare.user.entity.filter.OnboardedProductFilter; +import it.pagopa.selfcare.user.entity.filter.UserInstitutionFilter; import it.pagopa.selfcare.user.mapper.UserInstitutionMapper; import it.pagopa.selfcare.user.util.QueryUtils; +import it.pagopa.selfcare.user.util.UserUtils; import jakarta.enterprise.context.ApplicationScoped; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -33,6 +36,7 @@ public class UserInstitutionServiceDefault implements UserInstitutionService { private final UserInstitutionMapper userInstitutionMapper; private final QueryUtils queryUtils; + private final UserUtils userUtils; @Override public Uni findById(String id) { @@ -64,6 +68,14 @@ public Uni retrieveFirstFilteredUserInstitution(Map deleteUserInstitutionProduct(String userId, String institutionId, String productId) { + OnboardedProductFilter onboardedProductFilter = OnboardedProductFilter.builder().productId(productId).build(); + UserInstitutionFilter userInstitutionFilter = UserInstitutionFilter.builder().userId(userId).institutionId(institutionId).build(); + Map filterMap = userUtils.retrieveMapForFilter(onboardedProductFilter.constructMap(), userInstitutionFilter.constructMap()); + return updateUserStatusDao(filterMap, OnboardedProductState.DELETED); + } + @Override public Multi findAllWithFilter(Map queryParameter) { Document query = queryUtils.buildQueryDocument(queryParameter, USER_INSTITUTION_COLLECTION); diff --git a/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserService.java b/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserService.java index 09c20e01..73eb4e2f 100644 --- a/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserService.java +++ b/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserService.java @@ -22,4 +22,6 @@ Multi findAllUserInstitutions(String institutionId, List states, List products, List productRoles); + + Uni deleteUserInstitutionProduct(String userId, String institutionId, String productId); } diff --git a/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserServiceImpl.java b/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserServiceImpl.java index dc7d1f5a..cda61ec6 100644 --- a/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserServiceImpl.java +++ b/apps/user-ms/src/main/java/it/pagopa/selfcare/user/service/UserServiceImpl.java @@ -2,6 +2,7 @@ import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.Uni; +import it.pagopa.selfcare.user.constant.OnboardedProductState; import it.pagopa.selfcare.user.controller.response.UserInstitutionResponse; import it.pagopa.selfcare.user.controller.response.UserProductResponse; import it.pagopa.selfcare.user.entity.UserInstitution; @@ -25,6 +26,7 @@ import java.util.*; import static it.pagopa.selfcare.user.constant.CustomError.USER_NOT_FOUND_ERROR; +import static it.pagopa.selfcare.user.constant.CustomError.USER_TO_UPDATE_NOT_FOUND; import static it.pagopa.selfcare.user.util.GeneralUtils.formatQueryParameterList; @RequiredArgsConstructor @@ -97,6 +99,17 @@ public Multi findAllUserInstitutions(String institution return userInstitutions.onItem().transform(userInstitutionMapper::toResponse); } + @Override + public Uni deleteUserInstitutionProduct(String userId, String institutionId, String productId) { + return userInstitutionService.deleteUserInstitutionProduct(userId, institutionId, productId) + .onItem().transformToUni(aLong -> { + if (aLong < 1) { + return Uni.createFrom().failure(new ResourceNotFoundException(USER_TO_UPDATE_NOT_FOUND.getMessage())); + } + return Uni.createFrom().nullItem(); + }); + } + private Map buildQueryParams(String userId, String productId, String institutionId) { OnboardedProductFilter onboardedProductFilter = OnboardedProductFilter.builder() .productId(productId) diff --git a/apps/user-ms/src/main/java/it/pagopa/selfcare/user/util/UserUtils.java b/apps/user-ms/src/main/java/it/pagopa/selfcare/user/util/UserUtils.java index a7c35519..93b22c68 100644 --- a/apps/user-ms/src/main/java/it/pagopa/selfcare/user/util/UserUtils.java +++ b/apps/user-ms/src/main/java/it/pagopa/selfcare/user/util/UserUtils.java @@ -4,10 +4,19 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + @ApplicationScoped @RequiredArgsConstructor @Slf4j public class UserUtils { - + @SafeVarargs + public final Map retrieveMapForFilter(Map... maps) { + Map map = new HashMap<>(); + Arrays.stream(maps).forEach(map::putAll); + return map; + } } \ No newline at end of file diff --git a/apps/user-ms/src/test/java/it.pagopa.selfcare.user/service/UserInstitutionServiceTest.java b/apps/user-ms/src/test/java/it.pagopa.selfcare.user/service/UserInstitutionServiceTest.java index 3c628b0f..53b0a13e 100644 --- a/apps/user-ms/src/test/java/it.pagopa.selfcare.user/service/UserInstitutionServiceTest.java +++ b/apps/user-ms/src/test/java/it.pagopa.selfcare.user/service/UserInstitutionServiceTest.java @@ -134,6 +134,20 @@ void findAllWithFilter() { assertEquals(1, actual.size()); } + @Test + void deleteUserInstitutionProduct(){ + final String userId = "userId"; + String institutionId = "institutionId"; + PanacheMock.mock(UserInstitution.class); + ReactivePanacheUpdate update = Mockito.mock(ReactivePanacheUpdate.class); + when(UserInstitution.update(any(Document.class))) + .thenReturn(update); + when(update.where(any())).thenReturn(Uni.createFrom().item(1L)); + UniAssertSubscriber subscriber = userInstitutionService.deleteUserInstitutionProduct(userId, institutionId, "productID") + .subscribe().withSubscriber(UniAssertSubscriber.create()); + subscriber.assertCompleted().assertItem(1L); + } + private UserInstitution createDummyUserInstitution() { UserInstitution userInstitution = new UserInstitution(); userInstitution.setId(ObjectId.get()); diff --git a/apps/user-ms/src/test/java/it.pagopa.selfcare.user/service/UserServiceTest.java b/apps/user-ms/src/test/java/it.pagopa.selfcare.user/service/UserServiceTest.java index f1acc234..b9f162d4 100644 --- a/apps/user-ms/src/test/java/it.pagopa.selfcare.user/service/UserServiceTest.java +++ b/apps/user-ms/src/test/java/it.pagopa.selfcare.user/service/UserServiceTest.java @@ -12,6 +12,7 @@ import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.helpers.test.AssertSubscriber; import io.smallrye.mutiny.helpers.test.UniAssertSubscriber; +import io.smallrye.mutiny.subscription.UniSubscriber; import it.pagopa.selfcare.user.controller.response.UserInstitutionResponse; import it.pagopa.selfcare.user.controller.response.UserProductResponse; import it.pagopa.selfcare.user.entity.OnboardedProduct; @@ -35,9 +36,11 @@ import java.util.Map; import java.util.UUID; +import static it.pagopa.selfcare.user.constant.CustomError.USER_TO_UPDATE_NOT_FOUND; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; @QuarkusTest @@ -177,4 +180,28 @@ void retrieveUsersTest() { assertEquals(1, actual.size()); assertEquals(userInstitution.getUserId(), actual.get(0).getUserId()); } + + @Test + void deleteUserInstitutionProductFound(){ + when(userInstitutionService.deleteUserInstitutionProduct("userId", "institutionId", "productId")).thenReturn(Uni.createFrom().item(1L)); + UniAssertSubscriber subscriber = userService + .deleteUserInstitutionProduct("userId", "institutionId", "productId") + .subscribe() + .withSubscriber(UniAssertSubscriber.create()); + + subscriber.assertCompleted(); + + + } + + @Test + void deleteUserInstitutionProductNotFound(){ + when(userInstitutionService.deleteUserInstitutionProduct("userId", "institutionId", "productId")).thenReturn(Uni.createFrom().item(0L)); + UniAssertSubscriber subscriber = userService + .deleteUserInstitutionProduct("userId", "institutionId", "productId") + .subscribe() + .withSubscriber(UniAssertSubscriber.create()); + + subscriber.assertFailedWith(ResourceNotFoundException.class, USER_TO_UPDATE_NOT_FOUND.getMessage()); + } } diff --git a/apps/user-ms/src/test/java/it/pagopa/selfcare/user/controller/UserControllerTest.java b/apps/user-ms/src/test/java/it/pagopa/selfcare/user/controller/UserControllerTest.java index 595890de..cc148bbf 100644 --- a/apps/user-ms/src/test/java/it/pagopa/selfcare/user/controller/UserControllerTest.java +++ b/apps/user-ms/src/test/java/it/pagopa/selfcare/user/controller/UserControllerTest.java @@ -6,8 +6,10 @@ import io.quarkus.test.security.TestSecurity; import io.restassured.http.ContentType; import io.smallrye.mutiny.Uni; +import it.pagopa.selfcare.user.exception.InvalidRequestException; import it.pagopa.selfcare.user.exception.ResourceNotFoundException; import it.pagopa.selfcare.user.service.UserService; +import org.apache.http.HttpStatus; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.openapi.quarkus.user_registry_json.model.CertifiableFieldResourceOfLocalDate; @@ -133,4 +135,62 @@ void testGetUserInfoFails() { .statusCode(404); } + /** + * Method under test: + * {@link UserController#deleteProducts(String, String, String)} + */ + @Test + @TestSecurity(user = "userJwt") + void deleteDeleteProductsErrorTest() { + String PATH_USER_ID = "userId"; + String PATH_INSTITUTION_ID = "institutionId"; + String PATH_PRODUCT_ID = "productId"; + String PATH_DELETE_PRODUCT = "{userId}/institutions/{institutionId}/products/{productId}"; + + var user = "user1"; + var institution = "institution1"; + var product = "product1"; + Mockito.when(userService.deleteUserInstitutionProduct("user1","institution1", "product1")) + .thenThrow(InvalidRequestException.class); + + given() + .when() + .pathParam(PATH_USER_ID, user) + .pathParam(PATH_INSTITUTION_ID, institution) + .pathParam(PATH_PRODUCT_ID, product) + .delete(PATH_DELETE_PRODUCT) + .then() + .statusCode(HttpStatus.SC_BAD_REQUEST); + } + + /** + * Method under test: + * {@link UserController#deleteProducts(String, String, String)} + */ + @Test + @TestSecurity(user = "userJwt") + void deleteDeleteProductsOKTest() { + + String PATH_USER_ID = "userId"; + String PATH_INSTITUTION_ID = "institutionId"; + String PATH_PRODUCT_ID = "productId"; + String PATH_DELETE_PRODUCT = "{userId}/institutions/{institutionId}/products/{productId}"; + + var user = "user123"; + var institution = "institution123"; + var product = "prod-pagopa"; + + Mockito.when(userService.deleteUserInstitutionProduct("user123", "institution123", "prod-pagopa")) + .thenReturn(Uni.createFrom().voidItem()); + + given() + .when() + .pathParam(PATH_USER_ID, user) + .pathParam(PATH_INSTITUTION_ID, institution) + .pathParam(PATH_PRODUCT_ID, product) + .delete(PATH_DELETE_PRODUCT) + .then() + .statusCode(HttpStatus.SC_NO_CONTENT); + } + }