From 285e018b1a77dcb3ffa03667058b6f2da4f40951 Mon Sep 17 00:00:00 2001 From: PEDSF Date: Sun, 15 Nov 2020 11:54:28 +0100 Subject: [PATCH] add login by email and social login --- pom.xml | 53 ++++ .../petclinic/common/CommonAttribute.java | 4 + .../petclinic/common/CommonEndPoint.java | 20 ++ .../samples/petclinic/common/CommonError.java | 8 + .../petclinic/common/CommonParameter.java | 45 ++++ .../samples/petclinic/common/CommonView.java | 28 +++ .../petclinic/common/CommonWebSocket.java | 18 ++ .../configuration/WebSecurityConfig.java | 130 ++++++++++ .../petclinic/controller/PetController.java | 1 - .../petclinic/controller/UserController.java | 235 ++++++++++++++++++ .../petclinic/controller/VisitController.java | 1 - .../samples/petclinic/dto/RoleDTO.java | 12 + .../samples/petclinic/dto/UserDTO.java | 156 ++++++++++++ .../petclinic/model/{ => business}/Owner.java | 3 +- .../petclinic/model/{ => business}/Pet.java | 3 +- .../model/{ => business}/PetType.java | 4 +- .../model/{ => business}/Specialty.java | 4 +- .../petclinic/model/{ => business}/Vet.java | 3 +- .../petclinic/model/{ => business}/Vets.java | 2 +- .../petclinic/model/{ => business}/Visit.java | 3 +- .../petclinic/model/common/AuthProvider.java | 7 + .../model/{ => common}/BaseEntity.java | 2 +- .../model/{ => common}/NamedEntity.java | 2 +- .../petclinic/model/{ => common}/Person.java | 14 +- .../samples/petclinic/model/common/Role.java | 12 + .../samples/petclinic/model/common/User.java | 208 ++++++++++++++++ .../petclinic/repository/OwnerRepository.java | 2 +- .../petclinic/repository/PetRepository.java | 4 +- .../repository/PetTypeRepository.java | 3 +- .../petclinic/repository/RoleRepository.java | 42 ++++ .../repository/SpecialtyRepository.java | 3 +- .../petclinic/repository/UserRepository.java | 36 +++ .../petclinic/repository/VetRepository.java | 2 +- .../petclinic/repository/VisitRepository.java | 5 +- .../petclinic/service/OwnerService.java | 4 +- .../samples/petclinic/service/PetService.java | 6 +- .../petclinic/service/PetTypeService.java | 2 +- .../petclinic/service/RoleService.java | 86 +++++++ .../petclinic/service/SecurityService.java | 9 + .../service/SecurityServiceImpl.java | 50 ++++ .../petclinic/service/SpecialtyService.java | 4 +- .../service/UserDetailsServiceImpl.java | 50 ++++ .../petclinic/service/UserService.java | 117 +++++++++ .../samples/petclinic/service/VetService.java | 5 +- .../petclinic/service/VisitService.java | 2 +- .../petclinic/validator/PetValidator.java | 2 +- src/main/resources/application.properties | 32 +++ src/main/resources/db/h2/data.sql | 14 ++ src/main/resources/db/h2/schema.sql | 35 +++ src/main/resources/static/css/style.css | 7 - .../resources/static/resources/css/style.css | 141 +++++++++++ .../static/{ => resources}/js/notification.js | 0 .../templates/fragments/inputField.html | 2 + .../resources/templates/fragments/layout.html | 20 +- src/main/resources/templates/login.html | 49 ++++ .../users/createOrUpdateUserForm.html | 44 ++++ .../templates/users/userDetails.html | 83 +++++++ .../VetControllerIntegrationTest.java | 5 - .../VisitControllerIntegrationTest.java | 2 +- .../controller/VisitControllerTest.java | 2 +- .../formater/PetTypeDTOFormatterTest.java | 3 +- .../formater/PetTypeFormatterTest.java | 3 +- .../samples/petclinic/model/VetTest.java | 1 + .../petclinic/service/ClinicServiceTest.java | 10 +- .../petclinic/service/EntityUtils.java | 4 +- .../petclinic/service/OwnerServiceTest.java | 6 +- .../petclinic/service/PetServiceTest.java | 7 +- .../petclinic/service/VetServiceTest.java | 2 +- .../petclinic/validator/ValidatorTest.java | 2 +- 69 files changed, 1809 insertions(+), 77 deletions(-) create mode 100644 src/main/java/org/springframework/samples/petclinic/common/CommonParameter.java create mode 100644 src/main/java/org/springframework/samples/petclinic/configuration/WebSecurityConfig.java create mode 100644 src/main/java/org/springframework/samples/petclinic/controller/UserController.java create mode 100644 src/main/java/org/springframework/samples/petclinic/dto/RoleDTO.java create mode 100644 src/main/java/org/springframework/samples/petclinic/dto/UserDTO.java rename src/main/java/org/springframework/samples/petclinic/model/{ => business}/Owner.java (96%) rename src/main/java/org/springframework/samples/petclinic/model/{ => business}/Pet.java (96%) rename src/main/java/org/springframework/samples/petclinic/model/{ => business}/PetType.java (87%) rename src/main/java/org/springframework/samples/petclinic/model/{ => business}/Specialty.java (87%) rename src/main/java/org/springframework/samples/petclinic/model/{ => business}/Vet.java (94%) rename src/main/java/org/springframework/samples/petclinic/model/{ => business}/Vets.java (94%) rename src/main/java/org/springframework/samples/petclinic/model/{ => business}/Visit.java (94%) create mode 100644 src/main/java/org/springframework/samples/petclinic/model/common/AuthProvider.java rename src/main/java/org/springframework/samples/petclinic/model/{ => common}/BaseEntity.java (95%) rename src/main/java/org/springframework/samples/petclinic/model/{ => common}/NamedEntity.java (95%) rename src/main/java/org/springframework/samples/petclinic/model/{ => common}/Person.java (66%) create mode 100644 src/main/java/org/springframework/samples/petclinic/model/common/Role.java create mode 100644 src/main/java/org/springframework/samples/petclinic/model/common/User.java create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/RoleRepository.java create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/UserRepository.java create mode 100644 src/main/java/org/springframework/samples/petclinic/service/RoleService.java create mode 100644 src/main/java/org/springframework/samples/petclinic/service/SecurityService.java create mode 100644 src/main/java/org/springframework/samples/petclinic/service/SecurityServiceImpl.java create mode 100644 src/main/java/org/springframework/samples/petclinic/service/UserDetailsServiceImpl.java create mode 100644 src/main/java/org/springframework/samples/petclinic/service/UserService.java delete mode 100644 src/main/resources/static/css/style.css create mode 100644 src/main/resources/static/resources/css/style.css rename src/main/resources/static/{ => resources}/js/notification.js (100%) create mode 100644 src/main/resources/templates/login.html create mode 100644 src/main/resources/templates/users/createOrUpdateUserForm.html create mode 100644 src/main/resources/templates/users/userDetails.html diff --git a/pom.xml b/pom.xml index b7336fdb4..2e5afb68f 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ 2.3.8 0.0.4.RELEASE 0.0.25 + 2.2.4.RELEASE @@ -87,6 +88,15 @@ + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.cloud + spring-cloud-starter-security + ${spring-cloud-starter-security.version} + @@ -158,12 +168,50 @@ ${webjars-sockjs-client.version} + + + org.thymeleaf.extras + thymeleaf-extras-springsecurity5 + 3.0.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + + org.springframework.security + spring-security-oauth2-client + + + + org.springframework.security + spring-security-oauth2-jose + 5.3.4.RELEASE + + + + + io.jsonwebtoken + jjwt + 0.9.1 + + + org.springframework.boot spring-boot-devtools true + + org.springframework.security + spring-security-test + test + junit junit @@ -176,6 +224,11 @@ lombok ${lombok.version} + + org.springframework.security + spring-security-web + 5.3.3.RELEASE + diff --git a/src/main/java/org/springframework/samples/petclinic/common/CommonAttribute.java b/src/main/java/org/springframework/samples/petclinic/common/CommonAttribute.java index c3334533d..9c7beb87e 100644 --- a/src/main/java/org/springframework/samples/petclinic/common/CommonAttribute.java +++ b/src/main/java/org/springframework/samples/petclinic/common/CommonAttribute.java @@ -39,6 +39,10 @@ public final class CommonAttribute { public static final String PET_TYPE = "type"; + public static final String USER = "user"; + + public static final String USER_ID = "id"; + public static final String VETS = "vets"; public static final String VISIT = "visit"; diff --git a/src/main/java/org/springframework/samples/petclinic/common/CommonEndPoint.java b/src/main/java/org/springframework/samples/petclinic/common/CommonEndPoint.java index fa4177eb1..b292df05e 100644 --- a/src/main/java/org/springframework/samples/petclinic/common/CommonEndPoint.java +++ b/src/main/java/org/springframework/samples/petclinic/common/CommonEndPoint.java @@ -21,6 +21,26 @@ public final class CommonEndPoint { public static final String PETS_ID_EDIT = "/pets/{petId}/edit"; + public static final String USERS_ID = "/users/{userId}"; + + public static final String USERS_EDIT = "/users/edit"; + + public static final String USERS_ID_EDIT = "/users/{ownerId}/edit"; + + public static final String USERS_NEW = "/users/new"; + + public static final String LOGIN = "/login"; + + public static final String LOGIN_SUCCESS = "/login/success"; + + public static final String OAUTH2_SUCCESS = "/oauth2/success"; + + public static final String LOGOUT = "/logout"; + + public static final String LOGOUT_SUCCESS = "/logout/success"; + + public static final String REGISTER = "/register"; + public static final String VETS = "/vets"; public static final String VETS_HTML = "/vets.html"; diff --git a/src/main/java/org/springframework/samples/petclinic/common/CommonError.java b/src/main/java/org/springframework/samples/petclinic/common/CommonError.java index c7144975d..98415c80c 100644 --- a/src/main/java/org/springframework/samples/petclinic/common/CommonError.java +++ b/src/main/java/org/springframework/samples/petclinic/common/CommonError.java @@ -19,6 +19,14 @@ public final class CommonError { public static final String REQUIRED_MESSAGE = "required"; + public static final String FORMAT_BETWEEN = "Length should be between : "; + + public static final String FORMAT_LESS = "Length should less than : "; + + public static final String EMAIL_FORMAT = "Not a valid email address !"; + + public static final String PHONE_FORMAT = "Not a valid phone number !"; + private CommonError() { throw new IllegalStateException("Utility class"); } diff --git a/src/main/java/org/springframework/samples/petclinic/common/CommonParameter.java b/src/main/java/org/springframework/samples/petclinic/common/CommonParameter.java new file mode 100644 index 000000000..478e12567 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/common/CommonParameter.java @@ -0,0 +1,45 @@ +package org.springframework.samples.petclinic.common; + +public class CommonParameter { + + public static final int CITY_MAX = 50; + + public static final int COUNTRY_MAX = 50; + + public static final int EMAIL_MAX = 255; + + public static final int EMAIL_MIN = 4; + + public static final String EMAIL_REGEXP = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$"; + + public static final int FIRSTNAME_MAX = 50; + + public static final int FIRSTNAME_MIN = 2; + + public static final int LASTNAME_MAX = 50; + + public static final int LASTNAME_MIN = 2; + + public static final int PASSWORD_MAX = 255; + + public static final int PASSWORD_MIN = 4; + + public static final int PHONE_MAX = 14; + + public static final String PHONE_REGEXP = "^(?:(?:\\+|00)33[\\s.-]{0,3}(?:\\(0\\)[\\s.-]{0,3})?|0)[1-9](?:(?:[\\s.-]?\\d{2}){4}|\\d{2}(?:[\\s.-]?\\d{3}){2}|)$"; + + public static final int STATUS_MAX = 10; + + public static final int STREET_MAX = 50; + + public static final int ROLE_MAX = 10; + + public static final int ZIP_MAX = 6; + + public static final int ZIP_MIN = 5; + + private CommonParameter() { + throw new IllegalStateException("Utility class"); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/common/CommonView.java b/src/main/java/org/springframework/samples/petclinic/common/CommonView.java index ddde0c73b..5059e39b9 100644 --- a/src/main/java/org/springframework/samples/petclinic/common/CommonView.java +++ b/src/main/java/org/springframework/samples/petclinic/common/CommonView.java @@ -7,6 +7,8 @@ package org.springframework.samples.petclinic.common; */ public final class CommonView { + public static final String HOME = "redirect:/"; + public static final String OWNER_OWNERS_R = "redirect:/owners/"; public static final String OWNER_OWNERS_ID_R = "redirect:/owners/{ownerId}"; @@ -21,6 +23,32 @@ public final class CommonView { public static final String PET_CREATE_OR_UPDATE = "pets/createOrUpdatePetForm"; + public static final String USER_REGISTRATION = "users/registration"; + + public static final String USER_LOGIN = "/login"; + + public static final String USER_LOGIN_R = "redirect:/login"; + + public static final String USER_USERS_ID_R = "redirect:/users/{userId}"; + + public static final String USER_CREATE_OR_UPDATE = "users/createOrUpdateUserForm"; + + public static final String USER_DETAILS = "users/userDetails"; + + public static final String USER_ADD = "users/user-add"; + + public static final String USER_READ = "users/user-read"; + + public static final String USER_READ_R = "redirect:/users/read/"; + + public static final String USER_UPDATE = "users/user-update"; + + public static final String USER_UPDATE_R = "redirect:/users/edit/"; + + public static final String USER_UPDATE_PASSWORD = "users/user-password"; + + public static final String USER_UPDATE_PASSWORD_R = "redirect:/users/password/edit/"; + public static final String VET_VETS_LIST = "vets/vetList"; public static final String VISIT_CREATE_OR_UPDATE = "pets/createOrUpdateVisitForm"; diff --git a/src/main/java/org/springframework/samples/petclinic/common/CommonWebSocket.java b/src/main/java/org/springframework/samples/petclinic/common/CommonWebSocket.java index d6c3e6467..c91e888b4 100644 --- a/src/main/java/org/springframework/samples/petclinic/common/CommonWebSocket.java +++ b/src/main/java/org/springframework/samples/petclinic/common/CommonWebSocket.java @@ -35,6 +35,24 @@ public class CommonWebSocket { public static final String PET_DELETED_ERROR = "Error deleting Pet !"; + public static final String USER_LOGGED_IN = "User %s %s logged in successfully !"; + + public static final String USER_LOGGED_OUT = "User logged out successfully !"; + + public static final String USER_FIND_ERROR = "No User found !"; + + public static final String USER_CREATED = "User created"; + + public static final String USER_CREATION_ERROR = "Error creating User !"; + + public static final String USER_UPDATED = "User updated"; + + public static final String USER_UPDATED_ERROR = "Error updating User !"; + + public static final String USER_DELETED = "User deleted"; + + public static final String USER_DELETED_ERROR = "Error deleting User !"; + public static final String VET_FIND_ERROR = "No Vet found !"; public static final String VET_CREATED = "Vet created"; diff --git a/src/main/java/org/springframework/samples/petclinic/configuration/WebSecurityConfig.java b/src/main/java/org/springframework/samples/petclinic/configuration/WebSecurityConfig.java new file mode 100644 index 000000000..3238935cd --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/configuration/WebSecurityConfig.java @@ -0,0 +1,130 @@ +package org.springframework.samples.petclinic.configuration; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +import org.springframework.core.env.Environment; +import org.springframework.samples.petclinic.model.common.AuthProvider; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.oauth2.client.CommonOAuth2Provider; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; + +import javax.annotation.Resource; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Configuration +@EnableWebSecurity +@PropertySource("classpath:application.properties") +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + private static final String CLIENT_PROPERTY_KEY = "spring.security.oauth2.client.registration."; + + @Autowired + private UserDetailsService userDetailsService; + + @Resource + private Environment env; + + @Bean + public BCryptPasswordEncoder bCryptPasswordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public AuthenticationManager customAuthenticationManager() throws Exception { + return authenticationManager(); + } + + @Bean + public OAuth2AuthorizedClientService authorizedClientService() { + + return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository()); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + + http.authorizeRequests() + .antMatchers("/").anonymous() + .antMatchers("/login", "/logout", "/register").permitAll() + .antMatchers("/websocket/**", "/topic/**", "/app/**").permitAll() + .antMatchers("/resources/**").permitAll() + .antMatchers("/**").authenticated() + .antMatchers("/h2-console/**").permitAll() + .anyRequest().authenticated() + .and() + .formLogin() + .loginPage("/login") + .loginProcessingUrl("/login") + .defaultSuccessUrl("/login/success", true) + .usernameParameter("email") + .passwordParameter("password") + .failureUrl("/login") + .permitAll() + .and() + .logout() + .logoutUrl("/logout") + .logoutSuccessUrl("/logout/success") + .invalidateHttpSession(true) + .permitAll() + .and() + .oauth2Login() + .loginPage("/login") + .defaultSuccessUrl("/oauth2/success", true) + .failureUrl("/login") + .clientRegistrationRepository(clientRegistrationRepository()) + .authorizedClientService(authorizedClientService()) + .and() + .csrf().disable(); + + // @formatter:on + } + + private static final List clients = Arrays.asList("google", "facebook", "github"); + + @Bean + public ClientRegistrationRepository clientRegistrationRepository() { + List registrations = clients.stream().map(c -> getRegistration(c)) + .filter(registration -> registration != null).collect(Collectors.toList()); + + return new InMemoryClientRegistrationRepository(registrations); + } + + private ClientRegistration getRegistration(String client) { + String clientId = env.getProperty(CLIENT_PROPERTY_KEY + client + ".client-id"); + + if (clientId == null) { + return null; + } + + String clientSecret = env.getProperty(CLIENT_PROPERTY_KEY + client + ".client-secret"); + + if (client.equals(AuthProvider.google.name())) { + return CommonOAuth2Provider.GOOGLE.getBuilder(client).clientId(clientId).clientSecret(clientSecret).build(); + } + if (client.equals(AuthProvider.facebook.name())) { + return CommonOAuth2Provider.FACEBOOK.getBuilder(client).clientId(clientId).clientSecret(clientSecret) + .build(); + } + if (client.equals(AuthProvider.github.name())) { + return CommonOAuth2Provider.GITHUB.getBuilder(client).clientId(clientId).clientSecret(clientSecret).build(); + } + + return null; + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/controller/PetController.java b/src/main/java/org/springframework/samples/petclinic/controller/PetController.java index 1dec5d598..1cae0d2e3 100644 --- a/src/main/java/org/springframework/samples/petclinic/controller/PetController.java +++ b/src/main/java/org/springframework/samples/petclinic/controller/PetController.java @@ -19,7 +19,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.samples.petclinic.common.*; import org.springframework.samples.petclinic.controller.common.WebSocketSender; import org.springframework.samples.petclinic.dto.*; -import org.springframework.samples.petclinic.model.common.WebSocketMessage; import org.springframework.samples.petclinic.validator.PetDTOValidator; import org.springframework.samples.petclinic.service.*; import org.springframework.stereotype.Controller; diff --git a/src/main/java/org/springframework/samples/petclinic/controller/UserController.java b/src/main/java/org/springframework/samples/petclinic/controller/UserController.java new file mode 100644 index 000000000..e0d5b93a4 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/controller/UserController.java @@ -0,0 +1,235 @@ +package org.springframework.samples.petclinic.controller; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ResolvableType; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.samples.petclinic.common.CommonAttribute; +import org.springframework.samples.petclinic.common.CommonEndPoint; +import org.springframework.samples.petclinic.common.CommonView; +import org.springframework.samples.petclinic.common.CommonWebSocket; +import org.springframework.samples.petclinic.controller.common.WebSocketSender; +import org.springframework.samples.petclinic.dto.UserDTO; +import org.springframework.samples.petclinic.service.RoleService; +import org.springframework.samples.petclinic.service.SecurityServiceImpl; +import org.springframework.samples.petclinic.service.UserService; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.util.StringUtils; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.security.Principal; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@Slf4j +@Controller +public class UserController extends WebSocketSender { + + private static final String ROLE_ADMIN = "ADMIN"; + + private static final String ROLE_STAFF = "STAFF"; + + private static final String ROLE_USER = "USER"; + + private static final String authorizationRequestBaseUri = "oauth2/authorization"; + + private final UserService userService; + + private final RoleService roleService; + + private final SecurityServiceImpl securityService; + + private final BCryptPasswordEncoder bCryptPasswordEncoder; + + public UserController(UserService userService, RoleService roleService, SecurityServiceImpl securityService, + BCryptPasswordEncoder bCryptPasswordEncoder) { + this.userService = userService; + this.roleService = roleService; + this.securityService = securityService; + this.bCryptPasswordEncoder = bCryptPasswordEncoder; + } + + @InitBinder("user") + public void setAllowedFields(WebDataBinder dataBinder) { + dataBinder.setDisallowedFields(CommonAttribute.USER_ID); + } + + Map oauth2AuthenticationUrls = new HashMap<>(); + + @Autowired + private ClientRegistrationRepository clientRegistrationRepository; + + @Autowired + private OAuth2AuthorizedClientService authorizedClientService; + + @GetMapping(CommonEndPoint.REGISTER) + public String initCreationForm(Map model) { + UserDTO user = new UserDTO(); + model.put(CommonAttribute.USER, user); + return CommonView.USER_CREATE_OR_UPDATE; + } + + @PostMapping(CommonEndPoint.REGISTER) + public String processCreationForm(@ModelAttribute(CommonAttribute.USER) @Valid UserDTO user, BindingResult result) { + if (result.hasErrors()) { + sendErrorMessage(CommonWebSocket.USER_CREATION_ERROR); + return CommonView.USER_CREATE_OR_UPDATE; + } + + try { + userService.findByEmail(user.getEmail()); + result.rejectValue("email", "5", "Email already exist !"); + sendErrorMessage(CommonWebSocket.USER_CREATION_ERROR); + return CommonView.USER_CREATE_OR_UPDATE; + } + catch (Exception ex) { + } + + // set default role + user.addRole(roleService.findByName(ROLE_USER)); + + // encode password because we get clear password + user.setPassword(bCryptPasswordEncoder.encode(user.getPassword())); + user.setMatchingPassword(user.getPassword()); + + user = this.userService.save(user); + sendSuccessMessage(CommonWebSocket.USER_CREATED); + return CommonView.HOME + user.getId(); + + } + + @GetMapping(CommonEndPoint.LOGIN) + public String initLoginForm(Map model) { + + if (model.containsKey(CommonAttribute.USER)) { + return CommonView.HOME; + } + else { + UserDTO user = new UserDTO(); + model.put(CommonAttribute.USER, user); + } + + Iterable clientRegistrations = null; + ResolvableType type = ResolvableType.forInstance(clientRegistrationRepository).as(Iterable.class); + + if (type != ResolvableType.NONE && ClientRegistration.class.isAssignableFrom(type.resolveGenerics()[0])) { + clientRegistrations = (Iterable) clientRegistrationRepository; + } + + clientRegistrations.forEach(registration -> oauth2AuthenticationUrls.put(registration.getClientName(), + authorizationRequestBaseUri + "/" + registration.getRegistrationId())); + model.put("urls", oauth2AuthenticationUrls); + + return CommonView.USER_LOGIN; + } + + @GetMapping(CommonEndPoint.LOGIN_SUCCESS) + public String postLogin(Model model, Authentication authentication) { + UserDTO user = userService.findByEmail(authentication.getName()); + + model.addAttribute(CommonAttribute.USER, user); + String message = String.format(CommonWebSocket.USER_LOGGED_IN, user.getFirstName(), user.getLastName()); + sendSuccessMessage(message ); + + return CommonView.HOME; + } + + @GetMapping(CommonEndPoint.OAUTH2_SUCCESS) + public String postLogin(Model model, OAuth2AuthenticationToken authentication) { + + OAuth2AuthorizedClient client = authorizedClientService .loadAuthorizedClient(authentication.getAuthorizedClientRegistrationId(), authentication.getName()); + + String userInfoEndpointUri = client.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri(); + + UserDTO user = userService.findByEmail(authentication.getName()); + + if( user!=null) { + model.addAttribute(CommonAttribute.USER, user); + + String message = String.format(CommonWebSocket.USER_LOGGED_IN, user.getFirstName(), user.getLastName()); + sendSuccessMessage(message); + } + return CommonView.HOME; + } + + @GetMapping(CommonEndPoint.LOGOUT) + public String logout(HttpServletRequest request, HttpServletResponse response) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null) { + new SecurityContextLogoutHandler().logout(request, response, authentication); + } + + sendSuccessMessage(CommonWebSocket.USER_LOGGED_OUT); + return CommonView.USER_LOGIN_R; + } + + @GetMapping(CommonEndPoint.LOGOUT_SUCCESS) + public String postLogout(Model model) { + + sendSuccessMessage(CommonWebSocket.USER_LOGGED_OUT); + return CommonView.HOME; + } + + @GetMapping(CommonEndPoint.USERS_EDIT) + public String initUpdateOwnerForm(Model model) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (!authentication.getName().equals("anonymousUser")) { + + UserDTO user = userService.findByEmail(authentication.getName()); + model.addAttribute(CommonAttribute.USER, user); + return CommonView.USER_CREATE_OR_UPDATE; + } + + return CommonView.HOME; + } + + @PostMapping(CommonEndPoint.USERS_ID_EDIT) + public String processUpdateOwnerForm(@ModelAttribute(CommonAttribute.USER) @Valid UserDTO user, + BindingResult result, @PathVariable("userId") int userId) { + if (result.hasErrors()) { + sendErrorMessage(CommonWebSocket.USER_UPDATED_ERROR); + return CommonView.USER_CREATE_OR_UPDATE; + } + else { + user.setId(userId); + this.userService.save(user); + + sendSuccessMessage(CommonWebSocket.USER_UPDATED); + return CommonView.USER_USERS_ID_R; + } + } + + @GetMapping(CommonEndPoint.USERS_ID) + public ModelAndView showOwner(@PathVariable("userId") int userId) { + ModelAndView modelAndView = new ModelAndView(CommonView.USER_DETAILS); + UserDTO user = this.userService.findById(userId); + + modelAndView.addObject(CommonAttribute.USER, user); + return modelAndView; + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/controller/VisitController.java b/src/main/java/org/springframework/samples/petclinic/controller/VisitController.java index 6914a035f..1709fd43d 100644 --- a/src/main/java/org/springframework/samples/petclinic/controller/VisitController.java +++ b/src/main/java/org/springframework/samples/petclinic/controller/VisitController.java @@ -26,7 +26,6 @@ import org.springframework.samples.petclinic.common.CommonWebSocket; import org.springframework.samples.petclinic.controller.common.WebSocketSender; import org.springframework.samples.petclinic.dto.PetDTO; import org.springframework.samples.petclinic.dto.VisitDTO; -import org.springframework.samples.petclinic.model.common.WebSocketMessage; import org.springframework.samples.petclinic.service.PetService; import org.springframework.samples.petclinic.service.VisitService; import org.springframework.samples.petclinic.validator.VisitDTOValidator; diff --git a/src/main/java/org/springframework/samples/petclinic/dto/RoleDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/RoleDTO.java new file mode 100644 index 000000000..ed12efc05 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/dto/RoleDTO.java @@ -0,0 +1,12 @@ +package org.springframework.samples.petclinic.dto; + +import java.io.Serializable; + +/** + * Simple Data Transfert Object representing a list of roles. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public class RoleDTO extends NamedDTO implements Serializable { + +} diff --git a/src/main/java/org/springframework/samples/petclinic/dto/UserDTO.java b/src/main/java/org/springframework/samples/petclinic/dto/UserDTO.java new file mode 100644 index 000000000..da81f2e9c --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/dto/UserDTO.java @@ -0,0 +1,156 @@ +package org.springframework.samples.petclinic.dto; + +import org.springframework.beans.support.MutableSortDefinition; +import org.springframework.beans.support.PropertyComparator; +import org.springframework.samples.petclinic.common.CommonError; +import org.springframework.samples.petclinic.common.CommonParameter; + +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import javax.xml.bind.annotation.XmlElement; +import java.io.Serializable; +import java.util.*; + +public class UserDTO extends PersonDTO implements Serializable { + + @Size(min = CommonParameter.PASSWORD_MIN, max = CommonParameter.PASSWORD_MAX, message = CommonError.FORMAT_BETWEEN + + CommonParameter.PASSWORD_MIN + " AND " + CommonParameter.PASSWORD_MAX + " !") + private String password; + + @Size(min = CommonParameter.PASSWORD_MIN, max = CommonParameter.PASSWORD_MAX, message = CommonError.FORMAT_BETWEEN + + CommonParameter.PASSWORD_MIN + " AND " + CommonParameter.PASSWORD_MAX + " !") + private String matchingPassword; + + @Size(min = CommonParameter.EMAIL_MIN, max = CommonParameter.EMAIL_MAX, message = CommonError.FORMAT_BETWEEN + + CommonParameter.EMAIL_MIN + " AND " + CommonParameter.EMAIL_MAX + " !") + @Pattern(regexp = CommonParameter.EMAIL_REGEXP, message = CommonError.EMAIL_FORMAT) + private String email; + + @Size(max = CommonParameter.PHONE_MAX, message = CommonError.FORMAT_LESS + CommonParameter.PHONE_MAX) + @Pattern(regexp = CommonParameter.PHONE_REGEXP, message = CommonError.PHONE_FORMAT) + private String telephone; + + private Set roles; + + @Size(max = CommonParameter.STREET_MAX, message = CommonError.FORMAT_LESS + CommonParameter.STREET_MAX + " !") + private String street1; + + @Size(max = CommonParameter.STREET_MAX, message = CommonError.FORMAT_LESS + CommonParameter.STREET_MAX + " !") + private String street2; + + @Size(max = CommonParameter.STREET_MAX, message = CommonError.FORMAT_LESS + CommonParameter.STREET_MAX + " !") + private String street3; + + @Size(min = CommonParameter.ZIP_MIN, max = CommonParameter.ZIP_MAX, + message = CommonError.FORMAT_BETWEEN + CommonParameter.ZIP_MIN + " AND " + CommonParameter.ZIP_MAX + " !") + private String zipCode; + + @Size(max = CommonParameter.CITY_MAX, message = CommonError.FORMAT_LESS + CommonParameter.CITY_MAX + " !") + private String city; + + @Size(max = CommonParameter.COUNTRY_MAX, message = CommonError.FORMAT_LESS + CommonParameter.COUNTRY_MAX + " !") + private String country; + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getMatchingPassword() { + return matchingPassword; + } + + public void setMatchingPassword(String matchingPassword) { + this.matchingPassword = matchingPassword; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getTelephone() { + return telephone; + } + + public void setTelephone(String telephone) { + this.telephone = telephone; + } + + protected Set getRolesInternal() { + if (this.roles == null) { + this.roles = new HashSet<>(); + } + return this.roles; + } + + protected void setRolesInternal(Set roles) { + this.roles = roles; + } + + @XmlElement + public List getRoles() { + List sortedRoles = new ArrayList<>(getRolesInternal()); + PropertyComparator.sort(sortedRoles, new MutableSortDefinition("name", true, true)); + return Collections.unmodifiableList(sortedRoles); + } + + public void addRole(RoleDTO role) { + getRolesInternal().add(role); + } + + public String getStreet1() { + return street1; + } + + public void setStreet1(String street1) { + this.street1 = street1; + } + + public String getStreet2() { + return street2; + } + + public void setStreet2(String street2) { + this.street2 = street2; + } + + public String getStreet3() { + return street3; + } + + public void setStreet3(String street3) { + this.street3 = street3; + } + + public String getZipCode() { + return zipCode; + } + + public void setZipCode(String zipCode) { + this.zipCode = zipCode; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/model/Owner.java b/src/main/java/org/springframework/samples/petclinic/model/business/Owner.java similarity index 96% rename from src/main/java/org/springframework/samples/petclinic/model/Owner.java rename to src/main/java/org/springframework/samples/petclinic/model/business/Owner.java index 0c2453dc5..a86bc0c65 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/Owner.java +++ b/src/main/java/org/springframework/samples/petclinic/model/business/Owner.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.model; +package org.springframework.samples.petclinic.model.business; import java.util.ArrayList; import java.util.Collections; @@ -33,6 +33,7 @@ import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.PropertyComparator; import org.springframework.core.style.ToStringCreator; import org.springframework.samples.petclinic.common.CommonAttribute; +import org.springframework.samples.petclinic.model.common.Person; /** * Simple JavaBean domain object representing an owner. diff --git a/src/main/java/org/springframework/samples/petclinic/model/Pet.java b/src/main/java/org/springframework/samples/petclinic/model/business/Pet.java similarity index 96% rename from src/main/java/org/springframework/samples/petclinic/model/Pet.java rename to src/main/java/org/springframework/samples/petclinic/model/business/Pet.java index f6b0b26ed..0b612264c 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/Pet.java +++ b/src/main/java/org/springframework/samples/petclinic/model/business/Pet.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.model; +package org.springframework.samples.petclinic.model.business; import java.time.LocalDate; import java.util.ArrayList; @@ -34,6 +34,7 @@ import javax.persistence.Transient; import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.PropertyComparator; import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.samples.petclinic.model.common.NamedEntity; /** * Simple business object representing a pet. diff --git a/src/main/java/org/springframework/samples/petclinic/model/PetType.java b/src/main/java/org/springframework/samples/petclinic/model/business/PetType.java similarity index 87% rename from src/main/java/org/springframework/samples/petclinic/model/PetType.java rename to src/main/java/org/springframework/samples/petclinic/model/business/PetType.java index 8453778e8..aa213e530 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/PetType.java +++ b/src/main/java/org/springframework/samples/petclinic/model/business/PetType.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.model; +package org.springframework.samples.petclinic.model.business; + +import org.springframework.samples.petclinic.model.common.NamedEntity; import javax.persistence.Entity; import javax.persistence.Table; diff --git a/src/main/java/org/springframework/samples/petclinic/model/Specialty.java b/src/main/java/org/springframework/samples/petclinic/model/business/Specialty.java similarity index 87% rename from src/main/java/org/springframework/samples/petclinic/model/Specialty.java rename to src/main/java/org/springframework/samples/petclinic/model/business/Specialty.java index c6bcc0e0a..d1a23e288 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/Specialty.java +++ b/src/main/java/org/springframework/samples/petclinic/model/business/Specialty.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.model; +package org.springframework.samples.petclinic.model.business; + +import org.springframework.samples.petclinic.model.common.NamedEntity; import java.io.Serializable; diff --git a/src/main/java/org/springframework/samples/petclinic/model/Vet.java b/src/main/java/org/springframework/samples/petclinic/model/business/Vet.java similarity index 94% rename from src/main/java/org/springframework/samples/petclinic/model/Vet.java rename to src/main/java/org/springframework/samples/petclinic/model/business/Vet.java index dc45e5150..4ab2169e8 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/Vet.java +++ b/src/main/java/org/springframework/samples/petclinic/model/business/Vet.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.model; +package org.springframework.samples.petclinic.model.business; import java.util.ArrayList; import java.util.Collections; @@ -31,6 +31,7 @@ import javax.xml.bind.annotation.XmlElement; import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.PropertyComparator; +import org.springframework.samples.petclinic.model.common.Person; /** * Simple JavaBean domain object representing a veterinarian. diff --git a/src/main/java/org/springframework/samples/petclinic/model/Vets.java b/src/main/java/org/springframework/samples/petclinic/model/business/Vets.java similarity index 94% rename from src/main/java/org/springframework/samples/petclinic/model/Vets.java rename to src/main/java/org/springframework/samples/petclinic/model/business/Vets.java index 5ce52829f..723f882db 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/Vets.java +++ b/src/main/java/org/springframework/samples/petclinic/model/business/Vets.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.model; +package org.springframework.samples.petclinic.model.business; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/org/springframework/samples/petclinic/model/Visit.java b/src/main/java/org/springframework/samples/petclinic/model/business/Visit.java similarity index 94% rename from src/main/java/org/springframework/samples/petclinic/model/Visit.java rename to src/main/java/org/springframework/samples/petclinic/model/business/Visit.java index 859ca61a0..c5fd97024 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/Visit.java +++ b/src/main/java/org/springframework/samples/petclinic/model/business/Visit.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.model; +package org.springframework.samples.petclinic.model.business; import java.time.LocalDate; @@ -23,6 +23,7 @@ import javax.persistence.Table; import javax.validation.constraints.NotEmpty; import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.samples.petclinic.model.common.BaseEntity; /** * Simple JavaBean domain object representing a visit. diff --git a/src/main/java/org/springframework/samples/petclinic/model/common/AuthProvider.java b/src/main/java/org/springframework/samples/petclinic/model/common/AuthProvider.java new file mode 100644 index 000000000..d6fe764f0 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/model/common/AuthProvider.java @@ -0,0 +1,7 @@ +package org.springframework.samples.petclinic.model.common; + +public enum AuthProvider { + + local, facebook, google, github + +} diff --git a/src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java b/src/main/java/org/springframework/samples/petclinic/model/common/BaseEntity.java similarity index 95% rename from src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java rename to src/main/java/org/springframework/samples/petclinic/model/common/BaseEntity.java index 4cb9ffc0c..949ebe4dd 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java +++ b/src/main/java/org/springframework/samples/petclinic/model/common/BaseEntity.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.model; +package org.springframework.samples.petclinic.model.common; import java.io.Serializable; diff --git a/src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java b/src/main/java/org/springframework/samples/petclinic/model/common/NamedEntity.java similarity index 95% rename from src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java rename to src/main/java/org/springframework/samples/petclinic/model/common/NamedEntity.java index cafe7e218..2bb6a59fa 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java +++ b/src/main/java/org/springframework/samples/petclinic/model/common/NamedEntity.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.model; +package org.springframework.samples.petclinic.model.common; import javax.persistence.Column; import javax.persistence.MappedSuperclass; diff --git a/src/main/java/org/springframework/samples/petclinic/model/Person.java b/src/main/java/org/springframework/samples/petclinic/model/common/Person.java similarity index 66% rename from src/main/java/org/springframework/samples/petclinic/model/Person.java rename to src/main/java/org/springframework/samples/petclinic/model/common/Person.java index 709c3bec3..c061edd94 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/Person.java +++ b/src/main/java/org/springframework/samples/petclinic/model/common/Person.java @@ -13,11 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.model; +package org.springframework.samples.petclinic.model.common; + +import org.springframework.samples.petclinic.common.CommonError; +import org.springframework.samples.petclinic.common.CommonParameter; import javax.persistence.Column; import javax.persistence.MappedSuperclass; import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; /** * Simple JavaBean domain object representing an person. @@ -27,12 +31,16 @@ import javax.validation.constraints.NotEmpty; @MappedSuperclass public class Person extends BaseEntity { - @Column(name = "first_name") @NotEmpty + @Size(min = CommonParameter.FIRSTNAME_MIN, max = CommonParameter.FIRSTNAME_MAX, message = CommonError.FORMAT_BETWEEN + + CommonParameter.FIRSTNAME_MIN + " AND " + CommonParameter.FIRSTNAME_MAX + " !") + @Column(name = "first_name", length = CommonParameter.FIRSTNAME_MAX) private String firstName; - @Column(name = "last_name") @NotEmpty + @Size(min = CommonParameter.LASTNAME_MIN, max = CommonParameter.LASTNAME_MAX, message = CommonError.FORMAT_BETWEEN + + CommonParameter.LASTNAME_MIN + " AND " + CommonParameter.LASTNAME_MAX + " !") + @Column(name = "last_name", length = CommonParameter.LASTNAME_MAX) private String lastName; public String getFirstName() { 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 new file mode 100644 index 000000000..4aefcda52 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/model/common/Role.java @@ -0,0 +1,12 @@ +package org.springframework.samples.petclinic.model.common; + +import org.springframework.samples.petclinic.model.common.NamedEntity; + +import javax.persistence.*; +import java.io.Serializable; + +@Entity(name = "Role") +@Table(name = "roles") +public class Role extends NamedEntity implements Serializable { + +} 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 new file mode 100644 index 000000000..61cae26bc --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/model/common/User.java @@ -0,0 +1,208 @@ +package org.springframework.samples.petclinic.model.common; + +import org.springframework.beans.support.MutableSortDefinition; +import org.springframework.beans.support.PropertyComparator; +import org.springframework.samples.petclinic.common.CommonError; +import org.springframework.samples.petclinic.common.CommonParameter; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import javax.xml.bind.annotation.XmlElement; +import java.io.Serializable; +import java.util.*; + +/** + * Class used to manage application users + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@Entity(name = "User") +@Table(name = "users") +public class User extends Person implements Serializable { + + @NotNull + @Size(min = CommonParameter.EMAIL_MIN, max = CommonParameter.EMAIL_MAX, message = CommonError.FORMAT_BETWEEN + + CommonParameter.EMAIL_MIN + " AND " + CommonParameter.EMAIL_MAX + " !") + @Pattern(regexp = CommonParameter.EMAIL_REGEXP, message = CommonError.EMAIL_FORMAT) + @Column(name = "email", unique = true, length = CommonParameter.EMAIL_MAX) + private String email; + + @NotNull + @Column(name = "email_verified") + private Boolean emailVerified = false; + + @NotNull + @Size(min = CommonParameter.PASSWORD_MIN, max = CommonParameter.PASSWORD_MAX, message = CommonError.FORMAT_BETWEEN + + CommonParameter.PASSWORD_MIN + " AND " + CommonParameter.PASSWORD_MAX + " !") + @Column(name = "password", length = CommonParameter.PASSWORD_MAX) + private String password; + + @NotNull + @Enumerated(EnumType.STRING) + private AuthProvider provider; + + @Column(name = "provider_id") + private String providerId; + + @Size(max = CommonParameter.PHONE_MAX, message = CommonError.FORMAT_LESS + CommonParameter.PHONE_MAX) + @Pattern(regexp = CommonParameter.PHONE_REGEXP, message = CommonError.PHONE_FORMAT) + @Column(name = "telephone", length = CommonParameter.EMAIL_MAX) + private String telephone; + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "role_id")) + private Set roles; + + @NotNull + @Size(max = CommonParameter.STREET_MAX, message = CommonError.FORMAT_LESS + CommonParameter.STREET_MAX + " !") + @Column(name = "street1", length = CommonParameter.STREET_MAX) + private String street1; + + @Size(max = CommonParameter.STREET_MAX, message = CommonError.FORMAT_LESS + CommonParameter.STREET_MAX + " !") + @Column(name = "street2", length = CommonParameter.STREET_MAX) + private String street2; + + @Size(max = CommonParameter.STREET_MAX, message = CommonError.FORMAT_LESS + CommonParameter.STREET_MAX + " !") + @Column(name = "street3", length = CommonParameter.STREET_MAX) + private String street3; + + @NotNull + @Size(max = CommonParameter.ZIP_MAX, message = CommonError.FORMAT_LESS + CommonParameter.ZIP_MAX + " !") + @Column(name = "zip_code", length = CommonParameter.ZIP_MAX) + private String zipCode; + + @NotNull + @Size(max = CommonParameter.CITY_MAX, message = CommonError.FORMAT_LESS + CommonParameter.CITY_MAX + " !") + @Column(name = "city", length = CommonParameter.CITY_MAX) + private String city; + + @Size(max = CommonParameter.COUNTRY_MAX, message = CommonError.FORMAT_LESS + CommonParameter.COUNTRY_MAX + " !") + @Column(name = "country", length = CommonParameter.COUNTRY_MAX) + private String country; + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Boolean getEmailVerified() { + return emailVerified; + } + + public void setEmailVerified(Boolean emailVerified) { + this.emailVerified = emailVerified; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public AuthProvider getProvider() { + return provider; + } + + public void setProvider(AuthProvider provider) { + this.provider = provider; + } + + public String getProviderId() { + return providerId; + } + + public void setProviderId(String providerId) { + this.providerId = providerId; + } + + public String getTelephone() { + return telephone; + } + + public void setTelephone(String telephone) { + this.telephone = telephone; + } + + protected Set getRolesInternal() { + if (this.roles == null) { + this.roles = new HashSet<>(); + } + return this.roles; + } + + protected void setRolesInternal(Set roles) { + this.roles = roles; + } + + @XmlElement + public List getRoles() { + List sortedRoles = new ArrayList<>(getRolesInternal()); + PropertyComparator.sort(sortedRoles, new MutableSortDefinition("name", true, true)); + return Collections.unmodifiableList(sortedRoles); + } + + public int getNrOfRoles() { + return getRolesInternal().size(); + } + + public void addRole(Role role) { + getRolesInternal().add(role); + } + + public String getStreet1() { + return street1; + } + + public void setStreet1(String street1) { + this.street1 = street1; + } + + public String getStreet2() { + return street2; + } + + public void setStreet2(String street2) { + this.street2 = street2; + } + + public String getStreet3() { + return street3; + } + + public void setStreet3(String street3) { + this.street3 = street3; + } + + public String getZipCode() { + return zipCode; + } + + public void setZipCode(String zipCode) { + this.zipCode = zipCode; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java index fe1a248b5..172df27f9 100644 --- a/src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java @@ -21,7 +21,7 @@ import java.util.List; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.Repository; import org.springframework.data.repository.query.Param; -import org.springframework.samples.petclinic.model.Owner; +import org.springframework.samples.petclinic.model.business.Owner; import org.springframework.transaction.annotation.Transactional; /** diff --git a/src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java index 48b975bdf..88afe1bb4 100644 --- a/src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java @@ -19,8 +19,8 @@ import java.util.List; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.Repository; -import org.springframework.samples.petclinic.model.Pet; -import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.model.business.Pet; +import org.springframework.samples.petclinic.model.business.PetType; import org.springframework.transaction.annotation.Transactional; /** diff --git a/src/main/java/org/springframework/samples/petclinic/repository/PetTypeRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/PetTypeRepository.java index 5843e1719..84f9cec14 100644 --- a/src/main/java/org/springframework/samples/petclinic/repository/PetTypeRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/PetTypeRepository.java @@ -16,9 +16,8 @@ package org.springframework.samples.petclinic.repository; import org.springframework.data.repository.Repository; -import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.model.business.PetType; -import java.util.Collection; import java.util.List; /** diff --git a/src/main/java/org/springframework/samples/petclinic/repository/RoleRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/RoleRepository.java new file mode 100644 index 000000000..193f2c5ed --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/RoleRepository.java @@ -0,0 +1,42 @@ +package org.springframework.samples.petclinic.repository; + +import org.springframework.samples.petclinic.model.common.Role; +import org.springframework.data.repository.Repository; + +import java.util.List; + +/** + * Repository class for Role domain objects All method names are compliant + * with Spring Data naming conventions so this interface can easily be extended for Spring + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public interface RoleRepository extends Repository { + + /** + * Retrieve a {@link Role} from the data store by id. + * @param roleId the id to search for + * @return the {@link Role} if found + */ + Role findById(Integer roleId); + + /** + * Retrieve a {@link Role} from the data store by id. + * @param name the name to search for + * @return the {@link Role} if found + */ + Role findByName(String name); + + /** + * Retrieve all {@link Role}s from the data store + * @return a Collection of {@link Role}s (or an empty Collection if none + */ + List findAll(); + + /** + * Save a {@link Role} to the data store, either inserting or updating it. + * @param role the {@link Role} to save + */ + Role save(Role role); + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/SpecialtyRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/SpecialtyRepository.java index dd78d06c4..8bd6ec5ca 100644 --- a/src/main/java/org/springframework/samples/petclinic/repository/SpecialtyRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/SpecialtyRepository.java @@ -16,9 +16,8 @@ package org.springframework.samples.petclinic.repository; import org.springframework.data.repository.Repository; -import org.springframework.samples.petclinic.model.Specialty; +import org.springframework.samples.petclinic.model.business.Specialty; -import java.util.Collection; import java.util.List; /** diff --git a/src/main/java/org/springframework/samples/petclinic/repository/UserRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/UserRepository.java new file mode 100644 index 000000000..cbc45e820 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/UserRepository.java @@ -0,0 +1,36 @@ +package org.springframework.samples.petclinic.repository; + +import org.springframework.data.repository.Repository; +import org.springframework.samples.petclinic.model.common.User; + +import java.util.List; + +/** + * Repository class for User domain objects All method names are compliant + * with Spring Data naming conventions so this interface can easily be extended for Spring + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +public interface UserRepository extends Repository { + + User findById(Integer id); + + User findByEmail(String email); + + Boolean existsByEmail(String email); + + /** + * Retrieve all {@link User}s from the data store + * @return a Collection of {@link User}s (or an empty Collection if none + */ + List findAll(); + + /** + * Save an {@link User} to the data store, either inserting or updating it. + * @param user the {@link User} to save + */ + User save(User user); + + void deleteById(Integer id); + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java index af0a758d2..444e301de 100644 --- a/src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java @@ -19,7 +19,7 @@ import java.util.Collection; import org.springframework.cache.annotation.Cacheable; import org.springframework.data.repository.Repository; -import org.springframework.samples.petclinic.model.Vet; +import org.springframework.samples.petclinic.model.business.Vet; import org.springframework.transaction.annotation.Transactional; /** diff --git a/src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java index 534f2599c..81b4c0790 100644 --- a/src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java @@ -15,12 +15,11 @@ */ package org.springframework.samples.petclinic.repository; -import java.util.Collection; import java.util.List; import org.springframework.data.repository.Repository; -import org.springframework.samples.petclinic.model.BaseEntity; -import org.springframework.samples.petclinic.model.Visit; +import org.springframework.samples.petclinic.model.common.BaseEntity; +import org.springframework.samples.petclinic.model.business.Visit; /** * Repository class for Visit domain objects All method names are compliant diff --git a/src/main/java/org/springframework/samples/petclinic/service/OwnerService.java b/src/main/java/org/springframework/samples/petclinic/service/OwnerService.java index 5a783acca..b79cff504 100644 --- a/src/main/java/org/springframework/samples/petclinic/service/OwnerService.java +++ b/src/main/java/org/springframework/samples/petclinic/service/OwnerService.java @@ -4,8 +4,8 @@ import org.modelmapper.ModelMapper; import org.modelmapper.internal.util.Lists; import org.springframework.samples.petclinic.dto.OwnerDTO; import org.springframework.samples.petclinic.dto.PetDTO; -import org.springframework.samples.petclinic.model.Owner; -import org.springframework.samples.petclinic.model.Pet; +import org.springframework.samples.petclinic.model.business.Owner; +import org.springframework.samples.petclinic.model.business.Pet; import org.springframework.samples.petclinic.repository.OwnerRepository; import org.springframework.samples.petclinic.repository.PetRepository; import org.springframework.samples.petclinic.repository.PetTypeRepository; diff --git a/src/main/java/org/springframework/samples/petclinic/service/PetService.java b/src/main/java/org/springframework/samples/petclinic/service/PetService.java index ddd85a771..e331284a9 100644 --- a/src/main/java/org/springframework/samples/petclinic/service/PetService.java +++ b/src/main/java/org/springframework/samples/petclinic/service/PetService.java @@ -4,9 +4,9 @@ import org.modelmapper.ModelMapper; import org.springframework.samples.petclinic.dto.OwnerDTO; import org.springframework.samples.petclinic.dto.PetDTO; import org.springframework.samples.petclinic.dto.PetTypeDTO; -import org.springframework.samples.petclinic.model.Owner; -import org.springframework.samples.petclinic.model.Pet; -import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.model.business.Owner; +import org.springframework.samples.petclinic.model.business.Pet; +import org.springframework.samples.petclinic.model.business.PetType; import org.springframework.samples.petclinic.repository.PetRepository; import org.springframework.samples.petclinic.repository.PetTypeRepository; import org.springframework.samples.petclinic.repository.VisitRepository; diff --git a/src/main/java/org/springframework/samples/petclinic/service/PetTypeService.java b/src/main/java/org/springframework/samples/petclinic/service/PetTypeService.java index 79ab94a07..498e61d6b 100644 --- a/src/main/java/org/springframework/samples/petclinic/service/PetTypeService.java +++ b/src/main/java/org/springframework/samples/petclinic/service/PetTypeService.java @@ -2,7 +2,7 @@ package org.springframework.samples.petclinic.service; import org.modelmapper.ModelMapper; import org.springframework.samples.petclinic.dto.PetTypeDTO; -import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.model.business.PetType; import org.springframework.samples.petclinic.repository.PetTypeRepository; import org.springframework.stereotype.Service; diff --git a/src/main/java/org/springframework/samples/petclinic/service/RoleService.java b/src/main/java/org/springframework/samples/petclinic/service/RoleService.java new file mode 100644 index 000000000..2194bc21b --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/RoleService.java @@ -0,0 +1,86 @@ +package org.springframework.samples.petclinic.service; + +import org.modelmapper.ModelMapper; +import org.springframework.samples.petclinic.dto.RoleDTO; +import org.springframework.samples.petclinic.model.common.Role; +import org.springframework.samples.petclinic.repository.RoleRepository; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * Simple Service between Specialty entity and SpecialtyDTO Data Transfert Object. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@Service("RoleService") +public class RoleService implements BaseService { + + private final RoleRepository roleRepository; + + private final ModelMapper modelMapper = new ModelMapper(); + + public RoleService(RoleRepository roleRepository) { + this.roleRepository = roleRepository; + } + + @Override + public Role dtoToEntity(RoleDTO dto) { + if (dto != null) { + return modelMapper.map(dto, Role.class); + } + + return new Role(); + } + + @Override + public RoleDTO entityToDTO(Role entity) { + if (entity != null) { + return modelMapper.map(entity, RoleDTO.class); + } + + return new RoleDTO(); + } + + @Override + public List entitiesToDTOS(List entities) { + List dtos = new ArrayList<>(); + + entities.forEach(entity -> dtos.add(entityToDTO(entity))); + + return dtos; + } + + @Override + public List dtosToEntities(List dtos) { + List entities = new ArrayList<>(); + + dtos.forEach(dto -> entities.add(dtoToEntity(dto))); + + return entities; + } + + @Override + public RoleDTO findById(int id) { + return entityToDTO(roleRepository.findById(id)); + } + + @Override + public List findAll() { + return entitiesToDTOS(roleRepository.findAll()); + } + + @Override + public RoleDTO save(RoleDTO dto) { + Role role = dtoToEntity(dto); + role = roleRepository.save(role); + + return entityToDTO(role); + } + + public RoleDTO findByName(String name) { + return entityToDTO(roleRepository.findByName(name)); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/SecurityService.java b/src/main/java/org/springframework/samples/petclinic/service/SecurityService.java new file mode 100644 index 000000000..1e173e61c --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/SecurityService.java @@ -0,0 +1,9 @@ +package org.springframework.samples.petclinic.service; + +public interface SecurityService { + + String findLoggedInUsername(); + + void autoLogin(String email, String motDePasse); + +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/SecurityServiceImpl.java b/src/main/java/org/springframework/samples/petclinic/service/SecurityServiceImpl.java new file mode 100644 index 000000000..a5f5936eb --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/SecurityServiceImpl.java @@ -0,0 +1,50 @@ +package org.springframework.samples.petclinic.service; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; + +@Slf4j +@Service("SecurityService") +public class SecurityServiceImpl implements SecurityService { + + private final AuthenticationManager authenticationManager; + + private final UserDetailsServiceImpl userDetailsService; + + @Autowired + public SecurityServiceImpl(AuthenticationManager authenticationManager, UserDetailsServiceImpl userDetailsService) { + this.authenticationManager = authenticationManager; + this.userDetailsService = userDetailsService; + } + + @Override + public String findLoggedInUsername() { + Object userDetails = SecurityContextHolder.getContext().getAuthentication().getDetails(); + + if (userDetails instanceof UserDetails) { + return ((UserDetails) userDetails).getUsername(); + } + + return null; + } + + @Override + public void autoLogin(String email, String motDePasse) { + UserDetails userDetails = userDetailsService.loadUserByUsername(email); + + UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken( + userDetails, motDePasse, userDetails.getAuthorities()); + + authenticationManager.authenticate(usernamePasswordAuthenticationToken); + + if (usernamePasswordAuthenticationToken.isAuthenticated()) { + SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); + } + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/SpecialtyService.java b/src/main/java/org/springframework/samples/petclinic/service/SpecialtyService.java index 3afbb87e4..98234a027 100644 --- a/src/main/java/org/springframework/samples/petclinic/service/SpecialtyService.java +++ b/src/main/java/org/springframework/samples/petclinic/service/SpecialtyService.java @@ -2,13 +2,11 @@ package org.springframework.samples.petclinic.service; import org.modelmapper.ModelMapper; import org.springframework.samples.petclinic.dto.SpecialtyDTO; -import org.springframework.samples.petclinic.model.Specialty; +import org.springframework.samples.petclinic.model.business.Specialty; import org.springframework.samples.petclinic.repository.SpecialtyRepository; import org.springframework.stereotype.Service; import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; import java.util.List; /** diff --git a/src/main/java/org/springframework/samples/petclinic/service/UserDetailsServiceImpl.java b/src/main/java/org/springframework/samples/petclinic/service/UserDetailsServiceImpl.java new file mode 100644 index 000000000..86a249205 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/UserDetailsServiceImpl.java @@ -0,0 +1,50 @@ +package org.springframework.samples.petclinic.service; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.samples.petclinic.dto.RoleDTO; +import org.springframework.samples.petclinic.dto.UserDTO; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; + +import java.util.HashSet; +import java.util.Set; + +@Slf4j +@Service("UserDetailsService") +public class UserDetailsServiceImpl implements UserDetailsService { + + private final UserService userService; + + @Autowired + private BCryptPasswordEncoder bCryptPasswordEncoder; + + public UserDetailsServiceImpl(UserService userService) { + this.userService = userService; + } + + @Override + public UserDetails loadUserByUsername(String email) { + + UserDTO userDTO = userService.findByEmail(email); + + if (userDTO == null) + throw new UsernameNotFoundException("User not found with email :" + email); + + Set grantedAuthorities = new HashSet<>(); + + for (RoleDTO role : userDTO.getRoles()) { + grantedAuthorities.add(new SimpleGrantedAuthority(role.getName())); + } + + return new org.springframework.security.core.userdetails.User(userDTO.getEmail(), userDTO.getMatchingPassword(), + grantedAuthorities); + + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/UserService.java b/src/main/java/org/springframework/samples/petclinic/service/UserService.java new file mode 100644 index 000000000..b15ff430f --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/UserService.java @@ -0,0 +1,117 @@ +package org.springframework.samples.petclinic.service; + +import org.modelmapper.ModelMapper; +import org.springframework.samples.petclinic.dto.RoleDTO; +import org.springframework.samples.petclinic.dto.UserDTO; +import org.springframework.samples.petclinic.model.common.Role; +import org.springframework.samples.petclinic.model.common.User; +import org.springframework.samples.petclinic.repository.UserRepository; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * Simple Service between User entity and UserDTO Data Transfert Object. + * + * @author Paul-Emmanuel DOS SANTOS FACAO + */ +@Service("UserService") +public class UserService implements BaseService { + + private final UserRepository userRepository; + + private final ModelMapper modelMapper = new ModelMapper(); + + public UserService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Override + public User dtoToEntity(UserDTO dto) { + + if (dto == null) { + return null; + } + + User user = modelMapper.map(dto, User.class); + user.setPassword(dto.getPassword()); + + if (dto.getRoles() != null) { + for (RoleDTO roleDTO : dto.getRoles()) { + Role role = modelMapper.map(roleDTO, Role.class); + user.addRole(role); + } + } + + return user; + } + + @Override + public UserDTO entityToDTO(User entity) { + if (entity == null) { + return null; + } + + UserDTO userDto = modelMapper.map(entity, UserDTO.class); + userDto.setPassword(entity.getPassword()); + userDto.setMatchingPassword(entity.getPassword()); + + if (entity.getRoles() != null) { + for (Role role : entity.getRoles()) { + RoleDTO roleDTO = modelMapper.map(role, RoleDTO.class); + userDto.addRole(roleDTO); + } + } + + return userDto; + } + + @Override + public List entitiesToDTOS(List entities) { + List dtos = new ArrayList<>(); + + entities.forEach(entity -> dtos.add(entityToDTO(entity))); + + return dtos; + } + + @Override + public List dtosToEntities(List dtos) { + List entities = new ArrayList<>(); + + dtos.forEach(dto -> entities.add(dtoToEntity(dto))); + + return entities; + } + + @Override + public UserDTO findById(int id) { + User user = userRepository.findById(id); + + return entityToDTO(user); + } + + @Override + public List findAll() { + List users = userRepository.findAll(); + + return entitiesToDTOS(users); + } + + @Override + public UserDTO save(UserDTO dto) { + User user = dtoToEntity(dto); + + user = userRepository.save(user); + + return entityToDTO(user); + } + + public UserDTO findByEmail(String email) { + User user = userRepository.findByEmail(email); + + return entityToDTO(user); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/VetService.java b/src/main/java/org/springframework/samples/petclinic/service/VetService.java index 3eac5d666..11a7967fe 100644 --- a/src/main/java/org/springframework/samples/petclinic/service/VetService.java +++ b/src/main/java/org/springframework/samples/petclinic/service/VetService.java @@ -4,15 +4,14 @@ import org.modelmapper.ModelMapper; import org.modelmapper.internal.util.Lists; import org.springframework.samples.petclinic.dto.SpecialtyDTO; import org.springframework.samples.petclinic.dto.VetDTO; -import org.springframework.samples.petclinic.model.Specialty; +import org.springframework.samples.petclinic.model.business.Specialty; import org.springframework.samples.petclinic.repository.SpecialtyRepository; import org.springframework.samples.petclinic.repository.VetRepository; -import org.springframework.samples.petclinic.model.Vet; +import org.springframework.samples.petclinic.model.business.Vet; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; import java.util.List; /** diff --git a/src/main/java/org/springframework/samples/petclinic/service/VisitService.java b/src/main/java/org/springframework/samples/petclinic/service/VisitService.java index b5c4d5c4e..76be1578c 100644 --- a/src/main/java/org/springframework/samples/petclinic/service/VisitService.java +++ b/src/main/java/org/springframework/samples/petclinic/service/VisitService.java @@ -2,7 +2,7 @@ package org.springframework.samples.petclinic.service; import org.modelmapper.ModelMapper; import org.springframework.samples.petclinic.dto.VisitDTO; -import org.springframework.samples.petclinic.model.Visit; +import org.springframework.samples.petclinic.model.business.Visit; import org.springframework.samples.petclinic.repository.VisitRepository; import org.springframework.stereotype.Service; diff --git a/src/main/java/org/springframework/samples/petclinic/validator/PetValidator.java b/src/main/java/org/springframework/samples/petclinic/validator/PetValidator.java index 98f4ab025..aa7a67336 100644 --- a/src/main/java/org/springframework/samples/petclinic/validator/PetValidator.java +++ b/src/main/java/org/springframework/samples/petclinic/validator/PetValidator.java @@ -17,7 +17,7 @@ package org.springframework.samples.petclinic.validator; import org.springframework.samples.petclinic.common.CommonAttribute; import org.springframework.samples.petclinic.common.CommonError; -import org.springframework.samples.petclinic.model.Pet; +import org.springframework.samples.petclinic.model.business.Pet; import org.springframework.util.StringUtils; import org.springframework.validation.Errors; import org.springframework.validation.Validator; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 4d4784e36..11809f262 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -23,3 +23,35 @@ logging.level.org.springframework=INFO # Maximum time static resources should be cached spring.resources.cache.cachecontrol.max-age=12h + +########################################################################## DEBUG +#logging.level.root=DEBUG +#logging.level.org.springframework.web: DEBUG +#logging.level.org.hibernate: DEBUG +#logging.level.org.springframework.context.annotation=TRACE + + + +spring.datasource.hikari.connectionTimeout=20000 +spring.datasource.hikari.maximumPoolSize=5 +spring.datasource.initialize=true +spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=- 1;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= +spring.h2.console.enabled=true +spring.h2.console.path=/h2-console + +spring.security.oauth2.client.registration.google.client-id=${OAUTH2_GOOGLE_CLIENT_ID} +spring.security.oauth2.client.registration.google.client-secret=${OAUTH2_GOOGLE_CLIENT_SECRET} + +spring.security.oauth2.client.registration.github.client-id=${OAUTH2_GITHUB_CLIENT_ID} +spring.security.oauth2.client.registration.github.client-secret=${OAUTH2_GITHUB_CLIENT_SECRET} + + +#spring.security.oauth2.client.registration.facebook.client-id= +#spring.security.oauth2.client.registration.facebook.client-secret= + + +#spring.security.oauth2.client.registration.twitter.client-id= +#spring.security.oauth2.client.registration.twitter.client-secret= diff --git a/src/main/resources/db/h2/data.sql b/src/main/resources/db/h2/data.sql index 16dda3e84..a5aa7dd2d 100644 --- a/src/main/resources/db/h2/data.sql +++ b/src/main/resources/db/h2/data.sql @@ -51,3 +51,17 @@ INSERT INTO visits VALUES (1, 7, '2013-01-01', 'rabies shot'); INSERT INTO visits VALUES (2, 8, '2013-01-02', 'rabies shot'); INSERT INTO visits VALUES (3, 8, '2013-01-03', 'neutered'); INSERT INTO visits VALUES (4, 7, '2013-01-04', 'spayed'); + +INSERT INTO roles VALUES (1,'ADMIN'); +INSERT INTO roles VALUES (2,'STAFF'); +INSERT INTO roles VALUES (3,'USER'); + +INSERT INTO users VALUES (1, 'George', 'Franklin', 'georges.franklin@petclinic.com', true,'$2a$10$8KypNYtPopFo8Sk5jbKJ4.lCKeBhdApsrkmFfhwjB8nCls8qpzjZG', 'local', null, '6085551023', '110 W. Liberty St.','','',12354,'Madison','USA'); +INSERT INTO users VALUES (2, 'Betty', 'Davis', 'betty.davis@petclinic.com', true, '$2a$10$InKx/fhX3CmLi8zKpHYx/.ETHUlZwvT1xn.Za/pp2JR0iEtYV9a9O', 'local', null, '6085551749','638 Cardinal Ave.', '', '', 6546, 'Sun Prairie', 'USA'); +INSERT INTO users VALUES (3, 'Eduardo', 'Rodriquez', 'eduardo.rodriguez@petclinic.com', true, '$2a$10$P55nbvVibHpoyWzenHngjOf.oEmcj74mI/VJaUZwGX9v8klctzsNW', 'local', null, '6085558763','2693 Commerce St.', '', '', 65454, 'McFarland', 'USA'); + +INSERT INTO users_roles VALUES (1,1); +INSERT INTO users_roles VALUES (1,2); +INSERT INTO users_roles VALUES (1,3); +INSERT INTO users_roles VALUES (2,3); +INSERT INTO users_roles VALUES (3,3); diff --git a/src/main/resources/db/h2/schema.sql b/src/main/resources/db/h2/schema.sql index f3c6947b7..3c80a0076 100644 --- a/src/main/resources/db/h2/schema.sql +++ b/src/main/resources/db/h2/schema.sql @@ -5,6 +5,8 @@ DROP TABLE visits IF EXISTS; DROP TABLE pets IF EXISTS; DROP TABLE types IF EXISTS; DROP TABLE owners IF EXISTS; +DROP TABLE roles IF EXISTS; +DROP TABLE users IF EXISTS; CREATE TABLE vets ( @@ -62,3 +64,36 @@ CREATE TABLE visits ( ); ALTER TABLE visits ADD CONSTRAINT fk_visits_pets FOREIGN KEY (pet_id) REFERENCES pets (id); CREATE INDEX visits_pet_id ON visits (pet_id); + +CREATE TABLE roles ( + id INTEGER IDENTITY PRIMARY KEY, + name VARCHAR(20) NOT NULL +); +CREATE INDEX roles_name ON roles (name); + +CREATE TABLE users ( + id INTEGER IDENTITY PRIMARY KEY, + first_name VARCHAR(30) NOT NULL, + last_name VARCHAR_IGNORECASE(30) NOT NULL, + email VARCHAR(50) NOT NULL, + email_verified BOOLEAN NOT NULL, + password VARCHAR(255) NOT NULL, + provider VARCHAR(20), + provider_id VARCHAR(20), + telephone VARCHAR(20), + street1 VARCHAR(50), + street2 VARCHAR(50), + street3 VARCHAR(50), + zip_code VARCHAR(6), + city VARCHAR(80), + country VARCHAR(50) +); +CREATE INDEX users_email ON users (email); + +CREATE TABLE public.users_roles ( + user_id INTEGER NOT NULL, + role_id INTEGER NOT NULL +); +ALTER TABLE users_roles ADD CONSTRAINT fk_users_roles_user_id FOREIGN KEY (user_id) REFERENCES users (id); +ALTER TABLE users_roles ADD CONSTRAINT fk_users_roles_role_id FOREIGN KEY (role_id) REFERENCES roles (id); +CREATE INDEX users_roles_user_id ON users_roles (user_id); diff --git a/src/main/resources/static/css/style.css b/src/main/resources/static/css/style.css deleted file mode 100644 index 59c3f0594..000000000 --- a/src/main/resources/static/css/style.css +++ /dev/null @@ -1,7 +0,0 @@ -#footer { - position:absolute; - bottom:0; - width:100%; - height:60px; /* Height of the footer */ - background:#6cf; -} diff --git a/src/main/resources/static/resources/css/style.css b/src/main/resources/static/resources/css/style.css new file mode 100644 index 000000000..d02509799 --- /dev/null +++ b/src/main/resources/static/resources/css/style.css @@ -0,0 +1,141 @@ +#footer { + position:absolute; + bottom:0; + width:100%; + height:60px; /* Height of the footer */ + background:#6cf; +} + +body { + font-family: Arial, Helvetica, sans-serif; +} + +* { + box-sizing: border-box; +} + +/* style the container */ +.container { + position: relative; + border-radius: 5px; + background-color: #f2f2f2; + padding: 20px 0 30px 0; +} + +/* style inputs and link buttons */ +input, +.btn { + width: 100%; + padding: 12px; + border: none; + border-radius: 4px; + margin: 5px 0; + opacity: 0.85; + display: inline-block; + font-size: 17px; + line-height: 20px; + text-decoration: none; /* remove underline from anchors */ +} + +input:hover, +.btn:hover { + opacity: 1; +} + +/* add appropriate colors to fb, twitter and google buttons */ +.fb { + background-color: #3B5998; + color: white; +} + +.twitter { + background-color: #55ACEE; + color: white; +} + +.google { + background-color: #dd4b39; + color: white; +} + +.github { + background-color: #dd4b39; + color: white; +} + + +/* style the submit button */ +input[type=submit] { + background-color: #4CAF50; + color: white; + cursor: pointer; +} + +input[type=submit]:hover { + background-color: #45a049; +} + +/* Two-column layout */ +.col { + float: left; + width: 50%; + margin: auto; + padding: 0 50px; + margin-top: 6px; +} + +/* Clear floats after the columns */ +.row:after { + content: ""; + display: table; + clear: both; +} + +/* vertical line */ +.vl { + position: absolute; + left: 50%; + transform: translate(-50%); + border: 2px solid #ddd; + height: 175px; +} + +/* text inside the vertical line */ +.vl-innertext { + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + background-color: #f1f1f1; + border: 1px solid #ccc; + border-radius: 50%; + padding: 8px 10px; +} + +/* hide some text on medium and large screens */ +.hide-md-lg { + display: none; +} + +/* bottom container */ +.bottom-container { + text-align: center; + background-color: #666; + border-radius: 0px 0px 4px 4px; +} + +/* Responsive layout - when the screen is less than 650px wide, make the two columns stack on top of each other instead of next to each other */ +@media screen and (max-width: 650px) { + .col { + width: 100%; + margin-top: 0; + } + /* hide the vertical line */ + .vl { + display: none; + } + /* show the hidden text on small screens */ + .hide-md-lg { + display: block; + text-align: center; + } +} diff --git a/src/main/resources/static/js/notification.js b/src/main/resources/static/resources/js/notification.js similarity index 100% rename from src/main/resources/static/js/notification.js rename to src/main/resources/static/resources/js/notification.js diff --git a/src/main/resources/templates/fragments/inputField.html b/src/main/resources/templates/fragments/inputField.html index c3373bea0..0de081939 100644 --- a/src/main/resources/templates/fragments/inputField.html +++ b/src/main/resources/templates/fragments/inputField.html @@ -9,6 +9,8 @@
+ + diff --git a/src/main/resources/templates/fragments/layout.html b/src/main/resources/templates/fragments/layout.html index df5a761c9..663ab0d8c 100755 --- a/src/main/resources/templates/fragments/layout.html +++ b/src/main/resources/templates/fragments/layout.html @@ -17,9 +17,9 @@ + - - + @@ -69,12 +69,24 @@ Veterinarians -
  • +
  • Error
  • +
  • + + Sign In +
  • +
  • + + Logout +
  • +
  • + + My account +
  • +
    diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 000000000..f55a53034 --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,49 @@ + + + + + + +

    Login Manually

    + +
    +
    + + +
    + +
    +
    + + + Register +
    +
    + +
    + +

    Login with Social Media

    + + + + + diff --git a/src/main/resources/templates/users/createOrUpdateUserForm.html b/src/main/resources/templates/users/createOrUpdateUserForm.html new file mode 100644 index 000000000..9fba098f1 --- /dev/null +++ b/src/main/resources/templates/users/createOrUpdateUserForm.html @@ -0,0 +1,44 @@ + + + + +

    User

    +
    +
    + + + + + + + + + + + + +
    +
    +
    + + Cancel +
    +
    +
    + + diff --git a/src/main/resources/templates/users/userDetails.html b/src/main/resources/templates/users/userDetails.html new file mode 100644 index 000000000..383fa929f --- /dev/null +++ b/src/main/resources/templates/users/userDetails.html @@ -0,0 +1,83 @@ + + + + + + + +

    Owner Information

    + + + + + + + + + + + + + + + + + + + +
    Name
    Address
    City
    Telephone
    + + Edit + Owner + Add + New Pet + +
    +
    +
    +

    Pets and Visits

    + + + + + + + + +
    +
    +
    Name
    +
    +
    Birth Date
    +
    +
    Type
    +
    +
    +
    + + + + + + + + + + + + + + + +
    Visit DateDescription
    Edit + PetAdd + Visit
    +
    + + + + diff --git a/src/test/java/org/springframework/samples/petclinic/controller/VetControllerIntegrationTest.java b/src/test/java/org/springframework/samples/petclinic/controller/VetControllerIntegrationTest.java index 840d84aa6..8e630a475 100644 --- a/src/test/java/org/springframework/samples/petclinic/controller/VetControllerIntegrationTest.java +++ b/src/test/java/org/springframework/samples/petclinic/controller/VetControllerIntegrationTest.java @@ -13,18 +13,13 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.samples.petclinic.common.CommonAttribute; import org.springframework.samples.petclinic.common.CommonEndPoint; import org.springframework.samples.petclinic.common.CommonView; -import org.springframework.samples.petclinic.dto.VetDTO; import org.springframework.samples.petclinic.dto.VetsDTO; -import org.springframework.samples.petclinic.model.Vet; import org.springframework.samples.petclinic.repository.VetRepository; import org.springframework.samples.petclinic.service.VetService; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import java.util.Objects; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/org/springframework/samples/petclinic/controller/VisitControllerIntegrationTest.java b/src/test/java/org/springframework/samples/petclinic/controller/VisitControllerIntegrationTest.java index 789128026..0ed46b527 100644 --- a/src/test/java/org/springframework/samples/petclinic/controller/VisitControllerIntegrationTest.java +++ b/src/test/java/org/springframework/samples/petclinic/controller/VisitControllerIntegrationTest.java @@ -10,7 +10,7 @@ import org.springframework.samples.petclinic.common.CommonEndPoint; import org.springframework.samples.petclinic.common.CommonView; import org.springframework.samples.petclinic.dto.PetDTO; import org.springframework.samples.petclinic.dto.VisitDTO; -import org.springframework.samples.petclinic.model.Visit; +import org.springframework.samples.petclinic.model.business.Visit; import org.springframework.samples.petclinic.repository.VisitRepository; import org.springframework.samples.petclinic.service.PetService; import org.springframework.test.web.servlet.MockMvc; diff --git a/src/test/java/org/springframework/samples/petclinic/controller/VisitControllerTest.java b/src/test/java/org/springframework/samples/petclinic/controller/VisitControllerTest.java index 5679e4624..ca39cb720 100644 --- a/src/test/java/org/springframework/samples/petclinic/controller/VisitControllerTest.java +++ b/src/test/java/org/springframework/samples/petclinic/controller/VisitControllerTest.java @@ -39,7 +39,7 @@ import org.springframework.samples.petclinic.common.CommonView; import org.springframework.samples.petclinic.dto.PetDTO; import org.springframework.samples.petclinic.dto.PetTypeDTO; import org.springframework.samples.petclinic.dto.VisitDTO; -import org.springframework.samples.petclinic.model.Visit; +import org.springframework.samples.petclinic.model.business.Visit; import org.springframework.samples.petclinic.service.PetService; import org.springframework.samples.petclinic.service.VisitService; import org.springframework.test.web.servlet.MockMvc; diff --git a/src/test/java/org/springframework/samples/petclinic/formater/PetTypeDTOFormatterTest.java b/src/test/java/org/springframework/samples/petclinic/formater/PetTypeDTOFormatterTest.java index ab9b23748..7aa7f2d3c 100644 --- a/src/test/java/org/springframework/samples/petclinic/formater/PetTypeDTOFormatterTest.java +++ b/src/test/java/org/springframework/samples/petclinic/formater/PetTypeDTOFormatterTest.java @@ -24,9 +24,8 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.samples.petclinic.dto.PetTypeDTO; import org.springframework.samples.petclinic.formatter.PetTypeFormatter; -import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.model.business.PetType; import org.springframework.samples.petclinic.service.PetService; -import org.springframework.samples.petclinic.service.PetTypeService; import java.text.ParseException; import java.util.ArrayList; diff --git a/src/test/java/org/springframework/samples/petclinic/formater/PetTypeFormatterTest.java b/src/test/java/org/springframework/samples/petclinic/formater/PetTypeFormatterTest.java index 6404a7142..7aecc89d8 100644 --- a/src/test/java/org/springframework/samples/petclinic/formater/PetTypeFormatterTest.java +++ b/src/test/java/org/springframework/samples/petclinic/formater/PetTypeFormatterTest.java @@ -30,9 +30,8 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.samples.petclinic.dto.PetTypeDTO; import org.springframework.samples.petclinic.formatter.PetTypeFormatter; -import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.model.business.PetType; import org.springframework.samples.petclinic.service.PetService; -import org.springframework.samples.petclinic.service.PetTypeService; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; diff --git a/src/test/java/org/springframework/samples/petclinic/model/VetTest.java b/src/test/java/org/springframework/samples/petclinic/model/VetTest.java index 65b50f5f7..bc3c317a8 100644 --- a/src/test/java/org/springframework/samples/petclinic/model/VetTest.java +++ b/src/test/java/org/springframework/samples/petclinic/model/VetTest.java @@ -16,6 +16,7 @@ package org.springframework.samples.petclinic.model; import org.junit.jupiter.api.Test; +import org.springframework.samples.petclinic.model.business.Vet; import org.springframework.util.SerializationUtils; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTest.java b/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTest.java index 691702635..3a72dd174 100644 --- a/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTest.java +++ b/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTest.java @@ -25,14 +25,14 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.ComponentScan; -import org.springframework.samples.petclinic.model.Owner; +import org.springframework.samples.petclinic.model.business.Owner; import org.springframework.samples.petclinic.repository.OwnerRepository; -import org.springframework.samples.petclinic.model.Pet; +import org.springframework.samples.petclinic.model.business.Pet; import org.springframework.samples.petclinic.repository.PetRepository; -import org.springframework.samples.petclinic.model.PetType; -import org.springframework.samples.petclinic.model.Vet; +import org.springframework.samples.petclinic.model.business.PetType; +import org.springframework.samples.petclinic.model.business.Vet; import org.springframework.samples.petclinic.repository.VetRepository; -import org.springframework.samples.petclinic.model.Visit; +import org.springframework.samples.petclinic.model.business.Visit; import org.springframework.samples.petclinic.repository.VisitRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/src/test/java/org/springframework/samples/petclinic/service/EntityUtils.java b/src/test/java/org/springframework/samples/petclinic/service/EntityUtils.java index ca8bc41fc..89cacb8d1 100644 --- a/src/test/java/org/springframework/samples/petclinic/service/EntityUtils.java +++ b/src/test/java/org/springframework/samples/petclinic/service/EntityUtils.java @@ -19,7 +19,7 @@ package org.springframework.samples.petclinic.service; import java.util.Collection; import org.springframework.orm.ObjectRetrievalFailureException; -import org.springframework.samples.petclinic.model.BaseEntity; +import org.springframework.samples.petclinic.model.common.BaseEntity; /** * Utility methods for handling entities. Separate from the BaseEntity class mainly @@ -27,7 +27,7 @@ import org.springframework.samples.petclinic.model.BaseEntity; * * @author Juergen Hoeller * @author Sam Brannen - * @see org.springframework.samples.petclinic.model.BaseEntity + * @see BaseEntity * @since 29.10.2003 */ public abstract class EntityUtils { diff --git a/src/test/java/org/springframework/samples/petclinic/service/OwnerServiceTest.java b/src/test/java/org/springframework/samples/petclinic/service/OwnerServiceTest.java index 3cbcc62a3..f3c1dfbe1 100644 --- a/src/test/java/org/springframework/samples/petclinic/service/OwnerServiceTest.java +++ b/src/test/java/org/springframework/samples/petclinic/service/OwnerServiceTest.java @@ -12,9 +12,9 @@ import org.springframework.samples.petclinic.common.CommonAttribute; import org.springframework.samples.petclinic.dto.OwnerDTO; import org.springframework.samples.petclinic.dto.PetDTO; import org.springframework.samples.petclinic.dto.PetTypeDTO; -import org.springframework.samples.petclinic.model.Owner; -import org.springframework.samples.petclinic.model.Pet; -import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.model.business.Owner; +import org.springframework.samples.petclinic.model.business.Pet; +import org.springframework.samples.petclinic.model.business.PetType; import org.springframework.samples.petclinic.repository.OwnerRepository; import org.springframework.samples.petclinic.repository.PetRepository; import org.springframework.samples.petclinic.repository.PetTypeRepository; diff --git a/src/test/java/org/springframework/samples/petclinic/service/PetServiceTest.java b/src/test/java/org/springframework/samples/petclinic/service/PetServiceTest.java index be23962d6..e599eca39 100644 --- a/src/test/java/org/springframework/samples/petclinic/service/PetServiceTest.java +++ b/src/test/java/org/springframework/samples/petclinic/service/PetServiceTest.java @@ -8,13 +8,12 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.ComponentScan; -import org.springframework.samples.petclinic.common.CommonAttribute; import org.springframework.samples.petclinic.dto.OwnerDTO; import org.springframework.samples.petclinic.dto.PetDTO; import org.springframework.samples.petclinic.dto.PetTypeDTO; -import org.springframework.samples.petclinic.model.Owner; -import org.springframework.samples.petclinic.model.Pet; -import org.springframework.samples.petclinic.model.PetType; +import org.springframework.samples.petclinic.model.business.Owner; +import org.springframework.samples.petclinic.model.business.Pet; +import org.springframework.samples.petclinic.model.business.PetType; import org.springframework.samples.petclinic.repository.PetRepository; import org.springframework.samples.petclinic.repository.PetTypeRepository; import org.springframework.samples.petclinic.repository.VisitRepository; diff --git a/src/test/java/org/springframework/samples/petclinic/service/VetServiceTest.java b/src/test/java/org/springframework/samples/petclinic/service/VetServiceTest.java index 1528f281d..cbe2c985f 100644 --- a/src/test/java/org/springframework/samples/petclinic/service/VetServiceTest.java +++ b/src/test/java/org/springframework/samples/petclinic/service/VetServiceTest.java @@ -9,7 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.ComponentScan; import org.springframework.samples.petclinic.dto.VetDTO; -import org.springframework.samples.petclinic.model.Vet; +import org.springframework.samples.petclinic.model.business.Vet; import org.springframework.samples.petclinic.repository.SpecialtyRepository; import org.springframework.samples.petclinic.repository.VetRepository; import org.springframework.stereotype.Service; diff --git a/src/test/java/org/springframework/samples/petclinic/validator/ValidatorTest.java b/src/test/java/org/springframework/samples/petclinic/validator/ValidatorTest.java index 79b06ff6f..698863cde 100644 --- a/src/test/java/org/springframework/samples/petclinic/validator/ValidatorTest.java +++ b/src/test/java/org/springframework/samples/petclinic/validator/ValidatorTest.java @@ -24,7 +24,7 @@ import javax.validation.Validator; import org.junit.jupiter.api.Test; import org.springframework.context.i18n.LocaleContextHolder; -import org.springframework.samples.petclinic.model.Person; +import org.springframework.samples.petclinic.model.common.Person; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import static org.assertj.core.api.Assertions.assertThat;