NIHVIVO-2279 Implement the MyAccount page.

This commit is contained in:
j2blake 2011-06-01 15:32:00 +00:00
parent 64fa779638
commit 3b5eb3a846
10 changed files with 528 additions and 14 deletions

View file

@ -59,8 +59,8 @@ public abstract class UserAccountsPage {
userAccountsDao = wdf.getUserAccountsDao();
}
protected static boolean isEmailEnabled(HttpServletRequest req) {
return FreemarkerEmailFactory.isConfigured(req);
protected boolean isEmailEnabled() {
return FreemarkerEmailFactory.isConfigured(vreq);
}
protected String getStringParameter(String key, String defaultValue) {
@ -126,6 +126,7 @@ public abstract class UserAccountsPage {
map.put("list", UrlBuilder.getUrl("/accountsAdmin/list"));
map.put("add", UrlBuilder.getUrl("/accountsAdmin/add"));
map.put("delete", UrlBuilder.getUrl("/accountsAdmin/delete"));
map.put("myAccount", UrlBuilder.getUrl("/accounts/myAccount"));
map.put("createPassword", UrlBuilder.getUrl("/accounts/createPassword"));
map.put("resetPassword", UrlBuilder.getUrl("/accounts/resetPassword"));

View file

@ -54,7 +54,7 @@ public class UserAccountsAddPage extends UserAccountsPage {
super(vreq);
this.strategy = UserAccountsAddPageStrategy.getInstance(vreq, this,
isEmailEnabled(vreq));
isEmailEnabled());
parseRequestParameters();

View file

@ -63,7 +63,7 @@ public class UserAccountsEditPage extends UserAccountsPage {
super(vreq);
this.strategy = UserAccountsEditPageStrategy.getInstance(vreq, this,
isEmailEnabled(vreq));
isEmailEnabled());
parseRequestParameters();
validateUserAccountInfo();

View file

@ -13,6 +13,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsPage;
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage;
@ -166,7 +167,7 @@ public abstract class UserAccountsEditPageStrategy extends UserAccountsPage {
protected String additionalValidations() {
if (newPassword.isEmpty() && confirmPassword.isEmpty()) {
return "";
} else if (!checkPasswordLength()) {
} else if (!checkPasswordLength(newPassword)) {
return ERROR_WRONG_PASSWORD_LENGTH;
} else if (!newPassword.equals(confirmPassword)) {
return ERROR_PASSWORDS_DONT_MATCH;
@ -175,11 +176,6 @@ public abstract class UserAccountsEditPageStrategy extends UserAccountsPage {
}
}
private boolean checkPasswordLength() {
return newPassword.length() >= UserAccount.MIN_PASSWORD_LENGTH
&& newPassword.length() <= UserAccount.MAX_PASSWORD_LENGTH;
}
@Override
protected void addMoreBodyValues(Map<String, Object> body) {
body.put("newPassword", newPassword);
@ -190,8 +186,10 @@ public abstract class UserAccountsEditPageStrategy extends UserAccountsPage {
@Override
protected void setAdditionalProperties(UserAccount u) {
u.setMd5Password(newPassword);
u.setPasswordChangeRequired(true);
if (!newPassword.isEmpty()) {
u.setMd5Password(Authenticator.applyMd5Encoding(newPassword));
u.setPasswordChangeRequired(true);
}
}
@Override

View file

@ -0,0 +1,176 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.accounts.user;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
import edu.cornell.mannlib.vitro.webapp.beans.User;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsPage;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.admin.UserAccountsEditPage;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
import edu.cornell.mannlib.vitro.webapp.dao.UserDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
/**
* Handle the "My Account" form display and submission.
*/
public class UserAccountsMyAccountPage extends UserAccountsPage {
private static final Log log = LogFactory
.getLog(UserAccountsEditPage.class);
private static final String PARAMETER_SUBMIT = "submitMyAccount";
private static final String PARAMETER_EMAIL_ADDRESS = "emailAddress";
private static final String PARAMETER_FIRST_NAME = "firstName";
private static final String PARAMETER_LAST_NAME = "lastName";
private static final String ERROR_NO_EMAIL = "errorEmailIsEmpty";
private static final String ERROR_EMAIL_IN_USE = "errorEmailInUse";
private static final String ERROR_NO_FIRST_NAME = "errorFirstNameIsEmpty";
private static final String ERROR_NO_LAST_NAME = "errorLastNameIsEmpty";
private static final String TEMPLATE_NAME = "userAccounts-myAccount.ftl";
private final UserAccountsMyAccountPageStrategy strategy;
private final UserAccount userAccount;
/* The request parameters */
private boolean submit;
private String emailAddress = "";
private String firstName = "";
private String lastName = "";
/** The result of validating a "submit" request. */
private String errorCode = "";
/** The result of updating the account. */
private String confirmationCode = "";
public UserAccountsMyAccountPage(VitroRequest vreq) {
super(vreq);
this.userAccount = getLoggedInUser();
this.strategy = UserAccountsMyAccountPageStrategy.getInstance(vreq,
this, isExternalAccount());
parseRequestParameters();
if (isSubmit()) {
validateParameters();
}
}
public UserAccount getUserAccount() {
return userAccount;
}
private void parseRequestParameters() {
submit = isFlagOnRequest(PARAMETER_SUBMIT);
emailAddress = getStringParameter(PARAMETER_EMAIL_ADDRESS, "");
firstName = getStringParameter(PARAMETER_FIRST_NAME, "");
lastName = getStringParameter(PARAMETER_LAST_NAME, "");
strategy.parseAdditionalParameters();
}
public boolean isSubmit() {
return submit;
}
private void validateParameters() {
if (emailAddress.isEmpty()) {
errorCode = ERROR_NO_EMAIL;
} else if (emailIsChanged() && isEmailInUse()) {
errorCode = ERROR_EMAIL_IN_USE;
} else if (firstName.isEmpty()) {
errorCode = ERROR_NO_FIRST_NAME;
} else if (lastName.isEmpty()) {
errorCode = ERROR_NO_LAST_NAME;
} else {
errorCode = strategy.additionalValidations();
}
}
private boolean emailIsChanged() {
return !emailAddress.equals(userAccount.getEmailAddress());
}
private boolean isEmailInUse() {
return userAccountsDao.getUserAccountByEmail(emailAddress) != null;
}
public boolean isValid() {
return errorCode.isEmpty();
}
private UserAccount getLoggedInUser() {
// TODO This is a bogus measure.
// TODO It only works because for now we are not deleting old User
// structures, and there is a new UserAccount with email set to the old
// User username.
String uri = LoginStatusBean.getBean(vreq).getUserURI();
WebappDaoFactory wdf = (WebappDaoFactory) this.ctx
.getAttribute("webappDaoFactory");
User u = wdf.getUserDao().getUserByURI(uri);
UserAccount ua = userAccountsDao.getUserAccountByEmail(u.getUsername());
if (ua == null) {
throw new IllegalStateException("Couldn't find a UserAccount "
+ "for uri: '" + uri + "'");
}
log.debug("Logged-in user is " + ua);
return ua;
}
private boolean isExternalAccount() {
return LoginStatusBean.getBean(vreq).hasExternalAuthentication();
}
public final ResponseValues showPage() {
Map<String, Object> body = new HashMap<String, Object>();
if (isSubmit()) {
body.put("emailAddress", emailAddress);
body.put("firstName", firstName);
body.put("lastName", lastName);
} else {
body.put("emailAddress", userAccount.getEmailAddress());
body.put("firstName", userAccount.getFirstName());
body.put("lastName", userAccount.getLastName());
}
body.put("formUrls", buildUrlsMap());
if (!errorCode.isEmpty()) {
body.put(errorCode, Boolean.TRUE);
}
if (!confirmationCode.isEmpty()) {
body.put(confirmationCode, Boolean.TRUE);
}
strategy.addMoreBodyValues(body);
return new TemplateResponseValues(TEMPLATE_NAME, body);
}
public void updateAccount() {
userAccount.setEmailAddress(emailAddress);
userAccount.setFirstName(firstName);
userAccount.setLastName(lastName);
strategy.setAdditionalProperties(userAccount);
userAccountsDao.updateUserAccount(userAccount);
strategy.notifyUser();
confirmationCode = strategy.getConfirmationCode();
}
}

View file

@ -0,0 +1,196 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.accounts.user;
import static javax.mail.Message.RecipientType.TO;
import java.util.HashMap;
import java.util.Map;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsPage;
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage;
/**
* Handle the variant details of the MyAccounts page
*/
public abstract class UserAccountsMyAccountPageStrategy extends
UserAccountsPage {
private static final String CONFIRM_CHANGE = "confirmChange";
private static final String CONFIRM_EMAIL_SENT = "confirmEmailSent";
protected final UserAccountsMyAccountPage page;
public static UserAccountsMyAccountPageStrategy getInstance(
VitroRequest vreq, UserAccountsMyAccountPage page,
boolean externalAuth) {
if (externalAuth) {
return new ExternalAuthStrategy(vreq, page);
} else {
return new InternalAuthStrategy(vreq, page);
}
}
protected UserAccountsMyAccountPageStrategy(VitroRequest vreq,
UserAccountsMyAccountPage page) {
super(vreq);
this.page = page;
}
public abstract void parseAdditionalParameters();
public abstract String additionalValidations();
public abstract void addMoreBodyValues(Map<String, Object> body);
public abstract void setAdditionalProperties(UserAccount userAccount);
public abstract void notifyUser();
public abstract String getConfirmationCode();
// ----------------------------------------------------------------------
// Strategy to use if the account used External Authentication
// ----------------------------------------------------------------------
private static class ExternalAuthStrategy extends
UserAccountsMyAccountPageStrategy {
ExternalAuthStrategy(VitroRequest vreq, UserAccountsMyAccountPage page) {
super(vreq, page);
}
@Override
public void parseAdditionalParameters() {
// No additional parameters
}
@Override
public String additionalValidations() {
// No additional validations
return "";
}
@Override
public void addMoreBodyValues(Map<String, Object> body) {
body.put("externalAuth", Boolean.TRUE);
}
@Override
public void setAdditionalProperties(UserAccount userAccount) {
// No additional properties.
}
@Override
public void notifyUser() {
// No notification beyond the screen message.
}
@Override
public String getConfirmationCode() {
return CONFIRM_CHANGE;
}
}
// ----------------------------------------------------------------------
// Strategy to use if the account used Internal Authentication
// ----------------------------------------------------------------------
private static class InternalAuthStrategy extends
UserAccountsMyAccountPageStrategy {
private static final String PARAMETER_NEW_PASSWORD = "newPassword";
private static final String PARAMETER_CONFIRM_PASSWORD = "confirmPassword";
private static final String ERROR_WRONG_PASSWORD_LENGTH = "errorPasswordIsWrongLength";
private static final String ERROR_PASSWORDS_DONT_MATCH = "errorPasswordsDontMatch";
private final String originalEmail;
private String newPassword;
private String confirmPassword;
private boolean emailSent;
InternalAuthStrategy(VitroRequest vreq, UserAccountsMyAccountPage page) {
super(vreq, page);
originalEmail = page.getUserAccount().getEmailAddress();
}
@Override
public void parseAdditionalParameters() {
newPassword = getStringParameter(PARAMETER_NEW_PASSWORD, "");
confirmPassword = getStringParameter(PARAMETER_CONFIRM_PASSWORD, "");
}
@Override
public String additionalValidations() {
if (newPassword.isEmpty() && confirmPassword.isEmpty()) {
return "";
} else if (!newPassword.equals(confirmPassword)) {
return ERROR_PASSWORDS_DONT_MATCH;
} else if (!checkPasswordLength(newPassword)) {
return ERROR_WRONG_PASSWORD_LENGTH;
} else {
return "";
}
}
@Override
public void addMoreBodyValues(Map<String, Object> body) {
body.put("newPassword", newPassword);
body.put("confirmPassword", confirmPassword);
body.put("minimumLength", UserAccount.MIN_PASSWORD_LENGTH);
body.put("maximumLength", UserAccount.MAX_PASSWORD_LENGTH);
}
@Override
public void setAdditionalProperties(UserAccount userAccount) {
if (!newPassword.isEmpty()) {
userAccount.setMd5Password(Authenticator
.applyMd5Encoding(newPassword));
userAccount.setPasswordChangeRequired(false);
userAccount.setPasswordLinkExpires(0L);
}
}
@Override
public void notifyUser() {
if (!isEmailEnabled()) {
return;
}
if (!emailHasChanged()) {
return;
}
Map<String, Object> body = new HashMap<String, Object>();
body.put("userAccount", page.getUserAccount());
body.put("subjectLine", "Your VIVO email account has been changed.");
FreemarkerEmailMessage email = FreemarkerEmailFactory
.createNewMessage(vreq);
email.addRecipient(TO, page.getUserAccount().getEmailAddress());
email.setSubject("Your VIVO email account has been changed.");
email.setHtmlTemplate("userAccounts-confirmEmailChangedEmail-html.ftl");
email.setTextTemplate("userAccounts-confirmEmailChangedEmail-text.ftl");
email.setBodyMap(body);
email.send();
emailSent = true;
}
private boolean emailHasChanged() {
return !page.getUserAccount().getEmailAddress()
.equals(originalEmail);
}
@Override
public String getConfirmationCode() {
return emailSent ? CONFIRM_EMAIL_SENT : CONFIRM_CHANGE;
}
}
}

View file

@ -6,6 +6,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.EditOwnAccount;
import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
@ -23,10 +24,17 @@ public class UserAccountsUserController extends FreemarkerHttpServlet {
private static final String ACTION_CREATE_PASSWORD = "/createPassword";
private static final String ACTION_RESET_PASSWORD = "/resetPassword";
private static final String ACTION_MY_ACCOUNT = "/myAccount";
@Override
protected Actions requiredActions(VitroRequest vreq) {
return Actions.AUTHORIZED;
String action = vreq.getPathInfo();
if (ACTION_MY_ACCOUNT.equals(action)) {
return new Actions(new EditOwnAccount());
} else {
return Actions.AUTHORIZED;
}
}
@Override
@ -38,7 +46,9 @@ public class UserAccountsUserController extends FreemarkerHttpServlet {
String action = vreq.getPathInfo();
log.debug("action = '" + action + "'");
if (ACTION_CREATE_PASSWORD.equals(action)) {
if (ACTION_MY_ACCOUNT.equals(action)) {
return handleMyAccountRequest(vreq);
} else if (ACTION_CREATE_PASSWORD.equals(action)) {
return handleCreatePasswordRequest(vreq);
} else if (ACTION_RESET_PASSWORD.equals(action)) {
return handleResetPasswordRequest(vreq);
@ -47,6 +57,14 @@ public class UserAccountsUserController extends FreemarkerHttpServlet {
}
}
private ResponseValues handleMyAccountRequest(VitroRequest vreq) {
UserAccountsMyAccountPage page = new UserAccountsMyAccountPage(vreq);
if (page.isSubmit() && page.isValid()) {
page.updateAccount();
}
return page.showPage();
}
private ResponseValues handleCreatePasswordRequest(VitroRequest vreq) {
UserAccountsCreatePasswordPage page = new UserAccountsCreatePasswordPage(
vreq);