diff --git a/solr/exampleSolr/conf/schema.xml b/solr/exampleSolr/conf/schema.xml
index 0a4cc7445..ede99f821 100644
--- a/solr/exampleSolr/conf/schema.xml
+++ b/solr/exampleSolr/conf/schema.xml
@@ -488,7 +488,8 @@
-
+
+
diff --git a/solr/exampleSolr/conf/solrconfig.xml b/solr/exampleSolr/conf/solrconfig.xml
index 300d04530..b37a027ca 100644
--- a/solr/exampleSolr/conf/solrconfig.xml
+++ b/solr/exampleSolr/conf/solrconfig.xml
@@ -385,7 +385,10 @@
be based on the last SolrCore to be initialized.
-->
- 1024
+ -->
+
+ 50000
+
+
+
+
+
+
IndividualListController/individuallist
@@ -976,12 +982,6 @@
JSON Serviceedu.cornell.mannlib.vitro.webapp.controller.JSONServlet
-
JSON Service/dataservice
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/IndividualController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/IndividualController.java
index ec2d97ac1..2b2df0341 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/IndividualController.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/IndividualController.java
@@ -18,6 +18,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.datatypes.TypeMapper;
+import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
@@ -25,6 +26,9 @@ import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
+import com.hp.hpl.jena.rdf.model.ResourceFactory;
+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.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
@@ -73,7 +77,10 @@ public class IndividualController extends FreemarkerHttpServlet {
put("vitro", VitroVocabulary.vitroURI);
put("vitroPublic", VitroVocabulary.VITRO_PUBLIC);
}};
-
+
+ private static final Property extendedLinkedDataProperty = ResourceFactory.createProperty(namespaces.get("vitro") + "extendedLinkedData");
+ private static final Literal xsdTrue = ResourceFactory.createTypedLiteral("true", XSDDatatype.XSDboolean);
+
private static final String TEMPLATE_INDIVIDUAL_DEFAULT = "individual.ftl";
private static final String TEMPLATE_HELP = "individual-help.ftl";
private static MapqsMap;
@@ -329,8 +336,8 @@ public class IndividualController extends FreemarkerHttpServlet {
ontModel = (OntModel)session.getAttribute("jenaOntModel");
if( ontModel == null)
ontModel = (OntModel)getServletContext().getAttribute("jenaOntModel");
-
- Model newModel = getRDF(individual, ontModel, ModelFactory.createDefaultModel(), 0);
+
+ Model newModel = getRDF(individual, ontModel, ModelFactory.createDefaultModel(),0);
return new RdfResponseValues(rdfFormat, newModel);
}
@@ -548,7 +555,6 @@ public class IndividualController extends FreemarkerHttpServlet {
return null;
}
-
@SuppressWarnings("unused")
private boolean checkForSunset(VitroRequest vreq, Individual entity) {
// TODO Auto-generated method stub
@@ -591,11 +597,11 @@ public class IndividualController extends FreemarkerHttpServlet {
return "enabled".equals(property);
}
- private Model getRDF(Individual entity, OntModel contextModel, Model newModel, int recurseDepth ) {
+ private Model getRDF(Individual entity, OntModel contextModel, Model newModel, int recurseDepth) {
+
Resource subj = newModel.getResource(entity.getURI());
List dstates = entity.getDataPropertyStatements();
- //System.out.println("data: "+dstates.size());
TypeMapper typeMapper = TypeMapper.getInstance();
for (DataPropertyStatement ds: dstates) {
Property dp = newModel.getProperty(ds.getDatapropURI());
@@ -610,22 +616,48 @@ public class IndividualController extends FreemarkerHttpServlet {
newModel.add(newModel.createStatement(subj, dp, lit));
}
- if( recurseDepth < 5 ){
+ if (recurseDepth < 5) {
List ostates = entity.getObjectPropertyStatements();
+
for (ObjectPropertyStatement os: ostates) {
ObjectProperty objProp = os.getProperty();
- Property op = newModel.getProperty(os.getPropertyURI());
+ Property prop = newModel.getProperty(os.getPropertyURI());
Resource obj = newModel.getResource(os.getObjectURI());
- newModel.add(newModel.createStatement(subj, op, obj));
- if( objProp.getStubObjectRelation() )
+ newModel.add(newModel.createStatement(subj, prop, obj));
+ if ( includeInLinkedData(obj, contextModel)) {
newModel.add(getRDF(os.getObject(), contextModel, newModel, recurseDepth + 1));
+ } else {
+ contextModel.enterCriticalSection(Lock.READ);
+ try {
+ newModel.add(contextModel.listStatements(obj, RDFS.label, (RDFNode)null));
+ } finally {
+ contextModel.leaveCriticalSection();
+ }
+ }
}
}
newModel = getLabelAndTypes(entity, contextModel, newModel );
+
+ // get all the statements not covered by the object property / datatype property code above
+ // note implication that extendedLinkedData individuals will only be evaulated for the
+ // recognized object properties.
+ contextModel.enterCriticalSection(Lock.READ);
+ try {
+ StmtIterator iter = contextModel.listStatements(subj, (Property) null, (RDFNode) null);
+ while (iter.hasNext()) {
+ Statement stmt = iter.next();
+ if (!newModel.contains(stmt)) {
+ newModel.add(stmt);
+ }
+ }
+ } finally {
+ contextModel.leaveCriticalSection();
+ }
+
return newModel;
}
-
+
/* Get the properties that are difficult to get via a filtered WebappDaoFactory. */
private Model getLabelAndTypes(Individual entity, Model ontModel, Model newModel){
for( VClass vclass : entity.getVClasses()){
@@ -692,7 +724,27 @@ public class IndividualController extends FreemarkerHttpServlet {
return qsMap;
}
-// static String getAcceptedContentType(String acceptHeader,Mapqs){
-//
-// }
+ public static boolean includeInLinkedData(Resource object, Model contextModel) {
+
+ boolean retval = false;
+
+ contextModel.enterCriticalSection(Lock.READ);
+
+ try {
+ StmtIterator iter = contextModel.listStatements(object, RDF.type, (RDFNode)null);
+
+ while (iter.hasNext()) {
+ Statement stmt = iter.next();
+
+ if (stmt.getObject().isResource() && contextModel.contains(stmt.getObject().asResource(), extendedLinkedDataProperty, xsdTrue)) {
+ retval = true;
+ break;
+ }
+ }
+ } finally {
+ contextModel.leaveCriticalSection();
+ }
+
+ return retval;
+ }
}
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/controller/freemarker/SolrIndividualListController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/SolrIndividualListController.java
new file mode 100644
index 000000000..eec707bec
--- /dev/null
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/SolrIndividualListController.java
@@ -0,0 +1,337 @@
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
+
+package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.PrefixQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.TopDocs;
+
+import edu.cornell.mannlib.vitro.webapp.beans.Individual;
+import edu.cornell.mannlib.vitro.webapp.beans.VClass;
+import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup;
+import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
+import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ExceptionResponseValues;
+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.IndividualDao;
+import edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc;
+import edu.cornell.mannlib.vitro.webapp.search.lucene.LuceneIndexFactory;
+import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.ListedIndividualTemplateModel;
+import freemarker.ext.beans.BeansWrapper;
+import freemarker.template.TemplateModel;
+
+/**
+ * Generates a list of individuals for display in a template
+ */
+public class SolrIndividualListController extends FreemarkerHttpServlet {
+
+ private static final long serialVersionUID = 1L;
+ private static final Log log = LogFactory.getLog(SolrIndividualListController.class.getName());
+
+ public static final int ENTITY_LIST_CONTROLLER_MAX_RESULTS = 30000;
+ public static final int INDIVIDUALS_PER_PAGE = 30;
+ public static final int MAX_PAGES = 40; //must be even
+
+ private static final String TEMPLATE_DEFAULT = "individualList.ftl";
+
+ @Override
+ protected ResponseValues processRequest(VitroRequest vreq) {
+
+ String templateName = TEMPLATE_DEFAULT;
+ Map body = new HashMap();
+ String errorMessage = null;
+ String message = null;
+
+ try {
+ Object obj = vreq.getAttribute("vclass");
+ VClass vclass = null;
+ if ( obj == null ) { // look for vitroclass id parameter
+ String vitroClassIdStr = vreq.getParameter("vclassId");
+ if ( !StringUtils.isEmpty(vitroClassIdStr)) {
+ try {
+ //TODO have to change this so vclass's group and entity count are populated
+ vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vitroClassIdStr);
+ if (vclass == null) {
+ log.error("Couldn't retrieve vclass " + vitroClassIdStr);
+ errorMessage = "Class " + vitroClassIdStr + " not found";
+ }
+ } catch (Exception ex) {
+ throw new HelpException("IndividualListController: request parameter 'vclassId' must be a URI string.");
+ }
+ }
+ } else if (obj instanceof VClass) {
+ vclass = (VClass)obj;
+ } else {
+ throw new HelpException("IndividualListController: attribute 'vclass' must be of type "
+ + VClass.class.getName() + ".");
+ }
+
+ body.put("vclassId", vclass.getURI());
+
+ if (vclass != null) {
+ String alpha = getAlphaParameter(vreq);
+ int page = getPageParameter(vreq);
+ Map map = getResultsForVClass(
+ vclass.getURI(),
+ page,
+ alpha,
+ vreq.getWebappDaoFactory().getIndividualDao(),
+ getServletContext());
+ body.putAll(map);
+
+ List inds = (List)map.get("entities");
+ List indsTm = new ArrayList();
+ for(Individual ind : inds ){
+ indsTm.add(new ListedIndividualTemplateModel(ind,vreq));
+ }
+ body.put("individuals", indsTm);
+
+ List wpages = new ArrayList();
+ List pages = (List)body.get("pages");
+ BeansWrapper wrapper = new BeansWrapper();
+ for( PageRecord pr: pages ){
+ wpages.add( wrapper.wrap(pr) );
+ }
+
+ // Set title and subtitle. Title will be retrieved later in getTitle().
+ VClassGroup classGroup = vclass.getGroup();
+ String title;
+ if (classGroup == null) {
+ title = vclass.getName();
+ } else {
+ title = classGroup.getPublicName();
+ body.put("subtitle", vclass.getName());
+ }
+ body.put("title", title);
+ body.put("redirecturl", vreq.getContextPath()+"/entityurl/");
+ getServletContext().setAttribute("classuri", vclass.getURI());
+ }
+
+ } catch (HelpException help){
+ errorMessage = "Request attribute 'vclass' or request parameter 'vclassId' must be set before calling. Its value must be a class uri.";
+ } catch (Throwable e) {
+ return new ExceptionResponseValues(e);
+ }
+
+ if (errorMessage != null) {
+ templateName = Template.ERROR_MESSAGE.toString();
+ body.put("errorMessage", errorMessage);
+ } else if (message != null) {
+ body.put("message", message);
+ }
+
+ return new TemplateResponseValues(templateName, body);
+ }
+
+ private class HelpException extends Throwable {
+ private static final long serialVersionUID = 1L;
+
+ public HelpException(String string) {
+ super(string);
+ }
+ }
+
+ public static String getAlphaParameter(VitroRequest request){
+ return request.getParameter("alpha");
+ }
+
+ public static int getPageParameter(VitroRequest request) {
+ String pageStr = request.getParameter("page");
+ if( pageStr != null ){
+ try{
+ return Integer.parseInt(pageStr);
+ }catch(NumberFormatException nfe){
+ log.debug("could not parse page parameter");
+ return 1;
+ }
+ }else{
+ return 1;
+ }
+ }
+
+ /**
+ * This method is now called in a couple of places. It should be refactored
+ * into a DAO or similar object.
+ */
+ public static Map getResultsForVClass(String vclassURI, int page, String alpha, IndividualDao indDao, ServletContext context)
+ throws CorruptIndexException, IOException, ServletException{
+ Map rvMap = new HashMap();
+
+ //make lucene query for this rdf:type
+ Query query = getQuery(vclassURI, alpha);
+
+ //execute lucene query for individuals of the specified type
+ IndexSearcher index = LuceneIndexFactory.getIndexSearcher(context);
+ TopDocs docs = null;
+ try{
+ docs = index.search(query, null,
+ ENTITY_LIST_CONTROLLER_MAX_RESULTS,
+ new Sort(Entity2LuceneDoc.term.NAME_LOWERCASE));
+ }catch(Throwable th){
+ log.error("Could not run search. " + th.getMessage());
+ docs = null;
+ }
+
+ if( docs == null )
+ throw new ServletException("Could not run search in IndividualListController");
+
+ //get list of individuals for the search results
+ int size = docs.totalHits;
+ log.debug("Number of search results: " + size);
+
+ // don't get all the results, only get results for the requestedSize
+ List individuals = new ArrayList(INDIVIDUALS_PER_PAGE);
+ int individualsAdded = 0;
+ int ii = (page-1)*INDIVIDUALS_PER_PAGE;
+ while( individualsAdded < INDIVIDUALS_PER_PAGE && ii < size ){
+ ScoreDoc hit = docs.scoreDocs[ii];
+ if (hit != null) {
+ Document doc = index.doc(hit.doc);
+ if (doc != null) {
+ String uri = doc.getField(Entity2LuceneDoc.term.URI).stringValue();
+ Individual ind = indDao.getIndividualByURI( uri );
+ if( ind != null ){
+ individuals.add( ind );
+ individualsAdded++;
+ }
+ } else {
+ log.warn("no document found for lucene doc id " + hit.doc);
+ }
+ } else {
+ log.debug("hit was null");
+ }
+ ii++;
+ }
+
+ rvMap.put("count", size);
+
+ if( size > INDIVIDUALS_PER_PAGE ){
+ rvMap.put("showPages", Boolean.TRUE);
+ List pageRecords = makePagesList(size, INDIVIDUALS_PER_PAGE, page);
+ rvMap.put("pages", pageRecords);
+ }else{
+ rvMap.put("showPages", Boolean.FALSE);
+ rvMap.put("pages", Collections.emptyList());
+ }
+
+ rvMap.put("alpha",alpha);
+
+ rvMap.put("totalCount", size);
+ rvMap.put("entities",individuals);
+ if (individuals == null)
+ log.debug("entities list is null for vclass " + vclassURI );
+
+ return rvMap;
+ }
+
+ private static BooleanQuery getQuery(String vclassUri, String alpha){
+ BooleanQuery query = new BooleanQuery();
+ try{
+ //query term for rdf:type
+ query.add(
+ new TermQuery( new Term(Entity2LuceneDoc.term.RDFTYPE, vclassUri)),
+ BooleanClause.Occur.MUST );
+
+ //Add alpha filter if it is needed
+ Query alphaQuery = null;
+ if( alpha != null && !"".equals(alpha) && alpha.length() == 1){
+ alphaQuery =
+ new PrefixQuery(new Term(Entity2LuceneDoc.term.NAME_LOWERCASE, alpha.toLowerCase()));
+ query.add(alphaQuery,BooleanClause.Occur.MUST);
+ }
+
+ log.debug("Query: " + query);
+ return query;
+ } catch (Exception ex){
+ log.error(ex,ex);
+ return new BooleanQuery();
+ }
+ }
+
+ public static List makePagesList( int count, int pageSize, int selectedPage){
+
+ List records = new ArrayList( MAX_PAGES + 1 );
+ int requiredPages = count/pageSize ;
+ int remainder = count % pageSize ;
+ if( remainder > 0 )
+ requiredPages++;
+
+ if( selectedPage < MAX_PAGES && requiredPages > MAX_PAGES ){
+ //the selected pages is within the first maxPages, just show the normal pages up to maxPages.
+ for(int page = 1; page < requiredPages && page <= MAX_PAGES ; page++ ){
+ records.add( new PageRecord( "page=" + page, Integer.toString(page), Integer.toString(page), selectedPage == page ) );
+ }
+ records.add( new PageRecord( "page="+ (MAX_PAGES+1), Integer.toString(MAX_PAGES+1), "more...", false));
+ }else if( requiredPages > MAX_PAGES && selectedPage+1 > MAX_PAGES && selectedPage < requiredPages - MAX_PAGES){
+ //the selected pages is in the middle of the list of page
+ int startPage = selectedPage - MAX_PAGES / 2;
+ int endPage = selectedPage + MAX_PAGES / 2;
+ for(int page = startPage; page <= endPage ; page++ ){
+ records.add( new PageRecord( "page=" + page, Integer.toString(page), Integer.toString(page), selectedPage == page ) );
+ }
+ records.add( new PageRecord( "page="+ endPage+1, Integer.toString(endPage+1), "more...", false));
+ }else if ( requiredPages > MAX_PAGES && selectedPage > requiredPages - MAX_PAGES ){
+ //the selected page is in the end of the list
+ int startPage = requiredPages - MAX_PAGES;
+ double max = Math.ceil(count/pageSize);
+ for(int page = startPage; page <= max; page++ ){
+ records.add( new PageRecord( "page=" + page, Integer.toString(page), Integer.toString(page), selectedPage == page ) );
+ }
+ }else{
+ //there are fewer than maxPages pages.
+ for(int i = 1; i <= requiredPages; i++ ){
+ records.add( new PageRecord( "page=" + i, Integer.toString(i), Integer.toString(i), selectedPage == i ) );
+ }
+ }
+ return records;
+ }
+
+ public static class PageRecord {
+ public PageRecord(String param, String index, String text, boolean selected) {
+ this.param = param;
+ this.index = index;
+ this.text = text;
+ this.selected = selected;
+ }
+ public String param;
+ public String index;
+ public String text;
+ public boolean selected=false;
+
+ public String getParam() {
+ return param;
+ }
+ public String getIndex() {
+ return index;
+ }
+ public String getText() {
+ return text;
+ }
+ public boolean getSelected(){
+ return selected;
+ }
+ }
+
+}
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/src/edu/cornell/mannlib/vitro/webapp/search/controller/SolrAutocompleteController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/SolrAutocompleteController.java
index 4a06424c7..95c7fbf9b 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/SolrAutocompleteController.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/SolrAutocompleteController.java
@@ -13,15 +13,16 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.search.BooleanQuery;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.client.solrj.response.TermsResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
-import org.apache.solr.common.params.FacetParams;
import org.json.JSONArray;
import org.json.JSONObject;
@@ -113,6 +114,7 @@ public class SolrAutocompleteController extends VitroAjaxController {
}
}
+ // Since SolrQuery.setSortField() is buggy, sort the results here
Collections.sort(results);
// map.put("results", results);
@@ -130,38 +132,43 @@ public class SolrAutocompleteController extends VitroAjaxController {
}
}
- private SolrQuery getQuery(String querystr, VitroRequest vreq) {
+ private SolrQuery getQuery(String queryStr, VitroRequest vreq) {
- if ( querystr == null) {
+ if ( queryStr == null) {
log.error("There was no parameter '"+ PARAM_QUERY
+"' in the request.");
return null;
- } else if( querystr.length() > MAX_QUERY_LENGTH ) {
+ } else if( queryStr.length() > MAX_QUERY_LENGTH ) {
log.debug("The search was too long. The maximum " +
"query length is " + MAX_QUERY_LENGTH );
return null;
}
SolrQuery query = new SolrQuery();
- query = query.setStart(0);
- query = query.setRows(DEFAULT_MAX_HIT_COUNT);
+ query.setStart(0)
+ .setRows(DEFAULT_MAX_HIT_COUNT);
- query = setNameQuery(query, querystr, vreq);
+ setQuery(query, queryStr, vreq);
// Filter by type
String typeParam = (String) vreq.getParameter(PARAM_RDFTYPE);
if (typeParam != null) {
- query = query.addFilterQuery(VitroLuceneTermNames.RDFTYPE + ":\"" + typeParam + "\"");
+ query.addFilterQuery(VitroLuceneTermNames.RDFTYPE + ":\"" + typeParam + "\"");
}
- // Set the fields to retrieve **** RY
- // query = query.setFields( ... );
-
+ query.setFields(VitroLuceneTermNames.NAME_RAW, VitroLuceneTermNames.URI); // fields to retrieve
+ // Solr bug: generates sort=nameLowercase asc instead of sort=nameLowercase+asc
+ //.setSortField(VitroLuceneTermNames.NAME_LOWERCASE, SolrQuery.ORDER.asc);
+
return query;
}
- private SolrQuery setNameQuery(SolrQuery query, String querystr, HttpServletRequest request) {
+ private void setQuery(SolrQuery query, String queryStr, HttpServletRequest request) {
+ if (StringUtils.isBlank(queryStr)) {
+ log.error("No query string");
+ }
+
String tokenizeParam = (String) request.getParameter("tokenize");
boolean tokenize = "true".equals(tokenizeParam);
@@ -169,19 +176,21 @@ public class SolrAutocompleteController extends VitroAjaxController {
// query will not be stemmed. So we don't look at the stem parameter until we get to
// setTokenizedNameQuery().
if (tokenize) {
- return setTokenizedNameQuery(query, querystr, request);
+ setTokenizedQuery(query, queryStr, request);
} else {
- return setUntokenizedNameQuery(query, querystr);
+ setUntokenizedQuery(query, queryStr);
}
}
- private SolrQuery setTokenizedNameQuery(SolrQuery query, String querystr, HttpServletRequest request) {
+ private void setTokenizedQuery(SolrQuery query, String queryStr, HttpServletRequest request) {
+
+ // RY 5/18/2011 For now, just doing untokenized query, due to the interactions of wildcard
+ // query and stemming described below. Need to find a way to do this in Solr.
+ // Should take the same approach if we can figure out how to do a disjunction.
- String stemParam = (String) request.getParameter("stem");
- boolean stem = "true".equals(stemParam);
- String termName = stem ? VitroLuceneTermNames.AC_NAME_STEMMED : VitroLuceneTermNames.AC_NAME_UNSTEMMED ;
-
- BooleanQuery boolQuery = new BooleanQuery();
+// String stemParam = (String) request.getParameter("stem");
+// boolean stem = "true".equals(stemParam);
+// String termName = stem ? VitroLuceneTermNames.AC_NAME_STEMMED : VitroLuceneTermNames.AC_NAME_UNSTEMMED ;
// // Use the query parser to analyze the search term the same way the indexed text was analyzed.
// // For example, text is lowercased, and function words are stripped out.
@@ -190,7 +199,7 @@ public class SolrAutocompleteController extends VitroAjaxController {
// // The wildcard query doesn't play well with stemming. Query term name:tales* doesn't match
// // "tales", which is indexed as "tale", while query term name:tales does. Obviously we need
// // the wildcard for name:tal*, so the only way to get them all to match is use a disjunction
-// // of wildcard and non-wildcard queries. The query will look have only an implicit disjunction
+// // of wildcard and non-wildcard queries. The query will have only an implicit disjunction
// // operator: e.g., +(name:tales name:tales*)
// try {
// log.debug("Adding non-wildcard query for " + querystr);
@@ -210,20 +219,18 @@ public class SolrAutocompleteController extends VitroAjaxController {
// log.warn(e, e);
// }
- return query;
+ setUntokenizedQuery(query, queryStr);
}
- private SolrQuery setUntokenizedNameQuery(SolrQuery query, String querystr) {
+ private void setUntokenizedQuery(SolrQuery query, String queryStr) {
- // Using facet method described in http://solr.pl/en/2010/10/18/solr-and-autocomplete-part-1/
- // Consider using Solr Suggester in a future version.
- return query.setFacet(true)
- .addFacetField(VitroLuceneTermNames.NAME_LOWERCASE)
- .setFacetMinCount(1)
- .setFacetLimit(MAX_QUERY_LENGTH)
- .setFacetPrefix(querystr)//.toLowerCase())
- //.setFacetSort(FacetParams.FACET_SORT_INDEX) // sort by alpha (but doesn't work)
- .setQuery("*:*");
+ // We have to lowercase manually, because Solr doesn't do text analysis on wildcard queries
+ queryStr = queryStr.toLowerCase();
+ // Solr wants whitespace to be escaped with a backslash
+ // Better: replace \s+
+ queryStr = queryStr.replaceAll(" ", "\\\\ ");
+ queryStr = VitroLuceneTermNames.NAME_LOWERCASE + ":" + queryStr + "*";
+ query.setQuery(queryStr);
}
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/IndividualToSolrDocument.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/IndividualToSolrDocument.java
index bd6ac321e..4d2d1858d 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/IndividualToSolrDocument.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/IndividualToSolrDocument.java
@@ -161,7 +161,7 @@ public class IndividualToSolrDocument implements Obj2DocIface {
contextNodePropertyValues += contextNodesInclusionFactory.getPropertiesAssociatedWithPosition(ent.getURI());
contextNodePropertyValues += contextNodesInclusionFactory.getPropertiesAssociatedWithRelationship(ent.getURI());
contextNodePropertyValues += contextNodesInclusionFactory.getPropertiesAssociatedWithAwardReceipt(ent.getURI());
- contextNodePropertyValues += contextNodesInclusionFactory.getPropertiesAssociatedWithInformationResource(ent.getURI());
+ contextNodePropertyValues += contextNodesInclusionFactory.getPropertiesAssociatedWithInformationResource(ent.getURI());
doc.addField(term.CONTEXTNODE, contextNodePropertyValues);
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>
+
+ <#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 errorMessage?has_content>
+
+
+
${errorMessage}
+
+ #if>
+
+
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 -->
-
-
Account |
-
+
-
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas dui erat, dapibus non vehicula at, tristique eu sem. Suspendisse ligula felis, mollis vitae elementum eget, semper a nisl.
-
+<#if newUserAccount?? >
+
+
+ A new account for
+ ${newUserAccount.firstName} ${newUserAccount.lastName}
+ was successfully created. A notification email has been sent to ${newUserAccount.emailAddress}
+ with instructions for activating the account and creating a password.
+