Skip to content

Commit

Permalink
added API for get paginated UsersNotification
Browse files Browse the repository at this point in the history
  • Loading branch information
flaminiaScarciofolo committed Jan 29, 2024
1 parent 343c8a6 commit 72edbb0
Show file tree
Hide file tree
Showing 14 changed files with 283 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package it.pagopa.selfcare.user.constant;

import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor(access = AccessLevel.NONE)
public class CollectionUtil {

public static final String USER_INSTITUTION_COLLECTION = "userInstitutions";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import it.pagopa.selfcare.onboarding.common.PartyRole;
import it.pagopa.selfcare.user.constant.OnboardedProductState;
import it.pagopa.selfcare.user.controller.response.UserResponse;
import it.pagopa.selfcare.user.controller.response.UsersNotificationResponse;
import it.pagopa.selfcare.user.mapper.UserMapper;
import it.pagopa.selfcare.user.service.UserEventService;
import it.pagopa.selfcare.user.service.UserService;
Expand Down Expand Up @@ -104,5 +105,22 @@ public Uni<Response> updateUserStatus(@PathParam(value = "id") String userId,
.status(HttpStatus.SC_NO_CONTENT)
.build());
}

@Operation(summary = "Retrieve all users according to optional params in input")
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Uni<UsersNotificationResponse> getUsers(@QueryParam(value = "page") @DefaultValue("0") Integer page,
@QueryParam(value = "size") @DefaultValue("100") Integer size,
@QueryParam(value = "productId") String productId) {
return userService.findPaginatedUserNotificationToSend(size, page, productId)
.map(userNotificationToSends -> {
UsersNotificationResponse usersNotificationResponse = new UsersNotificationResponse();
usersNotificationResponse.setUsers(userNotificationToSends.stream()
.map(userMapper::toUserNotification)
.toList());
return usersNotificationResponse;
});
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package it.pagopa.selfcare.user.controller.response;

import it.pagopa.selfcare.user.constant.QueueEvent;
import it.pagopa.selfcare.user.model.notification.UserToNotify;
import lombok.Data;

import java.time.LocalDateTime;

/**
* This objects wrap user's info sent on topic sc-users
*/
@Data
public class UserNotificationResponse {

private String id;
private String institutionId;
private String productId;
private String onboardingTokenId;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private QueueEvent eventType;
private UserToNotify user;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package it.pagopa.selfcare.user.controller.response;

import lombok.Data;

import java.util.List;

@Data
public class UsersNotificationResponse {
private List<UserNotificationResponse> users;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package it.pagopa.selfcare.user.mapper;

import it.pagopa.selfcare.user.entity.OnboardedProduct;
import it.pagopa.selfcare.user.model.notification.UserNotificationToSend;
import it.pagopa.selfcare.user.model.notification.UserToNotify;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.openapi.quarkus.user_registry_json.model.UserResource;

import java.util.UUID;

@Mapper(componentModel = "cdi", imports = UUID.class)
public interface NotificationMapper {

@Mapping(source = "onboardedProduct.tokenId", target = "onboardingTokenId")
@Mapping(source = "onboardedProduct.productId", target = "productId")
UserNotificationToSend setNotificationDetailsFromOnboardedProduct(UserToNotify user, OnboardedProduct onboardedProduct, String institutionId);



@Mapping(source = "userResource.id", target = "userId")
@Mapping(source = "userResource.name.value", target = "name")
@Mapping(source = "userResource.familyName.value", target = "familyName")
@Mapping(source = "userResource.email.value", target = "email")
@Mapping(source = "onboardedProduct.role", target = "role")
@Mapping(source = "onboardedProduct.productRole", target = "productRole")
@Mapping(source = "onboardedProduct.status", target = "relationshipStatus")
UserToNotify toUserNotify(UserResource userResource, OnboardedProduct onboardedProduct, String userId);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package it.pagopa.selfcare.user.mapper;

import it.pagopa.selfcare.user.controller.response.UserNotificationResponse;
import it.pagopa.selfcare.user.controller.response.UserResponse;
import it.pagopa.selfcare.user.model.notification.UserNotificationToSend;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
Expand All @@ -12,6 +14,9 @@

@Mapper(componentModel = "cdi")
public interface UserMapper {

UserNotificationResponse toUserNotification(UserNotificationToSend user);

@Mapping(source = "userResource.fiscalCode", target = "taxCode")
@Mapping(source = "userResource.familyName", target = "surname")
@Mapping(target = "email", expression = "java(retrieveMailFromWorkContacts(userResource.getWorkContacts(), institutionId))")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package it.pagopa.selfcare.user.model.notification;

import it.pagopa.selfcare.user.constant.QueueEvent;
import lombok.Data;

import java.time.LocalDateTime;
@Data
public class UserNotificationToSend {

private String id;
private String institutionId;
private String productId;
private String onboardingTokenId;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private QueueEvent eventType;
private UserToNotify user;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package it.pagopa.selfcare.user.model.notification;

import it.pagopa.selfcare.onboarding.common.PartyRole;
import it.pagopa.selfcare.user.constant.OnboardedProductState;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserToNotify {

private String userId;
private String name;
private String familyName;
private String email;
private PartyRole role;
private String productRole;
private OnboardedProductState relationshipStatus;

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,14 @@
import java.util.List;
import java.util.Map;

import static it.pagopa.selfcare.user.constant.CollectionUtil.USER_INSTITUTION_COLLECTION;
import static it.pagopa.selfcare.user.constant.CollectionUtil.*;
import static it.pagopa.selfcare.user.entity.filter.OnboardedProductFilter.OnboardedProductEnum.*;

@Slf4j
@ApplicationScoped
@RequiredArgsConstructor
public class UserInstitutionServiceDefault implements UserInstitutionService {

private static final String CURRENT = ".$.";
private static final String CURRENT_ANY = ".$[].";

private final UserInstitutionMapper userInstitutionMapper;
private final QueryUtils queryUtils;
private final UserUtils userUtils;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
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.model.notification.UserNotificationToSend;
import org.openapi.quarkus.user_registry_json.model.UserResource;


Expand All @@ -14,10 +15,16 @@

public interface UserService {
Uni<List<String>> getUsersEmails(String institutionId, String productId);

Multi<UserProductResponse> getUserProductsByInstitution(String institutionId);

Uni<UserResource> retrievePerson(String userId, String productId, String institutionId);

Uni<Void> updateUserStatusWithOptionalFilter(String userId, String institutionId, String productId, PartyRole role, String productRole, OnboardedProductState status);

Multi<UserInstitutionResponse> findAllUserInstitutions(String institutionId, String userId, List<String> roles, List<String> states, List<String> products, List<String> productRoles);

Uni<Void> deleteUserInstitutionProduct(String userId, String institutionId, String productId);

Uni<List<UserNotificationToSend>> findPaginatedUserNotificationToSend(Integer size, Integer page, String productId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import it.pagopa.selfcare.user.exception.ResourceNotFoundException;
import it.pagopa.selfcare.user.mapper.OnboardedProductMapper;
import it.pagopa.selfcare.user.mapper.UserInstitutionMapper;
import it.pagopa.selfcare.user.model.notification.UserNotificationToSend;
import it.pagopa.selfcare.user.util.UserUtils;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
Expand All @@ -26,6 +27,8 @@
import java.util.*;

import static it.pagopa.selfcare.user.constant.CustomError.*;
import static it.pagopa.selfcare.user.constant.CustomError.USER_NOT_FOUND_ERROR;
import static it.pagopa.selfcare.user.util.UserUtils.VALID_USER_PRODUCT_STATES_FOR_NOTIFICATION;

@RequiredArgsConstructor
@ApplicationScoped
Expand All @@ -45,6 +48,7 @@ public class UserServiceImpl implements UserService {

private static final String USERS_WORKS_FIELD_LIST = "fiscalCode,familyName,email,name,workContacts";

private static final String USERS_FIELD_LIST_WITHOUT_FISCAL_CODE = "name,familyName,email,workContacts";

/**
* The updateUserStatus function updates the status of a user's onboarded product.
Expand Down Expand Up @@ -131,4 +135,35 @@ public Uni<Void> deleteUserInstitutionProduct(String userId, String institutionI
});
}

@Override
public Uni<List<UserNotificationToSend>> findPaginatedUserNotificationToSend(Integer size, Integer page, String productId) {
List<UserNotificationToSend> response = new ArrayList<>();
Map<String, Object> queryParameter;
if (StringUtils.isNotBlank(productId)) {
queryParameter = OnboardedProductFilter.builder().productId(productId).status(VALID_USER_PRODUCT_STATES_FOR_NOTIFICATION).build().constructMap();
} else {
queryParameter = OnboardedProductFilter.builder().status(VALID_USER_PRODUCT_STATES_FOR_NOTIFICATION).build().constructMap();
}
return userInstitutionService.paginatedFindAllWithFilter(queryParameter, page, size)
.map(userInstitutions -> {
log.info("size: {}", userInstitutions.size());
return userInstitutions;
})
.onItem().transformToMulti(Multi.createFrom()::iterable)
.onItem().transformToUniAndMerge(userInstitution -> userRegistryApi
.findByIdUsingGET(USERS_FIELD_LIST_WITHOUT_FISCAL_CODE, userInstitution.getUserId())
.map(userResource -> buildUsersNotificationResponse(userInstitution, userResource, productId)))
.collect()
.asList()
.map(lists -> {
lists.forEach(response::addAll);
return lists;
})
.replaceWith(response);
}

private List<UserNotificationToSend> buildUsersNotificationResponse(UserInstitution userInstitution, UserResource userResource, String productId) {
return userUtils.constructUserNotificationToSend(userInstitution, userResource, productId);
}

}
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package it.pagopa.selfcare.user.util;

import io.smallrye.mutiny.Uni;
import it.pagopa.selfcare.onboarding.common.PartyRole;
import it.pagopa.selfcare.product.entity.ProductRole;
import it.pagopa.selfcare.product.service.ProductService;
import it.pagopa.selfcare.user.constant.OnboardedProductState;
import it.pagopa.selfcare.user.entity.UserInstitution;
import it.pagopa.selfcare.user.exception.InvalidRequestException;
import it.pagopa.selfcare.user.mapper.NotificationMapper;
import it.pagopa.selfcare.user.model.notification.UserNotificationToSend;
import it.pagopa.selfcare.user.model.notification.UserToNotify;
import jakarta.enterprise.context.ApplicationScoped;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpStatus;
import org.gradle.internal.impldep.org.apache.commons.lang.StringUtils;
import org.jboss.resteasy.reactive.client.api.WebClientApplicationException;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.*;

import java.util.Arrays;
import java.util.HashMap;
Expand All @@ -26,6 +27,8 @@
public class UserUtils {

private final ProductService productService;
private final NotificationMapper notificationMapper;
public static final List<String> VALID_USER_PRODUCT_STATES_FOR_NOTIFICATION = List.of(OnboardedProductState.ACTIVE.name(), OnboardedProductState.DELETED.name(), OnboardedProductState.SUSPENDED.name());

@SafeVarargs
public final Map<String, Object> retrieveMapForFilter(Map<String, Object>... maps) {
Expand All @@ -51,4 +54,17 @@ public static boolean checkIfNotFoundException(Throwable throwable) {

return false;
}

public List<UserNotificationToSend> constructUserNotificationToSend(UserInstitution userInstitution, org.openapi.quarkus.user_registry_json.model.UserResource userResource, String productId) {
return userInstitution.getProducts().stream()
.map(onboardedProduct -> {
if (StringUtils.isBlank(productId) || productId.equals(onboardedProduct.getProductId()) && VALID_USER_PRODUCT_STATES_FOR_NOTIFICATION.contains(onboardedProduct.getStatus().name())) {
UserToNotify userToNotify = notificationMapper.toUserNotify(userResource, onboardedProduct, userInstitution.getUserId());
return notificationMapper.setNotificationDetailsFromOnboardedProduct(userToNotify, onboardedProduct, userInstitution.getInstitutionId());
}
return null;
})
.toList();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
import io.restassured.http.ContentType;
import io.smallrye.mutiny.Uni;
import it.pagopa.selfcare.user.constant.OnboardedProductState;
import it.pagopa.selfcare.user.controller.response.UserNotificationResponse;
import it.pagopa.selfcare.user.exception.InvalidRequestException;
import it.pagopa.selfcare.user.exception.ResourceNotFoundException;
import it.pagopa.selfcare.user.mapper.UserMapper;
import it.pagopa.selfcare.user.model.notification.UserNotificationToSend;
import it.pagopa.selfcare.user.service.UserService;
import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.openapi.quarkus.user_registry_json.model.CertifiableFieldResourceOfLocalDate;
Expand Down Expand Up @@ -230,4 +234,38 @@ void deleteDeleteProductsOKTest() {
.statusCode(HttpStatus.SC_NO_CONTENT);
}

@Test
void testGetUsersNotAuthorized() {
var productId = "productId";

given().when()
.contentType(ContentType.JSON)
.queryParam("page", 0)
.queryParam("size", 100)
.queryParam(productId, "productId")
.get("")
.then()
.statusCode(401);
}

@Test
@TestSecurity(user = "userJwt")
void testGetUsers() {
Mockito.when(userService.findPaginatedUserNotificationToSend(0, 100, "productId"))
.thenReturn(Uni.createFrom().item( List.of(new UserNotificationToSend())));

var productId = "productId";

given()
.when()
.contentType(ContentType.JSON)
.queryParam("page", 0)
.queryParam("size", 100)
.queryParam(productId, "productId")
.get("")
.then()
.statusCode(200);
}


}
Loading

0 comments on commit 72edbb0

Please sign in to comment.