Skip to content

Commit

Permalink
feat(rbac): add description field to projects
Browse files Browse the repository at this point in the history
  • Loading branch information
omar-chahbouni-decathlon committed Jan 30, 2023
1 parent 392e88d commit ebd2595
Show file tree
Hide file tree
Showing 23 changed files with 385 additions and 379 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand Down Expand Up @@ -253,7 +250,7 @@ public List<ProjectDTO> getCurrentUserProjects() throws ForbiddenException {
if (currentUserIsScopedUser) {
var scopedProjectsStream = currentUser.getRolesOnProjectWhenScopedUser().stream().map(UserEntityRoleOnProject::getProject);
var demoProjectStream = projectRepository.findByCode(DEMO_PROJECT_CODE).map(Stream::of).orElse(Stream.empty());
userProjectsStream = Stream.concat(scopedProjectsStream, demoProjectStream);
userProjectsStream = Stream.concat(scopedProjectsStream, demoProjectStream).sorted(Comparator.comparing(Project::getName));
}
return userProjectsStream.map(projectMapper::getProjectDTOFromProjectEntity).toList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@
import com.decathlon.ara.service.exception.NotFoundException;
import com.decathlon.ara.service.exception.NotUniqueException;
import com.decathlon.ara.service.mapper.ProjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -75,16 +75,16 @@ public ProjectService(
/**
* Create a new entity.
*
* @param dtoToCreate the entity to save
* @param projectToCreate the entity to save
* @return the persisted entity
* @throws NotUniqueException when the given code or name is already used by another entity
*/
public ProjectDTO create(@NonNull ProjectDTO dtoToCreate, @NonNull UserEntity creationUser) throws NotUniqueException {
validateBusinessRules(dtoToCreate);
final Project entity = projectMapper.getProjectEntityFromProjectDTO(dtoToCreate);
entity.setCreationUser(creationUser);
communicationService.initializeProject(entity);
final ProjectDTO createdProject = projectMapper.getProjectDTOFromProjectEntity(projectRepository.save(entity));
public ProjectDTO create(@NonNull ProjectDTO projectToCreate, @NonNull UserEntity creationUser) throws NotUniqueException {
validateBusinessRules(projectToCreate);
final Project projectToSave = projectMapper.getProjectEntityFromProjectDTO(projectToCreate);
projectToSave.setCreationUser(creationUser);
communicationService.initializeProject(projectToSave);
final ProjectDTO createdProject = projectMapper.getProjectDTOFromProjectEntity(projectRepository.save(projectToSave));

final long projectId = createdProject.getId();
rootCauseRepository.saveAll(Arrays.asList(
Expand Down Expand Up @@ -120,24 +120,31 @@ private static String getProjectNameFromCode(String projectCode) {
/**
* Update an entity.
*
* @param dtoToUpdate the entity to update
* @param projectToUpdate the entity to update
* @return the updated entity, if the entity was present in database
* @throws NotFoundException when the given entity ID is not present in database
* @throws NotUniqueException when the given code or name is already used by another entity
*/
public ProjectDTO update(@NonNull ProjectDTO dtoToUpdate, @NonNull UserEntity updateUser) throws BadRequestException {
Optional<Project> dataBaseEntity = projectRepository.findById(dtoToUpdate.getId());
if (!dataBaseEntity.isPresent()) {
throw new NotFoundException(Messages.NOT_FOUND_PROJECT, Entities.PROJECT);
public ProjectDTO update(@NonNull ProjectDTO projectToUpdate, @NonNull UserEntity updateUser) throws BadRequestException {
var newProjectName = projectToUpdate.getName();
if (StringUtils.isBlank(newProjectName)) {
throw new BadRequestException("The project name cannot be left blank!", Entities.PROJECT, "project_name_blank");
}

validateBusinessRules(dtoToUpdate);
var persistedProject = projectRepository.findByCode(projectToUpdate.getCode()).orElseThrow(() -> new NotFoundException(Messages.NOT_FOUND_PROJECT, Entities.PROJECT));

if (!newProjectName.equals(persistedProject.getName())) {
var projectNameAlreadyExists = projectRepository.existsByName(newProjectName);
if (projectNameAlreadyExists) {
throw new NotUniqueException(Messages.NOT_UNIQUE_PROJECT_NAME, Entities.PROJECT, "name", persistedProject.getId());
}
}

final Project entity = projectMapper.getProjectEntityFromProjectDTO(dtoToUpdate);
entity.setCommunications(dataBaseEntity.get().getCommunications());
entity.setUpdateDate(ZonedDateTime.now());
entity.setUpdateUser(updateUser);
return projectMapper.getProjectDTOFromProjectEntity(projectRepository.save(entity));
persistedProject.setName(newProjectName);
persistedProject.setDescription(projectToUpdate.getDescription());
persistedProject.setUpdateDate(ZonedDateTime.now());
persistedProject.setUpdateUser(updateUser);
return projectMapper.getProjectDTOFromProjectEntity(projectRepository.save(persistedProject));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public class ProjectDTO {
@Size(min = 1, max = 64, message = "The name is required and must not exceed {max} characters.")
private String name;

private String description;

@JsonProperty("creation_date")
@JsonFormat(pattern = DATE_FORMAT_YEAR_TO_SECOND)
private Date creationDate;
Expand Down Expand Up @@ -86,6 +88,14 @@ public String getName() {
return name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public Date getCreationDate() {
return creationDate;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public ProjectDTO getProjectDTOFromProjectEntity(@NonNull Project project) {
var code = project.getCode();
var name = project.getName();
var projectToConvert = new ProjectDTO(id, code, name);
projectToConvert.setDescription(project.getDescription());

var creationDate = project.getCreationDate();
if (creationDate != null) {
Expand All @@ -40,6 +41,8 @@ public Project getProjectEntityFromProjectDTO(@NonNull ProjectDTO projectDTO) {
var id = projectDTO.getId();
var code = projectDTO.getCode();
var name = projectDTO.getName();
return new Project(id, code, name);
var projectToConvert = new Project(id, code, name);
projectToConvert.setDescription(projectDTO.getDescription());
return projectToConvert;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,18 @@ public ResponseEntity<ProjectDTO> create(@Valid @RequestBody ProjectDTO dtoToCre
* Update an existing project.
*
* @param projectCode the code of the project to update
* @param dtoToUpdate the project to update
* @param projectToUpdate the project to update
* @return the ResponseEntity with status 200 (OK) and with body the updated project, or with status 400 (Bad Request) if the project is not
* valid, or with status 500 (Internal Server Error) if the project couldn't be updated
*/
@PutMapping(PROJECT_CODE_REQUEST_PARAMETER)
public ResponseEntity<ProjectDTO> update(@PathVariable String projectCode, @Valid @RequestBody ProjectDTO dtoToUpdate) {
public ResponseEntity<ProjectDTO> update(@PathVariable String projectCode, @Valid @RequestBody ProjectDTO projectToUpdate) {
try {
var projectId = projectService.toId(projectCode);
dtoToUpdate.setId(projectId); // HTTP PUT requires the URL to be the URL of the entity
var updateUser = userAccountService.getCurrentUserEntity().orElseThrow(() -> new ForbiddenException(Entities.PROJECT, "project update", Pair.of("code", projectCode)));
ProjectDTO updatedDto = projectService.update(dtoToUpdate, updateUser);
ProjectDTO updatedProject = projectService.update(projectToUpdate, updateUser);
return ResponseEntity.ok()
.headers(HeaderUtil.entityUpdated(NAME, updatedDto.getId()))
.body(updatedDto);
.headers(HeaderUtil.entityUpdated(NAME, updatedProject.getId()))
.body(updatedProject);
} catch (BadRequestException e) {
return ResponseUtil.handle(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.util.stream.Stream;

import static com.decathlon.ara.loader.DemoLoaderConstants.DEMO_PROJECT_CODE;
import static com.decathlon.ara.loader.DemoLoaderConstants.DEMO_PROJECT_NAME;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.junit.jupiter.api.Assertions.assertThrows;
Expand Down Expand Up @@ -715,6 +716,10 @@ void getCurrentUserProjects_returnProjectsInCurrentUserScopesWithoutDemoProject_
var userScope3 = mock(UserEntityRoleOnProject.class);
var userScopes = List.of(userScope1, userScope2, userScope3);

var projectName1 = "p2";
var projectName2 = "p3";
var projectName3 = "p1";

var project1 = mock(Project.class);
var project2 = mock(Project.class);
var project3 = mock(Project.class);
Expand All @@ -731,8 +736,11 @@ void getCurrentUserProjects_returnProjectsInCurrentUserScopesWithoutDemoProject_
when(persistedUser.getProfile()).thenReturn(profile);
when(persistedUser.getRolesOnProjectWhenScopedUser()).thenReturn(userScopes);
when(userScope1.getProject()).thenReturn(project1);
when(project1.getName()).thenReturn(projectName1);
when(userScope2.getProject()).thenReturn(project2);
when(project2.getName()).thenReturn(projectName2);
when(userScope3.getProject()).thenReturn(project3);
when(project3.getName()).thenReturn(projectName3);
when(projectRepository.findByCode(DEMO_PROJECT_CODE)).thenReturn(Optional.empty());
when(projectMapper.getProjectDTOFromProjectEntity(project1)).thenReturn(mappedProject1);
when(projectMapper.getProjectDTOFromProjectEntity(project2)).thenReturn(mappedProject2);
Expand All @@ -741,8 +749,7 @@ void getCurrentUserProjects_returnProjectsInCurrentUserScopesWithoutDemoProject_
// Then
var actualProjects = userAccountService.getCurrentUserProjects();

var expectedProjects = List.of(mappedProject1, mappedProject2, mappedProject3);
assertThat(actualProjects).containsExactlyInAnyOrderElementsOf(expectedProjects);
assertThat(actualProjects).containsExactly(mappedProject3, mappedProject1, mappedProject2);
verify(projectRepository, never()).findAllByOrderByName();
verify(projectRepository, times(1)).findByCode(DEMO_PROJECT_CODE);
verifyNoMoreInteractions(projectRepository);
Expand All @@ -763,6 +770,10 @@ void getCurrentUserProjects_returnProjectsInCurrentUserScopesWithDemoProject_whe
var userScope3 = mock(UserEntityRoleOnProject.class);
var userScopes = List.of(userScope1, userScope2, userScope3);

var projectName1 = "p2";
var projectName2 = "p3";
var projectName3 = "p1";

var project1 = mock(Project.class);
var project2 = mock(Project.class);
var project3 = mock(Project.class);
Expand All @@ -781,9 +792,13 @@ void getCurrentUserProjects_returnProjectsInCurrentUserScopesWithDemoProject_whe
when(persistedUser.getProfile()).thenReturn(profile);
when(persistedUser.getRolesOnProjectWhenScopedUser()).thenReturn(userScopes);
when(userScope1.getProject()).thenReturn(project1);
when(project1.getName()).thenReturn(projectName1);
when(userScope2.getProject()).thenReturn(project2);
when(project2.getName()).thenReturn(projectName2);
when(userScope3.getProject()).thenReturn(project3);
when(project3.getName()).thenReturn(projectName3);
when(projectRepository.findByCode(DEMO_PROJECT_CODE)).thenReturn(Optional.of(demoProject));
when(demoProject.getName()).thenReturn(DEMO_PROJECT_NAME);
when(projectMapper.getProjectDTOFromProjectEntity(project1)).thenReturn(mappedProject1);
when(projectMapper.getProjectDTOFromProjectEntity(project2)).thenReturn(mappedProject2);
when(projectMapper.getProjectDTOFromProjectEntity(project3)).thenReturn(mappedProject3);
Expand All @@ -792,8 +807,7 @@ void getCurrentUserProjects_returnProjectsInCurrentUserScopesWithDemoProject_whe
// Then
var actualProjects = userAccountService.getCurrentUserProjects();

var expectedProjects = List.of(mappedProject1, mappedProject2, mappedProject3, mappedDemoProject);
assertThat(actualProjects).containsExactlyInAnyOrderElementsOf(expectedProjects);
assertThat(actualProjects).containsExactly(mappedDemoProject, mappedProject3, mappedProject1, mappedProject2);
verify(projectRepository, never()).findAllByOrderByName();
verify(projectRepository, times(1)).findByCode(DEMO_PROJECT_CODE);
verifyNoMoreInteractions(projectRepository);
Expand Down
Loading

0 comments on commit ebd2595

Please sign in to comment.