package com.qprogramming.tasq.signup;
import com.qprogramming.tasq.account.Account;
import com.qprogramming.tasq.account.AccountService;
import com.qprogramming.tasq.account.Roles;
import com.qprogramming.tasq.error.TasqException;
import com.qprogramming.tasq.mail.MailMail;
import com.qprogramming.tasq.manage.AppService;
import com.qprogramming.tasq.manage.ThemeService;
import com.qprogramming.tasq.support.Utils;
import com.qprogramming.tasq.support.web.MessageHelper;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.io.File;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Controller
public class SignupController {
public static final String PASSWORD_REGEXP = "^^(?=.*[A-Z])(?=.*[0-9])(?=.*[a-z].*[a-z].*[a-z]).{8,}$";
private static final Logger LOG = LoggerFactory.getLogger(SignupController.class);
private static final String AVATAR_DIR = "avatar";
private static final String PNG = ".png";
private static final String LOGO = "logo";
private static final String SMALL = "small_";
private AccountService accountSrv;
private MessageSource msg;
private ThemeService themeSrv;
private AppService appSrv;
private MailMail mailer;
@Autowired
public SignupController(AccountService accountSrv, MessageSource msg, ThemeService themeSrv, AppService appSrv, MailMail mailer) {
this.accountSrv = accountSrv;
this.msg = msg;
this.themeSrv = themeSrv;
this.appSrv = appSrv;
this.mailer = mailer;
}
@RequestMapping(value = "signup")
public SignupForm signup(HttpServletRequest request) {
Utils.forceLogout(request);
return new SignupForm();
}
@RequestMapping(value = "signup", method = RequestMethod.POST)
public String signup(@Valid @ModelAttribute SignupForm signupForm, Errors errors, RedirectAttributes ra,
HttpServletRequest request) {
if (errors.hasErrors()) {
return null;
}
if (!signupForm.isPasswordConfirmed()) {
errors.rejectValue("password", "error.notMatchedPasswords");
return null;
}
Pattern pattern = Pattern.compile(PASSWORD_REGEXP);
Matcher matcher = pattern.matcher(signupForm.getPassword());
if (!matcher.matches()) {
errors.rejectValue("password", "signup.password.strength.hint");
return null;
}
Utils.setHttpRequest(request);
if (null != accountSrv.findByEmail(signupForm.getEmail())) {
errors.rejectValue("email", "error.email.notunique", new Object[]{signupForm.getEmail()}, Utils.getDefaultLocale().toString());
return null;
}
if (null != accountSrv.findByUsername((signupForm.getUsername()))) {
errors.rejectValue("username", "error.username.notunique", new Object[]{signupForm.getUsername()}, Utils.getDefaultLocale().toString());
return null;
}
HttpSession session = request.getSession();
ServletContext sc = session.getServletContext();
Account account = signupForm.createAccount();
account.setRole(Roles.valueOf(appSrv.getProperty(AppService.DEFAULTROLE)));
if (accountSrv.findAll().isEmpty()) {
// FIRST ACCOUNT EVER, LAUNCH SETUP TASKS
LOG.info("Creating first user in application and making him administrator");
account.setRole(Roles.ROLE_ADMIN);
// Copy logo
File appLogo = new File(getAvatarDir() + LOGO + PNG);
File smallAppLogo = new File(getAvatarDir() + SMALL + LOGO + PNG);
Utils.copyFile(sc, "/resources/img/logo.png", appLogo);
Utils.copyFile(sc, "/resources/img/small_logo.png", smallAppLogo);
LOG.info("Default logo app coppied into {}", appLogo.getAbsolutePath());
// set base url
Utils.setHttpRequest(request);
String url = Utils.getBaseURL();
appSrv.setProperty(AppService.URL, url);
LOG.info("App url set to {}", url);
}
account.setTheme(themeSrv.getDefault());
account = accountSrv.save(account, true);
// copy default avatar
File userAvatar = new File(getAvatar(account.getId()));
Utils.copyFile(sc, "/resources/img/avatar.png", userAvatar);
if (mailer.testConnection()) {
if (!accountSrv.sendConfirmationLink(account)) {
throw new TasqException(msg.getMessage("error.email.sending", null, Utils.getDefaultLocale()));
}
MessageHelper.addSuccessAttribute(ra, msg.getMessage("signup.success", null, Utils.getDefaultLocale()));
return "redirect:/";
}
MessageHelper.addWarningAttribute(ra, msg.getMessage("signup.success.emailerror", null, Utils.getDefaultLocale()));
return "redirect:/";
}
@RequestMapping(value = "/confirm", method = RequestMethod.GET)
public String confirm(@RequestParam(value = "id", required = true) String id, RedirectAttributes ra,
HttpServletRequest request) throws ServletException {
Account account = accountSrv.findByUuid(id);
if (account != null) {
account.setConfirmed(true);
accountSrv.update(account);
MessageHelper.addSuccessAttribute(ra, msg.getMessage("signup.confirmed", null, Utils.getDefaultLocale()));
Utils.forceLogout(request);
} else {
MessageHelper.addErrorAttribute(ra, "Verification error!");
}
return "redirect:/";
}
@RequestMapping(value = "/password", method = RequestMethod.GET)
public PasswordResetForm reset(@RequestParam(value = "id", required = true) String id, RedirectAttributes ra) {
PasswordResetForm form = new PasswordResetForm();
form.setId(id);
return form;
}
@Transactional
@RequestMapping(value = "/password", method = RequestMethod.POST)
public String resetSubmit(@Valid @ModelAttribute PasswordResetForm form, Errors errors, RedirectAttributes ra, HttpServletRequest request) {
if (!form.isPasswordConfirmed()) {
errors.rejectValue("password", "error.notMatchedPasswords");
}
Pattern pattern = Pattern.compile(PASSWORD_REGEXP);
Matcher matcher = pattern.matcher(form.getPassword());
if (!matcher.matches()) {
errors.rejectValue("password", "signup.password.strength.hint");
return null;
}
if (errors.hasErrors()) {
return null;
}
Account account = accountSrv.findByUuid(form.getId());
if (account != null) {
UUID uuid = UUID.fromString(form.getId());
DateTime date = new DateTime(Utils.getTimeFromUUID(uuid));
DateTime expireDate = date.plusHours(12);
if (date.isAfter(expireDate)) {
MessageHelper.addErrorAttribute(ra,
msg.getMessage("signin.password.token.expired", null, Utils.getDefaultLocale()));
} else {
account.setPassword(form.getPassword());
accountSrv.save(account, true);
MessageHelper.addSuccessAttribute(ra,
msg.getMessage("signin.password.success", null, Utils.getDefaultLocale()));
}
} else {
MessageHelper.addErrorAttribute(ra,
msg.getMessage("signin.password.token.invalid", null, Utils.getDefaultLocale()));
}
//if logged in user was chaning password, logout him
Utils.forceLogout(request);
return "redirect:/";
}
@RequestMapping(value = "/resetPassword", method = RequestMethod.GET)
public String resetPassword() {
return "signin/resetPassword";
}
@Transactional(rollbackFor = TasqException.class)
@RequestMapping(value = "/resetPassword", method = RequestMethod.POST)
public String resetPassword(@RequestParam(value = "email", required = true) String email, RedirectAttributes ra,
HttpServletRequest request) {
Account account = accountSrv.findByEmail(email);
if (account == null) {
MessageHelper.addWarningAttribute(ra,
msg.getMessage("signin.password.notfound", new Object[]{email}, Utils.getDefaultLocale()));
return "redirect:" + request.getHeader("Referer");
} else {
resetAccountPassword(account, ra, request);
}
return "redirect:/";
}
/**
* Sends reset link for currently logged in user
*
* @param ra
* @param request
* @return
*/
@Transactional(rollbackFor = TasqException.class)
@RequestMapping(value = "/sendResetPassword", method = RequestMethod.GET)
public String sendResetPassword(RedirectAttributes ra, HttpServletRequest request) {
resetAccountPassword(Utils.getCurrentAccount(), ra, request);
return "redirect:/settings";
}
private void resetAccountPassword(Account account, RedirectAttributes ra, HttpServletRequest request) {
accountSrv.save(account, false);
Utils.setHttpRequest(request);
if (!accountSrv.sendResetLink(account)) {
throw new TasqException(msg.getMessage("error.email.sending", null, Utils.getCurrentLocale()));
}
MessageHelper.addSuccessAttribute(ra,
msg.getMessage("singin.password.token.sent", new Object[]{account.getEmail()}, Utils.getDefaultLocale()));
}
private String getAvatarDir() {
return appSrv.getProperty(AppService.TASQROOTDIR) + File.separator + AVATAR_DIR + File.separator;
}
private String getAvatar(Long id) {
return getAvatarDir() + id + PNG;
}
}