package models;
import exceptions.AppException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import play.Configuration;
import play.data.format.Formats;
import play.data.validation.Constraints;
import play.db.ebean.Model;
import play.i18n.Messages;
import javax.annotation.Nullable;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;
@Entity
public class Token extends Model {
static Logger log = LoggerFactory.getLogger(Token.class);
// Reset tokens will expire after a day.
private static final int EXPIRATION_DAYS = 1;
public enum Type {
confirmation("confirm"), password("reset"), email("email");
private String urlPath;
Type(String urlPath) {
this.urlPath = urlPath;
}
public static Type fromUrlPath(String urlPath) {
for (Type type : Type.values()) {
if (type.urlPath.equalsIgnoreCase(urlPath)) return type;
}
String msg = String.format("not existent token type [%s]", urlPath);
log.error(msg);
throw new IllegalArgumentException(msg);
}
}
@Id
public String token;
@Constraints.Required
@Formats.NonEmpty
public Long userId;
@Constraints.Required
@Enumerated(EnumType.STRING)
public Type type;
@Formats.DateTime(pattern = "yyyy-MM-dd HH:mm:ss")
public Date dateCreation;
@Constraints.Required
@Formats.NonEmpty
public String email;
// -- Queries
@SuppressWarnings("unchecked")
public static Finder<String, Token> finder = new Finder(String.class, Token.class);
/**
* Retrieve a token by id and type.
*
* @param token token Id
* @param type type of token
* @return a resetToken
*/
public static Token findByTokenAndType(String token, Type type) {
return finder.where().eq("token", token).eq("type", type).findUnique();
}
/**
* @return true if the reset token is too old to use, false otherwise.
*/
public boolean isExpired() {
return dateCreation != null && dateCreation.before(expirationTime());
}
/**
* @return a date before which the password link has expired.
*/
private Date expirationTime() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DATE, -EXPIRATION_DAYS);
return cal.getTime();
}
/**
* Return a new Token.
*
* @param user user
* @param type type of token
* @param email email for a token change email
* @return a reset token
*/
private static Token getNewToken(User user, Type type, String email) {
Token token = new Token();
token.token = UUID.randomUUID().toString();
token.userId = user.id;
token.type = type;
token.email = email;
token.save();
return token;
}
/**
* Send the Email to confirm ask new password.
*
* @param user the current user
* @throws java.net.MalformedURLException if token is wrong.
*/
public static void sendMailResetPassword(User user) throws MalformedURLException, AppException {
sendMail(user, Type.password, null);
}
/**
* Send the Email to confirm ask new password.
*
* @param user the current user
* @param email email for a change email token
* @throws java.net.MalformedURLException if token is wrong.
*/
public static void sendMailChangeMail(User user, @Nullable String email) throws MalformedURLException, AppException {
sendMail(user, Type.email, email);
}
/**
* Send the Email to confirm the user account.
*
* @param user the current user
* @throws java.net.MalformedURLException if token is wrong.
*/
public static void sendConfirmationToken(User user) throws MalformedURLException, AppException {
sendMail(user, Type.confirmation, null);
}
/**
* creates a confirmation the user account.
*
* @param user the current user
* @throws java.net.MalformedURLException if token is wrong.
*/
public static Token createConfirmationToken(User user) throws MalformedURLException, AppException {
return getNewToken(user, Type.confirmation, user.email);
}
public URL getUrl() throws MalformedURLException {
String externalServer = Configuration.root().getString("server.hostname");
String urlString = urlString = "http://" + externalServer + "/" + type.urlPath + "/" + token;
return new URL(urlString);
}
/**
* Send the Email to confirm ask new password.
*
* @param user the current user
* @param type token type
* @param email email for a change email token
* @throws java.net.MalformedURLException if token is wrong.
*/
private static void sendMail(User user, Type type, String email) throws MalformedURLException, AppException {
Token token = getNewToken(user, type, email);
String externalServer = Configuration.root().getString("server.hostname");
String subject = null;
String message = null;
String toMail = null;
// Should use reverse routing here.
String urlString = urlString = "http://" + externalServer + "/tkn/" + type.urlPath + "/" + token.token;
URL url = new URL(urlString); // validate the URL
switch (type) {
case password:
subject = Messages.get("mail.reset.ask.subject");
message = Messages.get("mail.reset.ask.message", url.toString());
toMail = user.email;
break;
case email:
subject = Messages.get("mail.change.ask.subject");
message = Messages.get("mail.change.ask.message", url.toString());
toMail = token.email; // == email parameter
break;
case confirmation:
subject = Messages.get("mail.confirm.ask.subject");
message = Messages.get("mail.confirm.ask.message", url.toString());
toMail = user.email; // == email parameter
break;
default:
throw new AppException("unhandled token type " + type);
}
log.debug("sendMailResetLink: url = {}", url);
// Mail.Envelop envelop = new Mail.Envelop(subject, message, toMail);
// Mail.sendMail(envelop);
}
}