mirror of
https://github.com/spring-projects/spring-petclinic.git
synced 2025-07-22 15:25:49 +00:00
add password modification
This commit is contained in:
parent
285e018b1a
commit
47866a9f5d
65 changed files with 1632 additions and 250 deletions
7
pom.xml
7
pom.xml
|
@ -98,6 +98,13 @@
|
|||
<version>${spring-cloud-starter-security.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- ============================================================ MAIL -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- ========================================================= DATABASES -->
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.springframework.samples.petclinic.common;
|
|||
public final class CommonAttribute {
|
||||
|
||||
public static final String DESCRIPTION = "description";
|
||||
public static final String ID = "id";
|
||||
|
||||
public static final String NAME = "name";
|
||||
|
||||
|
@ -15,7 +16,7 @@ public final class CommonAttribute {
|
|||
|
||||
public static final String OWNER = "owner";
|
||||
|
||||
public static final String OWNER_ID = "id";
|
||||
public static final String OWNER_ID = "ownerId";
|
||||
|
||||
public static final String OWNER_LAST_NAME = "lastName";
|
||||
|
||||
|
@ -39,9 +40,11 @@ public final class CommonAttribute {
|
|||
|
||||
public static final String PET_TYPE = "type";
|
||||
|
||||
public static final String TOKEN = "token";
|
||||
|
||||
public static final String USER = "user";
|
||||
|
||||
public static final String USER_ID = "id";
|
||||
public static final String USER_ID = "userId";
|
||||
|
||||
public static final String VETS = "vets";
|
||||
|
||||
|
|
|
@ -25,7 +25,9 @@ public final class CommonEndPoint {
|
|||
|
||||
public static final String USERS_EDIT = "/users/edit";
|
||||
|
||||
public static final String USERS_ID_EDIT = "/users/{ownerId}/edit";
|
||||
public static final String USERS_ID_EDIT = "/users/{userId}/edit";
|
||||
|
||||
public static final String USERS_ID_EDIT_PASSWORD = "/users/{userId}/edit/password";
|
||||
|
||||
public static final String USERS_NEW = "/users/new";
|
||||
|
||||
|
@ -35,6 +37,8 @@ public final class CommonEndPoint {
|
|||
|
||||
public static final String OAUTH2_SUCCESS = "/oauth2/success";
|
||||
|
||||
public static final String CONFIRM_ACCOUNT = "/confirm-account";
|
||||
|
||||
public static final String LOGOUT = "/logout";
|
||||
|
||||
public static final String LOGOUT_SUCCESS = "/logout/success";
|
||||
|
|
|
@ -6,6 +6,8 @@ public class CommonParameter {
|
|||
|
||||
public static final int COUNTRY_MAX = 50;
|
||||
|
||||
public static final String DEFAULT_PROVIDER = "local";
|
||||
|
||||
public static final int EMAIL_MAX = 255;
|
||||
|
||||
public static final int EMAIL_MIN = 4;
|
||||
|
@ -32,6 +34,8 @@ public class CommonParameter {
|
|||
|
||||
public static final int STREET_MAX = 50;
|
||||
|
||||
public static final int TOKEN_EXPIRATION = 60 * 24;
|
||||
|
||||
public static final int ROLE_MAX = 10;
|
||||
|
||||
public static final int ZIP_MAX = 6;
|
||||
|
|
|
@ -23,7 +23,7 @@ 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_REGISTRATION = "users/userRegistrationForm";
|
||||
|
||||
public static final String USER_LOGIN = "/login";
|
||||
|
||||
|
@ -31,7 +31,9 @@ public final class CommonView {
|
|||
|
||||
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_UPDATE = "users/userUpdateForm";
|
||||
|
||||
public static final String USER_CHANGE_PASSWORD = "users/userChangePasswordForm";
|
||||
|
||||
public static final String USER_DETAILS = "users/userDetails";
|
||||
|
||||
|
@ -41,8 +43,6 @@ public final class CommonView {
|
|||
|
||||
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";
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
package org.springframework.samples.petclinic.configuration;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.ResourceBundleMessageSource;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||
import org.thymeleaf.ITemplateEngine;
|
||||
import org.thymeleaf.spring5.SpringTemplateEngine;
|
||||
import org.thymeleaf.templatemode.TemplateMode;
|
||||
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
|
||||
import org.thymeleaf.templateresolver.ITemplateResolver;
|
||||
import org.thymeleaf.templateresolver.StringTemplateResolver;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@Configuration
|
||||
public class MailConfig {
|
||||
|
||||
public static final String EMAIL_TEMPLATE_ENCODING = "UTF-8";
|
||||
|
||||
@Value("${spring.mail.host}")
|
||||
private String mailHost;
|
||||
|
||||
@Value("${spring.mail.port}")
|
||||
private String mailPort;
|
||||
|
||||
@Value("${spring.mail.protocol}")
|
||||
private String mailProtocol;
|
||||
|
||||
@Value("${spring.mail.username}")
|
||||
private String mailUsername;
|
||||
|
||||
@Value("${spring.mail.password}")
|
||||
private String mailPassword;
|
||||
|
||||
@Bean
|
||||
public JavaMailSender mailSender() {
|
||||
|
||||
final JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
|
||||
|
||||
// Basic mail sender configuration, based on emailconfig.properties
|
||||
mailSender.setHost(mailHost);
|
||||
mailSender.setPort(Integer.parseInt(mailPort));
|
||||
mailSender.setProtocol(mailProtocol);
|
||||
mailSender.setUsername(mailUsername);
|
||||
mailSender.setPassword(mailPassword);
|
||||
|
||||
return mailSender;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ResourceBundleMessageSource emailMessageSource() {
|
||||
final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
|
||||
messageSource.setBasename("mail/MailMessages");
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ITemplateEngine emailTemplateEngine() {
|
||||
final SpringTemplateEngine emailTemplateEngine = new SpringTemplateEngine();
|
||||
|
||||
// Resolver for TEXT emails
|
||||
emailTemplateEngine.addTemplateResolver(textTemplateResolver());
|
||||
// Resolver for HTML emails (except the editable one)
|
||||
emailTemplateEngine.addTemplateResolver(htmlTemplateResolver());
|
||||
// Resolver for HTML editable emails (which will be treated as a String)
|
||||
emailTemplateEngine.addTemplateResolver(stringTemplateResolver());
|
||||
// Message source, internationalization specific to emails
|
||||
emailTemplateEngine.setTemplateEngineMessageSource(emailMessageSource());
|
||||
|
||||
return emailTemplateEngine;
|
||||
}
|
||||
|
||||
private ITemplateResolver textTemplateResolver() {
|
||||
final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
|
||||
templateResolver.setOrder(Integer.valueOf(1));
|
||||
templateResolver.setResolvablePatterns(Collections.singleton("text/*"));
|
||||
templateResolver.setPrefix("/mail/");
|
||||
templateResolver.setSuffix(".txt");
|
||||
templateResolver.setTemplateMode(TemplateMode.TEXT);
|
||||
templateResolver.setCharacterEncoding(EMAIL_TEMPLATE_ENCODING);
|
||||
templateResolver.setCacheable(false);
|
||||
return templateResolver;
|
||||
}
|
||||
|
||||
private ITemplateResolver htmlTemplateResolver() {
|
||||
final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
|
||||
templateResolver.setOrder(Integer.valueOf(2));
|
||||
templateResolver.setResolvablePatterns(Collections.singleton("html/*"));
|
||||
templateResolver.setPrefix("/mail/");
|
||||
templateResolver.setSuffix(".html");
|
||||
templateResolver.setTemplateMode(TemplateMode.HTML);
|
||||
templateResolver.setCharacterEncoding(EMAIL_TEMPLATE_ENCODING);
|
||||
templateResolver.setCacheable(false);
|
||||
return templateResolver;
|
||||
}
|
||||
|
||||
private ITemplateResolver stringTemplateResolver() {
|
||||
final StringTemplateResolver templateResolver = new StringTemplateResolver();
|
||||
templateResolver.setOrder(Integer.valueOf(3));
|
||||
// No resolvable pattern, will simply process as a String template everything not
|
||||
// previously matched
|
||||
templateResolver.setTemplateMode("HTML5");
|
||||
templateResolver.setCacheable(false);
|
||||
return templateResolver;
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,6 @@ 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;
|
||||
|
@ -59,12 +58,13 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
// @formatter:off
|
||||
|
||||
http.authorizeRequests()
|
||||
.antMatchers("/").anonymous()
|
||||
.antMatchers("/login", "/logout", "/register").permitAll()
|
||||
.antMatchers("/").permitAll()
|
||||
.antMatchers("/login", "/logout", "/register","/confirm-account").permitAll()
|
||||
.antMatchers("/websocket/**", "/topic/**", "/app/**").permitAll()
|
||||
.antMatchers("/resources/**").permitAll()
|
||||
.antMatchers("/**").authenticated()
|
||||
.antMatchers("/h2-console/**").permitAll()
|
||||
.antMatchers("/**").authenticated()
|
||||
.antMatchers("/edit/**").authenticated()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
|
@ -94,10 +94,12 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
// @formatter:on
|
||||
}
|
||||
|
||||
private static final List<String> clients = Arrays.asList("google", "facebook", "github");
|
||||
|
||||
|
||||
@Bean
|
||||
public ClientRegistrationRepository clientRegistrationRepository() {
|
||||
List<String> clients = Arrays.asList("google", "facebook", "github");
|
||||
|
||||
List<ClientRegistration> registrations = clients.stream().map(c -> getRegistration(c))
|
||||
.filter(registration -> registration != null).collect(Collectors.toList());
|
||||
|
||||
|
@ -113,14 +115,14 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
|
||||
String clientSecret = env.getProperty(CLIENT_PROPERTY_KEY + client + ".client-secret");
|
||||
|
||||
if (client.equals(AuthProvider.google.name())) {
|
||||
if (client.equals("google")) {
|
||||
return CommonOAuth2Provider.GOOGLE.getBuilder(client).clientId(clientId).clientSecret(clientSecret).build();
|
||||
}
|
||||
if (client.equals(AuthProvider.facebook.name())) {
|
||||
if (client.equals("facebook")) {
|
||||
return CommonOAuth2Provider.FACEBOOK.getBuilder(client).clientId(clientId).clientSecret(clientSecret)
|
||||
.build();
|
||||
}
|
||||
if (client.equals(AuthProvider.github.name())) {
|
||||
if (client.equals("github")) {
|
||||
return CommonOAuth2Provider.GITHUB.getBuilder(client).clientId(clientId).clientSecret(clientSecret).build();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@ package org.springframework.samples.petclinic.controller;
|
|||
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.service.OwnerService;
|
||||
import org.springframework.samples.petclinic.service.VisitService;
|
||||
import org.springframework.samples.petclinic.service.business.OwnerService;
|
||||
import org.springframework.samples.petclinic.service.business.VisitService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
|
|
@ -19,8 +19,10 @@ 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.service.business.OwnerService;
|
||||
import org.springframework.samples.petclinic.service.business.PetService;
|
||||
import org.springframework.samples.petclinic.service.business.PetTypeService;
|
||||
import org.springframework.samples.petclinic.validator.PetDTOValidator;
|
||||
import org.springframework.samples.petclinic.service.*;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
|
|
@ -3,23 +3,15 @@ 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.data.repository.query.Param;
|
||||
import org.springframework.samples.petclinic.common.*;
|
||||
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.samples.petclinic.dto.common.CredentialDTO;
|
||||
import org.springframework.samples.petclinic.dto.common.MessageDTO;
|
||||
import org.springframework.samples.petclinic.dto.common.UserDTO;
|
||||
import org.springframework.samples.petclinic.service.common.*;
|
||||
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;
|
||||
|
@ -27,18 +19,16 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
|
|||
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.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -48,30 +38,25 @@ import java.util.Map;
|
|||
@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 CredentialService credentialService;
|
||||
|
||||
private final RoleService roleService;
|
||||
|
||||
private final SecurityServiceImpl securityService;
|
||||
|
||||
private final BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||
private final EmailService emailService;
|
||||
|
||||
public UserController(UserService userService, RoleService roleService, SecurityServiceImpl securityService,
|
||||
BCryptPasswordEncoder bCryptPasswordEncoder) {
|
||||
public UserController(UserService userService, CredentialService credentialService, RoleService roleService, SecurityServiceImpl securityService, EmailService emailService) {
|
||||
this.userService = userService;
|
||||
this.credentialService = credentialService;
|
||||
this.roleService = roleService;
|
||||
this.securityService = securityService;
|
||||
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
|
||||
this.emailService = emailService;
|
||||
}
|
||||
|
||||
|
||||
@InitBinder("user")
|
||||
public void setAllowedFields(WebDataBinder dataBinder) {
|
||||
dataBinder.setDisallowedFields(CommonAttribute.USER_ID);
|
||||
|
@ -89,36 +74,48 @@ public class UserController extends WebSocketSender {
|
|||
public String initCreationForm(Map<String, Object> model) {
|
||||
UserDTO user = new UserDTO();
|
||||
model.put(CommonAttribute.USER, user);
|
||||
return CommonView.USER_CREATE_OR_UPDATE;
|
||||
return CommonView.USER_REGISTRATION;
|
||||
}
|
||||
|
||||
@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;
|
||||
return CommonView.USER_REGISTRATION;
|
||||
}
|
||||
|
||||
try {
|
||||
userService.findByEmail(user.getEmail());
|
||||
if(userService.existByEmail(user.getEmail())) {
|
||||
result.rejectValue("email", "5", "Email already exist !");
|
||||
sendErrorMessage(CommonWebSocket.USER_CREATION_ERROR);
|
||||
return CommonView.USER_CREATE_OR_UPDATE;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return CommonView.USER_REGISTRATION;
|
||||
}
|
||||
|
||||
// set default role
|
||||
user.addRole(roleService.findByName(ROLE_USER));
|
||||
user.addRole(roleService.findByName("ROLE_USER"));
|
||||
|
||||
// encode password because we get clear password
|
||||
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
|
||||
user.setMatchingPassword(user.getPassword());
|
||||
|
||||
user.encode(user.getPassword());
|
||||
user = this.userService.save(user);
|
||||
sendSuccessMessage(CommonWebSocket.USER_CREATED);
|
||||
return CommonView.HOME + user.getId();
|
||||
|
||||
CredentialDTO credential = new CredentialDTO(user);
|
||||
credential = credentialService.save(credential);
|
||||
|
||||
sendSuccessMessage(CommonWebSocket.USER_CREATED);
|
||||
|
||||
// send confirmation mail
|
||||
MessageDTO message = new MessageDTO(
|
||||
user.getFirstName(), user.getLastName(),
|
||||
"admin@petclinic.com",
|
||||
user.getEmail(),
|
||||
"New connexion",
|
||||
"Your attempt to create new account. To confirm your account, please click here : ",
|
||||
"http://localhost:8080/confirm-account?token=" + credential.getToken());
|
||||
|
||||
// emailService.sendMailAsynch(message, Locale.getDefault());
|
||||
|
||||
log.info(message.toString());
|
||||
|
||||
return CommonView.HOME + user.getId();
|
||||
}
|
||||
|
||||
@GetMapping(CommonEndPoint.LOGIN)
|
||||
|
@ -140,7 +137,7 @@ public class UserController extends WebSocketSender {
|
|||
}
|
||||
|
||||
clientRegistrations.forEach(registration -> oauth2AuthenticationUrls.put(registration.getClientName(),
|
||||
authorizationRequestBaseUri + "/" + registration.getRegistrationId()));
|
||||
"oauth2/authorization/" + registration.getRegistrationId()));
|
||||
model.put("urls", oauth2AuthenticationUrls);
|
||||
|
||||
return CommonView.USER_LOGIN;
|
||||
|
@ -148,30 +145,85 @@ public class UserController extends WebSocketSender {
|
|||
|
||||
@GetMapping(CommonEndPoint.LOGIN_SUCCESS)
|
||||
public String postLogin(Model model, Authentication authentication) {
|
||||
UserDTO user = userService.findByEmail(authentication.getName());
|
||||
UserDTO user = (UserDTO) authentication.getPrincipal();
|
||||
|
||||
model.addAttribute(CommonAttribute.USER, user);
|
||||
String message = String.format(CommonWebSocket.USER_LOGGED_IN, user.getFirstName(), user.getLastName());
|
||||
sendSuccessMessage(message );
|
||||
sendSuccessMessage(message);
|
||||
|
||||
return CommonView.HOME;
|
||||
}
|
||||
|
||||
@GetMapping(CommonEndPoint.OAUTH2_SUCCESS)
|
||||
public String postLogin(Model model, OAuth2AuthenticationToken authentication) {
|
||||
String firstName = authentication.getPrincipal().getAttribute("given_name");
|
||||
String lastName = authentication.getPrincipal().getAttribute("family_name");
|
||||
|
||||
OAuth2AuthorizedClient client = authorizedClientService .loadAuthorizedClient(authentication.getAuthorizedClientRegistrationId(), authentication.getName());
|
||||
CredentialDTO credential = credentialService.findByAuthentication(authentication);
|
||||
|
||||
String userInfoEndpointUri = client.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri();
|
||||
if( credential.isNew()) {
|
||||
|
||||
UserDTO user = userService.findByEmail(authentication.getName());
|
||||
// first time authentification with this provider
|
||||
credential = credentialService.saveNew(authentication);
|
||||
String email = credential.getEmail();
|
||||
|
||||
if( user!=null) {
|
||||
model.addAttribute(CommonAttribute.USER, user);
|
||||
UserDTO user = userService.findByEmail(email);
|
||||
|
||||
String message = String.format(CommonWebSocket.USER_LOGGED_IN, user.getFirstName(), user.getLastName());
|
||||
if(user == null) {
|
||||
user = new UserDTO();
|
||||
user.setEmail(email);
|
||||
user.encode(credential.getPassword());
|
||||
user.setFirstName(firstName);
|
||||
user.setLastName(lastName);
|
||||
user.setEnabled(true);
|
||||
user.addRole(roleService.findByName("ROLE_USER"));
|
||||
user = userService.save(user);
|
||||
}
|
||||
|
||||
// send confirmation mail
|
||||
MessageDTO message = new MessageDTO(
|
||||
firstName, lastName,
|
||||
"admin@petclinic.com",
|
||||
credential.getEmail(),
|
||||
"New connexion from " + credential.getProvider(),
|
||||
"Your attempt to connect from " + credential.getProvider() + " To confirm this connection, please click the link below : ",
|
||||
"http://localhost:8080/confirm-account?token=" + credential.getToken());
|
||||
|
||||
log.info(message.toString());
|
||||
emailService.sendMailAsynch(message, Locale.getDefault());
|
||||
|
||||
// disconnect
|
||||
authentication.eraseCredentials();
|
||||
SecurityContextHolder.clearContext();
|
||||
|
||||
} else if( credential.isVerified()) {
|
||||
securityService.autoLogin(credential.getEmail(),credential.getPassword());
|
||||
String message = String.format(CommonWebSocket.USER_LOGGED_IN, firstName, lastName);
|
||||
sendSuccessMessage(message);
|
||||
}
|
||||
|
||||
|
||||
return CommonView.HOME;
|
||||
}
|
||||
|
||||
@RequestMapping(value = CommonEndPoint.CONFIRM_ACCOUNT, method = { RequestMethod.GET, RequestMethod.POST })
|
||||
public String confirmUserAccount(@RequestParam(CommonAttribute.TOKEN) String token, Model model) {
|
||||
CredentialDTO credential = credentialService.findByToken(token);
|
||||
|
||||
if (!credential.isNew() && credential.isNotExpired()) {
|
||||
credential.setVerified(true);
|
||||
credential.setToken("");
|
||||
credential.setExpiration(null);
|
||||
credential = credentialService.save(credential);
|
||||
|
||||
// find corresponding user
|
||||
UserDTO user = userService.findByEmail(credential.getEmail());
|
||||
|
||||
securityService.autoLogin(credential.getEmail(),credential.getPassword());
|
||||
model.addAttribute(CommonAttribute.USER, user);
|
||||
return CommonView.USER_UPDATE;
|
||||
}
|
||||
|
||||
return CommonView.HOME;
|
||||
}
|
||||
|
||||
|
@ -188,43 +240,48 @@ public class UserController extends WebSocketSender {
|
|||
|
||||
@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());
|
||||
try {
|
||||
UserDTO user = (UserDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
model.addAttribute(CommonAttribute.USER, user);
|
||||
return CommonView.USER_CREATE_OR_UPDATE;
|
||||
model.addAttribute(CommonAttribute.USER_ID, user.getId());
|
||||
return CommonView.USER_UPDATE;
|
||||
} catch (Exception exception) {
|
||||
// user don't have profile
|
||||
}
|
||||
|
||||
return CommonView.HOME;
|
||||
}
|
||||
|
||||
@PostMapping(CommonEndPoint.USERS_ID_EDIT)
|
||||
@PostMapping(CommonEndPoint.USERS_EDIT)
|
||||
public String processUpdateOwnerForm(@ModelAttribute(CommonAttribute.USER) @Valid UserDTO user,
|
||||
BindingResult result, @PathVariable("userId") int userId) {
|
||||
BindingResult result, Model model) {
|
||||
if (result.hasErrors()) {
|
||||
sendErrorMessage(CommonWebSocket.USER_UPDATED_ERROR);
|
||||
return CommonView.USER_CREATE_OR_UPDATE;
|
||||
return CommonView.USER_UPDATE;
|
||||
}
|
||||
else {
|
||||
user.setId(userId);
|
||||
this.userService.save(user);
|
||||
|
||||
if(!user.getPassword().equals(user.getMatchingPassword())) {
|
||||
sendErrorMessage(CommonWebSocket.USER_UPDATED_ERROR);
|
||||
return CommonView.USER_UPDATE;
|
||||
}
|
||||
|
||||
else {
|
||||
user = userService.save(user);
|
||||
|
||||
model.addAttribute(CommonAttribute.USER, user);
|
||||
sendSuccessMessage(CommonWebSocket.USER_UPDATED);
|
||||
return CommonView.USER_USERS_ID_R;
|
||||
return CommonView.HOME;
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping(CommonEndPoint.USERS_ID)
|
||||
public ModelAndView showOwner(@PathVariable("userId") int userId) {
|
||||
public ModelAndView showOwner(@PathVariable("userId") Integer userId) {
|
||||
ModelAndView modelAndView = new ModelAndView(CommonView.USER_DETAILS);
|
||||
UserDTO user = this.userService.findById(userId);
|
||||
|
||||
|
@ -232,4 +289,62 @@ public class UserController extends WebSocketSender {
|
|||
return modelAndView;
|
||||
}
|
||||
|
||||
@GetMapping("/user/{userId}/edit/password")
|
||||
public String editPassword(@PathVariable("userId") Integer userId, Model model){
|
||||
try {
|
||||
UserDTO operator = (UserDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
UserDTO user = userService.findById(userId);
|
||||
|
||||
if (user.equals(operator) || operator.getRoles().contains(roleService.findByName("ROLE_ADMIN"))) {
|
||||
model.addAttribute(CommonAttribute.USER, user);
|
||||
model.addAttribute(CommonAttribute.USER_ID, user.getId());
|
||||
return CommonView.USER_CHANGE_PASSWORD;
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
// user don't have profile
|
||||
}
|
||||
|
||||
return CommonView.HOME;
|
||||
}
|
||||
|
||||
@PostMapping("/user/{userId}/edit/password")
|
||||
public String updatePassword(@ModelAttribute(CommonAttribute.USER) @Valid UserDTO user, BindingResult bindingResult,
|
||||
@PathVariable(CommonAttribute.USER_ID) Integer userId,
|
||||
@Param("oldPassword") String oldPassword,
|
||||
@Param("newPassword") String newPassword,
|
||||
@Param("newMatchingPassword") String newMatchingPassword, Model model) {
|
||||
|
||||
// verify the matching with old password
|
||||
if(!user.matches(oldPassword)){
|
||||
bindingResult.rejectValue("password", "6", "Bad password !");
|
||||
model.addAttribute(CommonAttribute.USER, user);
|
||||
return CommonView.USER_CHANGE_PASSWORD;
|
||||
}
|
||||
|
||||
// verify matching between two password
|
||||
if(!newPassword.equals(newMatchingPassword)){
|
||||
bindingResult.rejectValue("password", "7", "Bad matching password !");
|
||||
model.addAttribute(CommonAttribute.USER, user);
|
||||
return CommonView.USER_CHANGE_PASSWORD;
|
||||
}
|
||||
|
||||
try {
|
||||
UserDTO operator = (UserDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
|
||||
if (user.equals(operator) || operator.getRoles().contains(roleService.findByName("ROLE_ADMIN"))) {
|
||||
// encode password
|
||||
user.encode(newPassword);
|
||||
user = userService.save(user);
|
||||
|
||||
model.addAttribute(CommonAttribute.USER, user);
|
||||
return CommonView.USER_UPDATE_R;
|
||||
}
|
||||
} catch (NullPointerException exception) {
|
||||
log.error(exception.getMessage());
|
||||
}
|
||||
|
||||
return CommonView.HOME;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ 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.VetsDTO;
|
||||
import org.springframework.samples.petclinic.service.VetService;
|
||||
import org.springframework.samples.petclinic.service.business.VetService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
|
|
@ -26,8 +26,8 @@ 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.service.PetService;
|
||||
import org.springframework.samples.petclinic.service.VisitService;
|
||||
import org.springframework.samples.petclinic.service.business.PetService;
|
||||
import org.springframework.samples.petclinic.service.business.VisitService;
|
||||
import org.springframework.samples.petclinic.validator.VisitDTOValidator;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package org.springframework.samples.petclinic.dto.common;
|
||||
|
||||
import org.springframework.samples.petclinic.dto.NamedDTO;
|
||||
|
||||
/**
|
||||
* Simple Data Transfert Object representing a Authorization Provider.
|
||||
*
|
||||
* @author Paul-Emmanuel DOS SANTOS FACAO
|
||||
*/
|
||||
public class AuthProviderDTO extends NamedDTO {
|
||||
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
package org.springframework.samples.petclinic.dto.common;
|
||||
|
||||
import org.springframework.samples.petclinic.common.CommonError;
|
||||
import org.springframework.samples.petclinic.common.CommonParameter;
|
||||
import org.springframework.samples.petclinic.dto.BaseDTO;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Simple Data Transfert Object representing a Credential.
|
||||
*
|
||||
* @author Paul-Emmanuel DOS SANTOS FACAO
|
||||
*/
|
||||
public class CredentialDTO extends BaseDTO {
|
||||
|
||||
@NotNull
|
||||
private String provider;
|
||||
|
||||
@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)
|
||||
private String email;
|
||||
|
||||
@NotNull
|
||||
private Boolean verified;
|
||||
|
||||
private String token;
|
||||
|
||||
private Date expiration;
|
||||
|
||||
@NotNull
|
||||
@Size(min = CommonParameter.PASSWORD_MIN, max = CommonParameter.PASSWORD_MAX, message = CommonError.FORMAT_BETWEEN
|
||||
+ CommonParameter.PASSWORD_MIN + " AND " + CommonParameter.PASSWORD_MAX + " !")
|
||||
private String password;
|
||||
|
||||
public CredentialDTO(UserDTO user) {
|
||||
this.verified = false;
|
||||
this.setToken();
|
||||
this.setExpiration();
|
||||
this.setProvider(CommonParameter.DEFAULT_PROVIDER);
|
||||
this.email = user.getEmail();
|
||||
this.password = user.getId().toString();
|
||||
}
|
||||
|
||||
public String getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
public void setProvider(String provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public void setDefaultProvider() {
|
||||
this.provider = CommonParameter.DEFAULT_PROVIDER;
|
||||
}
|
||||
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public Boolean isVerified() {
|
||||
return verified;
|
||||
}
|
||||
|
||||
public void setVerified(Boolean verified) {
|
||||
this.verified = verified;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public Date getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public void setExpiration(Date expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public void setExpiration() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(new Timestamp(cal.getTime().getTime()));
|
||||
cal.add(Calendar.MINUTE, CommonParameter.TOKEN_EXPIRATION);
|
||||
this.expiration = cal.getTime();
|
||||
}
|
||||
|
||||
public void setToken() {
|
||||
this.token = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public boolean isNotExpired() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(new Timestamp(cal.getTime().getTime()));
|
||||
|
||||
return this.expiration.after(Date.from(Instant.now()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
package org.springframework.samples.petclinic.dto.common;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.springframework.samples.petclinic.common.CommonError;
|
||||
import org.springframework.samples.petclinic.common.CommonParameter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class MessageDTO implements Serializable {
|
||||
|
||||
@NotNull
|
||||
@Size(min = CommonParameter.FIRSTNAME_MIN, max = CommonParameter.FIRSTNAME_MAX, message = CommonError.FORMAT_BETWEEN
|
||||
+ CommonParameter.FIRSTNAME_MIN + " AND " + CommonParameter.FIRSTNAME_MAX + " !")
|
||||
private String firstName;
|
||||
|
||||
@NotNull
|
||||
@Size(min = CommonParameter.LASTNAME_MIN, max = CommonParameter.LASTNAME_MAX, message = CommonError.FORMAT_BETWEEN
|
||||
+ CommonParameter.LASTNAME_MIN + " AND " + CommonParameter.LASTNAME_MAX + " !")
|
||||
private String lastName;
|
||||
|
||||
@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)
|
||||
private String from;
|
||||
|
||||
@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)
|
||||
private String to;
|
||||
|
||||
@NotNull
|
||||
private String subject;
|
||||
|
||||
@NotNull
|
||||
private String content;
|
||||
|
||||
private String link;
|
||||
|
||||
@JsonCreator
|
||||
public MessageDTO(@JsonProperty("firstName") String firstName, @JsonProperty("lastName") String lastName,
|
||||
@JsonProperty("from") String from, @JsonProperty("to") String to, @JsonProperty("subject") String subject,
|
||||
@JsonProperty("content") String content, @JsonProperty("link") String link) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.subject = subject;
|
||||
this.content = content;
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public void setFrom(String from) {
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
public String getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
public void setTo(String to) {
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
public String getSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
public void setSubject(String subject) {
|
||||
this.subject = subject;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getLink() {
|
||||
return link;
|
||||
}
|
||||
|
||||
public void setLink(String link) {
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MessageDTO{" +
|
||||
"first name='" + firstName + '\'' +
|
||||
", last name='" + lastName + '\'' +
|
||||
", from='" + from + '\'' +
|
||||
", to='" + to + '\'' +
|
||||
", subject='" + subject + '\'' +
|
||||
", content='" + content + '\'' +
|
||||
", link='" + link + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
package org.springframework.samples.petclinic.dto;
|
||||
package org.springframework.samples.petclinic.dto.common;
|
||||
|
||||
import org.springframework.samples.petclinic.dto.NamedDTO;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
@ -8,5 +10,4 @@ import java.io.Serializable;
|
|||
* @author Paul-Emmanuel DOS SANTOS FACAO
|
||||
*/
|
||||
public class RoleDTO extends NamedDTO implements Serializable {
|
||||
|
||||
}
|
|
@ -1,37 +1,48 @@
|
|||
package org.springframework.samples.petclinic.dto;
|
||||
package org.springframework.samples.petclinic.dto.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 org.springframework.samples.petclinic.dto.PersonDTO;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
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;
|
||||
public class UserDTO extends PersonDTO implements Serializable, UserDetails {
|
||||
|
||||
@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;
|
||||
@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;
|
||||
|
||||
private boolean enabled;
|
||||
private boolean accountNonExpired;
|
||||
private boolean accountNonLocked;
|
||||
private boolean credentialsNonExpired;
|
||||
|
||||
private Set<RoleDTO> roles;
|
||||
|
||||
|
||||
@Size(max = CommonParameter.PHONE_MAX, message = CommonError.FORMAT_LESS + CommonParameter.PHONE_MAX)
|
||||
// @Pattern(regexp = CommonParameter.PHONE_REGEXP, message = CommonError.PHONE_FORMAT)
|
||||
private String telephone;
|
||||
|
||||
@Size(max = CommonParameter.STREET_MAX, message = CommonError.FORMAT_LESS + CommonParameter.STREET_MAX + " !")
|
||||
private String street1;
|
||||
|
||||
|
@ -51,6 +62,28 @@ public class UserDTO extends PersonDTO implements Serializable {
|
|||
@Size(max = CommonParameter.COUNTRY_MAX, message = CommonError.FORMAT_LESS + CommonParameter.COUNTRY_MAX + " !")
|
||||
private String country;
|
||||
|
||||
public UserDTO() {
|
||||
super();
|
||||
this.enabled = false;
|
||||
this.accountNonLocked = true;
|
||||
this.accountNonExpired = true;
|
||||
this.credentialsNonExpired = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
@ -67,20 +100,49 @@ public class UserDTO extends PersonDTO implements Serializable {
|
|||
this.matchingPassword = matchingPassword;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getTelephone() {
|
||||
return telephone;
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return accountNonExpired;
|
||||
}
|
||||
|
||||
public void setTelephone(String telephone) {
|
||||
this.telephone = telephone;
|
||||
public void setAccountNonExpired(boolean accountNonExpired) {
|
||||
this.accountNonExpired = accountNonExpired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return accountNonLocked;
|
||||
}
|
||||
|
||||
public void setAccountNonLocked(boolean accountNonLocked) {
|
||||
this.accountNonLocked = accountNonLocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return credentialsNonExpired;
|
||||
}
|
||||
|
||||
public void setCredentialsNonExpired(boolean credentialsNonExpired) {
|
||||
this.credentialsNonExpired = credentialsNonExpired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
|
||||
|
||||
this.roles.forEach(role -> grantedAuthorities.add(new SimpleGrantedAuthority(role.getName())));
|
||||
|
||||
return grantedAuthorities;
|
||||
}
|
||||
|
||||
protected Set<RoleDTO> getRolesInternal() {
|
||||
|
@ -101,10 +163,27 @@ public class UserDTO extends PersonDTO implements Serializable {
|
|||
return Collections.unmodifiableList(sortedRoles);
|
||||
}
|
||||
|
||||
public int getNrOfRoles() {
|
||||
return getRolesInternal().size();
|
||||
}
|
||||
|
||||
public void addRole(RoleDTO role) {
|
||||
getRolesInternal().add(role);
|
||||
}
|
||||
|
||||
public void setRoles(Set<RoleDTO> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
public String getTelephone() {
|
||||
return telephone;
|
||||
}
|
||||
|
||||
public void setTelephone(String telephone) {
|
||||
this.telephone = telephone;
|
||||
}
|
||||
|
||||
|
||||
public String getStreet1() {
|
||||
return street1;
|
||||
}
|
||||
|
@ -153,4 +232,37 @@ public class UserDTO extends PersonDTO implements Serializable {
|
|||
this.country = country;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UserDTO{" +
|
||||
"email='" + email + '\'' +
|
||||
", password='" + password + '\'' +
|
||||
", matchingPassword='" + matchingPassword + '\'' +
|
||||
", user enabled=" + enabled +
|
||||
", account not expired=" + accountNonExpired +
|
||||
", account not locked=" + accountNonLocked +
|
||||
", credentials not xxpired=" + credentialsNonExpired +
|
||||
", roles=" + roles +
|
||||
", telephone='" + telephone + '\'' +
|
||||
", street1='" + street1 + '\'' +
|
||||
", street2='" + street2 + '\'' +
|
||||
", street3='" + street3 + '\'' +
|
||||
", zipCode='" + zipCode + '\'' +
|
||||
", city='" + city + '\'' +
|
||||
", country='" + country + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
public void encode(String rawPassword) {
|
||||
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
|
||||
|
||||
this.password = bCryptPasswordEncoder.encode(rawPassword);
|
||||
this.matchingPassword = this.password;
|
||||
}
|
||||
|
||||
public boolean matches(String rawPassword) {
|
||||
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
|
||||
|
||||
return bCryptPasswordEncoder.matches(rawPassword, this.password);
|
||||
}
|
||||
}
|
|
@ -21,8 +21,7 @@ import java.util.Locale;
|
|||
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.samples.petclinic.dto.PetTypeDTO;
|
||||
import org.springframework.samples.petclinic.service.PetService;
|
||||
import org.springframework.samples.petclinic.service.PetTypeService;
|
||||
import org.springframework.samples.petclinic.service.business.PetService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
package org.springframework.samples.petclinic.model.common;
|
||||
|
||||
public enum AuthProvider {
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
local, facebook, google, github
|
||||
/**
|
||||
* Class used to manage Authorization providers
|
||||
*
|
||||
* @author Paul-Emmanuel DOS SANTOS FACAO
|
||||
*/
|
||||
@Entity(name = "AuthProvider")
|
||||
@Table(name = "auth_providers")
|
||||
public class AuthProvider extends NamedEntity {
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
package org.springframework.samples.petclinic.model.common;
|
||||
|
||||
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 java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Class used to manage Credentials for users
|
||||
*
|
||||
* @author Paul-Emmanuel DOS SANTOS FACAO
|
||||
*/
|
||||
@Entity(name = "Credential")
|
||||
@Table(name = "credentials")
|
||||
public class Credential extends BaseEntity {
|
||||
private static final int TOKEN_EXPIRATION = 60 * 24;
|
||||
|
||||
@NotNull
|
||||
@Column(name = "provider_id")
|
||||
private Integer providerId;
|
||||
|
||||
@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", length = CommonParameter.EMAIL_MAX)
|
||||
private String email;
|
||||
|
||||
@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
|
||||
@Column(name = "verified")
|
||||
private Boolean verified;
|
||||
|
||||
@Column(name = "token")
|
||||
private String token;
|
||||
|
||||
@Column(name = "expiration")
|
||||
private Date expiration;
|
||||
|
||||
|
||||
public Integer getProviderId() {
|
||||
return providerId;
|
||||
}
|
||||
|
||||
public void setProviderId(Integer providerId) {
|
||||
this.providerId = providerId;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public Boolean isVerified() {
|
||||
return verified;
|
||||
}
|
||||
|
||||
public void setVerified(Boolean verified) {
|
||||
this.verified = verified;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public Date getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public void setExpiration(Date expirationDate) {
|
||||
this.expiration = expirationDate;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public void setExpiration() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(new Timestamp(cal.getTime().getTime()));
|
||||
cal.add(Calendar.MINUTE, TOKEN_EXPIRATION);
|
||||
this.expiration = cal.getTime();
|
||||
}
|
||||
|
||||
public void setToken() {
|
||||
this.token = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
package org.springframework.samples.petclinic.model.common;
|
||||
|
||||
import org.springframework.samples.petclinic.model.common.NamedEntity;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
|
|
@ -4,6 +4,9 @@ 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 org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
@ -20,7 +23,7 @@ import java.util.*;
|
|||
*/
|
||||
@Entity(name = "User")
|
||||
@Table(name = "users")
|
||||
public class User extends Person implements Serializable {
|
||||
public class User extends Person implements Serializable, UserDetails {
|
||||
|
||||
@NotNull
|
||||
@Size(min = CommonParameter.EMAIL_MIN, max = CommonParameter.EMAIL_MAX, message = CommonError.FORMAT_BETWEEN
|
||||
|
@ -29,34 +32,38 @@ public class User extends Person implements Serializable {
|
|||
@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 + " !")
|
||||
+ 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 = "enabled")
|
||||
private boolean enabled;
|
||||
|
||||
@Column(name = "provider_id")
|
||||
private String providerId;
|
||||
@NotNull
|
||||
@Column(name = "account_unexpired")
|
||||
private boolean accountNonExpired;
|
||||
|
||||
@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;
|
||||
@NotNull
|
||||
@Column(name = "account_unlocked")
|
||||
private boolean accountNonLocked;
|
||||
|
||||
@NotNull
|
||||
@Column(name = "credential_unexpired")
|
||||
private boolean credentialsNonExpired;
|
||||
|
||||
@ManyToMany(fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "role_id"))
|
||||
inverseJoinColumns = @JoinColumn(name = "role_id"))
|
||||
private Set<Role> roles;
|
||||
|
||||
@NotNull
|
||||
@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;
|
||||
|
||||
|
||||
@Size(max = CommonParameter.STREET_MAX, message = CommonError.FORMAT_LESS + CommonParameter.STREET_MAX + " !")
|
||||
@Column(name = "street1", length = CommonParameter.STREET_MAX)
|
||||
private String street1;
|
||||
|
@ -69,12 +76,10 @@ public class User extends Person implements Serializable {
|
|||
@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;
|
||||
|
@ -83,6 +88,11 @@ public class User extends Person implements Serializable {
|
|||
@Column(name = "country", length = CommonParameter.COUNTRY_MAX)
|
||||
private String country;
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
@ -91,14 +101,7 @@ public class User extends Person implements Serializable {
|
|||
this.email = email;
|
||||
}
|
||||
|
||||
public Boolean getEmailVerified() {
|
||||
return emailVerified;
|
||||
}
|
||||
|
||||
public void setEmailVerified(Boolean emailVerified) {
|
||||
this.emailVerified = emailVerified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
@ -107,28 +110,50 @@ public class User extends Person implements Serializable {
|
|||
this.password = password;
|
||||
}
|
||||
|
||||
public AuthProvider getProvider() {
|
||||
return provider;
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setProvider(AuthProvider provider) {
|
||||
this.provider = provider;
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getProviderId() {
|
||||
return providerId;
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return accountNonExpired;
|
||||
}
|
||||
|
||||
public void setProviderId(String providerId) {
|
||||
this.providerId = providerId;
|
||||
public void setAccountNonExpired(boolean accountNonExpired) {
|
||||
this.accountNonExpired = accountNonExpired;
|
||||
}
|
||||
|
||||
public String getTelephone() {
|
||||
return telephone;
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return accountNonLocked;
|
||||
}
|
||||
|
||||
public void setTelephone(String telephone) {
|
||||
this.telephone = telephone;
|
||||
public void setAccountNonLocked(boolean accountNonLocked) {
|
||||
this.accountNonLocked = accountNonLocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return credentialsNonExpired;
|
||||
}
|
||||
|
||||
public void setCredentialsNonExpired(boolean credentialsNonExpired) {
|
||||
this.credentialsNonExpired = credentialsNonExpired;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
|
||||
|
||||
this.roles.forEach(role -> grantedAuthorities.add(new SimpleGrantedAuthority(role.getName())));
|
||||
|
||||
return grantedAuthorities;
|
||||
}
|
||||
|
||||
protected Set<Role> getRolesInternal() {
|
||||
|
@ -157,6 +182,20 @@ public class User extends Person implements Serializable {
|
|||
getRolesInternal().add(role);
|
||||
}
|
||||
|
||||
|
||||
public void setRoles(Set<Role> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
public String getTelephone() {
|
||||
return telephone;
|
||||
}
|
||||
|
||||
public void setTelephone(String telephone) {
|
||||
this.telephone = telephone;
|
||||
}
|
||||
|
||||
|
||||
public String getStreet1() {
|
||||
return street1;
|
||||
}
|
||||
|
@ -205,4 +244,5 @@ public class User extends Person implements Serializable {
|
|||
this.country = country;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package org.springframework.samples.petclinic.repository;
|
||||
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.samples.petclinic.model.common.AuthProvider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Repository class for <code>AuthProvider</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 AuthProviderRepository extends Repository<AuthProvider, Integer> {
|
||||
|
||||
/**
|
||||
* Retrieve a {@link AuthProvider} from the data store by id.
|
||||
* @param providerId the id to search for
|
||||
* @return the {@link AuthProvider} if found
|
||||
*/
|
||||
AuthProvider findById(Integer providerId);
|
||||
|
||||
/**
|
||||
* Retrieve a {@link AuthProvider} from the data store by id.
|
||||
* @param providerName the name to search for
|
||||
* @return the {@link AuthProvider} if found
|
||||
*/
|
||||
AuthProvider findByName(String providerName);
|
||||
|
||||
/**
|
||||
* Retrieve all {@link AuthProvider}s from the data store
|
||||
* @return a Collection of {@link AuthProvider}s (or an empty Collection if none
|
||||
*/
|
||||
List<AuthProvider> findAll();
|
||||
|
||||
/**
|
||||
* Save a {@link AuthProvider} to the data store, either inserting or updating it.
|
||||
* @param authProvider the {@link AuthProvider} to save
|
||||
*/
|
||||
AuthProvider save(AuthProvider authProvider);
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package org.springframework.samples.petclinic.repository;
|
||||
|
||||
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.common.Credential;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Repository class for <code>Credential</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 CredentialRepository extends Repository<Credential, Integer> {
|
||||
|
||||
/**
|
||||
* Retrieve a {@link Credential} from the data store by email.
|
||||
* @param email the email to search for
|
||||
* @param providerId the provider to search for authorization
|
||||
* @return the {@link Credential} if found
|
||||
*/
|
||||
@Query("SELECT c FROM Credential c WHERE c.email = :email AND c.providerId = :providerId")
|
||||
@Transactional(readOnly = true)
|
||||
Credential findByEmailAndProvider(@Param("email") String email, @Param("providerId") Integer providerId);
|
||||
|
||||
/**
|
||||
* * Retrieve a {@link Credential} from the data store by token.
|
||||
* @param token the token to search for
|
||||
* @return the {@link Credential} if found
|
||||
*/
|
||||
@Query("SELECT DISTINCT c FROM Credential c WHERE c.token = :token")
|
||||
@Transactional(readOnly = true)
|
||||
Credential findByToken(@Param("token") String token);
|
||||
|
||||
/**
|
||||
* Retrieve all {@link Credential}s from the data store
|
||||
* @return a Collection of {@link Credential}s (or an empty Collection if none
|
||||
*/
|
||||
List<Credential> findAll();
|
||||
|
||||
/**
|
||||
* Save a {@link Credential} to the data store, either inserting or updating it.
|
||||
* @param credential the {@link Credential} to save
|
||||
*/
|
||||
Credential save(Credential credential);
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package org.springframework.samples.petclinic.service;
|
||||
package org.springframework.samples.petclinic.service.business;
|
||||
|
||||
import java.util.List;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.springframework.samples.petclinic.service;
|
||||
package org.springframework.samples.petclinic.service.business;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.modelmapper.internal.util.Lists;
|
|
@ -1,4 +1,4 @@
|
|||
package org.springframework.samples.petclinic.service;
|
||||
package org.springframework.samples.petclinic.service.business;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.samples.petclinic.dto.OwnerDTO;
|
|
@ -1,4 +1,4 @@
|
|||
package org.springframework.samples.petclinic.service;
|
||||
package org.springframework.samples.petclinic.service.business;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.samples.petclinic.dto.PetTypeDTO;
|
|
@ -1,4 +1,4 @@
|
|||
package org.springframework.samples.petclinic.service;
|
||||
package org.springframework.samples.petclinic.service.business;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.samples.petclinic.dto.SpecialtyDTO;
|
|
@ -1,4 +1,4 @@
|
|||
package org.springframework.samples.petclinic.service;
|
||||
package org.springframework.samples.petclinic.service.business;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.modelmapper.internal.util.Lists;
|
|
@ -1,4 +1,4 @@
|
|||
package org.springframework.samples.petclinic.service;
|
||||
package org.springframework.samples.petclinic.service.business;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.samples.petclinic.dto.VisitDTO;
|
|
@ -0,0 +1,87 @@
|
|||
package org.springframework.samples.petclinic.service.common;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.samples.petclinic.dto.common.AuthProviderDTO;
|
||||
import org.springframework.samples.petclinic.model.common.AuthProvider;
|
||||
import org.springframework.samples.petclinic.repository.AuthProviderRepository;
|
||||
import org.springframework.samples.petclinic.service.business.BaseService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Simple Service between AuthProvider entity and AuthProviderDTO Data Transfert Object.
|
||||
*
|
||||
* @author Paul-Emmanuel DOS SANTOS FACAO
|
||||
*/
|
||||
@Service("AuthProviderService")
|
||||
public class AuthProviderService implements BaseService<AuthProvider, AuthProviderDTO> {
|
||||
|
||||
private final AuthProviderRepository authProviderRepository;
|
||||
|
||||
private final ModelMapper modelMapper = new ModelMapper();
|
||||
|
||||
public AuthProviderService(AuthProviderRepository authProviderRepository) {
|
||||
this.authProviderRepository = authProviderRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthProvider dtoToEntity(AuthProviderDTO dto) {
|
||||
if (dto != null) {
|
||||
return modelMapper.map(dto, AuthProvider.class);
|
||||
}
|
||||
|
||||
return new AuthProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthProviderDTO entityToDTO(AuthProvider entity) {
|
||||
if (entity != null) {
|
||||
return modelMapper.map(entity, AuthProviderDTO.class);
|
||||
}
|
||||
|
||||
return new AuthProviderDTO();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuthProviderDTO> entitiesToDTOS(List<AuthProvider> entities) {
|
||||
List<AuthProviderDTO> dtos = new ArrayList<>();
|
||||
|
||||
entities.forEach(entity -> dtos.add(entityToDTO(entity)));
|
||||
|
||||
return dtos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuthProvider> dtosToEntities(List<AuthProviderDTO> dtos) {
|
||||
List<AuthProvider> entities = new ArrayList<>();
|
||||
|
||||
dtos.forEach(dto -> entities.add(dtoToEntity(dto)));
|
||||
|
||||
return entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthProviderDTO findById(int providerId) {
|
||||
return entityToDTO(authProviderRepository.findById(providerId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuthProviderDTO> findAll() {
|
||||
return entitiesToDTOS(authProviderRepository.findAll());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthProviderDTO save(AuthProviderDTO dto) {
|
||||
AuthProvider authProvider = dtoToEntity(dto);
|
||||
authProvider = authProviderRepository.save(authProvider);
|
||||
|
||||
return entityToDTO(authProvider);
|
||||
}
|
||||
|
||||
public AuthProviderDTO findByName(String providerName) {
|
||||
return entityToDTO(authProviderRepository.findByName(providerName));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
package org.springframework.samples.petclinic.service.common;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.samples.petclinic.common.CommonParameter;
|
||||
import org.springframework.samples.petclinic.dto.common.CredentialDTO;
|
||||
import org.springframework.samples.petclinic.dto.common.UserDTO;
|
||||
import org.springframework.samples.petclinic.model.common.AuthProvider;
|
||||
import org.springframework.samples.petclinic.model.common.Credential;
|
||||
import org.springframework.samples.petclinic.repository.AuthProviderRepository;
|
||||
import org.springframework.samples.petclinic.repository.CredentialRepository;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* Simple Service between User entity and UserDTO Data Transfert Object.
|
||||
*
|
||||
* @author Paul-Emmanuel DOS SANTOS FACAO
|
||||
*/
|
||||
@Service("CredentialService")
|
||||
public class CredentialService {
|
||||
|
||||
private final CredentialRepository credentialRepository;
|
||||
|
||||
private final BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||
|
||||
private final AuthProviderRepository authProviderRepository;
|
||||
|
||||
private final ModelMapper modelMapper = new ModelMapper();
|
||||
|
||||
public CredentialService(CredentialRepository credentialRepository, BCryptPasswordEncoder bCryptPasswordEncoder, AuthProviderRepository authProviderRepository) {
|
||||
this.credentialRepository = credentialRepository;
|
||||
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
|
||||
this.authProviderRepository = authProviderRepository;
|
||||
}
|
||||
|
||||
public Credential dtoToEntity(CredentialDTO dto) {
|
||||
if (dto != null) {
|
||||
Credential entity = modelMapper.map(dto, Credential.class);
|
||||
AuthProvider authProvider = authProviderRepository.findByName(dto.getProvider());
|
||||
if (authProvider == null) {
|
||||
authProvider = authProviderRepository.findByName(CommonParameter.DEFAULT_PROVIDER);
|
||||
}
|
||||
entity.setProviderId(authProvider.getId());
|
||||
return entity;
|
||||
}
|
||||
|
||||
return new Credential();
|
||||
}
|
||||
|
||||
public CredentialDTO entityToDTO(Credential entity) {
|
||||
if (entity != null) {
|
||||
CredentialDTO dto = modelMapper.map(entity, CredentialDTO.class);
|
||||
AuthProvider authProvider = authProviderRepository.findById(entity.getProviderId());
|
||||
|
||||
if (authProvider == null) {
|
||||
dto.setProvider(CommonParameter.DEFAULT_PROVIDER);
|
||||
}
|
||||
else {
|
||||
dto.setProvider(authProvider.getName());
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
return new CredentialDTO();
|
||||
}
|
||||
|
||||
public CredentialDTO findByEmailAndProvider(String email, String provider) {
|
||||
AuthProvider authProvider = authProviderRepository.findByName(provider);
|
||||
Credential credential = credentialRepository.findByEmailAndProvider(email, authProvider.getId());
|
||||
return entityToDTO(credential);
|
||||
}
|
||||
|
||||
public CredentialDTO findByToken(String token) {
|
||||
Credential credential = credentialRepository.findByToken(token);
|
||||
return entityToDTO(credential);
|
||||
}
|
||||
|
||||
public CredentialDTO findByAuthentication(OAuth2AuthenticationToken authentication) {
|
||||
String email = authentication.getPrincipal().getAttribute("email");
|
||||
String provider = authentication.getAuthorizedClientRegistrationId();
|
||||
|
||||
AuthProvider authProvider = authProviderRepository.findByName(provider);
|
||||
Credential credential = credentialRepository.findByEmailAndProvider(email, authProvider.getId());
|
||||
return entityToDTO(credential);
|
||||
}
|
||||
|
||||
|
||||
public CredentialDTO save(CredentialDTO dto) {
|
||||
Credential credential = dtoToEntity(dto);
|
||||
credential = credentialRepository.save(credential);
|
||||
return entityToDTO(credential);
|
||||
}
|
||||
|
||||
public CredentialDTO saveNew(UserDTO user) {
|
||||
Credential credential = new Credential();
|
||||
|
||||
AuthProvider authProvider = authProviderRepository.findByName(CommonParameter.DEFAULT_PROVIDER);
|
||||
|
||||
credential.setEmail(user.getEmail());
|
||||
credential.setProviderId(authProvider.getId());
|
||||
credential.setPassword(user.getPassword());
|
||||
credential.setVerified(false);
|
||||
credential.setToken();
|
||||
credential.setExpiration();
|
||||
|
||||
credential = credentialRepository.save(credential);
|
||||
return entityToDTO(credential);
|
||||
}
|
||||
|
||||
public CredentialDTO saveNew(OAuth2AuthenticationToken authentication) {
|
||||
Credential credential = new Credential();
|
||||
|
||||
AuthProvider authProvider = authProviderRepository.findByName(authentication.getAuthorizedClientRegistrationId());
|
||||
|
||||
credential.setEmail(authentication.getPrincipal().getAttribute("email"));
|
||||
credential.setProviderId(authProvider.getId());
|
||||
credential.setPassword(authentication.getPrincipal().getAttribute("sub"));
|
||||
credential.setVerified(false);
|
||||
credential.setToken();
|
||||
credential.setExpiration();
|
||||
|
||||
credential = credentialRepository.save(credential);
|
||||
return entityToDTO(credential);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package org.springframework.samples.petclinic.service.common;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
import org.springframework.samples.petclinic.dto.common.MessageDTO;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thymeleaf.ITemplateEngine;
|
||||
import org.thymeleaf.context.Context;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
@Slf4j
|
||||
@Service("EmailService")
|
||||
public class EmailService {
|
||||
|
||||
private static final String EMAIL_TEMPLATE = "email.html";
|
||||
|
||||
private static final String PNG_MIME = "image/png";
|
||||
|
||||
@Value("${mail.background}")
|
||||
private String mailBackground;
|
||||
|
||||
@Value("${mail.banner}")
|
||||
private String mailBanner;
|
||||
|
||||
@Value("${mail.logo}")
|
||||
private String mailLogo;
|
||||
|
||||
@Autowired
|
||||
protected JavaMailSender mailSender;
|
||||
|
||||
@Autowired
|
||||
protected ITemplateEngine templateEngine;
|
||||
|
||||
|
||||
/**
|
||||
* sendMailAsynch : for the controller MailController
|
||||
* send mail asynchronously
|
||||
*
|
||||
* @param messageDTO : message to be send by mail
|
||||
* @param locale : not used now
|
||||
*/
|
||||
@Async
|
||||
public void sendMailAsynch(MessageDTO messageDTO, Locale locale){
|
||||
sendMail(messageDTO, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* sendMail : build mail according to a Thymeleaf template and a MessageDTO object
|
||||
* @param messageDTO : message to be send by mail
|
||||
* @param locale : not used now
|
||||
*/
|
||||
public void sendMail(MessageDTO messageDTO, Locale locale) {
|
||||
MimeMessage mimeMessage = mailSender.createMimeMessage();
|
||||
MimeMessageHelper message;
|
||||
|
||||
// Prepare the evaluation context
|
||||
Context ctx = new Context(locale);
|
||||
ctx.setVariable("toFirstName", messageDTO.getFirstName());
|
||||
ctx.setVariable("toLastName", messageDTO.getLastName());
|
||||
ctx.setVariable("mailSubject", messageDTO.getSubject());
|
||||
ctx.setVariable("mailContent", messageDTO.getContent());
|
||||
ctx.setVariable("mailLink", messageDTO.getLink());
|
||||
ctx.setVariable("mailDate", new Date());
|
||||
|
||||
// Create the HTML body using Thymeleaf
|
||||
String output = templateEngine.process(EMAIL_TEMPLATE, ctx);
|
||||
|
||||
try {
|
||||
message = new MimeMessageHelper(mimeMessage, true /* multipart */, "UTF-8");
|
||||
|
||||
message.setFrom(messageDTO.getFrom());
|
||||
message.setTo(messageDTO.getTo());
|
||||
message.setSubject(messageDTO.getSubject());
|
||||
message.setText(output, true /* isHtml */);
|
||||
|
||||
message.addInline("mailBackground", new ClassPathResource(mailBackground), PNG_MIME);
|
||||
message.addInline("mailBanner", new ClassPathResource(mailBanner), PNG_MIME);
|
||||
message.addInline("mailLogo", new ClassPathResource(mailLogo), PNG_MIME);
|
||||
}
|
||||
catch (MessagingException ex) {
|
||||
log.error("Error sending mail !", ex);
|
||||
}
|
||||
|
||||
// Send mail
|
||||
this.mailSender.send(mimeMessage);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
package org.springframework.samples.petclinic.service;
|
||||
package org.springframework.samples.petclinic.service.common;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.samples.petclinic.dto.RoleDTO;
|
||||
import org.springframework.samples.petclinic.dto.common.RoleDTO;
|
||||
import org.springframework.samples.petclinic.model.common.Role;
|
||||
import org.springframework.samples.petclinic.repository.RoleRepository;
|
||||
import org.springframework.samples.petclinic.service.business.BaseService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
|
@ -1,4 +1,4 @@
|
|||
package org.springframework.samples.petclinic.service;
|
||||
package org.springframework.samples.petclinic.service.common;
|
||||
|
||||
public interface SecurityService {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.springframework.samples.petclinic.service;
|
||||
package org.springframework.samples.petclinic.service.common;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
@ -1,20 +1,14 @@
|
|||
package org.springframework.samples.petclinic.service;
|
||||
package org.springframework.samples.petclinic.service.common;
|
||||
|
||||
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.samples.petclinic.dto.common.UserDTO;
|
||||
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 {
|
||||
|
@ -36,15 +30,7 @@ public class UserDetailsServiceImpl implements UserDetailsService {
|
|||
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);
|
||||
|
||||
return userDTO;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
package org.springframework.samples.petclinic.service;
|
||||
package org.springframework.samples.petclinic.service.common;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.samples.petclinic.dto.RoleDTO;
|
||||
import org.springframework.samples.petclinic.dto.UserDTO;
|
||||
import org.springframework.samples.petclinic.dto.common.RoleDTO;
|
||||
import org.springframework.samples.petclinic.dto.common.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.samples.petclinic.service.business.BaseService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -37,13 +38,14 @@ public class UserService implements BaseService<User, UserDTO> {
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -56,14 +58,14 @@ public class UserService implements BaseService<User, UserDTO> {
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -114,4 +116,8 @@ public class UserService implements BaseService<User, UserDTO> {
|
|||
return entityToDTO(user);
|
||||
}
|
||||
|
||||
public boolean existByEmail(String email) {
|
||||
return userRepository.existsByEmail(email);
|
||||
}
|
||||
|
||||
}
|
|
@ -30,8 +30,6 @@ spring.resources.cache.cachecontrol.max-age=12h
|
|||
#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
|
||||
|
@ -42,6 +40,7 @@ spring.datasource.password=
|
|||
spring.h2.console.enabled=true
|
||||
spring.h2.console.path=/h2-console
|
||||
|
||||
######################################################################### OAUTH2
|
||||
spring.security.oauth2.client.registration.google.client-id=${OAUTH2_GOOGLE_CLIENT_ID}
|
||||
spring.security.oauth2.client.registration.google.client-secret=${OAUTH2_GOOGLE_CLIENT_SECRET}
|
||||
|
||||
|
@ -52,6 +51,17 @@ spring.security.oauth2.client.registration.github.client-secret=${OAUTH2_GITHUB_
|
|||
#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>
|
||||
|
||||
#################################################################### SPRING MAIL
|
||||
spring.mail.host=smtp.mailtrap.io
|
||||
spring.mail.port=2525
|
||||
spring.mail.protocol=smtp
|
||||
spring.mail.username=${SPRING_MAIL_USERNAME}
|
||||
spring.mail.password=${SPRING_MAIL_PASSWORD}
|
||||
mail.background=static/resources/images/mail-background.png
|
||||
mail.banner=static/resources/images/mail-banner.png
|
||||
mail.logo=static/resources/images/mail-logo.png
|
||||
|
||||
|
||||
|
|
|
@ -52,16 +52,30 @@ 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 roles (id, name) VALUES
|
||||
(1,'ROLE_ADMIN'),
|
||||
(2,'ROLE_STAFF'),
|
||||
(3,'ROLE_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 (id, first_name, last_name, email, password, enabled, telephone, street1, zip_code, city, country) VALUES
|
||||
(1, 'George', 'Franklin', 'georges.franklin@petclinic.com', '$2a$10$8KypNYtPopFo8Sk5jbKJ4.lCKeBhdApsrkmFfhwjB8nCls8qpzjZG', true, '6085551023', '110 W. Liberty St.',12354,'Madison','USA'),
|
||||
(2, 'Betty', 'Davis', 'betty.davis@petclinic.com', '$2a$10$InKx/fhX3CmLi8zKpHYx/.ETHUlZwvT1xn.Za/pp2JR0iEtYV9a9O', true, '6085551749','638 Cardinal Ave.', 6546, 'Sun Prairie', 'USA'),
|
||||
(3, 'Eduardo', 'Rodriquez', 'eduardo.rodriguez@petclinic.com', '$2a$10$P55nbvVibHpoyWzenHngjOf.oEmcj74mI/VJaUZwGX9v8klctzsNW', true, '6085558763','2693 Commerce St.', 65454, 'McFarland', 'USA'),
|
||||
(4, 'Paul-Emmanuel','DOS SANTOS FACAO','pedsf.fullstack@gmail.com','$2a$10$AzoUxi1IQFJMzLHcCGmDjuDHAQqAcAiRLz6UMeItdTL3mMWxMZEPC', true, '6085558763','2693 Commerce St.', 65454, 'McFarland', 'USA');
|
||||
|
||||
INSERT INTO users_roles (user_id, role_id) VALUES
|
||||
(1,1),(1,2),(1,3),
|
||||
(2,3),(3,3);
|
||||
|
||||
INSERT INTO auth_providers (id, name) VALUES
|
||||
(1,'local'),
|
||||
(2,'google'),
|
||||
(3,'github'),
|
||||
(4,'twitter');
|
||||
|
||||
INSERT INTO credentials (provider_id, email, password, verified) VALUES
|
||||
(1, 'georges.franklin@petclinic.com', '$2a$10$8KypNYtPopFo8Sk5jbKJ4.lCKeBhdApsrkmFfhwjB8nCls8qpzjZG', true),
|
||||
(1, 'betty.davis@petclinic.com', '$2a$10$InKx/fhX3CmLi8zKpHYx/.ETHUlZwvT1xn.Za/pp2JR0iEtYV9a9O', true),
|
||||
(1, 'eduardo.rodriguez@petclinic.com', '$2a$10$P55nbvVibHpoyWzenHngjOf.oEmcj74mI/VJaUZwGX9v8klctzsNW', true),
|
||||
(2, 'pedsf.fullstack@gmail.com','117496521794255275093', true);
|
||||
|
||||
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);
|
||||
|
|
|
@ -7,7 +7,10 @@ DROP TABLE types IF EXISTS;
|
|||
DROP TABLE owners IF EXISTS;
|
||||
DROP TABLE roles IF EXISTS;
|
||||
DROP TABLE users IF EXISTS;
|
||||
|
||||
DROP TABLE users_email IF EXISTS;
|
||||
DROP TABLE users_roles IF EXISTS;
|
||||
DROP TABLE auth_providers IF EXISTS;
|
||||
DROP TABLE credentials IF EXISTS;
|
||||
|
||||
CREATE TABLE vets (
|
||||
id INTEGER IDENTITY PRIMARY KEY,
|
||||
|
@ -72,21 +75,22 @@ CREATE TABLE roles (
|
|||
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)
|
||||
id INTEGER IDENTITY PRIMARY KEY,
|
||||
first_name VARCHAR(30) NOT NULL,
|
||||
last_name VARCHAR_IGNORECASE(30) NOT NULL,
|
||||
email VARCHAR(50) NOT NULL,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
enabled BOOLEAN NOT NULL,
|
||||
account_unexpired BOOLEAN NOT NULL DEFAULT true,
|
||||
account_unlocked BOOLEAN NOT NULL DEFAULT true,
|
||||
credential_unexpired BOOLEAN NOT NULL DEFAULT true,
|
||||
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);
|
||||
|
||||
|
@ -97,3 +101,21 @@ CREATE TABLE public.users_roles (
|
|||
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);
|
||||
|
||||
CREATE TABLE auth_providers (
|
||||
id INTEGER IDENTITY PRIMARY KEY,
|
||||
name VARCHAR(20) NOT NULL
|
||||
);
|
||||
CREATE INDEX auth_providers_name ON auth_providers (name);
|
||||
|
||||
CREATE TABLE credentials (
|
||||
id INTEGER IDENTITY PRIMARY KEY,
|
||||
provider_id INTEGER NOT NULL,
|
||||
email VARCHAR(50) NOT NULL,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
verified BOOLEAN NOT NULL,
|
||||
token VARCHAR(255) DEFAULT NULL,
|
||||
expiration DATE DEFAULT NULL
|
||||
);
|
||||
ALTER TABLE credentials ADD CONSTRAINT fk_credentials_provider_id FOREIGN KEY (provider_id) REFERENCES auth_providers (id);
|
||||
CREATE INDEX credentials_email ON credentials (email);
|
||||
|
|
BIN
src/main/resources/static/resources/images/mail-background.png
Normal file
BIN
src/main/resources/static/resources/images/mail-background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.9 KiB |
BIN
src/main/resources/static/resources/images/mail-banner.png
Normal file
BIN
src/main/resources/static/resources/images/mail-banner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
src/main/resources/static/resources/images/mail-logo.png
Normal file
BIN
src/main/resources/static/resources/images/mail-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
49
src/main/resources/templates/email.html
Normal file
49
src/main/resources/templates/email.html
Normal file
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title data-th-remove="all">Template for HTML email (editable)</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
</head>
|
||||
<body>
|
||||
<div style="background-color: #ccc; background-image: url(images/background.png)"
|
||||
data-th-style="|background-color: #ccc; background-image: url(cid:mailBackground)|">
|
||||
<div style="padding: 40px;">
|
||||
<div style="margin-left: auto; margin-right: auto; min-width: 320px; border: solid 1px #555; border-radius: 6px;">
|
||||
<div style="background-color: #555; padding: 4px 4px 0px 4px; text-align: left;">
|
||||
<div style="background-image: url(images/logo-background.png);"
|
||||
data-th-style="|background-image: url(cid:mailBanner)|">
|
||||
<img style="border: solid 1px #555; border-radius: 6px;"
|
||||
src="images/shop-logo.png" data-th-src="|cid:mailLogo|" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="padding: 15px 15px 30px 15px; font-family: Verdana, Arial, Helvetica, sans-serif; font-size:1em; background-color: #fff; color:#333;">
|
||||
<h1>
|
||||
<span data-th-text="${mailSubject}">Subject</span></p>
|
||||
</h1>
|
||||
<p>
|
||||
<span>Hello </span>
|
||||
<b data-th-text="${toFirstName}">FirstName</b>
|
||||
<b data-th-text="${toLastName}">toLastName</b>!
|
||||
</p>
|
||||
|
||||
<p th:utext="${#strings.replace(#strings.escapeXml(mailContent),' ','<br>')}">mail content</p>
|
||||
<a th:href="@{${mailLink}}">Approve the connection</a>
|
||||
|
||||
<p>
|
||||
<span data-th-text="${#dates.format(mailDate)}">date</span>
|
||||
</p>
|
||||
<p>Regards </p>
|
||||
</div>
|
||||
<div style="background-color: #555; padding: 4px 4px 0px 4px; text-align: right;">
|
||||
<div style="background-image: url(images/logo-background.png);"
|
||||
data-th-style="|background-image: url(cid:mailBackground)|">
|
||||
<img style="border: solid 1px #555; border-radius: 6px;"
|
||||
src="images/shop-logo.png" data-th-src="|cid:mailBanner|" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
<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/css/style.css}" /-->
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button
|
||||
th:with="text=${owner['new']} ? 'Add Owner' : 'Update Owner'"
|
||||
class="btn btn-default" type="submit" th:text="${text}">Add
|
||||
Owner</button>
|
||||
class="btn btn-default" type="submit" th:text="${text}">Add Owner
|
||||
</button>
|
||||
<a class="btn btn-default" href="/">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<html xmlns:th="https://www.thymeleaf.org"
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'users')}">
|
||||
|
||||
<body>
|
||||
|
||||
<h2>Change password</h2>
|
||||
<form th:object="${user}" class="form-horizontal" id="add-user-form" method="post">
|
||||
<input type="hidden" th:field="${user.id}" />
|
||||
<input type="hidden" th:field="${user.firstName}" />
|
||||
<input type="hidden" th:field="${user.lastName}" />
|
||||
<input type="hidden" th:field="${user.password}" />
|
||||
<input type="hidden" th:field="${user.matchingPassword}" />
|
||||
<input type="hidden" th:field="${user.enabled}" />
|
||||
<input type="hidden" th:field="${user.accountNonExpired}" />
|
||||
<input type="hidden" th:field="${user.accountNonLocked}" />
|
||||
<input type="hidden" th:field="${user.credentialsNonExpired}" />;
|
||||
<input type="hidden" th:field="${user.roles}" />
|
||||
<input type="hidden" th:field="${user.telephone}" />
|
||||
<input type="hidden" th:field="${user.street1}" />
|
||||
<input type="hidden" th:field="${user.street2}" />
|
||||
<input type="hidden" th:field="${user.street3}" />
|
||||
<input type="hidden" th:field="${user.zipCode}" />
|
||||
<input type="hidden" th:field="${user.city}" />
|
||||
<input type="hidden" th:field="${user.country}" />
|
||||
|
||||
<div class="form-group has-feedback">
|
||||
<div class="form-group">
|
||||
<label for="email">Email address</label>
|
||||
<input type="email" th:field="${user.email}" class="form-control input-lg" id="email" readonly>
|
||||
<small id="emailHelp" class="form-text text-muted">We'll never share your emailConfiguration with anyone else.</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="oldPassword">Present password</label>
|
||||
<input type="password" name="oldPassword" class="form-control input-lg" id="oldPassword" th:placeholder="password" value="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="newPassword">New password</label>
|
||||
<input type="password" name="newPassword" class="form-control input-lg" id="newPassword" th:placeholder="password" value="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="newMatchingPassword">Password</label>
|
||||
<input type="password" name="newMatchingPassword" class="form-control input-lg" id="newMatchingPassword" th:placeholder="password" value="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button class="btn btn-default" type="submit">Change password</button>
|
||||
<a class="btn btn-default" th:href="@{/}">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
|
@ -3,9 +3,16 @@
|
|||
|
||||
<body>
|
||||
|
||||
<h2>User</h2>
|
||||
<h2>User registration</h2>
|
||||
<form th:object="${user}" class="form-horizontal" id="add-user-form" method="post">
|
||||
<input type="hidden" th:field="${user.enabled}" />
|
||||
<input type="hidden" th:field="${user.accountNonExpired}" />
|
||||
<input type="hidden" th:field="${user.accountNonLocked}" />
|
||||
<input type="hidden" th:field="${user.credentialsNonExpired}" />
|
||||
|
||||
<div class="form-group has-feedback">
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Email', 'email', 'email')}" />
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('First Name', 'firstName', 'text')}" />
|
||||
<input
|
||||
|
@ -14,8 +21,6 @@
|
|||
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
|
||||
|
@ -33,10 +38,8 @@
|
|||
</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>
|
||||
<button class="btn btn-default" type="submit">Register</button>
|
||||
<a class="btn btn-default" th:href="@{/}">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
49
src/main/resources/templates/users/userUpdateForm.html
Normal file
49
src/main/resources/templates/users/userUpdateForm.html
Normal file
|
@ -0,0 +1,49 @@
|
|||
<html xmlns:th="https://www.thymeleaf.org"
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'users')}">
|
||||
|
||||
<body>
|
||||
|
||||
<h2>User update</h2>
|
||||
<form th:object="${user}" class="form-horizontal" id="add-user-form" method="post">
|
||||
<input type="hidden" th:field="${user.id}" />
|
||||
<input type="hidden" th:field="${user.password}" />
|
||||
<input type="hidden" th:field="${user.matchingPassword}" />
|
||||
<input type="hidden" th:field="${user.enabled}" />
|
||||
<input type="hidden" th:field="${user.accountNonExpired}" />
|
||||
<input type="hidden" th:field="${user.accountNonLocked}" />
|
||||
<input type="hidden" th:field="${user.credentialsNonExpired}" />
|
||||
<input type="hidden" th:field="${user.roles}" />
|
||||
|
||||
|
||||
<div class="form-group has-feedback">
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('Email', 'email', 'email')}" disabled />
|
||||
<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 ('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 class="btn btn-default" type="submit">Update</button>
|
||||
<a class="btn btn-default" th:href="@{'/user/' + ${user.id} + '/edit/password'}">Change password</a>
|
||||
<a class="btn btn-default" th:href="@{/}">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="https://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'home')}">
|
||||
<html xmlns:th="https://www.thymeleaf.org"
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'home')}">
|
||||
|
||||
<body>
|
||||
|
||||
|
@ -13,4 +12,4 @@
|
|||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -12,7 +12,7 @@ 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.dto.VisitDTO;
|
||||
import org.springframework.samples.petclinic.service.OwnerService;
|
||||
import org.springframework.samples.petclinic.service.business.OwnerService;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
|
|
|
@ -40,8 +40,8 @@ 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.dto.VisitDTO;
|
||||
import org.springframework.samples.petclinic.service.OwnerService;
|
||||
import org.springframework.samples.petclinic.service.VisitService;
|
||||
import org.springframework.samples.petclinic.service.business.OwnerService;
|
||||
import org.springframework.samples.petclinic.service.business.VisitService;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
|
|
|
@ -11,8 +11,8 @@ import org.springframework.samples.petclinic.common.CommonView;
|
|||
import org.springframework.samples.petclinic.dto.OwnerDTO;
|
||||
import org.springframework.samples.petclinic.dto.PetDTO;
|
||||
import org.springframework.samples.petclinic.repository.PetRepository;
|
||||
import org.springframework.samples.petclinic.service.OwnerService;
|
||||
import org.springframework.samples.petclinic.service.PetService;
|
||||
import org.springframework.samples.petclinic.service.business.OwnerService;
|
||||
import org.springframework.samples.petclinic.service.business.PetService;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
|
|
|
@ -42,9 +42,9 @@ 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.formatter.PetTypeFormatter;
|
||||
import org.springframework.samples.petclinic.service.OwnerService;
|
||||
import org.springframework.samples.petclinic.service.PetService;
|
||||
import org.springframework.samples.petclinic.service.PetTypeService;
|
||||
import org.springframework.samples.petclinic.service.business.OwnerService;
|
||||
import org.springframework.samples.petclinic.service.business.PetService;
|
||||
import org.springframework.samples.petclinic.service.business.PetTypeService;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,7 +15,7 @@ import org.springframework.samples.petclinic.common.CommonEndPoint;
|
|||
import org.springframework.samples.petclinic.common.CommonView;
|
||||
import org.springframework.samples.petclinic.dto.VetsDTO;
|
||||
import org.springframework.samples.petclinic.repository.VetRepository;
|
||||
import org.springframework.samples.petclinic.service.VetService;
|
||||
import org.springframework.samples.petclinic.service.business.VetService;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.springframework.samples.petclinic.controller;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
@ -40,10 +39,9 @@ import org.springframework.samples.petclinic.common.CommonView;
|
|||
import org.springframework.samples.petclinic.dto.SpecialtyDTO;
|
||||
import org.springframework.samples.petclinic.dto.VetDTO;
|
||||
import org.springframework.samples.petclinic.dto.VetsDTO;
|
||||
import org.springframework.samples.petclinic.service.VetService;
|
||||
import org.springframework.samples.petclinic.service.business.VetService;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
|
|
@ -12,7 +12,7 @@ import org.springframework.samples.petclinic.dto.PetDTO;
|
|||
import org.springframework.samples.petclinic.dto.VisitDTO;
|
||||
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.samples.petclinic.service.business.PetService;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
|
|
|
@ -40,8 +40,8 @@ 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.business.Visit;
|
||||
import org.springframework.samples.petclinic.service.PetService;
|
||||
import org.springframework.samples.petclinic.service.VisitService;
|
||||
import org.springframework.samples.petclinic.service.business.PetService;
|
||||
import org.springframework.samples.petclinic.service.business.VisitService;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ 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.business.PetType;
|
||||
import org.springframework.samples.petclinic.service.PetService;
|
||||
import org.springframework.samples.petclinic.service.business.PetService;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
|
|
|
@ -31,7 +31,7 @@ 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.business.PetType;
|
||||
import org.springframework.samples.petclinic.service.PetService;
|
||||
import org.springframework.samples.petclinic.service.business.PetService;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
|
|
@ -19,6 +19,9 @@ import org.springframework.samples.petclinic.repository.OwnerRepository;
|
|||
import org.springframework.samples.petclinic.repository.PetRepository;
|
||||
import org.springframework.samples.petclinic.repository.PetTypeRepository;
|
||||
import org.springframework.samples.petclinic.repository.VisitRepository;
|
||||
import org.springframework.samples.petclinic.service.business.OwnerService;
|
||||
import org.springframework.samples.petclinic.service.business.PetService;
|
||||
import org.springframework.samples.petclinic.service.business.PetTypeService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
|
|
@ -17,6 +17,9 @@ 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;
|
||||
import org.springframework.samples.petclinic.service.business.OwnerService;
|
||||
import org.springframework.samples.petclinic.service.business.PetService;
|
||||
import org.springframework.samples.petclinic.service.business.PetTypeService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.springframework.samples.petclinic.dto.VetDTO;
|
|||
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.samples.petclinic.service.business.VetService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
Loading…
Reference in a new issue