mirror of
https://github.com/spring-projects/spring-petclinic.git
synced 2025-07-22 15:25:49 +00:00
add login by email and social login
This commit is contained in:
parent
446d06ec46
commit
285e018b1a
69 changed files with 1809 additions and 77 deletions
53
pom.xml
53
pom.xml
|
@ -41,6 +41,7 @@
|
|||
<modelmapper.version>2.3.8</modelmapper.version>
|
||||
<nohttp-checkstyle.version>0.0.4.RELEASE</nohttp-checkstyle.version>
|
||||
<spring-format.version>0.0.25</spring-format.version>
|
||||
<spring-cloud-starter-security.version>2.2.4.RELEASE</spring-cloud-starter-security.version>
|
||||
</properties>
|
||||
|
||||
<!-- ===================================================================== -->
|
||||
|
@ -87,6 +88,15 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-security</artifactId>
|
||||
<version>${spring-cloud-starter-security.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- ========================================================= DATABASES -->
|
||||
<dependency>
|
||||
|
@ -158,12 +168,50 @@
|
|||
<version>${webjars-sockjs-client.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- =========================================== THYMELEAF SECURITY -->
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf.extras</groupId>
|
||||
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
|
||||
<version>3.0.4.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- OAuth2 Client -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-oauth2-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-oauth2-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-oauth2-jose</artifactId>
|
||||
<version>5.3.4.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT library -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>0.9.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- =========================================================== TESTING -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
@ -176,6 +224,11 @@
|
|||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>5.3.3.RELEASE</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!-- ===================================================================== -->
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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";
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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<String> clients = Arrays.asList("google", "facebook", "github");
|
||||
|
||||
@Bean
|
||||
public ClientRegistrationRepository clientRegistrationRepository() {
|
||||
List<ClientRegistration> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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<String, String> oauth2AuthenticationUrls = new HashMap<>();
|
||||
|
||||
@Autowired
|
||||
private ClientRegistrationRepository clientRegistrationRepository;
|
||||
|
||||
@Autowired
|
||||
private OAuth2AuthorizedClientService authorizedClientService;
|
||||
|
||||
@GetMapping(CommonEndPoint.REGISTER)
|
||||
public String initCreationForm(Map<String, Object> 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<String, Object> model) {
|
||||
|
||||
if (model.containsKey(CommonAttribute.USER)) {
|
||||
return CommonView.HOME;
|
||||
}
|
||||
else {
|
||||
UserDTO user = new UserDTO();
|
||||
model.put(CommonAttribute.USER, user);
|
||||
}
|
||||
|
||||
Iterable<ClientRegistration> clientRegistrations = null;
|
||||
ResolvableType type = ResolvableType.forInstance(clientRegistrationRepository).as(Iterable.class);
|
||||
|
||||
if (type != ResolvableType.NONE && ClientRegistration.class.isAssignableFrom(type.resolveGenerics()[0])) {
|
||||
clientRegistrations = (Iterable<ClientRegistration>) 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
||||
}
|
|
@ -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<RoleDTO> 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<RoleDTO> getRolesInternal() {
|
||||
if (this.roles == null) {
|
||||
this.roles = new HashSet<>();
|
||||
}
|
||||
return this.roles;
|
||||
}
|
||||
|
||||
protected void setRolesInternal(Set<RoleDTO> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public List<RoleDTO> getRoles() {
|
||||
List<RoleDTO> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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.
|
|
@ -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.
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
@ -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.
|
|
@ -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;
|
|
@ -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.
|
|
@ -0,0 +1,7 @@
|
|||
package org.springframework.samples.petclinic.model.common;
|
||||
|
||||
public enum AuthProvider {
|
||||
|
||||
local, facebook, google, github
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
@ -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;
|
|
@ -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() {
|
|
@ -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 {
|
||||
|
||||
}
|
|
@ -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<Role> 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<Role> getRolesInternal() {
|
||||
if (this.roles == null) {
|
||||
this.roles = new HashSet<>();
|
||||
}
|
||||
return this.roles;
|
||||
}
|
||||
|
||||
protected void setRolesInternal(Set<Role> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public List<Role> getRoles() {
|
||||
List<Role> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 <code>Role</code> 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<Role, Integer> {
|
||||
|
||||
/**
|
||||
* 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<Role> 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);
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 <code>User</code> 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, Integer> {
|
||||
|
||||
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<User> 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);
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 <code>Visit</code> domain objects All method names are compliant
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<Role, RoleDTO> {
|
||||
|
||||
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<RoleDTO> entitiesToDTOS(List<Role> entities) {
|
||||
List<RoleDTO> dtos = new ArrayList<>();
|
||||
|
||||
entities.forEach(entity -> dtos.add(entityToDTO(entity)));
|
||||
|
||||
return dtos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Role> dtosToEntities(List<RoleDTO> dtos) {
|
||||
List<Role> 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<RoleDTO> 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));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.springframework.samples.petclinic.service;
|
||||
|
||||
public interface SecurityService {
|
||||
|
||||
String findLoggedInUsername();
|
||||
|
||||
void autoLogin(String email, String motDePasse);
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<GrantedAuthority> 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);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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<User, UserDTO> {
|
||||
|
||||
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<UserDTO> entitiesToDTOS(List<User> entities) {
|
||||
List<UserDTO> dtos = new ArrayList<>();
|
||||
|
||||
entities.forEach(entity -> dtos.add(entityToDTO(entity)));
|
||||
|
||||
return dtos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<User> dtosToEntities(List<UserDTO> dtos) {
|
||||
List<User> 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<UserDTO> findAll() {
|
||||
List<User> 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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=<your client id>
|
||||
#spring.security.oauth2.client.registration.facebook.client-secret=<your client secret>
|
||||
|
||||
|
||||
#spring.security.oauth2.client.registration.twitter.client-id=<your client id>
|
||||
#spring.security.oauth2.client.registration.twitter.client-secret=<your client secret>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
#footer {
|
||||
position:absolute;
|
||||
bottom:0;
|
||||
width:100%;
|
||||
height:60px; /* Height of the footer */
|
||||
background:#6cf;
|
||||
}
|
141
src/main/resources/static/resources/css/style.css
Normal file
141
src/main/resources/static/resources/css/style.css
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -9,6 +9,8 @@
|
|||
<div class="col-sm-10">
|
||||
<div th:switch="${type}">
|
||||
<input th:case="'text'" class="form-control" type="text" th:field="*{__${name}__}" />
|
||||
<input th:case="'password'" class="form-control" type="password" th:field="*{__${name}__}" />
|
||||
<input th:case="'email'" class="form-control" type="email" th:field="*{__${name}__}" />
|
||||
<input th:case="'date'" class="form-control" type="text" th:field="*{__${name}__}"
|
||||
placeholder="YYYY-MM-DD" title="Enter a date in this format: YYYY-MM-DD"
|
||||
pattern="(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))"/>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" th:href="@{/resources/css/petclinic.css}" />
|
||||
<link rel="stylesheet" th:href="@{/resources/static/css/style.css}" />
|
||||
|
||||
<!--link rel="stylesheet" th:href="@{/resources/css/style.css}" /-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -69,12 +69,24 @@
|
|||
<span>Veterinarians</span>
|
||||
</li>
|
||||
|
||||
<li
|
||||
th:replace="::menuItem ('/oups','error','trigger a RuntimeException to see how it is handled','warning-sign','Error')">
|
||||
<li th:replace="::menuItem ('/oups','error','trigger a RuntimeException to see how it is handled','warning-sign','Error')">
|
||||
<span class="glyphicon glyphicon-warning-sign" aria-hidden="true"></span>
|
||||
<span>Error</span>
|
||||
</li>
|
||||
|
||||
<li th:replace="::menuItem ('/login','user','login for known users','log-in','Login')" sec:authorize="!isAuthenticated()">
|
||||
<span class="glyphicon glyphicon-log-in" aria-hidden="true"></span>
|
||||
<span>Sign In</span>
|
||||
</li>
|
||||
<li th:replace="::menuItem ('/logout','user','logout','log-out','Logout')" sec:authorize="isAuthenticated()">
|
||||
<span class="glyphicon glyphicon-log-out" aria-hidden="true"></span>
|
||||
<span>Logout</span>
|
||||
</li>
|
||||
<li th:replace="::menuItem ('/users/edit','user','Edit user profile','user','Profile')" sec:authorize="isAuthenticated()">
|
||||
<span class="glyphicon glyphicon-user" aria-hidden="true"></span>
|
||||
<span>My account</span>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
49
src/main/resources/templates/login.html
Normal file
49
src/main/resources/templates/login.html
Normal file
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="https://www.thymeleaf.org"
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'users')}">
|
||||
|
||||
<body>
|
||||
|
||||
<h2 style="text-align:center">Login Manually</h2>
|
||||
|
||||
<form th:object="${user}" class="form-horizontal" id="login-user-form" method="post">
|
||||
<div class="form-group has-feedback">
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Email', 'email', 'email')}" />
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Password', 'password', 'password')}" />
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button class="btn btn-default" type="submit">Login</button>
|
||||
<a href="/register" class="btn btn-default" ><span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
|
||||
<span>Register</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<h2 style="text-align:center">Login with Social Media</h2>
|
||||
|
||||
<div class="row col-md-12">
|
||||
<div class="col-md-6 offset-md-3" th:each="url : ${urls}" >
|
||||
<a th:if="${url.key == 'Google'}" th:href="${url.value}" class="btn btn-bloc" style="background-color: #dd4b39;color: white">
|
||||
<i class="fa fa-google fa-fw"></i> Login with Google
|
||||
</a>
|
||||
<a th:if="${url.key == 'Twitter'}" th:href="${url.value}" class="btn btn-bloc" style="background-color: #55ACEE;color: white">
|
||||
<i class="fa fa-twitter fa-fw"></i> Login with Twitter
|
||||
</a>
|
||||
<a th:if="${url.key == 'GitHub'}" th:href="${url.value}" class="btn btn-bloc" style="background-color: white;color: black">
|
||||
<i class="fa fa-github fa-fw"></i> Login with Github
|
||||
</a>
|
||||
<a th:if="${url.key == 'Facebook'}" th:href="${url.value}" class="btn btn-bloc" style="background-color: #3B5998;color: white">
|
||||
<i class="fa fa-facebook fa-fw"></i> Login with Facebook
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<html xmlns:th="https://www.thymeleaf.org"
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'users')}">
|
||||
|
||||
<body>
|
||||
|
||||
<h2>User</h2>
|
||||
<form th:object="${user}" class="form-horizontal" id="add-user-form" method="post">
|
||||
<div class="form-group has-feedback">
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('First Name', 'firstName', 'text')}" />
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Last Name', 'lastName', 'text')}" />
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Password', 'password', 'password')}" />
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Repeat password', 'matchingPassword', 'password')}" />
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Email', 'email', 'email')}" />
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Phone', 'telephone', 'text')}" />
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Address', 'street1', 'text')}" />
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Address', 'street2', 'text')}" />
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Address', 'street3', 'text')}" />
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('City', 'city', 'text')}" />
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Zip code', 'zipCode', 'text')}" />
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Country', 'country', 'text')}" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button
|
||||
th:with="text=${user['new']} ? 'Register' : 'Update User'"
|
||||
class="btn btn-default" type="submit" th:text="${text}">Add User</button>
|
||||
<a class="btn btn-default" href="/">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
83
src/main/resources/templates/users/userDetails.html
Normal file
83
src/main/resources/templates/users/userDetails.html
Normal file
|
@ -0,0 +1,83 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="https://www.thymeleaf.org"
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
<h2>Owner Information</h2>
|
||||
|
||||
|
||||
<table class="table table-striped" th:object="${owner}">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<td><b th:text="*{firstName + ' ' + lastName}"></b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Address</th>
|
||||
<td th:text="*{address}"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>City</th>
|
||||
<td th:text="*{city}"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Telephone</th>
|
||||
<td th:text="*{telephone}"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<a th:href="@{{id}/edit(id=${owner.id})}" class="btn btn-default">Edit
|
||||
Owner</a>
|
||||
<a th:href="@{{id}/pets/new(id=${owner.id})}" class="btn btn-default">Add
|
||||
New Pet</a>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<h2>Pets and Visits</h2>
|
||||
|
||||
<table class="table table-striped">
|
||||
|
||||
<tr th:each="pet : ${owner.pets}">
|
||||
<td valign="top">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>Name</dt>
|
||||
<dd th:text="${pet.name}"></dd>
|
||||
<dt>Birth Date</dt>
|
||||
<dd
|
||||
th:text="${#temporals.format(pet.birthDate, 'yyyy-MM-dd')}"></dd>
|
||||
<dt>Type</dt>
|
||||
<dd th:text="${pet.type}"></dd>
|
||||
</dl>
|
||||
</td>
|
||||
<td valign="top">
|
||||
<table class="table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Visit Date</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr th:each="visit : ${pet.visits}">
|
||||
<td th:text="${#temporals.format(visit.date, 'yyyy-MM-dd')}"></td>
|
||||
<td th:text="${visit?.description}"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a
|
||||
th:href="@{{ownerId}/pets/{petId}/edit(ownerId=${owner.id},petId=${pet.id})}">Edit
|
||||
Pet</a></td>
|
||||
<td><a
|
||||
th:href="@{{ownerId}/pets/{petId}/visits/new(ownerId=${owner.id},petId=${pet.id})}">Add
|
||||
Visit</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue