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-4488] Feat: Added V2 for usergroup API #384

Merged
merged 4 commits into from
Mar 22, 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
640 changes: 639 additions & 1 deletion app/src/main/resources/swagger/api-docs.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class SwaggerConfigTest {
@MockBean
private UserMapperV2 userMapperImpl;

@MockBean
private UserGroupV2Service userGroupServiceV2Mock;

@MockBean
private InstitutionResourceMapper institutionResourceMapper;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public interface UserApiConnector {

List<InstitutionBase> getUserInstitutions(String userId);

User getUserById(String userId);
User getUserById(String userId, List<String> fields);

User searchByFiscalCode(String fiscalCode);

Expand Down
7 changes: 7 additions & 0 deletions connector/rest/docs/openapi/selfcare-user-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,13 @@
"schema": {
"type": "string"
}
},
{
"name": "field",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,11 @@ public Boolean hasPermission(String institutionId, String permission, String pro
}

@Override
public User getUserById(String userId) {
public User getUserById(String userId, List<String> fields) {
log.trace("getUserById start");
log.debug("getUserById id = {}", userId);
User user = userMapper.toUser(userApiRestClient._usersIdDetailsGet(userId).getBody());
String fieldsString = !CollectionUtils.isEmpty(fields) ? String.join(",", fields) : null;
User user = userMapper.toUser(userApiRestClient._usersIdDetailsGet(userId, fieldsString).getBody());
log.debug(LogUtils.CONFIDENTIAL_MARKER, "getUserById = {}", user);
log.trace("getUserById end");
return user;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,12 @@ void getUserById(){
//given
String userId = "userId";
UserDetailResponse userDetailResponse = mockInstance(new UserDetailResponse());
when(userApiRestClient._usersIdDetailsGet(anyString())).thenReturn(new ResponseEntity<>(userDetailResponse, HttpStatus.OK));
when(userApiRestClient._usersIdDetailsGet(userId, null)).thenReturn(new ResponseEntity<>(userDetailResponse, HttpStatus.OK));
//when
User user = userConnector.getUserById(userId);
User user = userConnector.getUserById(userId, null);
//then
assertNotNull(user);
verify(userApiRestClient, times(1))._usersIdDetailsGet(userId);
verify(userApiRestClient, times(1))._usersIdDetailsGet(userId, null);
}
@Test
void verifyUserExist_UserExists() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package it.pagopa.selfcare.dashboard.core;

import it.pagopa.selfcare.dashboard.connector.model.groups.CreateUserGroup;
import it.pagopa.selfcare.dashboard.connector.model.groups.UpdateUserGroup;
import it.pagopa.selfcare.dashboard.connector.model.groups.UserGroupInfo;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.Optional;
import java.util.UUID;

public interface UserGroupV2Service {
void deleteMembersByUserId(String userId, String institutionId, String productId);

String createUserGroup(CreateUserGroup group);

void delete(String groupId);

void activate(String groupId);

void suspend(String groupId);

void updateUserGroup(String groupId, UpdateUserGroup group);

void addMemberToUserGroup(String groupId, UUID userId);

void deleteMemberFromUserGroup(String groupId, UUID userId);

UserGroupInfo getUserGroupById(String groupId, String institutionId);

Page<UserGroupInfo> getUserGroups(String institutionId, String productId, UUID userId, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
package it.pagopa.selfcare.dashboard.core;

import it.pagopa.selfcare.commons.base.logging.LogUtils;
import it.pagopa.selfcare.commons.base.security.SelfCareUser;
import it.pagopa.selfcare.dashboard.connector.api.UserApiConnector;
import it.pagopa.selfcare.dashboard.connector.api.UserGroupConnector;
import it.pagopa.selfcare.dashboard.connector.model.groups.CreateUserGroup;
import it.pagopa.selfcare.dashboard.connector.model.groups.UpdateUserGroup;
import it.pagopa.selfcare.dashboard.connector.model.groups.UserGroupFilter;
import it.pagopa.selfcare.dashboard.connector.model.groups.UserGroupInfo;
import it.pagopa.selfcare.dashboard.connector.model.user.User;
import it.pagopa.selfcare.dashboard.connector.model.user.UserInfo;
import it.pagopa.selfcare.dashboard.connector.model.user.UserInstitution;
import it.pagopa.selfcare.dashboard.core.exception.InvalidMemberListException;
import it.pagopa.selfcare.dashboard.core.exception.InvalidUserGroupException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;

import static it.pagopa.selfcare.dashboard.connector.model.institution.RelationshipState.ACTIVE;
import static it.pagopa.selfcare.dashboard.connector.model.institution.RelationshipState.SUSPENDED;
import static it.pagopa.selfcare.dashboard.connector.model.user.User.Fields.*;

@Component
@Slf4j
@RequiredArgsConstructor
public class UserGroupV2ServiceImpl implements UserGroupV2Service{


private static final EnumSet<User.Fields> MEMBER_FIELD_LIST = EnumSet.of(name, familyName, workContacts);
private static final EnumSet<User.Fields> FIELD_LIST = EnumSet.of(name, familyName);

private final UserGroupConnector groupConnector;
private final UserApiConnector userApiConnector;

static final String REQUIRED_GROUP_ID_MESSAGE = "A user group id is required";

@Override
public String createUserGroup(CreateUserGroup group) {
log.trace("createUserGroup start");
log.debug("createUserGroup group = {}", group);
UserInfo.UserInfoFilter userInfoFilter = new UserInfo.UserInfoFilter();
userInfoFilter.setProductId(group.getProductId());
userInfoFilter.setAllowedStates(List.of(ACTIVE, SUSPENDED));

List<String> retrievedId = retrievedIds(group.getInstitutionId(), userInfoFilter);

if (group.getMembers().stream()
.filter(uuid -> Collections.binarySearch(retrievedId, uuid) >= 0)
.count() != group.getMembers().size()) {
throw new InvalidMemberListException("Some members in the list aren't allowed for this institution");
}
String groupId = groupConnector.createUserGroup(group);
log.debug("createUserGroup result = {}", groupId);
log.trace("createUserGroup end");
return groupId;
}

@Override
public void delete(String groupId) {
log.trace("delete start");
log.debug("delete groupId = {}", groupId);
Assert.hasText(groupId, REQUIRED_GROUP_ID_MESSAGE);
groupConnector.delete(groupId);
log.trace("delete end");
}

@Override
public void activate(String groupId) {
log.trace("activate start");
log.debug("activate groupId = {}", groupId);
Assert.hasText(groupId, REQUIRED_GROUP_ID_MESSAGE);
groupConnector.activate(groupId);
log.trace("activate end");
}

private List<String> retrievedIds(String institutionId, UserInfo.UserInfoFilter userInfoFilter) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String loggedUserId = ((SelfCareUser) authentication.getPrincipal()).getId();
Collection<UserInfo> retrievedUsers = userApiConnector.getUsers(
institutionId,
userInfoFilter, loggedUserId);
return retrievedUsers.stream()
.map(UserInfo::getId)
.sorted()
.toList();
}

@Override
public void suspend(String groupId) {
log.trace("suspend start");
log.debug("suspend groupId = {}", groupId);
Assert.hasText(groupId, REQUIRED_GROUP_ID_MESSAGE);
groupConnector.suspend(groupId);
log.trace("suspend end");
}

@Override
public void updateUserGroup(String groupId, UpdateUserGroup group) {
log.trace("updateUserGroup start");
log.debug("updateUserGroup groupId = {}, group = {}", groupId, group);
UserGroupInfo userGroupInfo = groupConnector.getUserGroupById(groupId);

UserInfo.UserInfoFilter userInfoFilter = new UserInfo.UserInfoFilter();
userInfoFilter.setProductId(userGroupInfo.getProductId());
userInfoFilter.setAllowedStates(List.of(ACTIVE, SUSPENDED));

List<String> retrievedId = retrievedIds(userGroupInfo.getInstitutionId(), userInfoFilter);

if (group.getMembers().stream()
.filter(uuid -> Collections.binarySearch(retrievedId, uuid) >= 0)
.count() != group.getMembers().size()) {
throw new InvalidMemberListException("Some members in the list aren't allowed for this institution");
}
groupConnector.updateUserGroup(groupId, group);
log.trace("updateUserGroup end");
}

@Override
public void addMemberToUserGroup(String groupId, UUID userId) {
log.trace("addMemberToUserGroup start");
log.debug("addMemberToUserGroup groupId = {}, userId = {}", groupId, userId);
Assert.hasText(groupId, REQUIRED_GROUP_ID_MESSAGE);
Assert.notNull(userId, "A userId is required");
UserGroupInfo retrievedGroup = groupConnector.getUserGroupById(groupId);
UserInfo.UserInfoFilter userInfoFilter = new UserInfo.UserInfoFilter();
userInfoFilter.setProductId(retrievedGroup.getProductId());
userInfoFilter.setAllowedStates(List.of(ACTIVE, SUSPENDED));
List<String> retrievedIds = retrievedIds(retrievedGroup.getInstitutionId(), userInfoFilter);
if (!retrievedIds.contains(userId.toString())) {
throw new InvalidMemberListException("This user is not allowed for this group");
}
groupConnector.addMemberToUserGroup(groupId, userId);
log.trace("addMemberToUserGroup end");
}

@Override
public void deleteMemberFromUserGroup(String groupId, UUID userId) {
log.trace("deleteMemberFromUserGroup start");
log.debug("deleteMemberFromUserGroup groupId = {}, userId = {}", groupId, userId);
Assert.hasText(groupId, REQUIRED_GROUP_ID_MESSAGE);
Assert.notNull(userId, "A userId is required");
groupConnector.deleteMemberFromUserGroup(groupId, userId);
log.trace("deleteMemberFromUserGroup end");
}

@Override
public UserGroupInfo getUserGroupById(String groupId, String institutionId) {
log.trace("getUserGroupById start");
log.debug("getUserGroupById groupId = {}", groupId);
Assert.hasText(groupId, REQUIRED_GROUP_ID_MESSAGE);
UserGroupInfo userGroupInfo = groupConnector.getUserGroupById(groupId);
Optional.ofNullable(institutionId).ifPresent(value -> {
if (!value.equalsIgnoreCase(userGroupInfo.getInstitutionId())) {
throw new InvalidUserGroupException("Could not find a UserGroup for given institutionId");
}
});
Comparator<UserInfo> userInfoComparator = Comparator.comparing(UserInfo::getId);
UserInfo.UserInfoFilter userInfoFilter = new UserInfo.UserInfoFilter();
userInfoFilter.setProductId(userGroupInfo.getProductId());
userInfoFilter.setAllowedStates(List.of(ACTIVE, SUSPENDED));
List<UserInfo> userInfos = retrievedIds(userGroupInfo.getInstitutionId(), userInfoFilter).stream()
.map(id -> {
UserInfo userInfo = new UserInfo();
userInfo.setId(id);
return userInfo;
}).toList();
userGroupInfo.setMembers(userGroupInfo.getMembers().stream()
.map(userInfo -> {
int index = Collections.binarySearch(userInfos, userInfo, userInfoComparator);
if (index < 0) {
log.error(String.format("Member with uuid %s has no relationship with institution id '%s' and product id '%s'",
userInfo.getId(),
userGroupInfo.getInstitutionId(),
userGroupInfo.getProductId()));
return null;
}
userInfos.get(index).setUser(userApiConnector.getUserById(userInfo.getId(), MEMBER_FIELD_LIST.stream().map(Enum::name).toList()));
return userInfos.get(index);
}).filter(Objects::nonNull)
.toList());
User createdBy = userApiConnector.getUserById(userGroupInfo.getCreatedBy().getId(), FIELD_LIST.stream().map(Enum::name).toList());
userGroupInfo.setCreatedBy(createdBy);
if (userGroupInfo.getModifiedBy() != null) {
User modifiedBy = userApiConnector.getUserById(userGroupInfo.getModifiedBy().getId(), FIELD_LIST.stream().map(Enum::name).toList());
userGroupInfo.setModifiedBy(modifiedBy);
}
log.debug(LogUtils.CONFIDENTIAL_MARKER, "getUserGroupById userGroupInfo = {}", userGroupInfo);
log.trace("getUserGroupById end");
return userGroupInfo;
}

@Override
public Page<UserGroupInfo> getUserGroups(String institutionId, String productId, UUID userId, Pageable pageable) {
log.trace("getUserGroups start");
log.debug("getUserGroups institutionId = {}, productId = {}, userId = {}, pageable = {}", institutionId, productId, userId, pageable);
UserGroupFilter userGroupFilter = new UserGroupFilter();
userGroupFilter.setInstitutionId(Optional.ofNullable(institutionId));
userGroupFilter.setUserId(Optional.ofNullable(userId));
userGroupFilter.setProductId(Optional.ofNullable(productId));
Page<UserGroupInfo> groupInfos = groupConnector.getUserGroups(userGroupFilter, pageable);
log.debug("getUserGroups result = {}", groupInfos);
log.trace("getUserGroups end");

return groupInfos;
}

@Override
public void deleteMembersByUserId(String userId, String institutionId, String productId) {
log.trace("deleteMembersByUserId start");
log.debug("deleteMembersByUserId userId = {}", userId);
List<UserInstitution> userInstitutionList = userApiConnector.retrieveFilteredUser(userId, institutionId, productId);
if (CollectionUtils.isEmpty(userInstitutionList)) {
log.debug("User not found, deleting members for userId = {}", userId);
groupConnector.deleteMembers(userId, institutionId, productId);
} else {
log.debug("User found, not deleting members for userId = {}", userId);
}
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class UserV2ServiceImpl implements UserV2Service {

private final UserApiConnector userApiConnector;
private final MsCoreConnector msCoreConnector;
private final UserV2GroupService userGroupService;
private final UserGroupV2Service userGroupService;

@Override
public Collection<InstitutionBase> getInstitutions(String userId) {
Expand Down Expand Up @@ -66,7 +66,7 @@ public void suspendUserProduct(String userId, String institutionId, String produ
public User getUserById(String userId) {
log.trace("getUserById start");
log.debug("getUserById id = {}", userId);
User user = userApiConnector.getUserById(userId);
User user = userApiConnector.getUserById(userId, null);
log.debug(LogUtils.CONFIDENTIAL_MARKER, "getUserById = {}", user);
log.trace("getUserById end");
return user;
Expand Down
Loading