package org.datasurvey.web.rest; import java.util.*; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import org.apache.commons.lang3.StringUtils; import org.datasurvey.domain.User; import org.datasurvey.repository.UserRepository; import org.datasurvey.security.SecurityUtils; import org.datasurvey.service.MailService; import org.datasurvey.service.UserService; import org.datasurvey.service.dto.AdminUserDTO; import org.datasurvey.service.dto.PasswordChangeDTO; import org.datasurvey.service.dto.UserDTO; import org.datasurvey.web.rest.errors.*; import org.datasurvey.web.rest.vm.KeyAndPasswordVM; import org.datasurvey.web.rest.vm.ManagedUserVM; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; /** * REST controller for managing the current user's account. */ @RestController @RequestMapping("/api") public class AccountResource { private static class AccountResourceException extends RuntimeException { private AccountResourceException(String message) { super(message); } } private final Logger log = LoggerFactory.getLogger(AccountResource.class); private final UserRepository userRepository; private final UserService userService; private final MailService mailService; public AccountResource(UserRepository userRepository, UserService userService, MailService mailService) { this.userRepository = userRepository; this.userService = userService; this.mailService = mailService; } /** * {@code POST /register} : register the user. * * @param managedUserVM the managed user View Model. * @throws InvalidPasswordException {@code 400 (Bad Request)} if the password is incorrect. * @throws EmailAlreadyUsedException {@code 400 (Bad Request)} if the email is already used. * @throws LoginAlreadyUsedException {@code 400 (Bad Request)} if the login is already used. */ @PostMapping("/register") @ResponseStatus(HttpStatus.CREATED) public void registerAccount(@Valid @RequestBody ManagedUserVM managedUserVM) { if (isPasswordLengthInvalid(managedUserVM.getPassword())) { throw new InvalidPasswordException(); } User user = userService.registerUser( managedUserVM, managedUserVM.getPassword(), managedUserVM.getName(), managedUserVM.getProfileIcon(), managedUserVM.getIsAdmin(), managedUserVM.getIsGoogle() ); if (managedUserVM.getIsGoogle() != 1) { mailService.sendActivationEmail(user); } } /** * {@code GET /activate} : activate the registered user. * * @param key the activation key. * @throws RuntimeException {@code 500 (Internal Server Error)} if the user couldn't be activated. */ @GetMapping("/activate") public void activateAccount(@RequestParam(value = "key") String key) { Optional user = userService.activateRegistration(key); if (!user.isPresent()) { throw new AccountResourceException("No user was found for this activation key"); } } /** * {@code GET /authenticate} : check if the user is authenticated, and return its login. * * @param request the HTTP request. * @return the login if the user is authenticated. */ @GetMapping("/authenticate") public String isAuthenticated(HttpServletRequest request) { log.debug("REST request to check if the current user is authenticated"); return request.getRemoteUser(); } /** * {@code GET /account} : get the current user. * * @return the current user. * @throws RuntimeException {@code 500 (Internal Server Error)} if the user couldn't be returned. */ @GetMapping("/account") public AdminUserDTO getAccount() { return userService .getUserWithAuthorities() .map(AdminUserDTO::new) .orElseThrow(() -> new AccountResourceException("User could not be found")); } /** * {@code POST /account} : update the current user information. * * @param userDTO the current user information. * @throws EmailAlreadyUsedException {@code 400 (Bad Request)} if the email is already used. * @throws RuntimeException {@code 500 (Internal Server Error)} if the user login wasn't found. */ @PostMapping("/account") public void saveAccount(@Valid @RequestBody AdminUserDTO userDTO) { String userLogin = SecurityUtils .getCurrentUserLogin() .orElseThrow(() -> new AccountResourceException("Current user login not found")); Optional existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()); if (existingUser.isPresent() && (!existingUser.get().getLogin().equalsIgnoreCase(userLogin))) { throw new EmailAlreadyUsedException(); } Optional user = userRepository.findOneByLogin(userLogin); if (!user.isPresent()) { throw new AccountResourceException("User could not be found"); } userService.updateUser( userDTO.getFirstName(), userDTO.getLastName(), userDTO.getEmail(), userDTO.getLangKey(), userDTO.getImageUrl() ); } /** * {@code POST /account/change-password} : changes the current user's password. * * @param passwordChangeDto current and new password. * @throws InvalidPasswordException {@code 400 (Bad Request)} if the new password is incorrect. */ @PostMapping(path = "/account/change-password") public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) { if (isPasswordLengthInvalid(passwordChangeDto.getNewPassword())) { throw new InvalidPasswordException(); } userService.changePassword(passwordChangeDto.getCurrentPassword(), passwordChangeDto.getNewPassword()); } /** * {@code POST /account/reset-password/init} : Send an email to reset the password of the user. * * @param mail the mail of the user. */ @PostMapping(path = "/account/reset-password/init") public void requestPasswordReset(@RequestBody String mail) { Optional user = userService.requestPasswordReset(mail); if (user.isPresent()) { mailService.sendPasswordResetMail(user.get()); } else { // Pretend the request has been successful to prevent checking which emails really exist // but log that an invalid attempt has been made log.warn("Password reset requested for non existing mail"); } } /** * {@code POST /account/reset-password/finish} : Finish to reset the password of the user. * * @param keyAndPassword the generated key and the new password. * @throws InvalidPasswordException {@code 400 (Bad Request)} if the password is incorrect. * @throws RuntimeException {@code 500 (Internal Server Error)} if the password could not be reset. */ @PostMapping(path = "/account/reset-password/finish") public void finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) { if (isPasswordLengthInvalid(keyAndPassword.getNewPassword())) { throw new InvalidPasswordException(); } Optional user = userService.completePasswordReset(keyAndPassword.getNewPassword(), keyAndPassword.getKey()); if (!user.isPresent()) { throw new AccountResourceException("No user was found for this reset key"); } } private static boolean isPasswordLengthInvalid(String password) { return ( StringUtils.isEmpty(password) || password.length() < ManagedUserVM.PASSWORD_MIN_LENGTH || password.length() > ManagedUserVM.PASSWORD_MAX_LENGTH ); } }