NIHVIVO-2279 Implement account editing and password change.
This commit is contained in:
parent
d6bacf0c95
commit
a1915c8398
22 changed files with 1006 additions and 223 deletions
|
@ -3,8 +3,10 @@
|
|||
package edu.cornell.mannlib.vitro.webapp.controller.accounts;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -18,6 +20,7 @@ import org.apache.commons.logging.LogFactory;
|
|||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.PermissionSet;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
|
||||
|
@ -32,6 +35,12 @@ import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
|
|||
public abstract class UserAccountsPage {
|
||||
private static final Log log = LogFactory.getLog(UserAccountsPage.class);
|
||||
|
||||
/**
|
||||
* After the account is created, or the password is reset, the user has this
|
||||
* many days to repond to the email.
|
||||
*/
|
||||
protected static final int DAYS_TO_USE_PASSWORD_LINK = 90;
|
||||
|
||||
protected final VitroRequest vreq;
|
||||
protected final ServletContext ctx;
|
||||
protected final OntModel userAccountsModel;
|
||||
|
@ -82,6 +91,17 @@ public abstract class UserAccountsPage {
|
|||
return (value != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Treat the presence of a certain parameter, with a desired value, as a
|
||||
* boolean flag.
|
||||
*
|
||||
* An example would be radio buttons with values of "yes" and
|
||||
* "no". The expected value would be "yes".
|
||||
*/
|
||||
protected boolean isParameterAsExpected(String key, String expected) {
|
||||
return expected.equals(getStringParameter(key, ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of all known PermissionSets.
|
||||
*/
|
||||
|
@ -107,12 +127,25 @@ public abstract class UserAccountsPage {
|
|||
map.put("add", UrlBuilder.getUrl("/accountsAdmin/add"));
|
||||
map.put("delete", UrlBuilder.getUrl("/accountsAdmin/delete"));
|
||||
map.put("createPassword", UrlBuilder.getUrl("/accounts/createPassword"));
|
||||
map.put("resetPassword", UrlBuilder.getUrl("/accounts/resetPassword"));
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
protected static String editAccountUrl(String uri) {
|
||||
return UrlBuilder.getUrl("/accountsAdmin/edit",
|
||||
new ParamMap("editAccount", uri));
|
||||
return UrlBuilder.getUrl("/accountsAdmin/edit", new ParamMap(
|
||||
"editAccount", uri));
|
||||
}
|
||||
|
||||
protected Date figureExpirationDate() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.DATE, DAYS_TO_USE_PASSWORD_LINK);
|
||||
return c.getTime();
|
||||
}
|
||||
|
||||
protected boolean checkPasswordLength(String pw) {
|
||||
return pw.length() >= UserAccount.MIN_PASSWORD_LENGTH
|
||||
&& pw.length() <= UserAccount.MAX_PASSWORD_LENGTH;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -68,8 +68,9 @@ public class UserAccountsAddPage extends UserAccountsPage {
|
|||
emailAddress = getStringParameter(PARAMETER_EMAIL_ADDRESS, "");
|
||||
firstName = getStringParameter(PARAMETER_FIRST_NAME, "");
|
||||
lastName = getStringParameter(PARAMETER_LAST_NAME, "");
|
||||
selectedRoleUri = getRoleChoices();
|
||||
associateWithProfile = getAssociateFlag();
|
||||
selectedRoleUri = getStringParameter(PARAMETER_ROLE, "");
|
||||
associateWithProfile = isParameterAsExpected(
|
||||
PARAMETER_ASSOCIATE_WITH_PROFILE, "yes");
|
||||
|
||||
strategy.parseAdditionalParameters();
|
||||
}
|
||||
|
@ -126,22 +127,6 @@ public class UserAccountsAddPage extends UserAccountsPage {
|
|||
strategy.notifyUser();
|
||||
}
|
||||
|
||||
/** What role are they asking for? */
|
||||
private String getRoleChoices() {
|
||||
String[] roles = vreq.getParameterValues(PARAMETER_ROLE);
|
||||
if ((roles == null) || (roles.length == 0)) {
|
||||
return "";
|
||||
} else {
|
||||
return roles[0];
|
||||
}
|
||||
}
|
||||
|
||||
/** Are they associating with an Individual profile? */
|
||||
private boolean getAssociateFlag() {
|
||||
return "yes".equals(getStringParameter(
|
||||
PARAMETER_ASSOCIATE_WITH_PROFILE, "no"));
|
||||
}
|
||||
|
||||
public final ResponseValues showPage() {
|
||||
Map<String, Object> body = new HashMap<String, Object>();
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@ import static javax.mail.Message.RecipientType.TO;
|
|||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -34,7 +32,8 @@ public abstract class UserAccountsAddPageStrategy extends UserAccountsPage {
|
|||
}
|
||||
}
|
||||
|
||||
public UserAccountsAddPageStrategy(VitroRequest vreq, UserAccountsAddPage page) {
|
||||
public UserAccountsAddPageStrategy(VitroRequest vreq,
|
||||
UserAccountsAddPage page) {
|
||||
super(vreq);
|
||||
this.page = page;
|
||||
}
|
||||
|
@ -57,7 +56,6 @@ public abstract class UserAccountsAddPageStrategy extends UserAccountsPage {
|
|||
|
||||
private static class EmailStrategy extends UserAccountsAddPageStrategy {
|
||||
public static final String CREATE_PASSWORD_URL = "/accounts/createPassword";
|
||||
private static final int DAYS_TO_ACTIVATE_ACCOUNT = 90;
|
||||
|
||||
private boolean sentEmail;
|
||||
|
||||
|
@ -82,12 +80,6 @@ public abstract class UserAccountsAddPageStrategy extends UserAccountsPage {
|
|||
u.setStatus(Status.INACTIVE);
|
||||
}
|
||||
|
||||
private Date figureExpirationDate() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.DATE, DAYS_TO_ACTIVATE_ACCOUNT);
|
||||
return c.getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addMoreBodyValues(Map<String, Object> body) {
|
||||
body.put("emailIsEnabled", Boolean.TRUE);
|
||||
|
@ -117,8 +109,8 @@ public abstract class UserAccountsAddPageStrategy extends UserAccountsPage {
|
|||
String email = page.getAddedAccount().getEmailAddress();
|
||||
String hash = page.getAddedAccount()
|
||||
.getPasswordLinkExpiresHash();
|
||||
String relativeUrl = UrlBuilder.getUrl(CREATE_PASSWORD_URL, "user",
|
||||
email, "key", hash);
|
||||
String relativeUrl = UrlBuilder.getUrl(CREATE_PASSWORD_URL,
|
||||
"user", email, "key", hash);
|
||||
|
||||
URL context = new URL(vreq.getRequestURL().toString());
|
||||
URL url = new URL(context, relativeUrl);
|
||||
|
@ -156,10 +148,8 @@ public abstract class UserAccountsAddPageStrategy extends UserAccountsPage {
|
|||
|
||||
@Override
|
||||
protected void parseAdditionalParameters() {
|
||||
initialPassword = getStringParameter(
|
||||
PARAMETER_INITIAL_PASSWORD, "");
|
||||
confirmPassword = getStringParameter(
|
||||
PARAMETER_CONFIRM_PASSWORD, "");
|
||||
initialPassword = getStringParameter(PARAMETER_INITIAL_PASSWORD, "");
|
||||
confirmPassword = getStringParameter(PARAMETER_CONFIRM_PASSWORD, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -184,6 +174,8 @@ public abstract class UserAccountsAddPageStrategy extends UserAccountsPage {
|
|||
protected void addMoreBodyValues(Map<String, Object> body) {
|
||||
body.put("initialPassword", initialPassword);
|
||||
body.put("confirmPassword", confirmPassword);
|
||||
body.put("minimumLength", UserAccount.MIN_PASSWORD_LENGTH);
|
||||
body.put("maximumLength", UserAccount.MAX_PASSWORD_LENGTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,12 +9,15 @@ import org.apache.commons.logging.LogFactory;
|
|||
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.ManageUserAccounts;
|
||||
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;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.RedirectResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
|
||||
/**
|
||||
* Parcel out the different actions required of the Administrators portion of the UserAccounts GUI.
|
||||
* Parcel out the different actions required of the Administrators portion of
|
||||
* the UserAccounts GUI.
|
||||
*/
|
||||
public class UserAccountsAdminController extends FreemarkerHttpServlet {
|
||||
private static final Log log = LogFactory
|
||||
|
@ -64,7 +67,9 @@ public class UserAccountsAdminController extends FreemarkerHttpServlet {
|
|||
|
||||
private ResponseValues handleEditRequest(VitroRequest vreq) {
|
||||
UserAccountsEditPage page = new UserAccountsEditPage(vreq);
|
||||
if (page.isSubmit() && page.isValid()) {
|
||||
if (page.isBogus()) {
|
||||
return showHomePage(vreq, page.getBogusMessage());
|
||||
} else if (page.isSubmit() && page.isValid()) {
|
||||
page.updateAccount();
|
||||
UserAccountsListPage listPage = new UserAccountsListPage(vreq);
|
||||
return listPage.showPageWithUpdatedAccount(
|
||||
|
@ -87,4 +92,9 @@ public class UserAccountsAdminController extends FreemarkerHttpServlet {
|
|||
return page.showPage();
|
||||
}
|
||||
|
||||
private ResponseValues showHomePage(VitroRequest vreq, String message) {
|
||||
DisplayMessage.setMessage(vreq, message);
|
||||
return new RedirectResponseValues("/");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,75 +2,217 @@
|
|||
|
||||
package edu.cornell.mannlib.vitro.webapp.controller.accounts.admin;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
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.user.UserAccountsUserController;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||
|
||||
/**
|
||||
* TODO present the form. Get the submission.
|
||||
*
|
||||
* TODO If email is available, present the reset flag with message templage, and send email
|
||||
* TODO If email is available, present the reset flag with message templage, and
|
||||
* send email
|
||||
*
|
||||
* TODO if email is not available, allow password change with checks for validity
|
||||
* TODO if email is not available, allow password change with checks for
|
||||
* validity
|
||||
*
|
||||
* TODO If successful, go to AccountsList with message and optional password message.
|
||||
* TODO If successful, go to AccountsList with message and optional password
|
||||
* message.
|
||||
*
|
||||
* TODO if unsuccessful, go back to the page, with errors.
|
||||
*
|
||||
* TODO How much of this can be shared with AddPage? Email templates?
|
||||
*/
|
||||
public class UserAccountsEditPage extends UserAccountsPage {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(UserAccountsEditPage.class);
|
||||
|
||||
private static final String PARAMETER_SUBMIT = "submitEdit";
|
||||
private static final String PARAMETER_USER_URI = "editAccount";
|
||||
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 PARAMETER_ROLE = "role";
|
||||
private static final String PARAMETER_ASSOCIATE_WITH_PROFILE = "associate";
|
||||
|
||||
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 ERROR_NO_ROLE = "errorNoRoleSelected";
|
||||
|
||||
private static final String TEMPLATE_NAME = "userAccounts-edit.ftl";
|
||||
|
||||
private final UserAccountsEditPageStrategy strategy;
|
||||
|
||||
/* The request parameters */
|
||||
private boolean submit;
|
||||
private String userUri = "";
|
||||
private String emailAddress = "";
|
||||
private String firstName = "";
|
||||
private String lastName = "";
|
||||
private String selectedRoleUri = "";
|
||||
private boolean associateWithProfile;
|
||||
|
||||
private UserAccount userAccount;
|
||||
|
||||
/** The result of checking whether this request is even appropriate. */
|
||||
private String bogusMessage = "";
|
||||
|
||||
/** The result of validating a "submit" request. */
|
||||
private String errorCode = "";
|
||||
|
||||
public UserAccountsEditPage(VitroRequest vreq) {
|
||||
super(vreq);
|
||||
|
||||
this.strategy = UserAccountsEditPageStrategy.getInstance(vreq, this,
|
||||
isEmailEnabled(vreq));
|
||||
|
||||
parseRequestParameters();
|
||||
validateUserAccountInfo();
|
||||
|
||||
if (isSubmit() && !isBogus()) {
|
||||
validateParameters();
|
||||
}
|
||||
}
|
||||
|
||||
public ResponseValues showPage() {
|
||||
return new TemplateResponseValues(TEMPLATE_NAME);
|
||||
private void parseRequestParameters() {
|
||||
submit = isFlagOnRequest(PARAMETER_SUBMIT);
|
||||
userUri = getStringParameter(PARAMETER_USER_URI, "");
|
||||
emailAddress = getStringParameter(PARAMETER_EMAIL_ADDRESS, "");
|
||||
firstName = getStringParameter(PARAMETER_FIRST_NAME, "");
|
||||
lastName = getStringParameter(PARAMETER_LAST_NAME, "");
|
||||
selectedRoleUri = getStringParameter(PARAMETER_ROLE, "");
|
||||
associateWithProfile = isParameterAsExpected(
|
||||
PARAMETER_ASSOCIATE_WITH_PROFILE, "yes");
|
||||
|
||||
strategy.parseAdditionalParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public UserAccount updateAccount() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new RuntimeException("UserAccountsEditPage.updateAccount() not implemented.");
|
||||
private void validateUserAccountInfo() {
|
||||
userAccount = userAccountsDao.getUserAccountByUri(userUri);
|
||||
if (userAccount == null) {
|
||||
log.warn("Edit account for '" + userUri
|
||||
+ "' is bogus: no such user");
|
||||
bogusMessage = UserAccountsUserController.BOGUS_STANDARD_MESSAGE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean wasPasswordEmailSent() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new RuntimeException("UserAccountsEditPage.wasPasswordEmailSent() not implemented.");
|
||||
public boolean isBogus() {
|
||||
return !bogusMessage.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public UserAccount getUpdatedAccount() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new RuntimeException("UserAccountsEditPage.getUpdatedAccount() not implemented.");
|
||||
public String getBogusMessage() {
|
||||
return bogusMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean isValid() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new RuntimeException("UserAccountsEditPage.isValid() not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean isSubmit() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new RuntimeException("UserAccountsEditPage.isSubmit() not implemented.");
|
||||
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 if (selectedRoleUri.isEmpty()) {
|
||||
errorCode = ERROR_NO_ROLE;
|
||||
} 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();
|
||||
}
|
||||
|
||||
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);
|
||||
body.put("selectedRole", selectedRoleUri);
|
||||
} else {
|
||||
body.put("emailAddress", userAccount.getEmailAddress());
|
||||
body.put("firstName", userAccount.getFirstName());
|
||||
body.put("lastName", userAccount.getLastName());
|
||||
body.put("selectedRole", getExistingRoleUri());
|
||||
}
|
||||
body.put("roles", buildRolesList());
|
||||
if (associateWithProfile) {
|
||||
body.put("associate", Boolean.TRUE);
|
||||
}
|
||||
body.put("formUrls", buildUrlsMapWithEditUrl());
|
||||
|
||||
if (!errorCode.isEmpty()) {
|
||||
body.put(errorCode, Boolean.TRUE);
|
||||
}
|
||||
|
||||
strategy.addMoreBodyValues(body);
|
||||
|
||||
return new TemplateResponseValues(TEMPLATE_NAME, body);
|
||||
}
|
||||
|
||||
private String getExistingRoleUri() {
|
||||
Set<String> uris = userAccount.getPermissionSetUris();
|
||||
if (uris.isEmpty()) {
|
||||
return "";
|
||||
} else {
|
||||
return uris.iterator().next();
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> buildUrlsMapWithEditUrl() {
|
||||
Map<String, String> map = buildUrlsMap();
|
||||
map.put("edit", editAccountUrl(userAccount.getUri()));
|
||||
return map;
|
||||
}
|
||||
|
||||
public void updateAccount() {
|
||||
userAccount.setEmailAddress(emailAddress);
|
||||
userAccount.setFirstName(firstName);
|
||||
userAccount.setLastName(lastName);
|
||||
|
||||
userAccount.setPermissionSetUris(Collections.singleton(selectedRoleUri));
|
||||
|
||||
strategy.setAdditionalProperties(userAccount);
|
||||
|
||||
userAccountsDao.updateUserAccount(userAccount);
|
||||
|
||||
strategy.notifyUser();
|
||||
}
|
||||
|
||||
public boolean wasPasswordEmailSent() {
|
||||
return strategy.wasPasswordEmailSent();
|
||||
}
|
||||
|
||||
public UserAccount getUpdatedAccount() {
|
||||
return userAccount;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.controller.accounts.admin;
|
||||
|
||||
import static javax.mail.Message.RecipientType.TO;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
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.freemarker.UrlBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage;
|
||||
|
||||
/**
|
||||
* Handle the variant details of the UserAccountsAddPage.
|
||||
*/
|
||||
public abstract class UserAccountsEditPageStrategy extends UserAccountsPage {
|
||||
protected final UserAccountsEditPage page;
|
||||
|
||||
public static UserAccountsEditPageStrategy getInstance(VitroRequest vreq,
|
||||
UserAccountsEditPage page, boolean emailEnabled) {
|
||||
if (emailEnabled) {
|
||||
return new EmailStrategy(vreq, page);
|
||||
} else {
|
||||
return new NoEmailStrategy(vreq, page);
|
||||
}
|
||||
}
|
||||
|
||||
public UserAccountsEditPageStrategy(VitroRequest vreq,
|
||||
UserAccountsEditPage page) {
|
||||
super(vreq);
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
protected abstract void parseAdditionalParameters();
|
||||
|
||||
protected abstract String additionalValidations();
|
||||
|
||||
protected abstract void addMoreBodyValues(Map<String, Object> body);
|
||||
|
||||
protected abstract void setAdditionalProperties(UserAccount u);
|
||||
|
||||
protected abstract void notifyUser();
|
||||
|
||||
protected abstract boolean wasPasswordEmailSent();
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Strategy to use if email is enabled.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private static class EmailStrategy extends UserAccountsEditPageStrategy {
|
||||
private static final String PARAMETER_RESET_PASSWORD = "resetPassword";
|
||||
|
||||
public static final String RESET_PASSWORD_URL = "/accounts/resetPassword";
|
||||
|
||||
private boolean resetPassword;
|
||||
private boolean sentEmail;
|
||||
|
||||
public EmailStrategy(VitroRequest vreq, UserAccountsEditPage page) {
|
||||
super(vreq, page);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseAdditionalParameters() {
|
||||
resetPassword = isFlagOnRequest(PARAMETER_RESET_PASSWORD);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String additionalValidations() {
|
||||
// No additional validations
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setAdditionalProperties(UserAccount u) {
|
||||
if (resetPassword) {
|
||||
u.setPasswordLinkExpires(figureExpirationDate().getTime());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addMoreBodyValues(Map<String, Object> body) {
|
||||
body.put("emailIsEnabled", Boolean.TRUE);
|
||||
if (resetPassword) {
|
||||
body.put("resetPassword", Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyUser() {
|
||||
if (!resetPassword) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> body = new HashMap<String, Object>();
|
||||
body.put("userAccount", page.getUpdatedAccount());
|
||||
body.put("passwordLink", buildResetPasswordLink());
|
||||
body.put("subjectLine", "Reset password request");
|
||||
|
||||
FreemarkerEmailMessage email = FreemarkerEmailFactory
|
||||
.createNewMessage(vreq);
|
||||
email.addRecipient(TO, page.getUpdatedAccount().getEmailAddress());
|
||||
email.setSubject("Reset password request");
|
||||
email.setHtmlTemplate("userAccounts-resetPasswordEmail-html.ftl");
|
||||
email.setTextTemplate("userAccounts-resetPasswordEmail-text.ftl");
|
||||
email.setBodyMap(body);
|
||||
email.send();
|
||||
|
||||
sentEmail = true;
|
||||
}
|
||||
|
||||
private String buildResetPasswordLink() {
|
||||
try {
|
||||
String email = page.getUpdatedAccount().getEmailAddress();
|
||||
String hash = page.getUpdatedAccount()
|
||||
.getPasswordLinkExpiresHash();
|
||||
String relativeUrl = UrlBuilder.getUrl(RESET_PASSWORD_URL,
|
||||
"user", email, "key", hash);
|
||||
|
||||
URL context = new URL(vreq.getRequestURL().toString());
|
||||
URL url = new URL(context, relativeUrl);
|
||||
return url.toExternalForm();
|
||||
} catch (MalformedURLException e) {
|
||||
return "error_creating_password_link";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean wasPasswordEmailSent() {
|
||||
return sentEmail;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Strategy to use if email is not enabled.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private static class NoEmailStrategy extends UserAccountsEditPageStrategy {
|
||||
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 String newPassword;
|
||||
private String confirmPassword;
|
||||
|
||||
public NoEmailStrategy(VitroRequest vreq, UserAccountsEditPage page) {
|
||||
super(vreq, page);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseAdditionalParameters() {
|
||||
newPassword = getStringParameter(PARAMETER_NEW_PASSWORD, "");
|
||||
confirmPassword = getStringParameter(PARAMETER_CONFIRM_PASSWORD, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String additionalValidations() {
|
||||
if (newPassword.isEmpty() && confirmPassword.isEmpty()) {
|
||||
return "";
|
||||
} else if (!checkPasswordLength()) {
|
||||
return ERROR_WRONG_PASSWORD_LENGTH;
|
||||
} else if (!newPassword.equals(confirmPassword)) {
|
||||
return ERROR_PASSWORDS_DONT_MATCH;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
body.put("confirmPassword", confirmPassword);
|
||||
body.put("minimumLength", UserAccount.MIN_PASSWORD_LENGTH);
|
||||
body.put("maximumLength", UserAccount.MAX_PASSWORD_LENGTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setAdditionalProperties(UserAccount u) {
|
||||
u.setMd5Password(newPassword);
|
||||
u.setPasswordChangeRequired(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyUser() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean wasPasswordEmailSent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -105,6 +105,9 @@ public class UserAccountsListPage extends UserAccountsPage {
|
|||
|
||||
body.put("newUserAccount", new UserAccountWrapper(userAccount,
|
||||
Collections.<String> emptyList()));
|
||||
if (emailWasSent) {
|
||||
body.put("emailWasSent", Boolean.TRUE);
|
||||
}
|
||||
|
||||
return new TemplateResponseValues(TEMPLATE_NAME, body);
|
||||
}
|
||||
|
@ -114,8 +117,17 @@ public class UserAccountsListPage extends UserAccountsPage {
|
|||
*/
|
||||
public ResponseValues showPageWithUpdatedAccount(UserAccount userAccount,
|
||||
boolean emailWasSent) {
|
||||
throw new RuntimeException(
|
||||
"UserAccountsListPage.showPageWithUpdatedAccount not implemented.");
|
||||
UserAccountsSelection selection = UserAccountsSelector.select(
|
||||
userAccountsModel, criteria);
|
||||
Map<String, Object> body = buildTemplateBodyMap(selection);
|
||||
|
||||
body.put("updatedUserAccount", new UserAccountWrapper(userAccount,
|
||||
Collections.<String> emptyList()));
|
||||
if (emailWasSent) {
|
||||
body.put("emailWasSent", Boolean.TRUE);
|
||||
}
|
||||
|
||||
return new TemplateResponseValues(TEMPLATE_NAME, body);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,165 +2,68 @@
|
|||
|
||||
package edu.cornell.mannlib.vitro.webapp.controller.accounts.user;
|
||||
|
||||
import java.util.Date;
|
||||
import static javax.mail.Message.RecipientType.TO;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
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.responsevalues.ResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage;
|
||||
|
||||
/**
|
||||
* When the user clicks on the link in their notification email, handle their
|
||||
* request to create a password.
|
||||
*/
|
||||
public class UserAccountsCreatePasswordPage extends UserAccountsPage {
|
||||
public class UserAccountsCreatePasswordPage extends
|
||||
UserAccountsPasswordBasePage {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(UserAccountsCreatePasswordPage.class);
|
||||
|
||||
private static final String PARAMETER_SUBMIT = "submitCreatePassword";
|
||||
private static final String PARAMETER_USER = "user";
|
||||
private static final String PARAMETER_KEY = "key";
|
||||
private static final String PARAMETER_PASSWORD = "password";
|
||||
private static final String PARAMETER_CONFIRM_PASSWORD = "confirmPassword";
|
||||
|
||||
private static final String TEMPLATE_NAME = "userAccounts-createPassword.ftl";
|
||||
|
||||
private static final String ERROR_NO_PASSWORD = "errorPasswordIsEmpty";
|
||||
private static final String ERROR_WRONG_PASSWORD_LENGTH = "errorPasswordIsWrongLength";
|
||||
private static final String ERROR_PASSWORDS_DONT_MATCH = "errorPasswordsDontMatch";
|
||||
|
||||
private boolean submit;
|
||||
private String userEmail = "";
|
||||
private String key = "";
|
||||
private String password = "";
|
||||
private String confirmPassword = "";
|
||||
|
||||
private UserAccount userAccount;
|
||||
|
||||
/** The result of checking whether this request is even appropriate. */
|
||||
private String bogusMessage = "";
|
||||
|
||||
/** The result of validating a "submit" request. */
|
||||
private String errorCode = "";
|
||||
|
||||
public UserAccountsCreatePasswordPage(VitroRequest vreq) {
|
||||
super(vreq);
|
||||
|
||||
parseRequestParameters();
|
||||
validateUserAccountInfo();
|
||||
|
||||
if (isSubmit() && !isBogus()) {
|
||||
validateParameters();
|
||||
}
|
||||
}
|
||||
|
||||
private void parseRequestParameters() {
|
||||
submit = isFlagOnRequest(PARAMETER_SUBMIT);
|
||||
userEmail = getStringParameter(PARAMETER_USER, "");
|
||||
key = getStringParameter(PARAMETER_KEY, "");
|
||||
password = getStringParameter(PARAMETER_PASSWORD, "");
|
||||
confirmPassword = getStringParameter(PARAMETER_CONFIRM_PASSWORD, "");
|
||||
}
|
||||
|
||||
private void validateUserAccountInfo() {
|
||||
userAccount = userAccountsDao.getUserAccountByEmail(userEmail);
|
||||
if (userAccount == null) {
|
||||
log.warn("Create password for '" + userEmail
|
||||
+ "' is bogus: no such user");
|
||||
bogusMessage = UserAccountsUserController.BOGUS_STANDARD_MESSAGE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (userAccount.getPasswordLinkExpires() == 0L) {
|
||||
log.warn("Create password for '" + userEmail
|
||||
+ "' is bogus: password change is not pending.");
|
||||
bogusMessage = "The account for " + userEmail
|
||||
+ " has already been activated.";
|
||||
return;
|
||||
}
|
||||
|
||||
Date expirationDate = new Date(userAccount.getPasswordLinkExpires());
|
||||
if (expirationDate.before(new Date())) {
|
||||
log.warn("Create password for '" + userEmail
|
||||
+ "' is bogus: expiration date has passed.");
|
||||
bogusMessage = UserAccountsUserController.BOGUS_STANDARD_MESSAGE;
|
||||
return;
|
||||
}
|
||||
|
||||
String expectedKey = userAccount.getPasswordLinkExpiresHash();
|
||||
if (!key.equals(expectedKey)) {
|
||||
log.warn("Create password for '" + userEmail + "' is bogus: key ("
|
||||
+ key + ") doesn't match expected key (" + expectedKey
|
||||
+ ")");
|
||||
bogusMessage = UserAccountsUserController.BOGUS_STANDARD_MESSAGE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateParameters() {
|
||||
if (password.isEmpty()) {
|
||||
errorCode = ERROR_NO_PASSWORD;
|
||||
} else if (!checkPasswordLength(password)) {
|
||||
errorCode = ERROR_WRONG_PASSWORD_LENGTH;
|
||||
} else if (!password.equals(confirmPassword)) {
|
||||
errorCode = ERROR_PASSWORDS_DONT_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkPasswordLength(String pw) {
|
||||
return pw.length() >= UserAccount.MIN_PASSWORD_LENGTH
|
||||
&& pw.length() <= UserAccount.MAX_PASSWORD_LENGTH;
|
||||
}
|
||||
|
||||
public boolean isBogus() {
|
||||
return bogusMessage.isEmpty();
|
||||
}
|
||||
|
||||
public String getBogusMessage() {
|
||||
return bogusMessage;
|
||||
}
|
||||
|
||||
public boolean isSubmit() {
|
||||
return submit;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return errorCode.isEmpty();
|
||||
}
|
||||
|
||||
public void createPassword() {
|
||||
userAccount.setMd5Password(Authenticator.applyMd5Encoding(password));
|
||||
userAccount.setMd5Password(Authenticator.applyMd5Encoding(newPassword));
|
||||
userAccount.setPasswordLinkExpires(0L);
|
||||
userAccount.setStatus(Status.ACTIVE);
|
||||
userAccountsDao.updateUserAccount(userAccount);
|
||||
log.debug("Set password on '" + userAccount.getEmailAddress()
|
||||
+ "' to '" + password + "'");
|
||||
+ "' to '" + newPassword + "'");
|
||||
|
||||
notifyUser();
|
||||
}
|
||||
|
||||
public final ResponseValues showPage() {
|
||||
@Override
|
||||
protected String passwordChangeNotPendingMessage() {
|
||||
return "The account for " + userEmail + " has already been activated.";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String templateName() {
|
||||
return TEMPLATE_NAME;
|
||||
}
|
||||
|
||||
private void notifyUser() {
|
||||
Map<String, Object> body = new HashMap<String, Object>();
|
||||
|
||||
body.put("minimumLength", UserAccount.MIN_PASSWORD_LENGTH);
|
||||
body.put("maximumLength", UserAccount.MAX_PASSWORD_LENGTH);
|
||||
body.put("userAccount", userAccount);
|
||||
body.put("key", userAccount.getPasswordLinkExpiresHash());
|
||||
body.put("password", password);
|
||||
body.put("confirmPassword", confirmPassword);
|
||||
body.put("formUrls", buildUrlsMap());
|
||||
body.put("subjectLine", "Password successfully created.");
|
||||
|
||||
if (!errorCode.isEmpty()) {
|
||||
body.put(errorCode, Boolean.TRUE);
|
||||
FreemarkerEmailMessage email = FreemarkerEmailFactory
|
||||
.createNewMessage(vreq);
|
||||
email.addRecipient(TO, userAccount.getEmailAddress());
|
||||
email.setSubject("Password successfully created.");
|
||||
email.setHtmlTemplate("userAccounts-passwordCreatedEmail-html.ftl");
|
||||
email.setTextTemplate("userAccounts-passwordCreatedEmail-text.ftl");
|
||||
email.setBodyMap(body);
|
||||
email.send();
|
||||
}
|
||||
|
||||
return new TemplateResponseValues(TEMPLATE_NAME, body);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
/* $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 edu.cornell.mannlib.vitro.webapp.controller.accounts.user.UserAccountsUserController.BOGUS_STANDARD_MESSAGE;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
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.freemarker.responsevalues.ResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||
|
||||
/**
|
||||
* Routines in common to the "Create Password" and "Reset Password" pages.
|
||||
*/
|
||||
public abstract class UserAccountsPasswordBasePage extends UserAccountsPage {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(UserAccountsPasswordBasePage.class);
|
||||
|
||||
private static final String PARAMETER_SUBMIT = "submit";
|
||||
private static final String PARAMETER_USER = "user";
|
||||
private static final String PARAMETER_KEY = "key";
|
||||
private static final String PARAMETER_NEW_PASSWORD = "newPassword";
|
||||
private static final String PARAMETER_CONFIRM_PASSWORD = "confirmPassword";
|
||||
|
||||
private static final String ERROR_NO_PASSWORD = "errorPasswordIsEmpty";
|
||||
private static final String ERROR_WRONG_PASSWORD_LENGTH = "errorPasswordIsWrongLength";
|
||||
private static final String ERROR_PASSWORDS_DONT_MATCH = "errorPasswordsDontMatch";
|
||||
|
||||
protected boolean submit;
|
||||
protected String userEmail = "";
|
||||
protected String key = "";
|
||||
protected String newPassword = "";
|
||||
protected String confirmPassword = "";
|
||||
|
||||
protected UserAccount userAccount;
|
||||
|
||||
/** The result of checking whether this request is even appropriate. */
|
||||
private String bogusMessage = "";
|
||||
|
||||
/** The result of validating a "submit" request. */
|
||||
private String errorCode = "";
|
||||
|
||||
protected UserAccountsPasswordBasePage(VitroRequest vreq) {
|
||||
super(vreq);
|
||||
|
||||
parseRequestParameters();
|
||||
validateUserAccountInfo();
|
||||
|
||||
if (isSubmit() && !isBogus()) {
|
||||
validateParameters();
|
||||
}
|
||||
}
|
||||
|
||||
private void parseRequestParameters() {
|
||||
submit = isFlagOnRequest(PARAMETER_SUBMIT);
|
||||
userEmail = getStringParameter(PARAMETER_USER, "");
|
||||
key = getStringParameter(PARAMETER_KEY, "");
|
||||
newPassword = getStringParameter(PARAMETER_NEW_PASSWORD, "");
|
||||
confirmPassword = getStringParameter(PARAMETER_CONFIRM_PASSWORD, "");
|
||||
}
|
||||
|
||||
public boolean isSubmit() {
|
||||
return submit;
|
||||
}
|
||||
|
||||
private void validateUserAccountInfo() {
|
||||
userAccount = userAccountsDao.getUserAccountByEmail(userEmail);
|
||||
if (userAccount == null) {
|
||||
log.warn("Password request for '" + userEmail
|
||||
+ "' is bogus: no such user");
|
||||
bogusMessage = BOGUS_STANDARD_MESSAGE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (userAccount.getPasswordLinkExpires() == 0L) {
|
||||
log.warn("Password request for '" + userEmail
|
||||
+ "' is bogus: password change is not pending.");
|
||||
bogusMessage = passwordChangeNotPendingMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
Date expirationDate = new Date(userAccount.getPasswordLinkExpires());
|
||||
if (expirationDate.before(new Date())) {
|
||||
log.warn("Password request for '" + userEmail
|
||||
+ "' is bogus: expiration date has passed.");
|
||||
bogusMessage = BOGUS_STANDARD_MESSAGE;
|
||||
return;
|
||||
}
|
||||
|
||||
String expectedKey = userAccount.getPasswordLinkExpiresHash();
|
||||
if (!key.equals(expectedKey)) {
|
||||
log.warn("Password request for '" + userEmail + "' is bogus: key ("
|
||||
+ key + ") doesn't match expected key (" + expectedKey
|
||||
+ ")");
|
||||
bogusMessage = BOGUS_STANDARD_MESSAGE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBogus() {
|
||||
return !bogusMessage.isEmpty();
|
||||
}
|
||||
|
||||
public String getBogusMessage() {
|
||||
return bogusMessage;
|
||||
}
|
||||
|
||||
private void validateParameters() {
|
||||
if (newPassword.isEmpty()) {
|
||||
errorCode = ERROR_NO_PASSWORD;
|
||||
} else if (!checkPasswordLength(newPassword)) {
|
||||
errorCode = ERROR_WRONG_PASSWORD_LENGTH;
|
||||
} else if (!newPassword.equals(confirmPassword)) {
|
||||
errorCode = ERROR_PASSWORDS_DONT_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return errorCode.isEmpty();
|
||||
}
|
||||
|
||||
public final ResponseValues showPage() {
|
||||
Map<String, Object> body = new HashMap<String, Object>();
|
||||
|
||||
body.put("minimumLength", UserAccount.MIN_PASSWORD_LENGTH);
|
||||
body.put("maximumLength", UserAccount.MAX_PASSWORD_LENGTH);
|
||||
body.put("userAccount", userAccount);
|
||||
body.put("key", userAccount.getPasswordLinkExpiresHash());
|
||||
body.put("newPassword", newPassword);
|
||||
body.put("confirmPassword", confirmPassword);
|
||||
body.put("formUrls", buildUrlsMap());
|
||||
|
||||
if (!errorCode.isEmpty()) {
|
||||
body.put(errorCode, Boolean.TRUE);
|
||||
}
|
||||
|
||||
return new TemplateResponseValues(templateName(), body);
|
||||
}
|
||||
|
||||
protected abstract String passwordChangeNotPendingMessage();
|
||||
protected abstract String templateName();
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/* $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 org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
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;
|
||||
|
||||
/**
|
||||
* When the user clicks on the link in their notification email, handle their
|
||||
* request to reset their password.
|
||||
*/
|
||||
public class UserAccountsResetPasswordPage extends UserAccountsPasswordBasePage {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(UserAccountsResetPasswordPage.class);
|
||||
|
||||
private static final String TEMPLATE_NAME = "userAccounts-resetPassword.ftl";
|
||||
|
||||
protected UserAccountsResetPasswordPage(VitroRequest vreq) {
|
||||
super(vreq);
|
||||
}
|
||||
|
||||
public void resetPassword() {
|
||||
userAccount.setMd5Password(Authenticator.applyMd5Encoding(newPassword));
|
||||
userAccount.setPasswordLinkExpires(0L);
|
||||
userAccount.setStatus(Status.ACTIVE);
|
||||
userAccountsDao.updateUserAccount(userAccount);
|
||||
log.debug("Set password on '" + userAccount.getEmailAddress()
|
||||
+ "' to '" + newPassword + "'");
|
||||
|
||||
notifyUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String passwordChangeNotPendingMessage() {
|
||||
return "The password for " + userEmail + " has already been reset.";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String templateName() {
|
||||
return TEMPLATE_NAME;
|
||||
}
|
||||
|
||||
private void notifyUser() {
|
||||
Map<String, Object> body = new HashMap<String, Object>();
|
||||
body.put("userAccount", userAccount);
|
||||
body.put("subjectLine", "Password changed.");
|
||||
|
||||
FreemarkerEmailMessage email = FreemarkerEmailFactory
|
||||
.createNewMessage(vreq);
|
||||
email.addRecipient(TO, userAccount.getEmailAddress());
|
||||
email.setSubject("Password changed.");
|
||||
email.setHtmlTemplate("userAccounts-passwordResetEmail-html.ftl");
|
||||
email.setTextTemplate("userAccounts-passwordResetEmail-text.ftl");
|
||||
email.setBodyMap(body);
|
||||
email.send();
|
||||
}
|
||||
|
||||
}
|
|
@ -22,6 +22,7 @@ public class UserAccountsUserController extends FreemarkerHttpServlet {
|
|||
public static final String BOGUS_STANDARD_MESSAGE = "Request failed. Please contact your system administrator.";
|
||||
|
||||
private static final String ACTION_CREATE_PASSWORD = "/createPassword";
|
||||
private static final String ACTION_RESET_PASSWORD = "/resetPassword";
|
||||
|
||||
@Override
|
||||
protected Actions requiredActions(VitroRequest vreq) {
|
||||
|
@ -39,6 +40,8 @@ public class UserAccountsUserController extends FreemarkerHttpServlet {
|
|||
|
||||
if (ACTION_CREATE_PASSWORD.equals(action)) {
|
||||
return handleCreatePasswordRequest(vreq);
|
||||
} else if (ACTION_RESET_PASSWORD.equals(action)) {
|
||||
return handleResetPasswordRequest(vreq);
|
||||
} else {
|
||||
return handleInvalidRequest(vreq);
|
||||
}
|
||||
|
@ -59,6 +62,21 @@ public class UserAccountsUserController extends FreemarkerHttpServlet {
|
|||
|
||||
}
|
||||
|
||||
private ResponseValues handleResetPasswordRequest(VitroRequest vreq) {
|
||||
UserAccountsResetPasswordPage page = new UserAccountsResetPasswordPage(
|
||||
vreq);
|
||||
if (page.isBogus()) {
|
||||
return showHomePage(vreq, page.getBogusMessage());
|
||||
} else if (page.isSubmit() && page.isValid()) {
|
||||
page.resetPassword();
|
||||
return showHomePage(vreq,
|
||||
"Your password has been saved. Please log in.");
|
||||
} else {
|
||||
return page.showPage();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ResponseValues handleInvalidRequest(VitroRequest vreq) {
|
||||
return showHomePage(vreq, BOGUS_STANDARD_MESSAGE);
|
||||
}
|
||||
|
|
|
@ -68,6 +68,8 @@
|
|||
<label for="initial-password">Initial password<span class="requiredHint"> *</span></label>
|
||||
<input type="password" name="initialPassword" value="${initialPassword}" id="initial-password" role="input "/>
|
||||
|
||||
<p>Minimum of ${minimumLength} characters in length.</p>
|
||||
|
||||
<label for="confirm-password">Confirm initial password<span class="requiredHint"> *</span></label>
|
||||
<input type="text" name="confirmPassword" value="${confirmPassword}" id="confirm-password" role="input "/>
|
||||
</#if>
|
||||
|
@ -79,10 +81,6 @@
|
|||
<input type="radio" name="associate" value="no" role="radio" <#if !associate??>checked</#if> id="no-associate" />
|
||||
<label class="inline" for="no-associate"> No</label>
|
||||
|
||||
<br />
|
||||
<input type="checkbox" name="resetPassword" value="" id="reset-password" role="checkbox" />
|
||||
<label class="inline" for="reset-password"> Reset password</label>
|
||||
|
||||
<#if emailIsEnabled??>
|
||||
<p class="note">
|
||||
Note: An email will be sent to the address entered above
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<#-- Template for adding a user account -->
|
||||
|
||||
<h3>Add new account</h3>
|
||||
<h3>Create your Password</h3>
|
||||
|
||||
<#if errorPasswordIsEmpty??>
|
||||
<#assign errorMessage = "No password supplied." />
|
||||
|
@ -23,23 +23,23 @@
|
|||
</section>
|
||||
</#if>
|
||||
|
||||
<section id="add-account" role="region">
|
||||
<section id="create-password" role="region">
|
||||
<fieldset>
|
||||
<legend>Add new account</legend>
|
||||
<legend>Please enter your new password for ${userAccount.emailAddress}</legend>
|
||||
|
||||
<form method="POST" action="${formUrls.createPassword}" class="customForm" role="create password">
|
||||
<input type="hidden" name="user" value="${userAccount.emailAddress}" />
|
||||
<input type="hidden" name="key" value="${userAccount.passwordLinkExpiresHash}" />
|
||||
|
||||
<label for="password">Password<span class="requiredHint"> *</span></label>
|
||||
<input type="password" name="password" value="${password}" id="password" role="input "/>
|
||||
<label for="new-password">Password<span class="requiredHint"> *</span></label>
|
||||
<input type="password" name="newPassword" value="${newPassword}" id="new-password" role="input "/>
|
||||
|
||||
<p>Minimum of ${minimumLength} characters in length.</p>
|
||||
|
||||
<label for="confirm-password">Confirm Password<span class="requiredHint"> *</span></label>
|
||||
<input type="password" name="confirmPassword" value="${confirmPassword}" id="confirm-password" role="input "/>
|
||||
|
||||
<input type="submit" name="submitCreatePassword" value="Save changes" class="submit"/>
|
||||
<input type="submit" name="submit" value="Save changes" class="submit"/>
|
||||
|
||||
<p class="requiredHint">* required fields</p>
|
||||
</form>
|
||||
|
|
|
@ -2,5 +2,103 @@
|
|||
|
||||
<#-- Template for editing a user account -->
|
||||
|
||||
<h3>Edit user account</h3>
|
||||
<h3>Edit account</h3>
|
||||
|
||||
<#if errorEmailIsEmpty??>
|
||||
<#assign errorMessage = "You must supply an email address." />
|
||||
</#if>
|
||||
|
||||
<#if errorEmailInUse??>
|
||||
<#assign errorMessage = "An account with that email address already exists." />
|
||||
</#if>
|
||||
|
||||
<#if errorFirstNameIsEmpty??>
|
||||
<#assign errorMessage = "You must supply a first name." />
|
||||
</#if>
|
||||
|
||||
<#if errorLastNameIsEmpty??>
|
||||
<#assign errorMessage = "You must supply a last name." />
|
||||
</#if>
|
||||
|
||||
<#if errorNoRoleSelected??>
|
||||
<#assign errorMessage = "You must select a role." />
|
||||
</#if>
|
||||
|
||||
<#if errorPasswordIsEmpty??>
|
||||
<#assign errorMessage = "No password supplied." />
|
||||
</#if>
|
||||
|
||||
<#if errorPasswordIsWrongLength??>
|
||||
<#assign errorMessage = "Password must be between ${minimumLength} and ${maximumLength} characters." />
|
||||
</#if>
|
||||
|
||||
<#if errorPasswordsDontMatch??>
|
||||
<#assign errorMessage = "Passwords do not match." />
|
||||
</#if>
|
||||
|
||||
<#if errorMessage?has_content>
|
||||
<section id="error-alert" role="alert">
|
||||
<img src="${urls.images}/iconAlert.png" width="24" height="24" alert="Error alert icon"/>
|
||||
<p>${errorMessage}</p>
|
||||
</section>
|
||||
</#if>
|
||||
|
||||
<section id="edit-account" role="region">
|
||||
<fieldset>
|
||||
<legend>Edit new account</legend>
|
||||
|
||||
<form method="POST" action="${formUrls.edit}" class="customForm" role="edit account">
|
||||
<label for="email-address">Email address<span class="requiredHint"> *</span></label>
|
||||
<input type="text" name="emailAddress" value="${emailAddress}" id="email-address" role="input "/>
|
||||
|
||||
<label for="first-name">First name<span class="requiredHint"> *</span></label>
|
||||
<input type="text" name="firstName" value="${firstName}" id="first-name" role="input "/>
|
||||
|
||||
<label for="last-name">Last name<span class="requiredHint"> *</span></label>
|
||||
<input type="text" name="lastName" value="${lastName}" id="last-name" role="input "/>
|
||||
|
||||
<p>Roles<span class="requiredHint"> *</span> </p>
|
||||
<#list roles as role>
|
||||
<input type="radio" name="role" value="${role.uri}" role="radio" <#if selectedRole = role.uri>selected</#if> />
|
||||
<label class="inline" for="${role.label}"> ${role.label}</label>
|
||||
<br />
|
||||
</#list>
|
||||
|
||||
<#if !emailIsEnabled??>
|
||||
<label for="new-password">New password<span class="requiredHint"> *</span></label>
|
||||
<input type="password" name="newPassword" value="${newPassword}" id="new-password" role="input "/>
|
||||
|
||||
<p>Minimum of ${minimumLength} characters in length.</p>
|
||||
<p>Leaving this blank means that the password will not be changed.</p>
|
||||
|
||||
<label for="confirm-password">Confirm initial password<span class="requiredHint"> *</span></label>
|
||||
<input type="text" name="confirmPassword" value="${confirmPassword}" id="confirm-password" role="input "/>
|
||||
</#if>
|
||||
|
||||
<p>Associate a profile with this account</p>
|
||||
<input type="radio" name="associate" value="yes" role="radio" <#if associate??>checked</#if> id="associate" />
|
||||
<label class="inline" for="associate"> Yes</label>
|
||||
|
||||
<input type="radio" name="associate" value="no" role="radio" <#if !associate??>checked</#if> id="no-associate" />
|
||||
<label class="inline" for="no-associate"> No</label>
|
||||
|
||||
<br />
|
||||
<input type="checkbox" name="resetPassword" value="" id="reset-password" role="checkbox" />
|
||||
<label class="inline" for="reset-password"> Reset password</label>
|
||||
|
||||
<#if emailIsEnabled??>
|
||||
<p class="note">
|
||||
Note: A confirmation email with instructions for resetting a password
|
||||
will be sent to the address entered above.
|
||||
The password will not be reset until the user follows the link provided in this email.
|
||||
</p>
|
||||
</#if>
|
||||
|
||||
<input type="submit" name="submitEdit" value="Save changes" class="submit"/> or <a href="${formUrls.list}">Cancel</a>
|
||||
|
||||
<p class="requiredHint">* required fields</p>
|
||||
</form>
|
||||
</fieldset>
|
||||
</section>
|
||||
|
||||
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/edit/forms/css/customForm.css" />')}
|
|
@ -47,8 +47,26 @@
|
|||
<p>
|
||||
A new account for
|
||||
<a href="${newUserAccount.editUrl}">${newUserAccount.firstName} ${newUserAccount.lastName}</a>
|
||||
was successfully created. A notification email has been sent to ${newUserAccount.emailAddress}
|
||||
was successfully created.
|
||||
<#if emailWasSent?? >
|
||||
A notification email has been sent to ${newUserAccount.emailAddress}
|
||||
with instructions for activating the account and creating a password.
|
||||
</#if>
|
||||
</p>
|
||||
</section>
|
||||
</#if>
|
||||
|
||||
<#if updatedUserAccount?? >
|
||||
<section class="account-feedback">
|
||||
<p>
|
||||
The account for
|
||||
<a href="${updatedUserAccount.editUrl}">${updatedUserAccount.firstName} ${updatedUserAccount.lastName}</a>
|
||||
has been updated.
|
||||
<#if emailWasSent?? >
|
||||
A confirmation email has been sent to ${updatedUserAccount.emailAddress}
|
||||
with instructions for resetting a password.
|
||||
The password will not be reset until the user follows the link provided in this email.
|
||||
</#if>
|
||||
</p>
|
||||
</section>
|
||||
</#if>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#-- Confirmation that an account has been created. -->
|
||||
<#-- Confirmation that an password has been created. -->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
@ -16,7 +16,7 @@
|
|||
</p>
|
||||
|
||||
<p>
|
||||
Yout new password associated with ${userAccount.emailAddress} has been created.
|
||||
Your new password associated with ${userAccount.emailAddress} has been created.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#-- Confirmation that an account has been created. -->
|
||||
<#-- Confirmation that a password has been created. -->
|
||||
|
||||
${userAccount.firstName} ${userAccount.lastName}
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#-- Confirmation that an password has been reset. -->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>${subjectLine}</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
${userAccount.firstName} ${userAccount.lastName}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Password successfully changed.</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Your new password associated with ${userAccount.emailAddress} has been changed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Thank you.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#-- Confirmation that a password has been reset. -->
|
||||
|
||||
${userAccount.firstName} ${userAccount.lastName}
|
||||
|
||||
Password successfully changed.
|
||||
|
||||
Your new password associated with ${userAccount.emailAddress}
|
||||
has been changed.
|
||||
|
||||
Thank you.
|
|
@ -0,0 +1,49 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#-- Template for adding a user account -->
|
||||
|
||||
<h3>Reset your Password</h3>
|
||||
|
||||
<#if errorPasswordIsEmpty??>
|
||||
<#assign errorMessage = "No password supplied." />
|
||||
</#if>
|
||||
|
||||
<#if errorPasswordIsWrongLength??>
|
||||
<#assign errorMessage = "Password must be between ${minimumLength} and ${maximumLength} characters." />
|
||||
</#if>
|
||||
|
||||
<#if errorPasswordsDontMatch??>
|
||||
<#assign errorMessage = "Passwords do not match." />
|
||||
</#if>
|
||||
|
||||
<#if errorMessage?has_content>
|
||||
<section id="error-alert" role="alert">
|
||||
<img src="${urls.images}/iconAlert.png" width="24" height="24" alert="Error alert icon"/>
|
||||
<p>${errorMessage}</p>
|
||||
</section>
|
||||
</#if>
|
||||
|
||||
<section id="reset-password" role="region">
|
||||
<fieldset>
|
||||
<legend>Please enter your new password for ${userAccount.emailAddress}</legend>
|
||||
|
||||
<form method="POST" action="${formUrls.resetPassword}" class="customForm" role="create password">
|
||||
<input type="hidden" name="user" value="${userAccount.emailAddress}" />
|
||||
<input type="hidden" name="key" value="${userAccount.passwordLinkExpiresHash}" />
|
||||
|
||||
<label for="new-password">Password<span class="requiredHint"> *</span></label>
|
||||
<input type="password" name="newPassword" value="${newPassword}" id="new-password" role="input "/>
|
||||
|
||||
<p>Minimum of ${minimumLength} characters in length.</p>
|
||||
|
||||
<label for="confirm-password">Confirm Password<span class="requiredHint"> *</span></label>
|
||||
<input type="password" name="confirmPassword" value="${confirmPassword}" id="confirm-password" role="input "/>
|
||||
|
||||
<input type="submit" name="submit" value="Save changes" class="submit"/>
|
||||
|
||||
<p class="requiredHint">* required fields</p>
|
||||
</form>
|
||||
</fieldset>
|
||||
</section>
|
||||
|
||||
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/edit/forms/css/customForm.css" />')}
|
|
@ -0,0 +1,40 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#-- Notification that your password has been reset. -->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>${subjectLine}</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
${userAccount.firstName} ${userAccount.lastName}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We received a request to reset the password for your account (${userAccount.emailAddress}).
|
||||
Please follow the instructions below to proceed with your password reset.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you did not request this new account you can safely ignore this email.
|
||||
This request will expire if not acted upon for 30 days.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Click the link below to reset your password using our secure server.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="${passwordLink}">${passwordLink}</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If the link above doesn't work, you can copy and paste the link directly into your browser's address bar.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Thank you!
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,19 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#-- Notification that your password has been reset. -->
|
||||
|
||||
${userAccount.firstName} ${userAccount.lastName}
|
||||
|
||||
We received a request to reset the password for your account
|
||||
(${userAccount.emailAddress}).
|
||||
Please follow the instructions below to proceed with your password reset.
|
||||
|
||||
If you did not request this new account you can safely ignore this email.
|
||||
This request will expire if not acted upon for 30 days.
|
||||
|
||||
Paste the link below into your browser's address bar to reset your password
|
||||
using our secure server.
|
||||
|
||||
${passwordLink}
|
||||
|
||||
Thank you!
|
Loading…
Add table
Add a link
Reference in a new issue