diff --git a/src/main/java/org/springframework/samples/petclinic/dto/common/PrivilegeDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/common/PrivilegeDTO.java index d3f80bc93..3bce9e171 100644 --- a/src/main/java/org/springframework/samples/petclinic/dto/common/PrivilegeDTO.java +++ b/src/main/java/org/springframework/samples/petclinic/dto/common/PrivilegeDTO.java @@ -4,11 +4,10 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.apache.commons.lang3.builder.EqualsBuilder; -import org.apache.commons.lang3.builder.HashCodeBuilder; import java.io.Serializable; import java.util.Collection; +import java.util.HashSet; /** * Simple Data Transfert Object representing a Privileges. @@ -27,15 +26,26 @@ public class PrivilegeDTO implements Serializable { private Collection roles; - /* - * @Override public boolean equals(Object o) { if (this == o) return true; - * - * if (!(o instanceof PrivilegeDTO)) return false; - * - * PrivilegeDTO that = (PrivilegeDTO) o; - * - * return new EqualsBuilder().append(getId(), that.getId()).append(getName(), - * that.getName()) .append(getRoles(), that.getRoles()).isEquals(); } - */ + protected Collection getRolesInternal() { + if (this.roles == null) { + this.roles = new HashSet<>(); + } + + return this.roles; + } + + public Collection getRoles() { + return getRolesInternal(); + } + + public void addRole(RoleDTO role) { + if (this.getRoles() == null || !this.getRoles().contains(role)) { + getRolesInternal().add(role); + } + + if (!role.getPrivileges().contains(this)) { + role.addPrivilege(this); + } + } } diff --git a/src/main/java/org/springframework/samples/petclinic/dto/common/RoleDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/common/RoleDTO.java index 2de06a040..098ed093b 100644 --- a/src/main/java/org/springframework/samples/petclinic/dto/common/RoleDTO.java +++ b/src/main/java/org/springframework/samples/petclinic/dto/common/RoleDTO.java @@ -4,8 +4,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.apache.commons.lang3.builder.EqualsBuilder; -import org.apache.commons.lang3.builder.HashCodeBuilder; import org.springframework.samples.petclinic.common.CommonParameter; import javax.validation.constraints.NotEmpty; @@ -13,6 +11,7 @@ import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.io.Serializable; import java.util.Collection; +import java.util.HashSet; /** * Simple Data Transfert Object representing a list of roles. @@ -36,16 +35,46 @@ public class RoleDTO implements Serializable { private Collection privileges; - /* - * @Override public boolean equals(Object o) { if (this == o) return true; - * - * if (!(o instanceof RoleDTO)) return false; - * - * RoleDTO roleDTO = (RoleDTO) o; - * - * return new EqualsBuilder().append(getId(), roleDTO.getId()).append(getName(), - * roleDTO.getName()) .append(getUsers(), roleDTO.getUsers()).append(getPrivileges(), - * roleDTO.getPrivileges()).isEquals(); } - */ + protected Collection getUsersInternal() { + if (this.users == null) { + this.users = new HashSet<>(); + } + + return this.users; + } + + public Collection getUsers() { + return getUsersInternal(); + } + + public void addUser(UserDTO user) { + if (this.getUsers() == null || !this.getUsers().contains(user)) { + getUsersInternal().add(user); + } + if (!user.getRoles().contains(this)) { + user.addRole(this); + } + } + + protected Collection getPrivilegesInternal() { + if (this.privileges == null) { + this.privileges = new HashSet<>(); + } + + return this.privileges; + } + + public Collection getPrivileges() { + return getPrivilegesInternal(); + } + + public void addPrivilege(PrivilegeDTO privilege) { + if (this.getPrivileges() == null || !this.getPrivileges().contains(privilege)) { + getPrivilegesInternal().add(privilege); + } + if (!privilege.getRoles().contains(this)) { + privilege.addRole(this); + } + } } diff --git a/src/main/java/org/springframework/samples/petclinic/dto/common/UserDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/common/UserDTO.java index 0d21a17dd..c1d08bd8b 100644 --- a/src/main/java/org/springframework/samples/petclinic/dto/common/UserDTO.java +++ b/src/main/java/org/springframework/samples/petclinic/dto/common/UserDTO.java @@ -6,6 +6,7 @@ import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.springframework.samples.petclinic.common.CommonError; import org.springframework.samples.petclinic.common.CommonParameter; +import org.springframework.samples.petclinic.model.common.Role; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; @@ -118,12 +119,25 @@ public class UserDTO extends PersonDTO implements Serializable, UserDetails { return false; } - public void addRole(RoleDTO role) { + protected Collection getRolesInternal() { if (this.roles == null) { this.roles = new HashSet<>(); } - this.roles.add(role); + return this.roles; + } + + public Collection getRoles() { + return getRolesInternal(); + } + + public void addRole(RoleDTO role) { + if (this.getRoles() == null || !this.getRoles().contains(role)) { + getRolesInternal().add(role); + } + if (!role.getUsers().contains(this)) { + role.addUser(this); + } } public void removeRole(RoleDTO role) { diff --git a/src/main/java/org/springframework/samples/petclinic/model/common/Privilege.java b/src/main/java/org/springframework/samples/petclinic/model/common/Privilege.java index db0cb6bd8..bdeda4668 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/common/Privilege.java +++ b/src/main/java/org/springframework/samples/petclinic/model/common/Privilege.java @@ -9,6 +9,7 @@ import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.io.Serializable; import java.util.Collection; +import java.util.HashSet; @Entity @Table(name = "privileges") @@ -31,4 +32,26 @@ public class Privilege implements Serializable { @ManyToMany(mappedBy = "privileges", fetch = FetchType.EAGER) private Collection roles; + protected Collection getRolesInternal() { + if (this.roles == null) { + this.roles = new HashSet<>(); + } + + return this.roles; + } + + public Collection getRoles() { + return getRolesInternal(); + } + + public void addRole(Role role) { + if (this.getRoles() == null || !this.getRoles().contains(role)) { + getRolesInternal().add(role); + } + + if (!role.getPrivileges().contains(this)) { + role.addPrivilege(this); + } + } + } diff --git a/src/main/java/org/springframework/samples/petclinic/model/common/Role.java b/src/main/java/org/springframework/samples/petclinic/model/common/Role.java index c77d8ad72..b5add48f1 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/common/Role.java +++ b/src/main/java/org/springframework/samples/petclinic/model/common/Role.java @@ -11,6 +11,7 @@ import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.io.Serializable; import java.util.Collection; +import java.util.HashSet; /** * Entity representing a Role. @@ -45,4 +46,55 @@ public class Role implements Serializable { inverseJoinColumns = @JoinColumn(name = "privilege_id", referencedColumnName = "id")) private Collection privileges; + protected Collection getUsersInternal() { + if (this.users == null) { + this.users = new HashSet<>(); + } + + return this.users; + } + + public Collection getUsers() { + return getUsersInternal(); + } + + public void addUser(User user) { + if (this.getUsers() == null || !this.getUsers().contains(user)) { + getUsersInternal().add(user); + } + + if (!user.getRoles().contains(this)) { + user.addRole(this); + } + } + + public void removeUser(User user) { + this.getUsers().remove(user); + } + + protected Collection getPrivilegesInternal() { + if (this.privileges == null) { + this.privileges = new HashSet<>(); + } + + return this.privileges; + } + + public Collection getPrivileges() { + return getPrivilegesInternal(); + } + + public void addPrivilege(Privilege privilege) { + if (this.getPrivileges() == null || !this.getPrivileges().contains(privilege)) { + getPrivilegesInternal().add(privilege); + } + if (!privilege.getRoles().contains(this)) { + privilege.addRole(this); + } + } + + public void removePrivilege(Privilege privilege) { + this.getPrivileges().remove(privilege); + } + } diff --git a/src/main/java/org/springframework/samples/petclinic/model/common/User.java b/src/main/java/org/springframework/samples/petclinic/model/common/User.java index e7e394194..d306b105f 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/common/User.java +++ b/src/main/java/org/springframework/samples/petclinic/model/common/User.java @@ -115,12 +115,25 @@ public class User extends Person implements Serializable, UserDetails { return credentialsNonExpired; } - public void addRole(Role role) { + protected Collection getRolesInternal() { if (this.roles == null) { this.roles = new HashSet<>(); } - this.roles.add(role); - role.getUsers().add(this); + + return this.roles; + } + + public Collection getRoles() { + return getRolesInternal(); + } + + public void addRole(Role role) { + if (this.getRoles() == null || !this.getRoles().contains(role)) { + getRolesInternal().add(role); + } + if (!role.getUsers().contains(this)) { + role.addUser(this); + } } public void removeRole(Role role) { @@ -156,32 +169,5 @@ public class User extends Person implements Serializable, UserDetails { return getGrantedAuthorities(getPrivileges(this.roles)); } - /* - * @Override public boolean equals(Object o) { if (this == o) return true; - * - * if (!(o instanceof User)) return false; - * - * User user = (User) o; - * - * return new EqualsBuilder().appendSuper(super.equals(o)).append(isEnabled(), - * user.isEnabled()) .append(isAccountNonExpired(), user.isAccountNonExpired()) - * .append(isAccountNonLocked(), user.isAccountNonLocked()) - * .append(isCredentialsNonExpired(), - * user.isCredentialsNonExpired()).append(getEmail(), user.getEmail()) - * .append(getPassword(), user.getPassword()).append(getRoles(), user.getRoles()) - * .append(getTelephone(), user.getTelephone()).append(getStreet1(), - * user.getStreet1()) .append(getStreet2(), user.getStreet2()).append(getStreet3(), - * user.getStreet3()) .append(getZipCode(), user.getZipCode()).append(getCity(), - * user.getCity()) .append(getCountry(), user.getCountry()).isEquals(); } - * - * @Override public int hashCode() { return new HashCodeBuilder(17, - * 37).append(getEmail()).append(getPassword()).append(isEnabled()) - * .append(isAccountNonExpired()).append(isAccountNonLocked()).append( - * isCredentialsNonExpired()) - * .append(getRoles()).append(getTelephone()).append(getStreet1()).append(getStreet2() - * ) - * .append(getStreet3()).append(getZipCode()).append(getCity()).append(getCountry()). - * toHashCode(); } - */ } diff --git a/src/main/java/org/springframework/samples/petclinic/service/common/UserService.java b/src/main/java/org/springframework/samples/petclinic/service/common/UserService.java index 03d56f9cd..1ba257ffa 100644 --- a/src/main/java/org/springframework/samples/petclinic/service/common/UserService.java +++ b/src/main/java/org/springframework/samples/petclinic/service/common/UserService.java @@ -37,10 +37,7 @@ public class UserService implements BaseService { return null; } - User user = modelMapper.map(dto, User.class); - dto.getRoles().forEach(role -> user.addRole(modelMapper.map(role, Role.class))); - - return user; + return modelMapper.map(dto, User.class); } @Override @@ -101,6 +98,20 @@ public class UserService implements BaseService { return entityToDTO(user); } + public UserDTO delete(UserDTO dto) { + User user = dtoToEntity(dto); + + // remove user from roles + User finalUser = user; + user.getRoles().forEach(role -> { + role.removeUser(finalUser); + roleRepository.save(role); + }); + user = userRepository.delete(user); + + return entityToDTO(user); + } + public UserDTO findByEmail(String email) { User user = userRepository.findByEmail(email); diff --git a/src/main/resources/db/h2/schema.sql b/src/main/resources/db/h2/schema.sql index 02d11325f..c3508c056 100644 --- a/src/main/resources/db/h2/schema.sql +++ b/src/main/resources/db/h2/schema.sql @@ -64,14 +64,14 @@ CREATE INDEX visits_pet_id ON visits (pet_id); DROP TABLE roles IF EXISTS; CREATE TABLE roles ( id INTEGER IDENTITY PRIMARY KEY, - name VARCHAR(20) NOT NULL + name VARCHAR(20) NOT NULL UNIQUE ); CREATE INDEX roles_name ON roles (name); DROP TABLE privileges IF EXISTS; CREATE TABLE privileges ( id INTEGER IDENTITY PRIMARY KEY, - name VARCHAR(20) NOT NULL + name VARCHAR(20) NOT NULL UNIQUE ); CREATE INDEX privileges_name ON privileges (name); @@ -110,6 +110,8 @@ CREATE TABLE roles_privileges ( role_id INTEGER NOT NULL, privilege_id INTEGER NOT NULL ); +ALTER TABLE roles_privileges ADD CONSTRAINT fk_roles_privileges_role_id FOREIGN KEY (role_id) REFERENCES roles (id); +ALTER TABLE roles_privileges ADD CONSTRAINT fk_roles_privileges_privilege_id FOREIGN KEY (privilege_id) REFERENCES privileges (id); DROP TABLE auth_providers IF EXISTS; CREATE TABLE auth_providers ( diff --git a/src/main/resources/db/hsqldb/schema.sql b/src/main/resources/db/hsqldb/schema.sql index 4845d1bc4..128f3f06f 100644 --- a/src/main/resources/db/hsqldb/schema.sql +++ b/src/main/resources/db/hsqldb/schema.sql @@ -66,14 +66,14 @@ CREATE INDEX visits_pet_id ON visits (pet_id); DROP TABLE roles IF EXISTS; CREATE TABLE roles ( id INTEGER IDENTITY PRIMARY KEY, - name VARCHAR(20) NOT NULL + name VARCHAR(20) NOT NULL UNIQUE ); CREATE INDEX roles_name ON roles (name); DROP TABLE privileges IF EXISTS; CREATE TABLE privileges ( id INTEGER IDENTITY PRIMARY KEY, - name VARCHAR(20) NOT NULL + name VARCHAR(20) NOT NULL UNIQUE ); CREATE INDEX privileges_name ON privileges (name); @@ -113,7 +113,8 @@ CREATE TABLE roles_privileges ( role_id INTEGER NOT NULL, privilege_id INTEGER NOT NULL ); - +ALTER TABLE roles_privileges ADD CONSTRAINT fk_roles_privileges_role_id FOREIGN KEY (role_id) REFERENCES roles (id); +ALTER TABLE roles_privileges ADD CONSTRAINT fk_roles_privileges_privilege_id FOREIGN KEY (privilege_id) REFERENCES privileges (id); DROP TABLE auth_providers IF EXISTS; CREATE TABLE auth_providers ( diff --git a/src/test/java/org/springframework/samples/petclinic/service/common/UserServiceTest.java b/src/test/java/org/springframework/samples/petclinic/service/common/UserServiceTest.java new file mode 100644 index 000000000..5d8d1421c --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/service/common/UserServiceTest.java @@ -0,0 +1,232 @@ +package org.springframework.samples.petclinic.service.common; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.samples.petclinic.dto.common.PrivilegeDTO; +import org.springframework.samples.petclinic.dto.common.RoleDTO; +import org.springframework.samples.petclinic.dto.common.UserDTO; +import org.springframework.samples.petclinic.model.common.Privilege; +import org.springframework.samples.petclinic.model.common.Role; +import org.springframework.samples.petclinic.model.common.User; +import org.springframework.samples.petclinic.repository.RoleRepository; +import org.springframework.samples.petclinic.repository.UserRepository; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; + +@AutoConfigureTestDatabase +@SpringBootTest +@RunWith(SpringRunner.class) +class UserServiceTest { + + private final static Integer USER_ID = 11; + + private final static String USER_FIRST_NAME = "Sam"; + + private final static String USER_LAST_NAME = "Schultz"; + + private final static String USER_EMAIL = "Sam.Schultz@petclinic.com"; + + private final static String USER_PASSWORD = "PASSWORD_TEST9879879$^m$*ùm*^$*ù"; + + private final static String USER_ADDRESS = "4, Evans Street"; + + private final static String USER_CITY = "Wollongong"; + + private final static String USER_ZIPCODE = "65879"; + + private final static String USER_COUNTRY = "USA"; + + private final static String USER_PHONE = "1234567890"; + + private final static Integer ROLE_ID = 4; + + private final static Integer PRIVILEGE_ID = 3; + + private final static String ROLE_NAME = "ROLE_TEST"; + + @Autowired + private RoleRepository roleRepository; + + @Autowired + private UserRepository userRepository; + + @Autowired + private PrivilegeService privilegeService; + + @Autowired + private RoleService roleService; + + private UserService userService; + + private User user; + + private UserDTO userDTO; + + private Role role; + + private RoleDTO roleDTO; + + private Privilege privilege; + + private PrivilegeDTO privilegeDTO; + + @BeforeEach + void beforeEach() { + userService = new UserService(userRepository, roleRepository); + user = new User(); + userDTO = new UserDTO(); + + roleDTO = roleService.findById(2); + role = roleService.dtoToEntity(roleDTO); + + user.setId(USER_ID); + user.setFirstName(USER_FIRST_NAME); + user.setLastName(USER_LAST_NAME); + user.setEmail(USER_EMAIL); + user.setPassword(USER_PASSWORD); + user.setAccountNonExpired(true); + user.setAccountNonLocked(true); + user.setCredentialsNonExpired(true); + user.setEnabled(true); + user.setTelephone(USER_PHONE); + user.setStreet1(USER_ADDRESS); + user.setCity(USER_CITY); + user.setZipCode(USER_ZIPCODE); + user.setCountry(USER_COUNTRY); + user.setRoles(Collections.singleton(role)); + role.addUser(user); + + userDTO.setId(USER_ID); + userDTO.setFirstName(USER_FIRST_NAME); + userDTO.setLastName(USER_LAST_NAME); + userDTO.setEmail(USER_EMAIL); + userDTO.setPassword(USER_PASSWORD); + userDTO.setMatchingPassword(USER_PASSWORD); + userDTO.setAccountNonExpired(true); + userDTO.setAccountNonLocked(true); + userDTO.setCredentialsNonExpired(true); + userDTO.setEnabled(true); + userDTO.setTelephone(USER_PHONE); + userDTO.setStreet1(USER_ADDRESS); + userDTO.setCity(USER_CITY); + userDTO.setZipCode(USER_ZIPCODE); + userDTO.setCountry(USER_COUNTRY); + userDTO.setRoles(Collections.singleton(roleDTO)); + roleDTO.addUser(userDTO); + + } + + @Test + @Tag("dtoToEntity") + @DisplayName("Verify the convertion from DTO to Entity") + void dtoToEntity() { + User found = userService.dtoToEntity(userDTO); + + assertThat(found).isEqualToIgnoringGivenFields(user, "roles"); + assertThat(found.getRoles()).usingElementComparatorIgnoringFields("users", "privileges").contains(role); + } + + @Test + @Tag("entityToDTO") + @DisplayName("Verify the convertion from Entity to DTO") + void entityToDTO() { + UserDTO found = userService.entityToDTO(user); + + assertThat(found).isEqualToIgnoringGivenFields(userDTO, "roles"); + assertThat(found.getRoles()).usingElementComparatorIgnoringFields("users", "privileges").contains(roleDTO); + } + + @Test + @Tag("dtosToEntities") + @DisplayName("Verify the convertion from DTOs list to Entities list") + void dtosToEntities() { + List userDTOS = userService.findAll(); + List expected = new ArrayList<>(); + userDTOS.forEach(dto -> expected.add(userService.dtoToEntity(dto))); + List found = userService.dtosToEntities(userDTOS); + + assertThat(found).hasSameSizeAs(expected); + + for (int i = 0; i < found.size(); i++) { + assertThat(found.get(i)).isEqualToIgnoringGivenFields(expected.get(i), "roles"); + assertThat(found.get(i).getRoles()).usingElementComparatorIgnoringFields("users", "privileges") + .contains(expected.get(i).getRoles().toArray(new Role[0])); + } + } + + @Test + @Tag("entitiesToDTOS") + @DisplayName("Verify the convertion from Entities list to DTOs list") + void entitiesToDTOS() { + List expected = userService.findAll(); + List users = new ArrayList<>(); + expected.forEach(dto -> users.add(userService.dtoToEntity(dto))); + List found = userService.entitiesToDTOS(users); + + assertThat(found).hasSameSizeAs(expected); + + for (int i = 0; i < found.size(); i++) { + assertThat(found.get(i)).isEqualToIgnoringGivenFields(expected.get(i), "roles"); + assertThat(found.get(i).getRoles()).usingElementComparatorIgnoringFields("users", "privileges") + .contains(expected.get(i).getRoles().toArray(new RoleDTO[0])); + } + } + + @Test + @Tag("findById") + @DisplayName("Verify that we get UserDTO by his ID") + void findById() { + List userDTOS = userService.findAll(); + UserDTO expected = userDTOS.get(2); + + UserDTO found = userService.findById(expected.getId()); + + assertThat(found).isEqualToIgnoringGivenFields(expected, "roles"); + assertThat(found.getRoles()).usingElementComparatorIgnoringFields("users", "privileges") + .contains(expected.getRoles().toArray(new RoleDTO[0])); + } + + @Test + @Tag("findAll") + @DisplayName("Verify that the UserDTO list contain all previous elements and the new saved one") + void findAll() { + List expected = userService.findAll(); + userDTO.setRoles(new HashSet<>()); + + assertThat(expected).doesNotContain(userDTO); + + UserDTO saved = userService.save(userDTO); + expected.add(saved); + List found = userService.findAll(); + + assertThat(found).usingElementComparatorIgnoringFields("roles").containsOnlyOnceElementsOf(expected); + + userService.delete(saved); + } + + @Test + @Tag("save") + @DisplayName("Verify that all UserDTO list contain the new saved one") + void save() { + Collection expected = userService.findAll(); + assertThat(expected).doesNotContain(userDTO); + + UserDTO saved = userService.save(userDTO); + + assertThat(saved).isEqualToIgnoringGivenFields(userDTO, "id", "roles"); + assertThat(saved.getRoles()).usingElementComparatorIgnoringFields("users", "privileges") + .contains(userDTO.getRoles().toArray(new RoleDTO[0])); + + userService.delete(saved); + } + +}