NIHVIVO-2279 convert UserAccountsAjaxController from its first version, which was essentially a stub.

This commit is contained in:
j2blake 2011-07-01 16:13:23 +00:00
parent f86f8e893c
commit 555e068d6a
3 changed files with 354 additions and 73 deletions

View file

@ -0,0 +1,128 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.accounts.admin.ajax;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
import org.json.JSONObject;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.SelfEditingConfiguration;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.admin.ajax.UserAccountsAjaxController.AjaxResponder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
/**
* What is our reaction to this possible External Auth ID?
*
* Is somebody already using it (other than ourselves)? Does it match an
* existing Profile? Neither?
*
* If the userAccountUri or the externalAuthId is empty, or if there is any
* error, say "neither".
*/
class ExternalAuthChecker extends AjaxResponder {
private static final Log log = LogFactory.getLog(ExternalAuthChecker.class);
private static final String PARAMETER_USER_ACCOUNT_URI = "userAccountUri";
private static final String PARAMETER_ETERNAL_AUTH_ID = "externalAuthId";
private static final String RESPONSE_ID_IN_USE = "idInUse";
private static final String RESPONSE_MATCHES_PROFILE = "matchesProfile";
private static final String RESPONSE_PROFILE_URI = "profileUri";
private static final String RESPONSE_PROFILE_URL = "profileUrl";
private static final String RESPONSE_PROFILE_LABEL = "profileLabel";
private final String userAccountUri;
private final String externalAuthId;
private Individual matchingProfile;
public ExternalAuthChecker(HttpServlet parent, VitroRequest vreq,
HttpServletResponse resp) {
super(parent, vreq, resp);
userAccountUri = getStringParameter(PARAMETER_USER_ACCOUNT_URI, "");
externalAuthId = getStringParameter(PARAMETER_ETERNAL_AUTH_ID, "");
}
@Override
public String prepareResponse() throws IOException, JSONException {
if (someoneElseIsUsingThisExternalAuthId()) {
return respondExternalAuthIdAlreadyUsed();
}
checkForMatchingProfile();
if (matchingProfile != null) {
return respondWithMatchingProfile();
}
return EMPTY_RESPONSE;
}
private boolean someoneElseIsUsingThisExternalAuthId() {
if (externalAuthId.isEmpty()) {
log.debug("externalAuthId is empty.");
return false;
}
UserAccount user = uaDao.getUserAccountByExternalAuthId(externalAuthId);
if (user == null) {
log.debug("no user account has externalAuthId='" + externalAuthId
+ "'");
return false;
}
if (user.getUri().equals(userAccountUri)) {
log.debug("externalAuthId '" + externalAuthId
+ "' belongs to current user '" + userAccountUri + "'");
return false;
}
log.debug(user.getEmailAddress() + " is already using externalAuthId '"
+ externalAuthId + "'");
return true;
}
private String respondExternalAuthIdAlreadyUsed() throws JSONException {
JSONObject jsonObject = new JSONObject();
jsonObject.put(RESPONSE_ID_IN_USE, true);
return jsonObject.toString();
}
private void checkForMatchingProfile() {
if (userAccountUri.isEmpty()) {
log.debug("userAccountUri is empty");
return;
}
List<Individual> inds = SelfEditingConfiguration.getBean(vreq)
.getAssociatedIndividuals(indDao, externalAuthId);
if (inds.isEmpty()) {
log.debug("No profiles match '" + externalAuthId + "'");
return;
}
this.matchingProfile = inds.get(0);
}
private String respondWithMatchingProfile() throws JSONException {
String uri = matchingProfile.getURI();
String url = UrlBuilder.getIndividualProfileUrl(uri, vreq);
String label = matchingProfile.getRdfsLabel();
JSONObject jsonObject = new JSONObject();
jsonObject.put(RESPONSE_MATCHES_PROFILE, true);
jsonObject.put(RESPONSE_PROFILE_URI, uri);
jsonObject.put(RESPONSE_PROFILE_URL, url);
jsonObject.put(RESPONSE_PROFILE_LABEL, label);
return jsonObject.toString();
}
}

View file

@ -0,0 +1,191 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.accounts.admin.ajax;
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.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONException;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.Syntax;
import edu.cornell.mannlib.vitro.webapp.beans.SelfEditingConfiguration;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.admin.ajax.UserAccountsAjaxController.AjaxResponder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
/**
* Get a list of Profiles with last names that begin with this search term, and
* that have no matching property, unless it matches the current externalAuthId.
* (So a Profile that is currently associated with the user is not excluded from
* the list.)
*
* For each such Profile, return the label, the URL and the URI.
*
* If the matching property is not defined, or if the search term is empty, or
* if an error occurs, return an empty result.
*/
class ProfileAutoCompleter extends AjaxResponder {
private static final Log log = LogFactory
.getLog(ProfileAutoCompleter.class);
private static final String PARAMETER_SEARCH_TERM = "term";
private static final String PARAMETER_ETERNAL_AUTH_ID = "externalAuthId";
private static final Syntax SYNTAX = Syntax.syntaxARQ;
private static final String QUERY_TEMPLATE = "" //
+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n"
+ "PREFIX foaf: <http://xmlns.com/foaf/0.1/> \n" + "\n" //
+ "SELECT DISTINCT ?uri ?fn ?ln \n" //
+ "WHERE {\n" //
+ " ?uri rdf:type foaf:Person ; \n" //
+ " foaf:firstName ?fn ; \n" //
+ " foaf:lastName ?ln . \n" //
+ " OPTIONAL { ?uri <%matchingPropertyUri%> ?id} \n" //
+ " FILTER ( !bound(?id) || (?id = '%externalAuthId%') ) \n" //
+ " FILTER ( REGEX(?ln, '%searchTerm%', 'i') ) \n" //
+ "} \n" //
+ "ORDER BY ?ln ?fn \n" //
+ "LIMIT 20 \n";
private final String term;
private final String externalAuthId;
private final String selfEditingIdMatchingProperty;
private final OntModel fullModel;
public ProfileAutoCompleter(HttpServlet parent, VitroRequest vreq,
HttpServletResponse resp) {
super(parent, vreq, resp);
term = getStringParameter(PARAMETER_SEARCH_TERM, "");
externalAuthId = getStringParameter(PARAMETER_ETERNAL_AUTH_ID, "");
// TODO This seems to expose the matching property and mechanism too
// much. Can this be done within SelfEditingConfiguration somehow?
selfEditingIdMatchingProperty = SelfEditingConfiguration.getBean(vreq)
.getMatchingPropertyUri();
fullModel = vreq.getJenaOntModel();
}
@Override
public String prepareResponse() throws IOException, JSONException {
if (term.isEmpty()) {
return EMPTY_RESPONSE;
}
if (selfEditingIdMatchingProperty == null) {
return EMPTY_RESPONSE;
}
if (selfEditingIdMatchingProperty.isEmpty()) {
return EMPTY_RESPONSE;
}
return doSparqlQueryAndParseResult();
}
private String doSparqlQueryAndParseResult() throws JSONException {
String queryStr = prepareQueryString();
QueryExecution qe = null;
List<ProfileInfo> results;
try {
Query query = QueryFactory.create(queryStr, SYNTAX);
qe = QueryExecutionFactory.create(query, fullModel);
results = parseResults(qe.execSelect());
} catch (Exception e) {
log.error("Failed to execute the query: " + queryStr, e);
results = Collections.emptyList();
} finally {
if (qe != null) {
qe.close();
}
}
JSONArray jsonArray = prepareJsonArray(results);
return jsonArray.toString();
}
private String prepareQueryString() {
String queryString = QUERY_TEMPLATE
.replace("%matchingPropertyUri%", selfEditingIdMatchingProperty)
.replace("%searchTerm%", term)
.replace("%externalAuthId%", externalAuthId);
log.debug("Query string is '" + queryString + "'");
return queryString;
}
private List<ProfileInfo> parseResults(ResultSet results) {
List<ProfileInfo> profiles = new ArrayList<ProfileInfo>();
while (results.hasNext()) {
QuerySolution solution = results.next();
ProfileInfo pi = parseSolution(solution);
profiles.add(pi);
}
log.debug("Results are: " + profiles);
return profiles;
}
private ProfileInfo parseSolution(QuerySolution solution) {
String uri = solution.getResource("uri").getURI();
String url = UrlBuilder.getIndividualProfileUrl(uri, vreq);
String firstName = solution.getLiteral("fn").getString();
String lastName = solution.getLiteral("ln").getString();
String label = lastName + ", " + firstName;
return new ProfileInfo(uri, url, label);
}
private JSONArray prepareJsonArray(List<ProfileInfo> results)
throws JSONException {
JSONArray jsonArray = new JSONArray();
for (int i = 0; i < results.size(); i++) {
ProfileInfo profile = results.get(i);
Map<String, String> map = new HashMap<String, String>();
map.put("label", profile.label);
map.put("uri", profile.uri);
map.put("url", profile.url);
jsonArray.put(i, map);
}
return jsonArray;
}
private static class ProfileInfo {
final String uri;
final String url;
final String label;
public ProfileInfo(String uri, String url, String label) {
this.uri = uri;
this.url = url;
this.label = label;
}
@Override
public String toString() {
return "ProfileInfo[label=" + label + ", uri=" + uri + ", url="
+ url + "]";
}
}
}

View file

@ -8,18 +8,24 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
import org.json.JSONObject;
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.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.ajax.VitroAjaxController;
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
/**
* Handle the AJAX functions that are specific to the UserAccounts pages.
*/
public class UserAccountsAjaxController extends VitroAjaxController {
private static final Log log = LogFactory
.getLog(UserAccountsAjaxController.class);
private static final String PARAMETER_FUNCTION = "function";
@Override
@ -30,27 +36,49 @@ public class UserAccountsAjaxController extends VitroAjaxController {
@Override
protected void doRequest(VitroRequest vreq, HttpServletResponse resp)
throws ServletException, IOException {
String function = vreq.getParameter(PARAMETER_FUNCTION);
if ("checkExternalAuth".equals(function)) {
new ExternalAuthChecker(this, vreq, resp).processRequest();
} else {
new ErrorResponder(this, vreq, resp).processRequest();
try {
String function = vreq.getParameter(PARAMETER_FUNCTION);
if ("checkExternalAuth".equals(function)) {
new ExternalAuthChecker(this, vreq, resp).processRequest();
} else if ("autoCompleteProfile".equals(function)) {
new ProfileAutoCompleter(this, vreq, resp).processRequest();
} else {
resp.getWriter().write("[]");
}
} catch (Exception e) {
log.error(e, e);
resp.getWriter().write("[]");
}
}
static abstract class AjaxResponder {
protected static final String EMPTY_RESPONSE = "[]";
protected final HttpServlet parent;
protected final VitroRequest vreq;
protected final HttpServletResponse resp;
protected final IndividualDao indDao;
protected final UserAccountsDao uaDao;
public AjaxResponder(HttpServlet parent, VitroRequest vreq,
HttpServletResponse resp) {
this.parent = parent;
this.vreq = vreq;
this.resp = resp;
this.indDao = vreq.getWebappDaoFactory().getIndividualDao();
this.uaDao = vreq.getWebappDaoFactory().getUserAccountsDao();
}
public abstract void processRequest() throws IOException;
public final void processRequest() {
try {
resp.getWriter().write(prepareResponse());
} catch (Exception e) {
log.error("Problem with AJAX response", e);
}
}
protected abstract String prepareResponse() throws IOException,
JSONException;
protected String getStringParameter(String key, String defaultValue) {
String value = vreq.getParameter(key);
@ -59,70 +87,4 @@ public class UserAccountsAjaxController extends VitroAjaxController {
}
/**
* What is our reaction to this possible External Auth ID?
*
* Is somebody already using it (other than ourselves)? Does it match an
* existing Profile? Neither?
*/
private static class ExternalAuthChecker extends AjaxResponder {
private static final String PARAMETER_USER_ACCOUNT_URI = "userAccountUri";
private static final String PARAMETER_ETERNAL_AUTH_ID = "externalAuthId";
private static final String RESPONSE_ID_IN_USE = "idInUse";
private static final String RESPONSE_MATCHES_PROFILE = "matchesProfile";
private static final String RESPONSE_PROFILE_URI = "profileUri";
private static final String RESPONSE_PROFILE_URL = "profileUrl";
private static final String RESPONSE_PROFILE_LABEL = "profileLabel";
private final String userAccountUri;
private final String externalAuthId;
public ExternalAuthChecker(HttpServlet parent, VitroRequest vreq,
HttpServletResponse resp) {
super(parent, vreq, resp);
userAccountUri = getStringParameter(PARAMETER_USER_ACCOUNT_URI, "");
externalAuthId = getStringParameter(PARAMETER_ETERNAL_AUTH_ID, "");
}
@Override
public void processRequest() throws IOException {
// TODO For now, a totally bogus response:
// If "A", somebody else is already using the externalAuthId
// If "B", matches "Joe Blow"
// Anything else, no match.
try {
if ("A".equals(externalAuthId)) {
JSONObject jsonObject = new JSONObject();
jsonObject.put(RESPONSE_ID_IN_USE, true);
resp.getWriter().write(jsonObject.toString());
} else if ("B".equals(externalAuthId)) {
JSONObject jsonObject = new JSONObject();
jsonObject.put(RESPONSE_MATCHES_PROFILE, true);
jsonObject.put(RESPONSE_PROFILE_URI,
"http://some.bogus.profile");
jsonObject.put(RESPONSE_PROFILE_URL,
"http://some.bogus.profileUrl");
jsonObject.put(RESPONSE_PROFILE_LABEL, "bogus label");
resp.getWriter().write(jsonObject.toString());
} else {
resp.getWriter().write("[]");
}
} catch (JSONException e) {
resp.getWriter().write("[]");
}
}
}
private static class ErrorResponder extends AjaxResponder {
public ErrorResponder(HttpServlet parent, VitroRequest vreq,
HttpServletResponse resp) {
super(parent, vreq, resp);
}
@Override
public void processRequest() throws IOException {
resp.getWriter().write("[]");
}
}
}