diff --git a/webapp/config/web.xml b/webapp/config/web.xml index d82026d64..24e86255f 100644 --- a/webapp/config/web.xml +++ b/webapp/config/web.xml @@ -763,12 +763,12 @@ - UserAccountsList - edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsListController + UserAccounts + edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsController - UserAccountsList - /listUserAccounts + UserAccounts + /userAccounts/* diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/VitroHttpServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/VitroHttpServlet.java index 5f7858b16..26d09c8a0 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/VitroHttpServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/VitroHttpServlet.java @@ -197,18 +197,20 @@ public class VitroHttpServlet extends HttpServlet { } /** - * If logging is set to the TRACE level, dump the HTTP headers on the - * request. + * If logging on the subclass is set to the TRACE level, dump the HTTP + * headers on the request. */ private void dumpRequestHeaders(HttpServletRequest req) { @SuppressWarnings("unchecked") Enumeration names = req.getHeaderNames(); - log.trace("----------------------request:" + req.getRequestURL()); + Log subclassLog = LogFactory.getLog(this.getClass()); + subclassLog.trace("----------------------request:" + + req.getRequestURL()); while (names.hasMoreElements()) { String name = names.nextElement(); if (!BORING_HEADERS.contains(name)) { - log.trace(name + "=" + req.getHeader(name)); + subclassLog.trace(name + "=" + req.getHeader(name)); } } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsAddPage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsAddPage.java new file mode 100644 index 000000000..3f0513735 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsAddPage.java @@ -0,0 +1,148 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.accounts; + +import java.util.Collections; +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.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; + +/** + * TODO + */ +public class UserAccountsAddPage extends UserAccountsPage { + private static final String PARAMETER_SUBMIT = "submitAdd"; + 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-add.ftl"; + + /* The request parameters */ + private boolean submit; + private String emailAddress = ""; + private String firstName = ""; + private String lastName = ""; + private String selectedRoleUri = ""; + private boolean associateWithProfile; + + /* The result of validating a "submit" request. */ + private String errorCode = ""; + + public UserAccountsAddPage(VitroRequest vreq) { + super(vreq); + } + + public void parseParametersAndValidate() { + parseRequestParameters(); + + if (submit) { + validateParameters(); + } + } + + private void parseRequestParameters() { + submit = isFlagOnRequest(PARAMETER_SUBMIT); + emailAddress = getStringParameter(PARAMETER_EMAIL_ADDRESS, ""); + firstName = getStringParameter(PARAMETER_FIRST_NAME, ""); + lastName = getStringParameter(PARAMETER_LAST_NAME, ""); + selectedRoleUri = getRoleChoices(); + associateWithProfile = getAssociateFlag(); + } + + public boolean isSubmit() { + return submit; + } + + private void validateParameters() { + if (emailAddress.isEmpty()) { + errorCode = ERROR_NO_EMAIL; + } else if (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; + } + } + + private boolean isEmailInUse() { + return userAccountsDao.getUserAccountByEmail(emailAddress) != null; + } + + public boolean isValid() { + return errorCode.isEmpty(); + } + + public UserAccount 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)); + + String uri = userAccountsDao.insertUserAccount(u); + return userAccountsDao.getUserAccountByUri(uri); + } + + /** 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 ResponseValues showPage() { + Map body = new HashMap(); + + body.put("emailAddress", emailAddress); + body.put("firstName", firstName); + body.put("lastName", lastName); + body.put("selectedRole", selectedRoleUri); + body.put("associate", associateWithProfile); + + body.put("roles", buildRolesList()); + + body.put("formUrls", buildUrlsMap()); + + if (!errorCode.isEmpty()) { + body.put(errorCode, Boolean.TRUE); + } + + return new TemplateResponseValues(TEMPLATE_NAME, body); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsController.java new file mode 100644 index 000000000..fd01a956b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsController.java @@ -0,0 +1,75 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.accounts; + +import java.util.Collection; + +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.ManageUserAccounts; +import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; +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.ResponseValues; + +/** + * Parcel out the different actions required of the UserAccounts GUI. + */ +public class UserAccountsController extends FreemarkerHttpServlet { + private static final Log log = LogFactory + .getLog(UserAccountsController.class); + + private static final String ACTION_ADD = "/add"; + private static final String ACTION_DELETE = "/delete"; + private static final String ACTION_EDIT = "/edit"; + + @Override + protected Actions requiredActions(VitroRequest vreq) { + return new Actions(new ManageUserAccounts()); + } + + @Override + protected ResponseValues processRequest(VitroRequest vreq) { + if (log.isDebugEnabled()) { + dumpRequestParameters(vreq); + } + + String action = vreq.getPathInfo(); + 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(); + } + + } else if (ACTION_EDIT.equals(action)) { + return new UserAccountsEditPage(vreq).showPage(); + + } else if (ACTION_DELETE.equals(action)) { + UserAccountsDeleter deleter = new UserAccountsDeleter(vreq); + Collection deletedUris = deleter.delete(); + + return new UserAccountsListPage(vreq) + .showPageWithDeletions(deletedUris); + + } else { + UserAccountsListPage page = new UserAccountsListPage(vreq); + return page.showPage(); + } + } + + private ResponseValues addAccountAndShowList(VitroRequest vreq, + UserAccountsAddPage addPage) { + UserAccount userAccount = addPage.createNewAccount(); + + UserAccountsListPage listPage = new UserAccountsListPage(vreq); + return listPage.showPageWithNewAccount(userAccount); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsDeleter.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsDeleter.java new file mode 100644 index 000000000..02d5b5931 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsDeleter.java @@ -0,0 +1,27 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.accounts; + +import java.util.Collection; + +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; + +/** + * TODO + */ +public class UserAccountsDeleter extends UserAccountsPage { + + protected UserAccountsDeleter(VitroRequest vreq) { + super(vreq); + } + + /** + * @return + * + */ + public Collection delete() { + // TODO Auto-generated method stub + throw new RuntimeException("UserAccountsDeleter.delete() not implemented."); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsEditPage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsEditPage.java new file mode 100644 index 000000000..f1e7d637b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsEditPage.java @@ -0,0 +1,24 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.accounts; + +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; + +/** + * TODO + */ +public class UserAccountsEditPage extends UserAccountsPage { + private static final String TEMPLATE_NAME = "userAccounts-edit.ftl"; + + public UserAccountsEditPage(VitroRequest vreq) { + super(vreq); + } + + public ResponseValues showPage() { + return new TemplateResponseValues(TEMPLATE_NAME); + } + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsListController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsListPage.java similarity index 57% rename from webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsListController.java rename to webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsListPage.java index 40c36689a..d65f7b72e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsListController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsListPage.java @@ -5,41 +5,32 @@ package edu.cornell.mannlib.vitro.webapp.controller.accounts; import static edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsSelectionCriteria.DEFAULT_ACCOUNTS_PER_PAGE; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.servlet.ServletException; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import com.hp.hpl.jena.ontology.OntModel; - -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.PermissionSet; 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.UserAccountsOrdering.Direction; import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsOrdering.Field; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; 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.UserAccountsDao; -import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; -import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector; /** - * Display the paginated list of User Accounts. + * Handle the List page. */ -public class UserAccountsListController extends FreemarkerHttpServlet { +public class UserAccountsListPage extends UserAccountsPage { private static final Log log = LogFactory - .getLog(UserAccountsListController.class); + .getLog(UserAccountsListPage.class); public static final String PARAMETER_ACCOUNTS_PER_PAGE = "accountsPerPage"; public static final String PARAMETER_PAGE_INDEX = "pageIndex"; @@ -54,67 +45,19 @@ public class UserAccountsListController extends FreemarkerHttpServlet { private static final String TEMPLATE_NAME = "userAccounts-list.ftl"; - private OntModel userAccountsModel; - private UserAccountsDao userAccountsDao; + private UserAccountsSelectionCriteria criteria = UserAccountsSelectionCriteria.DEFAULT_CRITERIA; - @Override - public void init() throws ServletException { - super.init(); - - OntModelSelector oms = (OntModelSelector) getServletContext() - .getAttribute("baseOntModelSelector"); - userAccountsModel = oms.getUserAccountsModel(); - - WebappDaoFactory wdf = (WebappDaoFactory) getServletContext() - .getAttribute("webappDaoFactory"); - userAccountsDao = wdf.getUserAccountsDao(); - } - - @Override - protected Actions requiredActions(VitroRequest vreq) { - return new Actions(new ManageUserAccounts()); + public UserAccountsListPage(VitroRequest vreq) { + super(vreq); } /** - * Assume the default criteria for display. Modify the criteria based on - * parameters in the request. Get the selected accounts and display them. + * Build the criteria from the request parameters. */ - @Override - protected ResponseValues processRequest(VitroRequest vreq) { - if (log.isDebugEnabled()) { - dumpRequestParameters(vreq); - } - - Map body = new HashMap(); - - UserAccountsSelectionCriteria criteria = buildCriteria(vreq); - - body.put("accountsPerPage", criteria.getAccountsPerPage()); - body.put("pageIndex", criteria.getPageIndex()); - body.put("orderDirection", criteria.getOrderBy().getDirection().keyword); - body.put("orderField", criteria.getOrderBy().getField().name); - body.put("roleFilterUri", criteria.getRoleFilterUri()); - body.put("searchTerm", criteria.getSearchTerm()); - - UserAccountsSelection selection = UserAccountsSelector.select( - userAccountsModel, criteria); - - body.put("accounts", wrapUserAccounts(selection)); - body.put("total", selection.getResultCount()); - body.put("page", buildPageMap(selection)); - - body.put("formUrl", buildFormUrl(vreq)); - body.put("roles", buildRolesList()); - - body.put("messages", buildMessagesMap(vreq)); - - return new TemplateResponseValues(TEMPLATE_NAME, body); - } - - private UserAccountsSelectionCriteria buildCriteria(VitroRequest vreq) { - int accountsPerPage = getIntegerParameter(vreq, - PARAMETER_ACCOUNTS_PER_PAGE, DEFAULT_ACCOUNTS_PER_PAGE); - int pageIndex = getIntegerParameter(vreq, PARAMETER_PAGE_INDEX, 1); + public void parseParameters() { + int accountsPerPage = getIntegerParameter(PARAMETER_ACCOUNTS_PER_PAGE, + DEFAULT_ACCOUNTS_PER_PAGE); + int pageIndex = getIntegerParameter(PARAMETER_PAGE_INDEX, 1); Direction orderingDirection = Direction.fromKeyword(vreq .getParameter(PARAMETER_ORDERING_DIRECTION)); @@ -123,33 +66,72 @@ public class UserAccountsListController extends FreemarkerHttpServlet { UserAccountsOrdering ordering = new UserAccountsOrdering(orderingField, orderingDirection); - String roleFilterUri = getStringParameter(vreq, - PARAMETER_ROLE_FILTER_URI, ""); - String searchTerm = getStringParameter(vreq, PARAMETER_SEARCH_TERM, ""); + String roleFilterUri = getStringParameter(PARAMETER_ROLE_FILTER_URI, ""); + String searchTerm = getStringParameter(PARAMETER_SEARCH_TERM, ""); - return new UserAccountsSelectionCriteria(accountsPerPage, pageIndex, - ordering, roleFilterUri, searchTerm); + criteria = new UserAccountsSelectionCriteria(accountsPerPage, + pageIndex, ordering, roleFilterUri, searchTerm); } - private String getStringParameter(VitroRequest vreq, String key, - String defaultValue) { - String value = vreq.getParameter(key); - return (value == null) ? defaultValue : value; + /** + * Build the selection criteria from the request, select the accounts, and + * create the ResponseValues to display the page. + */ + public ResponseValues showPage() { + UserAccountsSelection selection = UserAccountsSelector.select( + userAccountsModel, criteria); + Map body = buildTemplateBodyMap(selection); + return new TemplateResponseValues(TEMPLATE_NAME, body); } - private int getIntegerParameter(VitroRequest vreq, String key, - int defaultValue) { - String value = vreq.getParameter(key); - if (value == null) { - return defaultValue; - } + /** + * We just came from adding a new account. Show the list with a message. + */ + public ResponseValues showPageWithNewAccount(UserAccount userAccount) { + UserAccountsSelection selection = UserAccountsSelector.select( + userAccountsModel, criteria); + Map body = buildTemplateBodyMap(selection); - try { - return Integer.parseInt(value); - } catch (NumberFormatException e) { - log.warn("Invalid integer for parameter '" + key + "': " + value); - return defaultValue; - } + body.put("newUserAccount", new UserAccountWrapper(vreq, userAccount, + Collections. emptyList())); + + return new TemplateResponseValues(TEMPLATE_NAME, body); + } + + /** + * We just came from deleting accounts. Show the list with a message. + */ + public ResponseValues showPageWithDeletions(Collection deletedUris) { + UserAccountsSelection selection = UserAccountsSelector.select( + userAccountsModel, criteria); + Map body = buildTemplateBodyMap(selection); + + body.put("deletedAccountCount", deletedUris.size()); + + return new TemplateResponseValues(TEMPLATE_NAME, body); + } + + private Map buildTemplateBodyMap( + UserAccountsSelection selection) { + Map body = new HashMap(); + + body.put("accountsPerPage", criteria.getAccountsPerPage()); + body.put("pageIndex", criteria.getPageIndex()); + body.put("orderDirection", criteria.getOrderBy().getDirection().keyword); + body.put("orderField", criteria.getOrderBy().getField().name); + body.put("roleFilterUri", criteria.getRoleFilterUri()); + body.put("searchTerm", criteria.getSearchTerm()); + + body.put("accounts", wrapUserAccounts(selection)); + body.put("total", selection.getResultCount()); + body.put("page", buildPageMap(selection)); + + body.put("formUrls", buildUrlsMap()); + body.put("roles", buildRolesList()); + + body.put("messages", buildMessagesMap()); + + return body; } private Map buildPageMap(UserAccountsSelection selection) { @@ -175,50 +157,31 @@ public class UserAccountsListController extends FreemarkerHttpServlet { return map; } - private String buildFormUrl(VitroRequest vreq) { - UrlBuilder urlBuilder = new UrlBuilder(vreq.getAppBean()); - return urlBuilder.getPortalUrl("/listUserAccounts"); - } - - private List buildRolesList() { - List list = new ArrayList(); - list.addAll(userAccountsDao.getAllPermissionSets()); - Collections.sort(list, new Comparator() { - @Override - public int compare(PermissionSet ps1, PermissionSet ps2) { - return ps1.getUri().compareTo(ps2.getUri()); - } - }); - return list; - } - - private Map buildMessagesMap(VitroRequest vreq) { + private Map buildMessagesMap() { Map map = new HashMap(); - UserAccount newUser = getUserFromUriParameter(vreq, - PARAMETER_NEW_USER_URI); + UserAccount newUser = getUserFromUriParameter(PARAMETER_NEW_USER_URI); if (newUser != null) { map.put("newUser", newUser); } - UserAccount updatedUser = getUserFromUriParameter(vreq, - PARAMETER_UPDATED_USER_URI); + UserAccount updatedUser = getUserFromUriParameter(PARAMETER_UPDATED_USER_URI); if (updatedUser != null) { map.put("updatedUser", updatedUser); } - if (isFlagOnRequest(vreq, FLAG_UPDATED_USER_PW)) { + if (isFlagOnRequest(FLAG_UPDATED_USER_PW)) { map.put("updatedUserPw", true); } - if (isFlagOnRequest(vreq, FLAG_USERS_DELETED)) { + if (isFlagOnRequest(FLAG_USERS_DELETED)) { map.put("usersDeleted", true); } return map; } - private UserAccount getUserFromUriParameter(VitroRequest vreq, String key) { + private UserAccount getUserFromUriParameter(String key) { String uri = vreq.getParameter(key); if ((uri == null) || uri.isEmpty()) { return null; @@ -227,11 +190,6 @@ public class UserAccountsListController extends FreemarkerHttpServlet { return userAccountsDao.getUserAccountByUri(uri); } - private boolean isFlagOnRequest(VitroRequest vreq, String key) { - String value = vreq.getParameter(key); - return (value != null); - } - /** * The UserAccount has a list of PermissionSetUris, but the Freemarker * template needs a list of PermissionSet labels instead. @@ -240,7 +198,7 @@ public class UserAccountsListController extends FreemarkerHttpServlet { UserAccountsSelection selection) { List list = new ArrayList(); for (UserAccount account : selection.getUserAccounts()) { - list.add(new UserAccountWrapper(account, + list.add(new UserAccountWrapper(vreq, account, findPermissionSetLabels(account))); } return list; @@ -263,11 +221,16 @@ public class UserAccountsListController extends FreemarkerHttpServlet { public static class UserAccountWrapper { private final UserAccount account; private final List permissionSets; + private final String editUrl; - public UserAccountWrapper(UserAccount account, + public UserAccountWrapper(VitroRequest vreq, UserAccount account, List permissionSets) { this.account = account; this.permissionSets = permissionSets; + + UrlBuilder urlBuilder = new UrlBuilder(vreq.getAppBean()); + this.editUrl = urlBuilder.getPortalUrl("/userAccounts/edit", + new ParamMap("editAccount", account.getUri())); } public String getUri() { @@ -303,6 +266,10 @@ public class UserAccountsListController extends FreemarkerHttpServlet { return permissionSets; } + public String getEditUrl() { + return editUrl; + } + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsPage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsPage.java new file mode 100644 index 000000000..92cae670a --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsPage.java @@ -0,0 +1,108 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.accounts; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletContext; + +import org.apache.commons.logging.Log; +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.controller.VitroRequest; +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; + +/** + * Common routines for the page controllers. + */ +public abstract class UserAccountsPage { + private static final Log log = LogFactory.getLog(UserAccountsPage.class); + + protected final VitroRequest vreq; + protected final ServletContext ctx; + protected final OntModel userAccountsModel; + protected final UserAccountsDao userAccountsDao; + + protected UserAccountsPage(VitroRequest vreq) { + this.vreq = vreq; + this.ctx = vreq.getSession().getServletContext(); + + OntModelSelector oms = (OntModelSelector) this.ctx + .getAttribute("baseOntModelSelector"); + userAccountsModel = oms.getUserAccountsModel(); + + WebappDaoFactory wdf = (WebappDaoFactory) this.ctx + .getAttribute("webappDaoFactory"); + userAccountsDao = wdf.getUserAccountsDao(); + } + + protected String getStringParameter(String key, String defaultValue) { + String value = vreq.getParameter(key); + return (value == null) ? defaultValue : value; + } + + protected int getIntegerParameter(String key, int defaultValue) { + String value = vreq.getParameter(key); + if (value == null) { + return defaultValue; + } + + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + log.warn("Invalid integer for parameter '" + key + "': " + value); + return defaultValue; + } + } + + /** + * Check for the presence of a parameter, regardless of its value, even if + * it's an empty string. + */ + protected boolean isFlagOnRequest(String key) { + String value = vreq.getParameter(key); + return (value != null); + } + + /** + * Create a list of all known PermissionSets. + */ + protected List buildRolesList() { + List list = new ArrayList(); + list.addAll(userAccountsDao.getAllPermissionSets()); + Collections.sort(list, new Comparator() { + @Override + public int compare(PermissionSet ps1, PermissionSet ps2) { + return ps1.getUri().compareTo(ps2.getUri()); + } + }); + return list; + } + + /** + * Make these URLs available to all of the pages. + */ + protected Map buildUrlsMap() { + UrlBuilder urlBuilder = new UrlBuilder(vreq.getAppBean()); + + Map map = new HashMap(); + + map.put("list", urlBuilder.getPortalUrl("/userAccounts/list")); + map.put("add", urlBuilder.getPortalUrl("/userAccounts/add")); + map.put("delete", urlBuilder.getPortalUrl("/userAccounts/delete")); + + return map; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsSelectionCriteria.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsSelectionCriteria.java index 42f0b854f..8a10c5c2d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsSelectionCriteria.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/UserAccountsSelectionCriteria.java @@ -11,6 +11,10 @@ package edu.cornell.mannlib.vitro.webapp.controller.accounts; public class UserAccountsSelectionCriteria { public static final int DEFAULT_ACCOUNTS_PER_PAGE = 25; + public static final UserAccountsSelectionCriteria DEFAULT_CRITERIA = new UserAccountsSelectionCriteria( + DEFAULT_ACCOUNTS_PER_PAGE, 1, + UserAccountsOrdering.DEFAULT_ORDERING, "", ""); + /** How many accounts should we bring back, at most? */ private final int accountsPerPage; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/SiteAdminController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/SiteAdminController.java index 51b9c8570..ebc82cd76 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/SiteAdminController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/SiteAdminController.java @@ -124,7 +124,7 @@ public class SiteAdminController extends FreemarkerHttpServlet { urls.put("users", urlBuilder.getPortalUrl("/listUsers")); } if (PolicyHelper.isAuthorizedForActions(vreq, new ManageUserAccounts())) { - urls.put("userList", urlBuilder.getPortalUrl("/listUserAccounts")); + urls.put("userList", urlBuilder.getPortalUrl("/userAccounts")); } if (PolicyHelper.isAuthorizedForActions(vreq, new EditSiteInformation())) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDao.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDao.java index ba00580f6..d0baff184 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDao.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDao.java @@ -20,6 +20,14 @@ public interface UserAccountsDao { */ UserAccount getUserAccountByUri(String uri); + /** + * Get the UserAccount for this Email address. + * + * @return null if the Email address is null, or if there is no such + * UserAccount + */ + UserAccount getUserAccountByEmail(String emailAddress); + /** * Create a new UserAccount in the model. * diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/UserAccountsDaoFiltering.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/UserAccountsDaoFiltering.java index 7da3d2fc1..ab46abac6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/UserAccountsDaoFiltering.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/UserAccountsDaoFiltering.java @@ -17,7 +17,7 @@ public class UserAccountsDaoFiltering extends BaseFiltering implements UserAccountsDao { private final UserAccountsDao innerDao; - + @SuppressWarnings("unused") private final VitroFilters filters; @@ -32,6 +32,11 @@ public class UserAccountsDaoFiltering extends BaseFiltering implements return innerDao.getUserAccountByUri(uri); } + @Override + public UserAccount getUserAccountByEmail(String emailAddress) { + return innerDao.getUserAccountByEmail(emailAddress); + } + @Override public String insertUserAccount(UserAccount userAccount) { return innerDao.insertUserAccount(userAccount); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJena.java index fd28ece40..512c80b81 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJena.java @@ -11,6 +11,7 @@ import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntResource; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.Statement; +import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.util.iterator.ClosableIterator; import com.hp.hpl.jena.vocabulary.RDF; @@ -71,6 +72,28 @@ public class UserAccountsDaoJena extends JenaBaseDao implements UserAccountsDao } } + @Override + public UserAccount getUserAccountByEmail(String emailAddress) { + if (emailAddress == null) { + return null; + } + + String userUri = null; + + getOntModel().enterCriticalSection(Lock.READ); + try { + StmtIterator stmts = getOntModel().listStatements(null, USERACCOUNT_EMAIL_ADDRESS, + getOntModel().createLiteral(emailAddress)); + if (stmts.hasNext()) { + userUri = stmts.next().getSubject().getURI(); + } + } finally { + getOntModel().leaveCriticalSection(); + } + + return getUserAccountByUri(userUri); + } + @Override public String insertUserAccount(UserAccount userAccount) { if (userAccount == null) { diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJenaTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJenaTest.java index 33399e2d9..157f826f1 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJenaTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJenaTest.java @@ -2,6 +2,7 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena; +import static org.junit.Assert.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; @@ -46,6 +47,9 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass { private static final String URI_USER1 = NS_MINE + "user01"; private static final String URI_NO_SUCH_USER = NS_MINE + "bogusUser"; + private static final String EMAIL_USER1 = "email@able.edu"; + private static final String EMAIL_NO_SUCH_USER = NS_MINE + "bogus@email.com"; + private static final String URI_ROLE1 = NS_MINE + "role1"; private static final String URI_ROLE2 = NS_MINE + "role2"; private static final String URI_ROLE3 = NS_MINE + "role3"; @@ -100,6 +104,24 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass { assertNull("null result", u); } + @Test + public void getUserAccountByEmailSuccess() { + UserAccount u = dao.getUserAccountByEmail(EMAIL_USER1); + assertEquals("uri", URI_USER1, u.getUri()); + } + + @Test + public void getUserAccountByEmailNull() { + UserAccount u = dao.getUserAccountByEmail(null); + assertEquals("uri", null, u); + } + + @Test + public void getUserAccountByEmailNotFound() { + UserAccount u = dao.getUserAccountByEmail(EMAIL_NO_SUCH_USER); + assertEquals("uri", null, u); + } + @Test public void insertUserAccountSuccess() { UserAccount in = new UserAccount(); diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-add.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-add.ftl new file mode 100644 index 000000000..1f937f6c1 --- /dev/null +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-add.ftl @@ -0,0 +1,70 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#-- Template for adding a user account --> + +

Add new account

+ + <#if errorEmailIsEmpty??> + <#assign errorMessage = "You must supply an email address." /> + + + <#if errorEmailInUse??> + <#assign errorMessage = "An account with that email address already exists." /> + + + <#if errorFirstNameIsEmpty??> + <#assign errorMessage = "You must supply a first name." /> + + + <#if errorLastNameIsEmpty??> + <#assign errorMessage = "You must supply a last name." /> + + + <#if errorNoRoleSelected??> + <#assign errorMessage = "You must select a role." /> + + + <#if errorMessage?has_content> + + + +
+ Email address * +
+ +
+ First name * +
+ +
+ Last name * +
+ +
+
+ Roles * +
+ <#list roles as role> + selected />${role.label} +
+ +
+ Associate a profile with this account +
+ checked />Yes +
+ checked />No +
+ +

+ Note: An email will be sent to the address entered above + notifying that an account has been created. + It will include instructions for activating the account and creating a password. +

+ + + or Cancel +
diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-edit.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-edit.ftl new file mode 100644 index 000000000..95dc4a47f --- /dev/null +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-edit.ftl @@ -0,0 +1,6 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#-- Template for editing a user account --> + +

Edit user account

+ diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-list.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-list.ftl index e6264302d..d4cc2cc31 100644 --- a/webapp/web/templates/freemarker/body/accounts/userAccounts-list.ftl +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-list.ftl @@ -2,7 +2,7 @@ <#-- Template for displaying list of user accounts --> -
+ <#--current page:
--> @@ -38,12 +38,28 @@ -->
-

Account |

- +
+

Account |

+
- +<#if newUserAccount?? > + + + +<#if deletedAccountCount?? > + +
-
- - - -
+
+
+ + + +
+
-
- - + -