Unverified Commit f0bab8ae authored by pyXelians's avatar pyXelians Committed by GitHub
Browse files

[Xelians] User preferencies gestion (#523)



* [TRTL-878]  Setting up UserInfo: APIs

* [US TRTL-878] fix TU

* [US TRTL-1016] make userInfoId optional

* [US TRTL-936] migration of user infos

* [FIX TRTL-1082] show language on my account

* [TECH] Handle conflict

* [TECH] fix rebase

* [TECH] Fix index auto creation to test

* [TECH] FIX unit test front

* [FIX REC-385] Fix role duplication

* delete unused packages

* delete ui-frontend-common tar

Co-authored-by: default avatarNOUMANE <ahmed.noumane@xelians.fr>
Co-authored-by: default avatarCindy <cindy.nacibide@teamdlab.com>
Co-authored-by: default avatarFadil <fadil.zemmari@xelians.fr>
Co-authored-by: default avatarbouhaddouzay <youcef.bouhaddouza@xelians.fr>
Co-authored-by: default avatarEL HAJJIOUI Nabil <nabil.elhajjioui@smile.fr>
parent 2d4fb025
......@@ -104,7 +104,7 @@ public class Utils {
userDto.setIdentifier("code");
userDto.setStatus(UserStatusEnum.ENABLED);
userDto.setType(UserTypeEnum.NOMINATIVE);
userDto.setLanguage(LanguageDto.FRENCH.toString());
userDto.setUserInfoId(id);
userDto.setLevel(level);
userDto.setMobile("+33671270699");
userDto.setPhone("+33134237766");
......
......@@ -57,6 +57,8 @@ public abstract class RestApi {
public static final String V1_USERS_URL = "/iam/v1/users";
public static final String V1_USERS_INFO_URL = "/iam/v1/userinfos";
public static final String V1_ACCOUNTS_URL = "/iam/v1/accounts";
public static final String V1_GROUPS_URL = "/iam/v1/groups";
......@@ -76,6 +78,7 @@ public abstract class RestApi {
public static final String CAS_CHANGE_PASSWORD_PATH = "/password/change";
public static final String CAS_USERS_PATH = "/users";
public static final String CAS_USER_INFO_PATH = "/userinfos";
public static final String USERS_PROVISIONING = "/provisioning";
......
......@@ -41,7 +41,7 @@ public class IamDtoBuilder {
userDto.setIdentifier("code");
userDto.setStatus(UserStatusEnum.ENABLED);
userDto.setType(UserTypeEnum.NOMINATIVE);
userDto.setLanguage(LanguageDto.FRENCH.toString());
userDto.setUserInfoId("userInfoId");
userDto.setLevel(level);
userDto.setMobile("+33671270699");
userDto.setPhone("+33134237766");
......@@ -62,7 +62,7 @@ public class IamDtoBuilder {
userDto.setOtp(true);
userDto.setIdentifier("code");
userDto.setType(UserTypeEnum.NOMINATIVE);
userDto.setLanguage(LanguageDto.FRENCH.toString());
userDto.setUserInfoId("userInfoId");
userDto.setLevel("level");
userDto.setMobile("+33671270699");
userDto.setPhone("+33134237766");
......
......@@ -89,6 +89,10 @@ public class IamExternalRestClientFactory extends BaseRestClientFactory {
return new UserExternalRestClient(getRestTemplate(), getBaseUrl());
}
public UserInfoExternalRestClient getUserInfoInfoExternalRestClient() {
return new UserInfoExternalRestClient(getRestTemplate(), getBaseUrl());
}
public OwnerExternalRestClient getOwnerExternalRestClient() {
return new OwnerExternalRestClient(getRestTemplate(), getBaseUrl());
}
......
/**
* Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2020)
* and the signatories of the "VITAM - Accord du Contributeur" agreement.
*
* contact@programmevitam.fr
*
* This software is a computer program whose purpose is to implement
* implement a digital archiving front-office system for the secure and
* efficient high volumetry VITAM solution.
*
* This software is governed by the CeCILL-C license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL-C
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package fr.gouv.vitamui.iam.external.client;
import java.net.URI;
import java.util.List;
import java.util.Map;
import org.apache.http.client.utils.URIBuilder;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import fr.gouv.vitamui.commons.api.CommonConstants;
import fr.gouv.vitamui.commons.api.domain.PaginatedValuesDto;
import fr.gouv.vitamui.commons.api.domain.UserDto;
import fr.gouv.vitamui.commons.api.domain.UserInfoDto;
import fr.gouv.vitamui.commons.api.logger.VitamUILogger;
import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory;
import fr.gouv.vitamui.commons.rest.client.BasePaginatingAndSortingRestClient;
import fr.gouv.vitamui.commons.rest.client.ExternalHttpContext;
import fr.gouv.vitamui.iam.common.rest.RestApi;
/**
* A REST client to check existence, read, create, update and delete the user infos.
*
*
*/
public class UserInfoExternalRestClient extends BasePaginatingAndSortingRestClient<UserInfoDto, ExternalHttpContext> {
private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(UserInfoExternalRestClient.class);
public UserInfoExternalRestClient(final RestTemplate restTemplate, final String baseUrl) {
super(restTemplate, baseUrl);
}
public UserInfoDto getMe(final ExternalHttpContext context) {
LOGGER.debug("GetMe");
final HttpEntity<?> request = new HttpEntity<>(buildHeaders(context));
final URIBuilder uriBuilder = getUriBuilderFromPath(CommonConstants.PATH_ME);
final URI uri = buildUriBuilder(uriBuilder);
final ResponseEntity<UserInfoDto> response = restTemplate.exchange(uri, HttpMethod.GET, request,getDtoClass());
checkResponse(response);
return response.getBody();
}
public UserInfoDto patchMe(final ExternalHttpContext context, final Map<String, Object> partialDto) {
LOGGER.debug("Patch me partialDto={}");
final URIBuilder uriBuilder = getUriBuilderFromPath(CommonConstants.PATH_ME);
final MultiValueMap<String, String> headers = buildHeaders(context);
final URI uri = buildUriBuilder(uriBuilder);
final HttpEntity<Map<String, Object>> request = new HttpEntity<>(partialDto, headers);
final ResponseEntity<UserInfoDto> response = restTemplate.exchange(uri, HttpMethod.PATCH, request, getDtoClass());
checkResponse(response);
return response.getBody();
}
@Override
public String getPathUrl() {
return RestApi.V1_USERS_INFO_URL;
}
@Override
protected Class<UserInfoDto> getDtoClass() {
return UserInfoDto.class;
}
@Override
protected ParameterizedTypeReference<List<UserInfoDto>> getDtoListClass() {
return new ParameterizedTypeReference<>() {
};
}
@Override
protected ParameterizedTypeReference<PaginatedValuesDto<UserInfoDto>> getDtoPaginatedClass() {
return new ParameterizedTypeReference<>() {
};
}
}
......@@ -56,6 +56,7 @@ import fr.gouv.vitamui.iam.internal.client.OwnerInternalRestClient;
import fr.gouv.vitamui.iam.internal.client.ProfileInternalRestClient;
import fr.gouv.vitamui.iam.internal.client.SubrogationInternalRestClient;
import fr.gouv.vitamui.iam.internal.client.TenantInternalRestClient;
import fr.gouv.vitamui.iam.internal.client.UserInfoInternalRestClient;
import fr.gouv.vitamui.iam.internal.client.UserInternalRestClient;
import fr.gouv.vitamui.iam.security.provider.ExternalApiAuthenticationProvider;
import fr.gouv.vitamui.iam.security.service.ExternalAuthentificationService;
......@@ -167,6 +168,13 @@ public class ApiIamServerConfig extends AbstractContextConfiguration {
return iamInternalRestClientFactory.getUserInternalRestClient();
}
@Bean
public UserInfoInternalRestClient userInfoInternalRestClient(final IamInternalRestClientFactory iamInternalRestClientFactory) {
return iamInternalRestClientFactory.getUserInfoInternalRestClient();
}
@Bean
public OwnerInternalRestClient ownerInternalRestClient(final IamInternalRestClientFactory iamInternalRestClientFactory) {
return iamInternalRestClientFactory.getOwnerInternalRestClient();
......
/**
* Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2020)
* and the signatories of the "VITAM - Accord du Contributeur" agreement.
*
* contact@programmevitam.fr
*
* This software is a computer program whose purpose is to implement
* implement a digital archiving front-office system for the secure and
* efficient high volumetry VITAM solution.
*
* This software is governed by the CeCILL-C license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL-C
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package fr.gouv.vitamui.iam.external.server.rest;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import fr.gouv.vitamui.commons.api.CommonConstants;
import fr.gouv.vitamui.commons.api.domain.ServicesData;
import fr.gouv.vitamui.commons.api.domain.UserInfoDto;
import fr.gouv.vitamui.commons.api.exception.NotImplementedException;
import fr.gouv.vitamui.commons.api.logger.VitamUILogger;
import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory;
import fr.gouv.vitamui.commons.rest.CrudController;
import fr.gouv.vitamui.iam.common.rest.RestApi;
import fr.gouv.vitamui.iam.external.server.service.UserInfoExternalService;
import lombok.Getter;
import lombok.Setter;
@RestController
@RequestMapping(RestApi.V1_USERS_INFO_URL)
@Getter
@Setter
public class UserInfoExternalController implements CrudController<UserInfoDto> {
private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(UserInfoExternalController.class);
private final UserInfoExternalService userInfoExternalService;
@Autowired
public UserInfoExternalController(final UserInfoExternalService userInfoExternalService) {
this.userInfoExternalService = userInfoExternalService;
}
@Override
@PostMapping
@Secured(ServicesData.ROLE_CREATE_USER_INFOS)
public UserInfoDto create(final @Valid @RequestBody UserInfoDto dto) {
LOGGER.debug("Create {}", dto);
return userInfoExternalService.create(dto);
}
@Override
public UserInfoDto update(final String id, final UserInfoDto dto) {
throw new NotImplementedException("update not supported");
}
@Override
public void delete(final String id) {
throw new NotImplementedException("delete not supported");
}
@Override
public Collection<UserInfoDto> getAll(final Optional<String> criteria) {
throw new NotImplementedException("getAll not supported");
}
@Override
public ResponseEntity<Void> checkExist(final String criteria) {
throw new NotImplementedException("checkExist not supported");
}
@Override
@GetMapping(CommonConstants.PATH_ID)
@Secured(ServicesData.ROLE_GET_USER_INFOS)
public UserInfoDto getOne(final @PathVariable("id") String id) {
LOGGER.debug("Get {}", id);
return userInfoExternalService.getOne(id);
}
/**
* Get user info for current user .
*
* @return
*/
@GetMapping(CommonConstants.PATH_ME)
public UserInfoDto getMe() {
LOGGER.debug("getMe {}");
return userInfoExternalService.getMe();
}
@PatchMapping(CommonConstants.PATH_ME)
public UserInfoDto patchMe(@RequestBody final Map<String, Object> partialDto) {
LOGGER.debug("Patch me with {}", partialDto);
return userInfoExternalService.patchMe(partialDto);
}
@Override
@PatchMapping(CommonConstants.PATH_ID)
@Secured(ServicesData.ROLE_UPDATE_USER_INFOS)
public UserInfoDto patch(final @PathVariable("id") String id, final @RequestBody Map<String, Object> partialDto) {
LOGGER.debug("Patch User {} with {}", id, partialDto);
Assert.isTrue(StringUtils.equals(id, (String) partialDto.get("id")), "Unable to patch user : the DTO id must match the path id");
return userInfoExternalService.patch(partialDto);
}
}
/**
* Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2020)
* and the signatories of the "VITAM - Accord du Contributeur" agreement.
*
* contact@programmevitam.fr
*
* This software is a computer program whose purpose is to implement
* implement a digital archiving front-office system for the secure and
* efficient high volumetry VITAM solution.
*
* This software is governed by the CeCILL-C license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL-C
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package fr.gouv.vitamui.iam.external.server.service;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import fr.gouv.vitamui.commons.api.domain.UserDto;
import fr.gouv.vitamui.commons.api.domain.UserInfoDto;
import fr.gouv.vitamui.commons.security.client.dto.AuthUserDto;
import fr.gouv.vitamui.iam.internal.client.UserInfoInternalRestClient;
import fr.gouv.vitamui.iam.security.client.AbstractResourceClientService;
import fr.gouv.vitamui.iam.security.service.ExternalSecurityService;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Service
public class UserInfoExternalService extends AbstractResourceClientService<UserInfoDto, UserInfoDto> {
private final UserInfoInternalRestClient userInfoInternalRestClient;
@Autowired
public UserInfoExternalService(final UserInfoInternalRestClient userInfoInternalRestClient, final ExternalSecurityService externalSecurityService) {
super(externalSecurityService);
this.userInfoInternalRestClient = userInfoInternalRestClient;
}
@Override
public UserInfoDto create(final UserInfoDto userInfoDto) {
return super.create(userInfoDto);
}
@Override
public UserInfoDto getOne(final String id) {
return super.getOne(id);
}
public UserInfoDto getMe() {
return userInfoInternalRestClient.getMe(getInternalHttpContext());
}
public UserInfoDto patchMe(final Map<String, Object> partialDto) {
final AuthUserDto user = externalSecurityService.getUser();
partialDto.put("id", user.getUserInfoId());
return patch(partialDto);
}
@Override
public UserInfoDto patch(final Map<String, Object> partialDto) {
return super.patch(partialDto);
}
@Override
protected String getVersionApiCrtieria() {
return CRITERIA_VERSION_V2;
}
@Override
protected UserInfoInternalRestClient getClient() {
return userInfoInternalRestClient;
}
}
package fr.gouv.vitamui.iam.external.server.rest;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import com.google.common.collect.ImmutableMap;
import fr.gouv.vitamui.commons.api.domain.ServicesData;
import fr.gouv.vitamui.commons.api.domain.UserInfoDto;
import fr.gouv.vitamui.commons.api.logger.VitamUILogger;
import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory;
import fr.gouv.vitamui.iam.common.rest.RestApi;
import fr.gouv.vitamui.iam.external.server.service.UserInfoExternalService;
import fr.gouv.vitamui.iam.external.server.utils.ApiIamServerUtils;
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = {UserInfoExternalController.class})
class UserInfoExternalControllerTest extends ApiIamControllerTest<UserInfoDto> {
private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(UserInfoExternalControllerTest.class);
@MockBean
private UserInfoExternalService userExternalService;
private final UserInfoExternalController userExternalController = MvcUriComponentsBuilder.on(UserInfoExternalController.class);
@Test
void test_patch_should_be_Ok() throws Exception {
final String id = "iduser";
final String endpoint = "/" + id;
final ResultActions result = super.performPatch(endpoint, asJsonString(ImmutableMap.of("id", id, "language", "fr")));
result.andExpect(MockMvcResultMatchers.handler().methodCall(userExternalController.patch(null, null)));
Mockito.verify(userExternalService, Mockito.times(1)).patch(ArgumentMatchers.any());
}
@Override
protected UserInfoDto buildDto() {
return ApiIamServerUtils.buildUserInfoDto("id");
}
@Override
protected VitamUILogger getLog() {
return LOGGER;
}
@Override
protected void preparedServices() {
}
@Override
protected String getRessourcePrefix() {
return RestApi.V1_USERS_INFO_URL;
}
@Override
protected String[] getServices() {
return new String[]{ServicesData.SERVICE_USER_INFOS};
}
@Override
protected Class<UserInfoDto> getDtoClass() {
return UserInfoDto.class;
}
}
\ No newline at end of file
......@@ -2,6 +2,7 @@ package fr.gouv.vitamui.iam.external.server.utils;
import fr.gouv.vitamui.commons.api.domain.ExternalParamProfileDto;
import fr.gouv.vitamui.commons.api.domain.ProfileDto;
import fr.gouv.vitamui.commons.api.domain.UserInfoDto;
import fr.gouv.vitamui.iam.common.dto.CustomerDto;
import fr.gouv.vitamui.commons.api.domain.UserDto;
import fr.gouv.vitamui.iam.commons.utils.IamDtoBuilder;
......@@ -18,6 +19,13 @@ public class ApiIamServerUtils {
return basicUserDto;
}
public static UserInfoDto buildUserInfoDto(final String id) {
final UserInfoDto userInfoDto = new UserInfoDto();
userInfoDto.setId(id);
userInfoDto.setLanguage("fr");