NIHVIVO-2279 Implement Add Account (no associations) and Delete Accounts.

This commit is contained in:
j2blake 2011-05-24 21:15:56 +00:00
parent 3fbbd561c5
commit 0aef0368c6
12 changed files with 426 additions and 90 deletions

View file

@ -7,6 +7,8 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
/**
* Information about the account of a user. URI, email, password, etc.
*/
@ -107,6 +109,11 @@ public class UserAccount {
return passwordLinkExpires;
}
public String getPasswordLinkExpiresHash() {
return Authenticator.applyMd5Encoding(String
.valueOf(passwordLinkExpires));
}
public void setPasswordLinkExpires(long passwordLinkExpires) {
this.passwordLinkExpires = Math.max(0, passwordLinkExpires);
}

View file

@ -16,11 +16,6 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.Tem
* Handle the "Add new account" form display and submission.
*
* TODO Associate a profile from this account
*
* TODO Handle sending of email.
*
* TODO Handle initial password set if email isn't available. Set password
* fields, change-required flag, account is active.
*/
public class UserAccountsAddPage extends UserAccountsPage {
private static final String PARAMETER_SUBMIT = "submitAdd";
@ -38,6 +33,8 @@ public class UserAccountsAddPage extends UserAccountsPage {
private static final String TEMPLATE_NAME = "userAccounts-add.ftl";
private final UserAccountsAddPageStrategy strategy;
/* The request parameters */
private boolean submit;
private String emailAddress = "";
@ -46,14 +43,18 @@ public class UserAccountsAddPage extends UserAccountsPage {
private String selectedRoleUri = "";
private boolean associateWithProfile;
/* The result of validating a "submit" request. */
/** The result of validating a "submit" request. */
private String errorCode = "";
/** The new user account, if one was created. */
private UserAccount addedAccount;
public UserAccountsAddPage(VitroRequest vreq) {
super(vreq);
}
public void parseParametersAndValidate() {
this.strategy = UserAccountsAddPageStrategy.getInstance(this,
isEmailEnabled(vreq));
parseRequestParameters();
if (submit) {
@ -68,6 +69,8 @@ public class UserAccountsAddPage extends UserAccountsPage {
lastName = getStringParameter(PARAMETER_LAST_NAME, "");
selectedRoleUri = getRoleChoices();
associateWithProfile = getAssociateFlag();
strategy.parseAdditionalParameters();
}
public boolean isSubmit() {
@ -85,6 +88,8 @@ public class UserAccountsAddPage extends UserAccountsPage {
errorCode = ERROR_NO_LAST_NAME;
} else if (selectedRoleUri.isEmpty()) {
errorCode = ERROR_NO_ROLE;
} else {
errorCode = strategy.additionalValidations();
}
}
@ -96,24 +101,28 @@ public class UserAccountsAddPage extends UserAccountsPage {
return errorCode.isEmpty();
}
public UserAccount createNewAccount() {
public void createNewAccount() {
UserAccount u = new UserAccount();
u.setEmailAddress(emailAddress);
u.setFirstName(firstName);
u.setLastName(lastName);
u.setExternalAuthId("");
u.setMd5Password("");
u.setOldPassword("");
u.setPasswordChangeRequired(false);
u.setPasswordLinkExpires(0);
u.setLoginCount(0);
u.setStatus(Status.INACTIVE);
u.setPermissionSetUris(Collections.singleton(selectedRoleUri));
strategy.setAdditionalProperties(u);
String uri = userAccountsDao.insertUserAccount(u);
return userAccountsDao.getUserAccountByUri(uri);
this.addedAccount = userAccountsDao.getUserAccountByUri(uri);
strategy.notifyUser();
}
/** What role are they asking for? */
@ -132,40 +141,34 @@ public class UserAccountsAddPage extends UserAccountsPage {
PARAMETER_ASSOCIATE_WITH_PROFILE, "no"));
}
public ResponseValues showPage() {
public final ResponseValues showPage() {
Map<String, Object> body = new HashMap<String, Object>();
body.put("emailAddress", emailAddress);
body.put("firstName", firstName);
body.put("lastName", lastName);
body.put("selectedRole", selectedRoleUri);
body.put("associate", associateWithProfile);
if (associateWithProfile) {
body.put("associate", Boolean.TRUE);
}
body.put("roles", buildRolesList());
body.put("formUrls", buildUrlsMap());
if (!errorCode.isEmpty()) {
body.put(errorCode, Boolean.TRUE);
}
strategy.addMoreBodyValues(body);
return new TemplateResponseValues(TEMPLATE_NAME, body);
}
/**
* @return
*/
public UserAccount getAddedAccount() {
// TODO Auto-generated method stub
throw new RuntimeException("UserAccountsAddPage.getAddedAccount() not implemented.");
return addedAccount;
}
/**
* @return
*/
public boolean wasPasswordEmailSent() {
// TODO Auto-generated method stub
throw new RuntimeException("UserAccountsAddPage.wasPasswordEmailSent() not implemented.");
return this.strategy.wasPasswordEmailSent();
}
}

View file

@ -0,0 +1,197 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.accounts;
import static javax.mail.Message.RecipientType.TO;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
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.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 UserAccountsAddPageStrategy {
protected final UserAccountsAddPage page;
public static UserAccountsAddPageStrategy getInstance(
UserAccountsAddPage page, boolean emailEnabled) {
if (emailEnabled) {
return new EmailStrategy(page);
} else {
return new NoEmailStrategy(page);
}
}
public UserAccountsAddPageStrategy(UserAccountsAddPage page) {
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 UserAccountsAddPageStrategy {
public static final String CREATE_PASSWORD_URL = "/userAccounts/createPassword";
private boolean sentEmail;
public EmailStrategy(UserAccountsAddPage page) {
super(page);
}
@Override
protected void parseAdditionalParameters() {
// No additional parameters
}
@Override
protected String additionalValidations() {
// No additional validations
return "";
}
@Override
protected void setAdditionalProperties(UserAccount u) {
u.setPasswordLinkExpires(new Date().getTime());
u.setStatus(Status.INACTIVE);
}
@Override
protected void addMoreBodyValues(Map<String, Object> body) {
body.put("emailIsEnabled", Boolean.TRUE);
}
@Override
protected void notifyUser() {
Map<String, Object> body = new HashMap<String, Object>();
body.put("userAccount", page.getAddedAccount());
body.put("passwordLink", buildCreatePasswordLink());
body.put("subjectLine", "Your VIVO account has been created.");
FreemarkerEmailMessage email = FreemarkerEmailFactory
.createNewMessage(page.vreq);
email.addRecipient(TO, page.getAddedAccount().getEmailAddress());
email.setSubject("Your VIVO account has been created.");
email.setHtmlTemplate("userAccounts-createdEmail-html.ftl");
email.setTextTemplate("userAccounts-createdEmail-text.ftl");
email.setBodyMap(body);
email.send();
sentEmail = true;
}
private String buildCreatePasswordLink() {
try {
String uri = page.getAddedAccount().getUri();
String hash = page.getAddedAccount()
.getPasswordLinkExpiresHash();
String relativeUrl = UrlBuilder.getUrl(CREATE_PASSWORD_URL, "user",
uri, "key", hash);
URL context = new URL(page.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 UserAccountsAddPageStrategy {
private static final String PARAMETER_INITIAL_PASSWORD = "initialPassword";
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";
private String initialPassword;
private String confirmPassword;
public NoEmailStrategy(UserAccountsAddPage page) {
super(page);
}
@Override
protected void parseAdditionalParameters() {
initialPassword = page.getStringParameter(
PARAMETER_INITIAL_PASSWORD, "");
confirmPassword = page.getStringParameter(
PARAMETER_CONFIRM_PASSWORD, "");
}
@Override
protected String additionalValidations() {
if (initialPassword.isEmpty()) {
return ERROR_NO_PASSWORD;
} else if (!checkPasswordLength()) {
return ERROR_WRONG_PASSWORD_LENGTH;
} else if (!initialPassword.equals(confirmPassword)) {
return ERROR_PASSWORDS_DONT_MATCH;
} else {
return "";
}
}
private boolean checkPasswordLength() {
return initialPassword.length() >= UserAccount.MIN_PASSWORD_LENGTH
&& initialPassword.length() <= UserAccount.MAX_PASSWORD_LENGTH;
}
@Override
protected void addMoreBodyValues(Map<String, Object> body) {
body.put("initialPassword", initialPassword);
body.put("confirmPassword", confirmPassword);
}
@Override
protected void setAdditionalProperties(UserAccount u) {
u.setMd5Password(initialPassword);
u.setPasswordChangeRequired(true);
u.setStatus(Status.ACTIVE);
}
@Override
protected void notifyUser() {
// Do nothing.
}
@Override
protected boolean wasPasswordEmailSent() {
return false;
}
}
}

View file

@ -39,50 +39,52 @@ public class UserAccountsController extends FreemarkerHttpServlet {
log.debug("action = '" + action + "'");
if (ACTION_ADD.equals(action)) {
UserAccountsAddPage page = new UserAccountsAddPage(vreq);
page.parseParametersAndValidate();
if (page.isSubmit() && page.isValid()) {
return addAccountAndShowList(vreq, page);
} else {
return page.showPage();
}
return handleAddRequest(vreq);
} else if (ACTION_EDIT.equals(action)) {
UserAccountsEditPage page = new UserAccountsEditPage(vreq);
page.parseParametersAndValidate();
if (page.isSubmit() && page.isValid()) {
return editAccountAndShowList(vreq, page);
} else {
return page.showPage();
}
return handleEditRequest(vreq);
} else if (ACTION_DELETE.equals(action)) {
UserAccountsDeleter deleter = new UserAccountsDeleter(vreq);
Collection<String> deletedUris = deleter.delete();
return new UserAccountsListPage(vreq)
.showPageWithDeletions(deletedUris);
return handleDeleteRequest(vreq);
} else {
return handleListRequest(vreq);
}
}
private ResponseValues handleAddRequest(VitroRequest vreq) {
UserAccountsAddPage page = new UserAccountsAddPage(vreq);
if (page.isSubmit() && page.isValid()) {
page.createNewAccount();
UserAccountsListPage listPage = new UserAccountsListPage(vreq);
return listPage.showPageWithNewAccount(page.getAddedAccount(),
page.wasPasswordEmailSent());
} else {
UserAccountsListPage page = new UserAccountsListPage(vreq);
return page.showPage();
}
}
private ResponseValues addAccountAndShowList(VitroRequest vreq,
UserAccountsAddPage addPage) {
addPage.createNewAccount();
UserAccountsListPage listPage = new UserAccountsListPage(vreq);
return listPage.showPageWithNewAccount(addPage.getAddedAccount(),
addPage.wasPasswordEmailSent());
private ResponseValues handleEditRequest(VitroRequest vreq) {
UserAccountsEditPage page = new UserAccountsEditPage(vreq);
page.parseParametersAndValidate();
if (page.isSubmit() && page.isValid()) {
page.updateAccount();
UserAccountsListPage listPage = new UserAccountsListPage(vreq);
return listPage.showPageWithUpdatedAccount(
page.getUpdatedAccount(), page.wasPasswordEmailSent());
} else {
return page.showPage();
}
}
private ResponseValues editAccountAndShowList(VitroRequest vreq,
UserAccountsEditPage editPage) {
editPage.updateAccount();
UserAccountsListPage listPage = new UserAccountsListPage(vreq);
return listPage.showPageWithUpdatedAccount(
editPage.getUpdatedAccount(), editPage.wasPasswordEmailSent());
private ResponseValues handleDeleteRequest(VitroRequest vreq) {
UserAccountsDeleter deleter = new UserAccountsDeleter(vreq);
Collection<String> deletedUris = deleter.delete();
return new UserAccountsListPage(vreq)
.showPageWithDeletions(deletedUris);
}
private ResponseValues handleListRequest(VitroRequest vreq) {
UserAccountsListPage page = new UserAccountsListPage(vreq);
return page.showPage();
}
}

View file

@ -2,29 +2,51 @@
package edu.cornell.mannlib.vitro.webapp.controller.accounts;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
/**
* TODO delete and kick to Accounts list with message, telling how many were
* deleted. If there was a problem, the user will need to infer it from the
* count??
* Process a request to delete User Accounts.
*/
public class UserAccountsDeleter extends UserAccountsPage {
private static final String PARAMETER_DELETE_ACCOUNT = "deleteAccount";
/** Might be empty, but never null. */
private final String[] uris;
protected UserAccountsDeleter(VitroRequest vreq) {
super(vreq);
String[] values = vreq.getParameterValues(PARAMETER_DELETE_ACCOUNT);
if (values == null) {
this.uris = new String[0];
} else {
this.uris = values;
}
}
/**
* @return
*
*/
public Collection<String> delete() {
// TODO Auto-generated method stub
throw new RuntimeException(
"UserAccountsDeleter.delete() not implemented.");
List<String> deletedUris = new ArrayList<String>();
WebappDaoFactory wadf = vreq.getWebappDaoFactory();
UserAccountsDao dao = wadf.getUserAccountsDao();
for (String uri: uris) {
UserAccount u = dao.getUserAccountByUri(uri);
if (u != null) {
dao.deleteUserAccount(uri);
deletedUris.add(uri);
}
}
return deletedUris;
}
}

View file

@ -54,12 +54,13 @@ public class UserAccountsListPage extends UserAccountsPage {
public UserAccountsListPage(VitroRequest vreq) {
super(vreq);
parseParameters();
}
/**
* Build the criteria from the request parameters.
*/
public void parseParameters() {
private void parseParameters() {
int accountsPerPage = getIntegerParameter(PARAMETER_ACCOUNTS_PER_PAGE,
DEFAULT_ACCOUNTS_PER_PAGE);
int pageIndex = getIntegerParameter(PARAMETER_PAGE_INDEX, 1);
@ -76,6 +77,7 @@ public class UserAccountsListPage extends UserAccountsPage {
criteria = new UserAccountsSelectionCriteria(accountsPerPage,
pageIndex, ordering, roleFilterUri, searchTerm);
log.debug("selection criteria is: " + criteria);
}
/**

View file

@ -2,7 +2,6 @@
package edu.cornell.mannlib.vitro.webapp.controller.accounts;
/**
* How are the accounts to be sorted?
*/
@ -78,4 +77,10 @@ public class UserAccountsOrdering {
public Direction getDirection() {
return direction;
}
@Override
public String toString() {
return "UserAccountsOrdering[field=" + field + ", direction="
+ direction + "]";
}
}

View file

@ -10,6 +10,7 @@ import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -22,6 +23,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
/**
* Common routines for the page controllers.
@ -47,6 +49,10 @@ public abstract class UserAccountsPage {
userAccountsDao = wdf.getUserAccountsDao();
}
protected static boolean isEmailEnabled(HttpServletRequest req) {
return FreemarkerEmailFactory.isConfigured(req);
}
protected String getStringParameter(String key, String defaultValue) {
String value = vreq.getParameter(key);
return (value == null) ? defaultValue : value;
@ -74,7 +80,7 @@ public abstract class UserAccountsPage {
String value = vreq.getParameter(key);
return (value != null);
}
/**
* Create a list of all known PermissionSets.
*/
@ -94,13 +100,11 @@ public abstract class UserAccountsPage {
* Make these URLs available to all of the pages.
*/
protected Map<String, String> buildUrlsMap() {
UrlBuilder urlBuilder = new UrlBuilder(vreq.getAppBean());
Map<String, String> map = new HashMap<String, String>();
map.put("list", urlBuilder.getPortalUrl("/userAccounts/list"));
map.put("add", urlBuilder.getPortalUrl("/userAccounts/add"));
map.put("delete", urlBuilder.getPortalUrl("/userAccounts/delete"));
map.put("list", UrlBuilder.getUrl("/userAccounts/list"));
map.put("add", UrlBuilder.getUrl("/userAccounts/add"));
map.put("delete", UrlBuilder.getUrl("/userAccounts/delete"));
return map;
}

View file

@ -75,4 +75,11 @@ public class UserAccountsSelectionCriteria {
return (t == null) ? nullValue : t;
}
@Override
public String toString() {
return "UserAccountsSelectionCriteria[accountsPerPage="
+ accountsPerPage + ", pageIndex=" + pageIndex + ", orderBy="
+ orderBy + ", roleFilterUri='" + roleFilterUri
+ "', searchTerm='" + searchTerm + "']";
}
}