package edu.gatech.oad.rocket.findmythings.server.spi;
import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.appengine.api.datastore.PhoneNumber;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
import com.googlecode.objectify.Key;
import edu.gatech.oad.rocket.findmythings.server.db.DatabaseService;
import edu.gatech.oad.rocket.findmythings.server.db.model.DBMember;
import edu.gatech.oad.rocket.findmythings.server.model.AppMember;
import edu.gatech.oad.rocket.findmythings.server.model.MessageBean;
import edu.gatech.oad.rocket.findmythings.server.util.Config;
import edu.gatech.oad.rocket.findmythings.server.util.HTTP;
import edu.gatech.oad.rocket.findmythings.server.util.Messages;
import edu.gatech.oad.rocket.findmythings.shared.util.validation.EmailValidator;
import edu.gatech.oad.rocket.findmythings.shared.util.validation.RegexValidator;
import javax.annotation.Nullable;
import javax.inject.Named;
@Api(name = "fmthings", version = "v1")
public class AccountV1 extends BaseEndpoint {
boolean emailIsInvalid(String email) {
return email == null || email.length() == 0 || !EmailValidator.getInstance().isValid(email);
}
private static final RegexValidator PHONE_VALIDATOR = new RegexValidator("[0-9]-([0-9]{3})-[0-9]{3}-[0-9]{4}", false);
MessageBean mailWelcomeReturnOK(String email) {
Queue queue = QueueFactory.getDefaultQueue();
queue.add(TaskOptions.Builder.withUrl("/sendWelcomeMail")
.param(Config.USERNAME_PARAM, email));
return new MessageBean(HTTP.Status.OK.toInt(), Messages.Status.OK.toString());
}
MessageBean mailAuthenticationTokenSendOK(String email, boolean isForgot) {
String registrationToken = DatabaseService.ofy().createRegistrationTicket(email);
// send email with registrationToken
Queue queue = QueueFactory.getDefaultQueue();
queue.add(TaskOptions.Builder.withUrl("/sendMail")
.param(Config.USERNAME_PARAM, email)
.param(Config.FORGOT_PASSWORD_PARAM, Boolean.toString(isForgot))
.param(Config.TICKET_PARAM, registrationToken));
return new MessageBean(HTTP.Status.OK.toInt(), Messages.Status.OK.toString());
}
private MessageBean createMember(String email, String password, String passwordAlt,
String phone, String name, String address, boolean isAdmin) {
try {
if (emailIsInvalid(email)) {
return new MessageBean(HTTP.Status.BAD_REQUEST.toInt(), Messages.Status.FAILED.toString(), Messages.Register.BAD_EMAIL_ADDRESS.toString());
}
AppMember user = getMemberWithEmail(email);
if (user != null && user.isRegistered()) {
return new MessageBean(HTTP.Status.BAD_REQUEST.toInt(), Messages.Status.FAILED.toString(), Messages.Register.ALREADY_USER.toString());
}
if (password == null || password.length() < 3 || passwordAlt == null || passwordAlt.length() < 3) {
return new MessageBean(HTTP.Status.BAD_REQUEST.toInt(), Messages.Status.FAILED.toString(), Messages.Register.BAD_PASSWORD.toString());
}
if (!password.equals(passwordAlt)) {
return new MessageBean(HTTP.Status.BAD_REQUEST.toInt(), Messages.Status.FAILED.toString(), Messages.Register.PASSWORDS_MATCH.toString());
}
if (phone != null && !PHONE_VALIDATOR.isValid(phone)) {
return new MessageBean(HTTP.Status.BAD_REQUEST.toInt(), Messages.Status.FAILED.toString(), Messages.Register.INVALID_PHONE.toString());
}
PhoneNumber phoneNum = null;
if (phone != null) {
phoneNum = new PhoneNumber(phone);
}
DBMember newUser = (DBMember)user;
if (newUser == null) {
newUser = new DBMember(email, password, null, null, true);
}
if (phoneNum != null) newUser.setPhone(phoneNum);
if (name != null) newUser.setName(name);
if (address != null) newUser.setAddress(address);
newUser.setAdmin(isAdmin);
DatabaseService.ofy().save().entity(newUser);
return mailWelcomeReturnOK(email);
} catch (Exception e) {
return new MessageBean(HTTP.Status.BAD_REQUEST.toInt(), Messages.Status.FAILED.toString(), Messages.Register.INVALID_DATA.toString());
}
}
@ApiMethod(name = "account.createAdmin", path = "register/admin")
public MessageBean createAdmin(@Named("email") String email, @Named("password") String password,
@Named("password_alt") String passwordAlt, @Named("phone") @Nullable String phone,
@Named("name") @Nullable String name, @Named("address") @Nullable String address) {
return createMember(email, password, passwordAlt, phone, name, address, true);
}
@ApiMethod(name = "account.register", path = "register")
public MessageBean createUser(@Named("email") String email, @Named("password") String password,
@Named("password_alt") String passwordAlt, @Named("phone") @Nullable String phone,
@Named("name") @Nullable String name, @Named("address") @Nullable String address) {
return createMember(email, password, passwordAlt, phone, name, address, false);
}
@ApiMethod(name = "account.forgot", path = "forgot")
public MessageBean memberForgotPassword(@Named("email") String email) {
try {
if (emailIsInvalid(email)) {
return new MessageBean(HTTP.Status.BAD_REQUEST.toInt(), Messages.Status.FAILED.toString(), Messages.Register.BAD_EMAIL_ADDRESS.toString());
}
if (memberExistsWithEmail(email)) {
return mailAuthenticationTokenSendOK(email, true);
} else {
return new MessageBean(HTTP.Status.BAD_REQUEST.toInt(), Messages.Status.FAILED.toString(), Messages.Register.NO_SUCH_MEMBER.toString());
}
} catch (Exception e) {
return new MessageBean(HTTP.Status.BAD_REQUEST.toInt(), Messages.Status.FAILED.toString(), Messages.Register.INVALID_DATA.toString());
}
}
@ApiMethod(name = "account.get", path = "account")
public AppMember getCurrentMember() {
return getMemberWithEmail(getCurrentMemberEmail());
}
@ApiMethod(name = "account.update", path = "account/update")
public AppMember updateMember(AppMember member) {
if (member.isEditable()) {
Key<DBMember> result = DatabaseService.ofy().save().entity((DBMember)member).now();
return DatabaseService.ofy().load().key(result).get();
}
return null;
}
@ApiMethod(name = "account.login", path = "account/login")
public MessageBean getLoginToken(@Named("email") String email, @Named("password") String password) {
// this was caught by BearerTokenAuthenticatingFilter
return new MessageBean(HTTP.Status.OK.toInt(), Messages.Status.OK.toString());
}
@ApiMethod(name = "account.logout", path = "account/logout")
public MessageBean deleteLoginToken() {
// this was caught by BearerTokenRevokeFilter
return new MessageBean(HTTP.Status.OK.toInt(), Messages.Status.OK.toString());
}
}