Merge branch 'maint-rel-1.6' into develop
This commit is contained in:
commit
c95c812c1d
14 changed files with 685 additions and 624 deletions
|
@ -28,7 +28,6 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.DropDataPr
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.DropObjectPropertyStatement;
|
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.DropObjectPropertyStatement;
|
||||||
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
|
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
|
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.BasicAuthenticator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A collection of static methods to help determine whether requested actions
|
* A collection of static methods to help determine whether requested actions
|
||||||
|
@ -66,43 +65,49 @@ public class PolicyHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the email/password authorized for these actions?
|
* Is the email/password authorized for these actions? This should be used
|
||||||
* This should be used when a controller or something needs allow
|
* when a controller or something needs allow actions if the user passes in
|
||||||
* actions if the user passes in their email and password.
|
* their email and password.
|
||||||
*
|
*
|
||||||
* It may be better to check this as part of a servlet Filter and
|
* It may be better to check this as part of a servlet Filter and add an
|
||||||
* add an identifier bundle.
|
* identifier bundle.
|
||||||
*/
|
*/
|
||||||
public static boolean isAuthorizedForActions(HttpServletRequest req,
|
public static boolean isAuthorizedForActions(HttpServletRequest req,
|
||||||
String email, String password,
|
String email, String password, Actions actions) {
|
||||||
Actions actions){
|
|
||||||
|
|
||||||
if( password == null || email == null ||
|
if (password == null || email == null || password.isEmpty()
|
||||||
password.isEmpty() || email.isEmpty()){
|
|| email.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Authenticator auth = Authenticator.getInstance(req);
|
Authenticator auth = Authenticator.getInstance(req);
|
||||||
UserAccount user = auth.getAccountForInternalAuth(email);
|
UserAccount user = auth.getAccountForInternalAuth(email);
|
||||||
log.debug("userAccount is " + user==null?"null":user.getUri() );
|
if (user == null) {
|
||||||
|
log.debug("No account for '" + email + "'");
|
||||||
if( ! auth.isCurrentPassword( user, password ) ){
|
|
||||||
log.debug(String.format("UNAUTHORIZED, password not accepted for %s, account URI: %s",
|
|
||||||
user.getEmailAddress(), user.getUri()));
|
|
||||||
return false;
|
return false;
|
||||||
}else{
|
|
||||||
log.debug(String.format("password accepted for %s, account URI: %s",
|
|
||||||
user.getEmailAddress(), user.getUri() ));
|
|
||||||
// figure out if that account can do the actions
|
|
||||||
IdentifierBundle ids =
|
|
||||||
ActiveIdentifierBundleFactories.getUserIdentifierBundle(req,user);
|
|
||||||
PolicyIface policy = ServletPolicyList.getPolicies(req);
|
|
||||||
return PolicyHelper.isAuthorizedForActions( ids, policy, actions );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String uri = user.getUri();
|
||||||
|
log.debug("userAccount is '" + uri + "'");
|
||||||
|
|
||||||
|
if (!auth.isCurrentPassword(user, password)) {
|
||||||
|
log.debug(String.format("UNAUTHORIZED, password not accepted "
|
||||||
|
+ "for %s, account URI: %s", email, uri));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
log.debug(String.format("password accepted for %s, "
|
||||||
|
+ "account URI: %s", email, uri));
|
||||||
|
|
||||||
|
// figure out if that account can do the actions
|
||||||
|
IdentifierBundle ids = ActiveIdentifierBundleFactories
|
||||||
|
.getUserIdentifierBundle(req, user);
|
||||||
|
PolicyIface policy = ServletPolicyList.getPolicies(req);
|
||||||
|
return PolicyHelper.isAuthorizedForActions(ids, policy, actions);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
log.error("Error while attempting to authorize actions " + actions.toString(), ex);
|
log.error(
|
||||||
|
"Error while attempting to authorize actions "
|
||||||
|
+ actions.toString(), ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,8 +125,8 @@ public class PolicyHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
Resource subject = stmt.getSubject();
|
Resource subject = stmt.getSubject();
|
||||||
edu.cornell.mannlib.vitro.webapp.beans.Property predicate =
|
edu.cornell.mannlib.vitro.webapp.beans.Property predicate = new edu.cornell.mannlib.vitro.webapp.beans.Property(
|
||||||
new edu.cornell.mannlib.vitro.webapp.beans.Property(stmt.getPredicate().getURI());
|
stmt.getPredicate().getURI());
|
||||||
RDFNode objectNode = stmt.getObject();
|
RDFNode objectNode = stmt.getObject();
|
||||||
if ((subject == null) || (predicate == null) || (objectNode == null)) {
|
if ((subject == null) || (predicate == null) || (objectNode == null)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -130,8 +135,8 @@ public class PolicyHelper {
|
||||||
RequestedAction action;
|
RequestedAction action;
|
||||||
if (objectNode.isResource()) {
|
if (objectNode.isResource()) {
|
||||||
action = new AddObjectPropertyStatement(modelToBeModified,
|
action = new AddObjectPropertyStatement(modelToBeModified,
|
||||||
subject.getURI(), predicate, objectNode
|
subject.getURI(), predicate, objectNode.asResource()
|
||||||
.asResource().getURI());
|
.getURI());
|
||||||
} else {
|
} else {
|
||||||
action = new AddDataPropertyStatement(modelToBeModified,
|
action = new AddDataPropertyStatement(modelToBeModified,
|
||||||
subject.getURI(), predicate.getURI(), objectNode
|
subject.getURI(), predicate.getURI(), objectNode
|
||||||
|
@ -153,8 +158,7 @@ public class PolicyHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
Resource subject = stmt.getSubject();
|
Resource subject = stmt.getSubject();
|
||||||
edu.cornell.mannlib.vitro.webapp.beans.Property predicate =
|
edu.cornell.mannlib.vitro.webapp.beans.Property predicate = new edu.cornell.mannlib.vitro.webapp.beans.Property();
|
||||||
new edu.cornell.mannlib.vitro.webapp.beans.Property();
|
|
||||||
predicate.setURI(stmt.getPredicate().getURI());
|
predicate.setURI(stmt.getPredicate().getURI());
|
||||||
RDFNode objectNode = stmt.getObject();
|
RDFNode objectNode = stmt.getObject();
|
||||||
if ((subject == null) || (predicate == null) || (objectNode == null)) {
|
if ((subject == null) || (predicate == null) || (objectNode == null)) {
|
||||||
|
@ -164,8 +168,8 @@ public class PolicyHelper {
|
||||||
RequestedAction action;
|
RequestedAction action;
|
||||||
if (objectNode.isResource()) {
|
if (objectNode.isResource()) {
|
||||||
action = new DropObjectPropertyStatement(modelToBeModified,
|
action = new DropObjectPropertyStatement(modelToBeModified,
|
||||||
subject.getURI(), predicate, objectNode
|
subject.getURI(), predicate, objectNode.asResource()
|
||||||
.asResource().getURI());
|
.getURI());
|
||||||
} else {
|
} else {
|
||||||
action = new DropDataPropertyStatement(modelToBeModified,
|
action = new DropDataPropertyStatement(modelToBeModified,
|
||||||
subject.getURI(), predicate.getURI(), objectNode
|
subject.getURI(), predicate.getURI(), objectNode
|
||||||
|
@ -310,7 +314,6 @@ public class PolicyHelper {
|
||||||
+ stmt.getObject() + ">";
|
+ stmt.getObject() + ">";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* No need to instantiate this helper class - all methods are static.
|
* No need to instantiate this helper class - all methods are static.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.controller.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When you try to use an API that you aren't authorized for, we don't redirect
|
||||||
|
* you to the login page. We complain.
|
||||||
|
*/
|
||||||
|
public class NotAuthorizedToUseApiException extends Exception {
|
||||||
|
public NotAuthorizedToUseApiException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotAuthorizedToUseApiException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotAuthorizedToUseApiException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,15 +3,8 @@
|
||||||
package edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest;
|
package edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletRequestWrapper;
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
|
@ -19,8 +12,6 @@ import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
import org.apache.commons.fileupload.FileItem;
|
import org.apache.commons.fileupload.FileItem;
|
||||||
import org.apache.commons.fileupload.FileUploadException;
|
import org.apache.commons.fileupload.FileUploadException;
|
||||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -51,41 +42,22 @@ import org.apache.commons.logging.LogFactory;
|
||||||
* implemented in the sub-classes.
|
* implemented in the sub-classes.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public abstract class FileUploadServletRequest extends HttpServletRequestWrapper {
|
public abstract class FileUploadServletRequest extends HttpServletRequestWrapper {
|
||||||
|
|
||||||
private static final Log log = LogFactory
|
|
||||||
.getLog(FileUploadServletRequest.class);
|
|
||||||
|
|
||||||
public static final String FILE_ITEM_MAP = "file_item_map";
|
public static final String FILE_ITEM_MAP = "file_item_map";
|
||||||
public static final String FILE_UPLOAD_EXCEPTION = "file_upload_exception";
|
public static final String FILE_UPLOAD_EXCEPTION = "file_upload_exception";
|
||||||
|
|
||||||
private Map<String, List<String>> parameters;
|
|
||||||
private Map<String, List<FileItem>> files;
|
|
||||||
private FileUploadException fileUploadException;
|
|
||||||
|
|
||||||
private static final String[] EMPTY_ARRAY = new String[0];
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
// The factory method
|
// The factory method
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap this {@link HttpServletRequest} in an appropriate wrapper class.
|
* Wrap this {@link HttpServletRequest} in an appropriate wrapper class.
|
||||||
* set maxTempFileSize to 0 or -1 if streaming is desired. Set it to > 0 if
|
|
||||||
* you want any parts uploaded to a temporary directory
|
|
||||||
*/
|
*/
|
||||||
public static FileUploadServletRequest parseRequest(
|
public static FileUploadServletRequest parseRequest(
|
||||||
HttpServletRequest request, int maxTempFileSize) throws IOException {
|
HttpServletRequest request, int maxFileSize) throws IOException {
|
||||||
|
|
||||||
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
|
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
|
||||||
|
|
||||||
if (isMultipart) {
|
if (isMultipart) {
|
||||||
if( maxTempFileSize <= 0 ){
|
return new MultipartHttpServletRequest(request, maxFileSize);
|
||||||
return new StreamingMultipartHttpServletRequest(request);
|
|
||||||
}else{
|
|
||||||
return new MultipartHttpServletRequest(request, maxTempFileSize);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return new SimpleHttpServletRequestWrapper(request);
|
return new SimpleHttpServletRequestWrapper(request);
|
||||||
}
|
}
|
||||||
|
@ -113,183 +85,28 @@ public abstract class FileUploadServletRequest extends HttpServletRequestWrapper
|
||||||
/** Was this a multipart HTTP request? */
|
/** Was this a multipart HTTP request? */
|
||||||
public abstract boolean isMultipart();
|
public abstract boolean isMultipart();
|
||||||
|
|
||||||
protected void stashParametersInRequest(HttpServletRequest request, ServletFileUpload upload){
|
/**
|
||||||
Map<String, List<String>> parameters = new HashMap<String, List<String>>();
|
* Get the map of file items, by name.
|
||||||
Map<String, List<FileItem>> files = new HashMap<String, List<FileItem>>();
|
*/
|
||||||
|
public abstract Map<String, List<FileItem>> getFiles();
|
||||||
parseQueryString(request.getQueryString(), parameters);
|
|
||||||
|
|
||||||
try {
|
|
||||||
List<FileItem> items = upload.parseRequest( request );
|
|
||||||
|
|
||||||
for (FileItem item : items) {
|
|
||||||
// Process a regular form field
|
|
||||||
if (item.isFormField()) {
|
|
||||||
addToParameters(parameters, item.getFieldName(), item
|
|
||||||
.getString("UTF-8"));
|
|
||||||
log.debug("Form field (parameter) " + item.getFieldName()
|
|
||||||
+ "=" + item.getString());
|
|
||||||
} else {
|
|
||||||
addToFileItems(files, item);
|
|
||||||
log.debug("File " + item.getFieldName() + ": "
|
|
||||||
+ item.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (FileUploadException e) {
|
|
||||||
fileUploadException = e;
|
|
||||||
request.setAttribute(
|
|
||||||
FileUploadServletRequest.FILE_UPLOAD_EXCEPTION, e);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
log.error("could not convert to UTF-8",e);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.parameters = Collections.unmodifiableMap(parameters);
|
|
||||||
log.debug("Parameters are: " + this.parameters);
|
|
||||||
this.files = Collections.unmodifiableMap(files);
|
|
||||||
log.debug("Files are: " + this.files);
|
|
||||||
request.setAttribute(FILE_ITEM_MAP, this.files);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pull any parameters out of the URL.
|
* Find a non-empty file item with this name.
|
||||||
|
*
|
||||||
|
* @return the first such file item, or <code>null</code> if no matching,
|
||||||
|
* non-empty items were found.
|
||||||
*/
|
*/
|
||||||
private void parseQueryString(String queryString,
|
public abstract FileItem getFileItem(String string);
|
||||||
Map<String, List<String>> parameters) {
|
|
||||||
log.debug("Query string is : '" + queryString + "'");
|
|
||||||
if (queryString != null) {
|
|
||||||
String[] pieces = queryString.split("&");
|
|
||||||
|
|
||||||
for (String piece : pieces) {
|
|
||||||
int equalsHere = piece.indexOf('=');
|
|
||||||
if (piece.trim().isEmpty()) {
|
|
||||||
// Ignore an empty piece.
|
|
||||||
} else if (equalsHere <= 0) {
|
|
||||||
// A parameter without a value.
|
|
||||||
addToParameters(parameters, decode(piece), "");
|
|
||||||
} else {
|
|
||||||
// A parameter with a value.
|
|
||||||
String key = piece.substring(0, equalsHere);
|
|
||||||
String value = piece.substring(equalsHere + 1);
|
|
||||||
addToParameters(parameters, decode(key), decode(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.debug("Parameters from query string are: " + parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove any special URL-style encoding.
|
* Was there an exception when uploading the file items?
|
||||||
*/
|
*/
|
||||||
private String decode(String encoded) {
|
public abstract boolean hasFileUploadException();
|
||||||
try {
|
|
||||||
return URLDecoder.decode(encoded, "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
log.error(e, e);
|
|
||||||
return encoded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Either create a new List for the value, or add to an existing List. */
|
|
||||||
private void addToParameters(Map<String, List<String>> map, String name,
|
|
||||||
String value) {
|
|
||||||
if (!map.containsKey(name)) {
|
|
||||||
map.put(name, new ArrayList<String>());
|
|
||||||
}
|
|
||||||
map.get(name).add(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Either create a new List for the file, or add to an existing List. */
|
|
||||||
private void addToFileItems(Map<String, List<FileItem>> map, FileItem file) {
|
|
||||||
String name = file.getFieldName();
|
|
||||||
if (!map.containsKey(name)) {
|
|
||||||
map.put(name, new ArrayList<FileItem>());
|
|
||||||
}
|
|
||||||
map.get(name).add(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public FileUploadException getFileUploadException() {
|
|
||||||
return fileUploadException;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasFileUploadException() {
|
|
||||||
return fileUploadException != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
// Parameter-related methods won't find anything on the delegate request,
|
|
||||||
// since parsing consumed the parameters. So we need to look to the parsed
|
|
||||||
// info for the answers.
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getParameter(String name) {
|
|
||||||
if (parameters.containsKey(name)) {
|
|
||||||
return parameters.get(name).get(0);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Enumeration<?> getParameterNames() {
|
|
||||||
return Collections.enumeration(parameters.keySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getParameterValues(String name) {
|
|
||||||
if (parameters.containsKey(name)) {
|
|
||||||
return parameters.get(name).toArray(EMPTY_ARRAY);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, String[]> getParameterMap() {
|
|
||||||
Map<String, String[]> result = new HashMap<String, String[]>();
|
|
||||||
for (Entry<String, List<String>> entry : parameters.entrySet()) {
|
|
||||||
result.put(entry.getKey(), entry.getValue().toArray(EMPTY_ARRAY));
|
|
||||||
}
|
|
||||||
log.debug("resulting parameter map: " + result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* Get the exception that occurred when uploading the file items. If no such
|
||||||
* <p>
|
* exception, return <code>null</code>.
|
||||||
* There may be more than one file item with the given name. If the first
|
|
||||||
* one is empty (size is zero), keep looking for a non-empty one.
|
|
||||||
* </p>
|
|
||||||
*/
|
*/
|
||||||
public FileItem getFileItem(String name) {
|
public abstract FileUploadException getFileUploadException();
|
||||||
List<FileItem> items = files.get(name);
|
|
||||||
if (items == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (FileItem item : items) {
|
|
||||||
if (item.getSize() > 0L) {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a map of parameter names to files.
|
|
||||||
* This will should return null.
|
|
||||||
*/
|
|
||||||
public Map<String, List<FileItem>> getFiles() {
|
|
||||||
if( files == null )
|
|
||||||
return Collections.emptyMap();
|
|
||||||
else
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,32 +29,99 @@ import org.apache.commons.logging.LogFactory;
|
||||||
* any parameter-related requests. File-related information will also be held
|
* any parameter-related requests. File-related information will also be held
|
||||||
* here, to answer file-related requests.
|
* here, to answer file-related requests.
|
||||||
*/
|
*/
|
||||||
public class MultipartHttpServletRequest extends FileUploadServletRequest {
|
class MultipartHttpServletRequest extends FileUploadServletRequest {
|
||||||
private static final Log log = LogFactory
|
private static final Log log = LogFactory
|
||||||
.getLog(MultipartHttpServletRequest.class);
|
.getLog(MultipartHttpServletRequest.class);
|
||||||
|
|
||||||
private int maxFileSize = 0;
|
private static final String[] EMPTY_ARRAY = new String[0];
|
||||||
private File tempDir = null;
|
|
||||||
|
private final Map<String, List<String>> parameters;
|
||||||
|
private final Map<String, List<FileItem>> files;
|
||||||
|
private FileUploadException fileUploadException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the multipart request. Store the info about the request parameters
|
* Parse the multipart request. Store the info about the request parameters
|
||||||
* and the uploaded files to a temporary directory.
|
* and the uploaded files.
|
||||||
*
|
|
||||||
* This offers a simple way to deal with uploaded files by having a size
|
|
||||||
* limit. This limit may be rather large if desired. Many megabytes for example.
|
|
||||||
*/
|
*/
|
||||||
public MultipartHttpServletRequest(HttpServletRequest request,
|
public MultipartHttpServletRequest(HttpServletRequest request,
|
||||||
int maxFileSize) throws IOException {
|
int maxFileSize) throws IOException {
|
||||||
super(request);
|
super(request);
|
||||||
|
|
||||||
this.maxFileSize = maxFileSize;
|
Map<String, List<String>> parameters = new HashMap<String, List<String>>();
|
||||||
this.tempDir = figureTemporaryDirectory(request);
|
Map<String, List<FileItem>> files = new HashMap<String, List<FileItem>>();
|
||||||
|
|
||||||
//use an upload handler that will stash the file items in a temporary directory.
|
File tempDir = figureTemporaryDirectory(request);
|
||||||
ServletFileUpload upload = createUploadHandler( this.maxFileSize, this.tempDir );
|
ServletFileUpload upload = createUploadHandler(maxFileSize, tempDir);
|
||||||
stashParametersInRequest( request , upload );
|
|
||||||
|
parseQueryString(request.getQueryString(), parameters);
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<FileItem> items = parseRequestIntoFileItems(request, upload);
|
||||||
|
|
||||||
|
for (FileItem item : items) {
|
||||||
|
// Process a regular form field
|
||||||
|
if (item.isFormField()) {
|
||||||
|
addToParameters(parameters, item.getFieldName(), item
|
||||||
|
.getString("UTF-8"));
|
||||||
|
log.debug("Form field (parameter) " + item.getFieldName()
|
||||||
|
+ "=" + item.getString());
|
||||||
|
} else {
|
||||||
|
addToFileItems(files, item);
|
||||||
|
log.debug("File " + item.getFieldName() + ": "
|
||||||
|
+ item.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (FileUploadException e) {
|
||||||
|
fileUploadException = e;
|
||||||
|
request.setAttribute(
|
||||||
|
FileUploadServletRequest.FILE_UPLOAD_EXCEPTION, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.parameters = Collections.unmodifiableMap(parameters);
|
||||||
|
log.debug("Parameters are: " + this.parameters);
|
||||||
|
this.files = Collections.unmodifiableMap(files);
|
||||||
|
log.debug("Files are: " + this.files);
|
||||||
|
request.setAttribute(FILE_ITEM_MAP, this.files);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pull any parameters out of the URL.
|
||||||
|
*/
|
||||||
|
private void parseQueryString(String queryString,
|
||||||
|
Map<String, List<String>> parameters) {
|
||||||
|
log.debug("Query string is : '" + queryString + "'");
|
||||||
|
if (queryString != null) {
|
||||||
|
String[] pieces = queryString.split("&");
|
||||||
|
|
||||||
|
for (String piece : pieces) {
|
||||||
|
int equalsHere = piece.indexOf('=');
|
||||||
|
if (piece.trim().isEmpty()) {
|
||||||
|
// Ignore an empty piece.
|
||||||
|
} else if (equalsHere <= 0) {
|
||||||
|
// A parameter without a value.
|
||||||
|
addToParameters(parameters, decode(piece), "");
|
||||||
|
} else {
|
||||||
|
// A parameter with a value.
|
||||||
|
String key = piece.substring(0, equalsHere);
|
||||||
|
String value = piece.substring(equalsHere + 1);
|
||||||
|
addToParameters(parameters, decode(key), decode(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.debug("Parameters from query string are: " + parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove any special URL-style encoding.
|
||||||
|
*/
|
||||||
|
private String decode(String encoded) {
|
||||||
|
try {
|
||||||
|
return URLDecoder.decode(encoded, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
log.error(e, e);
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the temporary storage directory for this webapp.
|
* Find the temporary storage directory for this webapp.
|
||||||
|
@ -79,10 +146,116 @@ public class MultipartHttpServletRequest extends FileUploadServletRequest {
|
||||||
return upload;
|
return upload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Either create a new List for the value, or add to an existing List. */
|
||||||
|
private void addToParameters(Map<String, List<String>> map, String name,
|
||||||
|
String value) {
|
||||||
|
if (!map.containsKey(name)) {
|
||||||
|
map.put(name, new ArrayList<String>());
|
||||||
|
}
|
||||||
|
map.get(name).add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Either create a new List for the file, or add to an existing List. */
|
||||||
|
private void addToFileItems(Map<String, List<FileItem>> map, FileItem file) {
|
||||||
|
String name = file.getFieldName();
|
||||||
|
if (!map.containsKey(name)) {
|
||||||
|
map.put(name, new ArrayList<FileItem>());
|
||||||
|
}
|
||||||
|
map.get(name).add(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Minimize the code that uses the unchecked cast. */
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private List<FileItem> parseRequestIntoFileItems(HttpServletRequest req,
|
||||||
|
ServletFileUpload upload) throws FileUploadException {
|
||||||
|
return upload.parseRequest(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// This is a multipart request, so make the file info available. If there
|
||||||
|
// was an exception during parsing, make that available too.
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMultipart() {
|
public boolean isMultipart() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<FileItem>> getFiles() {
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* <p>
|
||||||
|
* There may be more than one file item with the given name. If the first
|
||||||
|
* one is empty (size is zero), keep looking for a non-empty one.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FileItem getFileItem(String name) {
|
||||||
|
List<FileItem> items = files.get(name);
|
||||||
|
if (items == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FileItem item : items) {
|
||||||
|
if (item.getSize() > 0L) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileUploadException getFileUploadException() {
|
||||||
|
return fileUploadException;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasFileUploadException() {
|
||||||
|
return fileUploadException != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// Parameter-related methods won't find anything on the delegate request,
|
||||||
|
// since parsing consumed the parameters. So we need to look to the parsed
|
||||||
|
// info for the answers.
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getParameter(String name) {
|
||||||
|
if (parameters.containsKey(name)) {
|
||||||
|
return parameters.get(name).get(0);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<?> getParameterNames() {
|
||||||
|
return Collections.enumeration(parameters.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getParameterValues(String name) {
|
||||||
|
if (parameters.containsKey(name)) {
|
||||||
|
return parameters.get(name).toArray(EMPTY_ARRAY);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String[]> getParameterMap() {
|
||||||
|
Map<String, String[]> result = new HashMap<String, String[]>();
|
||||||
|
for (Entry<String, List<String>> entry : parameters.entrySet()) {
|
||||||
|
result.put(entry.getKey(), entry.getValue().toArray(EMPTY_ARRAY));
|
||||||
|
}
|
||||||
|
log.debug("resulting parameter map: " + result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,25 @@ class SimpleHttpServletRequestWrapper extends FileUploadServletRequest {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<FileItem>> getFiles() {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileItem getFileItem(String string) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileUploadException getFileUploadException() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasFileUploadException() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
// Since this is not a multipart request, the parameter methods can be
|
// Since this is not a multipart request, the parameter methods can be
|
||||||
|
@ -45,7 +64,7 @@ class SimpleHttpServletRequestWrapper extends FileUploadServletRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String[]> getParameterMap() {
|
public Map<?, ?> getParameterMap() {
|
||||||
return getDelegate().getParameterMap();
|
return getDelegate().getParameterMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapping ServletRequest that does multipart. In order to allow
|
|
||||||
* streaming, this class does NOT save the parts to a temporary directory.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class StreamingMultipartHttpServletRequest extends
|
|
||||||
FileUploadServletRequest {
|
|
||||||
/**
|
|
||||||
* Parse the multipart request. Store the info about the request parameters.
|
|
||||||
* Don't store the uploaded files to a temporary directory to allow streaming.
|
|
||||||
*
|
|
||||||
* Only use this if you plan to consume the FileItems using streaming
|
|
||||||
* to deal with inputs of very large sizes.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public StreamingMultipartHttpServletRequest(HttpServletRequest request) {
|
|
||||||
super(request);
|
|
||||||
|
|
||||||
//use a file uploader that does not save the files to a temporary directory.
|
|
||||||
stashParametersInRequest( request , new ServletFileUpload());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isMultipart() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -2,7 +2,12 @@
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.search.controller;
|
package edu.cornell.mannlib.vitro.webapp.search.controller;
|
||||||
|
|
||||||
|
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||||
|
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -10,23 +15,15 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.ActiveIdentifierBundleFactories;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission;
|
import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission;
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
|
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ServletPolicyList;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
|
import edu.cornell.mannlib.vitro.webapp.controller.api.NotAuthorizedToUseApiException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.BasicAuthenticator;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ExceptionResponseValues;
|
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.ResponseValues;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||||
import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest;
|
import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest;
|
||||||
import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.MultipartHttpServletRequest;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder;
|
import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,44 +31,11 @@ import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder;
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class SearchServiceController extends FreemarkerHttpServlet {
|
public class SearchServiceController extends FreemarkerHttpServlet {
|
||||||
private static final Log log = LogFactory.getLog(SearchServiceController.class);
|
private static final Log log = LogFactory
|
||||||
|
.getLog(SearchServiceController.class);
|
||||||
/**
|
|
||||||
* Attempt to check if there is a email and password in the request parameters.
|
|
||||||
* If there is not, fall back on the normal usage pattern of requestedAction().
|
|
||||||
* If there is, then try to authenticate and authorize the
|
|
||||||
* userAccount associated with the email.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Actions requiredActions(VitroRequest vreq) {
|
|
||||||
try{
|
|
||||||
// Works by side effect: parse the multi-part request and stash FileItems in request
|
|
||||||
FileUploadServletRequest.parseRequest(vreq, 0);
|
|
||||||
|
|
||||||
//first figure out if the password and email login to an account with a password
|
|
||||||
String pw = vreq.getParameter("password");
|
|
||||||
String email = vreq.getParameter("email");
|
|
||||||
|
|
||||||
if( pw == null || email == null || pw.isEmpty() || email.isEmpty()){
|
|
||||||
return SimplePermission.MANAGE_SEARCH_INDEX.ACTIONS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( PolicyHelper.isAuthorizedForActions(vreq, email, pw,
|
|
||||||
SimplePermission.MANAGE_SEARCH_INDEX.ACTIONS ) ){
|
|
||||||
return Actions.AUTHORIZED;
|
|
||||||
}else{
|
|
||||||
log.debug(email + " is unauthorized to manage the search index. " +
|
|
||||||
"client IP "+vreq.getClientAddr());
|
|
||||||
return Actions.UNAUTHORIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
}catch(Exception ex){
|
|
||||||
log.error("Error while client IP "+ vreq.getClientAddr() + " attempting to log in " +
|
|
||||||
"to SearchServiceController: " + ex.getMessage());
|
|
||||||
return Actions.UNAUTHORIZED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/** Limit file size to 1 Gigabyte. */
|
||||||
|
public static final int MAXIMUM_FILE_SIZE = 1024 * 1024 * 1024;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the different actions. If not specified, the default action is to
|
* Handle the different actions. If not specified, the default action is to
|
||||||
|
@ -80,54 +44,101 @@ public class SearchServiceController extends FreemarkerHttpServlet {
|
||||||
@Override
|
@Override
|
||||||
protected ResponseValues processRequest(VitroRequest req) {
|
protected ResponseValues processRequest(VitroRequest req) {
|
||||||
try {
|
try {
|
||||||
|
req = new VitroRequest(FileUploadServletRequest.parseRequest(req,
|
||||||
|
MAXIMUM_FILE_SIZE));
|
||||||
|
|
||||||
//figure out what action to perform
|
// Check the authorization here, because we don't want to redirect
|
||||||
String pathInfo = req.getPathInfo();
|
// to the login page if they are not authorized. (The file upload
|
||||||
|
// would be lost.
|
||||||
|
confirmAuthorization(req);
|
||||||
|
|
||||||
if( pathInfo == null || pathInfo.trim().isEmpty() || "/".equals(pathInfo.trim()) ){
|
switch (figureActionVerb(req)) {
|
||||||
return doHelpForm(req);
|
case UPDATE_URIS_IN_SEARCH:
|
||||||
}
|
|
||||||
|
|
||||||
pathInfo = pathInfo.substring(1); //get rid of leading slash
|
|
||||||
|
|
||||||
if (VERBS.UPDATE_URIS_IN_SEARCH.verb.equals( pathInfo )) {
|
|
||||||
return doUpdateUrisInSearch(req);
|
return doUpdateUrisInSearch(req);
|
||||||
} else {
|
default:
|
||||||
return doHelpForm(req);
|
return doHelpForm();
|
||||||
}
|
}
|
||||||
|
} catch (NotAuthorizedToUseApiException e) {
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
map.put("errorMessage", e.getMessage());
|
||||||
|
return new TemplateResponseValues("error-message.ftl", map,
|
||||||
|
SC_FORBIDDEN);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return new ExceptionResponseValues(e);
|
return new ExceptionResponseValues(e, SC_INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process requests to the web service to update a list of URIs in the search index. */
|
* Process requests to the web service to update a list of URIs in the
|
||||||
public ResponseValues doUpdateUrisInSearch(HttpServletRequest req )
|
* search index.
|
||||||
|
*/
|
||||||
|
private ResponseValues doUpdateUrisInSearch(HttpServletRequest req)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
|
|
||||||
IndexBuilder builder = IndexBuilder.getBuilder(getServletContext());
|
IndexBuilder builder = IndexBuilder.getBuilder(getServletContext());
|
||||||
if( builder == null )
|
int uriCount = new UpdateUrisInIndex().doUpdateUris(req, builder);
|
||||||
throw new ServletException( "Could not get search index builder from context. Check smoke test");
|
|
||||||
|
|
||||||
new UpdateUrisInIndex().doUpdateUris( req, builder);
|
Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("msg", "Received " + uriCount + " URIs.");
|
||||||
|
|
||||||
TemplateResponseValues trv = new TemplateResponseValues( "" );
|
return new TemplateResponseValues("searchService-help.ftl", body);
|
||||||
return trv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResponseValues doHelpForm() {
|
||||||
public ResponseValues doHelpForm(HttpServletRequest req){
|
|
||||||
return new TemplateResponseValues("searchService-help.ftl");
|
return new TemplateResponseValues("searchService-help.ftl");
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum VERBS{
|
private void confirmAuthorization(VitroRequest vreq)
|
||||||
UPDATE_URIS_IN_SEARCH("updateUrisInSearch");
|
throws NotAuthorizedToUseApiException {
|
||||||
|
Verb verb = figureActionVerb(vreq);
|
||||||
|
String pw = vreq.getParameter("password");
|
||||||
|
String email = vreq.getParameter("email");
|
||||||
|
|
||||||
|
// If you just want the help screen, no problem.
|
||||||
|
if (verb == Verb.VIEW_HELP_FORM) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// For other functions, your credentials must have moxie.
|
||||||
|
if (PolicyHelper.isAuthorizedForActions(vreq, email, pw,
|
||||||
|
SimplePermission.MANAGE_SEARCH_INDEX.ACTIONS)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Otherwise, you can't do this.
|
||||||
|
throw new NotAuthorizedToUseApiException(email
|
||||||
|
+ " is not authorized to manage the search index.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Verb figureActionVerb(VitroRequest vreq) {
|
||||||
|
String pathInfo = vreq.getPathInfo();
|
||||||
|
if (pathInfo == null) {
|
||||||
|
pathInfo = "";
|
||||||
|
}
|
||||||
|
if (pathInfo.startsWith("/")) {
|
||||||
|
pathInfo = pathInfo.substring(1);
|
||||||
|
}
|
||||||
|
return Verb.fromString(pathInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// Helper class
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
public enum Verb {
|
||||||
|
VIEW_HELP_FORM("viewHelpForm"), UPDATE_URIS_IN_SEARCH(
|
||||||
|
"updateUrisInSearch");
|
||||||
|
|
||||||
public final String verb;
|
public final String verb;
|
||||||
VERBS(String verb){
|
|
||||||
|
Verb(String verb) {
|
||||||
this.verb = verb;
|
this.verb = verb;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
static Verb fromString(String s) {
|
||||||
|
for (Verb v : values()) {
|
||||||
|
if (v.verb.equals(s)) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return VIEW_HELP_FORM;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,81 +2,91 @@
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.search.controller;
|
package edu.cornell.mannlib.vitro.webapp.search.controller;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import static edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest.FILE_ITEM_MAP;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.util.ArrayList;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Scanner;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.apache.commons.fileupload.FileItemIterator;
|
import org.apache.commons.fileupload.FileItem;
|
||||||
import org.apache.commons.fileupload.FileItemStream;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.commons.fileupload.FileUploadException;
|
|
||||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder;
|
import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that performs the update of the uris in the search index
|
* Class that performs the update of the uris in the search index for the
|
||||||
* for the SearchService.
|
* SearchService.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class UpdateUrisInIndex {
|
public class UpdateUrisInIndex {
|
||||||
private static final Log log = LogFactory.getLog(UpdateUrisInIndex.class);
|
private static final Log log = LogFactory.getLog(UpdateUrisInIndex.class);
|
||||||
|
|
||||||
|
/** Pattern to split URIs on whitespace and commas. */
|
||||||
|
public static final Pattern DELIMITER = Pattern.compile("[,\\s]+");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Web service for update in search index of a list of URIs.
|
* Web service for update in search index of a list of URIs.
|
||||||
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
protected void doUpdateUris(HttpServletRequest req, IndexBuilder builder)
|
protected int doUpdateUris(HttpServletRequest req, IndexBuilder builder)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
if( ! ServletFileUpload.isMultipartContent(req) )
|
Map<String, List<FileItem>> map = (Map<String, List<FileItem>>) req
|
||||||
|
.getAttribute(FILE_ITEM_MAP);
|
||||||
|
if (map == null) {
|
||||||
throw new ServletException("Expected Multipart Content");
|
throw new ServletException("Expected Multipart Content");
|
||||||
|
}
|
||||||
|
|
||||||
String enc = getEncoding(req);
|
Charset enc = getEncoding(req);
|
||||||
try{
|
|
||||||
//loop over the fileds and add any URIs to the IndexBuilder queue
|
|
||||||
ServletFileUpload upload = new ServletFileUpload();
|
|
||||||
FileItemIterator iter = upload.getItemIterator(req);
|
|
||||||
while( iter.hasNext()){
|
|
||||||
FileItemStream item = iter.next();
|
|
||||||
String name = item.getFieldName();
|
|
||||||
if( "email".equals(name) || "password".equals(name) )
|
|
||||||
continue; //skip the password and email fields
|
|
||||||
|
|
||||||
InputStream stream = item.openStream();
|
int uriCount = 0;
|
||||||
try{
|
for (String name : map.keySet()) {
|
||||||
addToSearchQueue(builder, stream, enc);
|
for (FileItem item : map.get(name)) {
|
||||||
}finally{
|
log.debug("Found " + item.getSize() + " byte file for '" + name + "'");
|
||||||
stream.close();
|
uriCount += processFileItem(builder, name, item, enc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}catch (FileUploadException fex){
|
return uriCount;
|
||||||
throw new ServletException("Could not upload file to SearchServiceController", fex);
|
|
||||||
}finally{
|
|
||||||
builder.doUpdateIndex();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int processFileItem(IndexBuilder builder, String name,
|
||||||
|
FileItem item, Charset enc) throws IOException {
|
||||||
|
int count = 0;
|
||||||
|
Reader reader = new InputStreamReader(item.getInputStream(), enc.name());
|
||||||
|
try (Scanner scanner = createScanner(reader)) {
|
||||||
|
while (scanner.hasNext()) {
|
||||||
|
String uri = scanner.next();
|
||||||
|
log.debug("Request to index uri '" + uri + "'");
|
||||||
|
builder.addToChanged(uri);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("resource")
|
||||||
|
protected Scanner createScanner(Reader in) {
|
||||||
|
return new Scanner(in).useDelimiter(DELIMITER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the encoding of the request, default to UTF-8
|
* Get the encoding of the request, default to UTF-8 since that is in the
|
||||||
* since that is in the vitro install instructions
|
* vitro install instructions to put on the connector.
|
||||||
* to put on the connector.
|
|
||||||
*/
|
*/
|
||||||
private String getEncoding(HttpServletRequest req){
|
private Charset getEncoding(HttpServletRequest req) {
|
||||||
String enc = req.getCharacterEncoding();
|
String enc = req.getCharacterEncoding();
|
||||||
if( enc == null || enc.isEmpty() ){
|
if (StringUtils.isBlank(enc)) {
|
||||||
log.debug("No encoding on POST request, That is acceptable.");
|
log.debug("No encoding on POST request, That is acceptable.");
|
||||||
enc = "UTF-8";
|
enc = "UTF-8";
|
||||||
} else if (enc.length() > 30) {
|
} else if (enc.length() > 30) {
|
||||||
|
@ -86,107 +96,7 @@ public class UpdateUrisInIndex {
|
||||||
log.debug("Encoding set on POST request: " + enc);
|
log.debug("Encoding set on POST request: " + enc);
|
||||||
}
|
}
|
||||||
log.debug("Reading POSTed URIs with encoding " + enc);
|
log.debug("Reading POSTed URIs with encoding " + enc);
|
||||||
return enc;
|
return Charset.forName(enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds URIs from Reader to search queue.
|
|
||||||
*/
|
|
||||||
private void addToSearchQueue( IndexBuilder builder, InputStream stream , String charEncoding )
|
|
||||||
throws IOException{
|
|
||||||
|
|
||||||
Iterator<String> uris =
|
|
||||||
new UrisFromInputIterator( new InputStreamReader(stream, charEncoding) );
|
|
||||||
|
|
||||||
while(uris.hasNext()){
|
|
||||||
String uri = uris.next();
|
|
||||||
log.debug("Request to index uri '" + uri + "'");
|
|
||||||
builder.addToChanged( uri );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterator for URIs in a reader to make top level methods simpler.
|
|
||||||
*/
|
|
||||||
public static class UrisFromInputIterator implements Iterator<String> {
|
|
||||||
BufferedReader reader;
|
|
||||||
Iterator<String> uris;
|
|
||||||
|
|
||||||
public UrisFromInputIterator(Reader in ){
|
|
||||||
this.reader = new BufferedReader(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove(){ throw new UnsupportedOperationException() ; }
|
|
||||||
|
|
||||||
public boolean hasNext(){
|
|
||||||
if( uris != null && uris.hasNext() ){
|
|
||||||
return true;
|
|
||||||
}else{
|
|
||||||
try {
|
|
||||||
return getFromBuffer();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String next(){
|
|
||||||
return uris.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns true if there are uris to get.
|
|
||||||
* @throws IOException */
|
|
||||||
private boolean getFromBuffer() throws IOException{
|
|
||||||
uris = null;
|
|
||||||
|
|
||||||
while( uris == null || !uris.hasNext() ){
|
|
||||||
String chunk = reader.readLine();
|
|
||||||
if( chunk == null ){ //at end of input
|
|
||||||
break;
|
|
||||||
} else if( chunk.trim().isEmpty() ){
|
|
||||||
continue;
|
|
||||||
}else{
|
|
||||||
uris = lineToUris(chunk).iterator();
|
|
||||||
if( uris.hasNext() ){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes null and empty elements from in.
|
|
||||||
* Returned list will not be null.
|
|
||||||
*/
|
|
||||||
private static List<String> removeNullAndEmpty(List<String> in ){
|
|
||||||
ArrayList<String> out = new ArrayList<String>();
|
|
||||||
if( in == null )
|
|
||||||
return out;
|
|
||||||
|
|
||||||
for( String s : in ){
|
|
||||||
if( s != null && !s.trim().isEmpty() ){
|
|
||||||
out.add(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a line to a list of URIs.
|
|
||||||
* Retruned list will not be null.
|
|
||||||
* No elements in returned list will be empty or null.
|
|
||||||
*/
|
|
||||||
protected static List<String> lineToUris(String line){
|
|
||||||
List<String> parts = removeNullAndEmpty( Arrays.asList(commaAndWhitespace.split( line ) ));
|
|
||||||
return parts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Pattern to split URIs on whitespace and commas. */
|
|
||||||
private static final Pattern commaAndWhitespace = Pattern.compile("[,\\s]");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,8 @@
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.search.controller;
|
package edu.cornell.mannlib.vitro.webapp.search.controller;
|
||||||
|
|
||||||
|
import java.io.Reader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
@ -15,52 +14,76 @@ import org.junit.Test;
|
||||||
*/
|
*/
|
||||||
public class UpdateUrisInIndexTest {
|
public class UpdateUrisInIndexTest {
|
||||||
|
|
||||||
@Test
|
@Test(expected = NullPointerException.class)
|
||||||
public void lineToUrisTest(){
|
public void nullString() {
|
||||||
Assert.assertEquals(Arrays.asList("uri1"), UpdateUrisInIndex.lineToUris( "uri1"));
|
scan(null, 0);
|
||||||
Assert.assertEquals(Arrays.asList("uri1", "uri2"), UpdateUrisInIndex.lineToUris( "uri1,uri2"));
|
|
||||||
|
|
||||||
Assert.assertEquals(Arrays.asList("uri1"), UpdateUrisInIndex.lineToUris( "uri1\n"));
|
|
||||||
Assert.assertEquals(Arrays.asList("uri1","uri2"), UpdateUrisInIndex.lineToUris( "uri1\nuri2"));
|
|
||||||
|
|
||||||
Assert.assertEquals(Collections.EMPTY_LIST, UpdateUrisInIndex.lineToUris( "" ));
|
|
||||||
Assert.assertEquals(Collections.EMPTY_LIST, UpdateUrisInIndex.lineToUris( "," ));
|
|
||||||
Assert.assertEquals(Collections.EMPTY_LIST, UpdateUrisInIndex.lineToUris( " , " ));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void UrisFromInputIteratorTest(){
|
public void emptyString() {
|
||||||
doUrisFromInputIterator("",0);
|
scan("", 0);
|
||||||
doUrisFromInputIterator(" ",0);
|
|
||||||
doUrisFromInputIterator(" , ",0);
|
|
||||||
doUrisFromInputIterator("\n",0);
|
|
||||||
doUrisFromInputIterator("\n\n\n",0);
|
|
||||||
doUrisFromInputIterator("http://bogus.com/n234",1);
|
|
||||||
doUrisFromInputIterator("http://bogus.com/n234\nhttp://bogus.com/n442",2);
|
|
||||||
doUrisFromInputIterator("http://bogus.com/n234, http://bogus.com/n442",2);
|
|
||||||
doUrisFromInputIterator("http://bogus.com/n234,\nhttp://bogus.com/n442\n",2);
|
|
||||||
|
|
||||||
doUrisFromInputIterator("http://bogus.com/n234\n",1);
|
|
||||||
doUrisFromInputIterator("\nhttp://bogus.com/n234",1);
|
|
||||||
doUrisFromInputIterator("\nhttp://bogus.com/n234\n",1);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doUrisFromInputIterator(String input, int expectedUris){
|
@Test
|
||||||
Iterator<String> it = new UpdateUrisInIndex.UrisFromInputIterator( new StringReader(input) );
|
public void nothingButDelimiters() {
|
||||||
|
scan(" , ", 0);
|
||||||
|
scan("\n", 0);
|
||||||
|
scan("\n\n\n", 0);
|
||||||
|
scan("\n, \t\r ,\n\n", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void oneTokenNoDelimiters() {
|
||||||
|
scan("http://bogus.com/n234", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void oneTokenAssortedDelimiters() {
|
||||||
|
scan("http://bogus.com/n234\n", 1);
|
||||||
|
scan("\nhttp://bogus.com/n234", 1);
|
||||||
|
scan("\nhttp://bogus.com/n234\n", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void twoTokensAssortedDelimiters() {
|
||||||
|
scan("http://bogus.com/n234\nhttp://bogus.com/n442", 2);
|
||||||
|
scan("http://bogus.com/n234, http://bogus.com/n442", 2);
|
||||||
|
scan("http://bogus.com/n234,\nhttp://bogus.com/n442\n", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nonBreakingSpace() {
|
||||||
|
scan("non\u00A0breaking\u00A0space", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void omnibus() {
|
||||||
|
scan(" a , b,c d\t,\re", 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// Helper methods
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
public void scan(String input, int expectedUris) {
|
||||||
|
Reader reader = (input == null) ? null : new StringReader(input);
|
||||||
|
Iterator<String> it = new UpdateUrisInIndex().createScanner(reader);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
String uri = it.next();
|
String uri = it.next();
|
||||||
if( uri == null)
|
if (uri == null) {
|
||||||
Assert.fail("UrisFromInputIterator should not return null strings \n " +
|
Assert.fail("Scanner should not return null strings \n "
|
||||||
"Null string for uri #" + count + " for input '" + input + "'");
|
+ "Null string for uri #" + count + " for input '"
|
||||||
if( uri.isEmpty())
|
+ input + "'");
|
||||||
Assert.fail("UrisFromInputIterator should not return empty strings \n " +
|
} else if (uri.isEmpty()) {
|
||||||
"Empty string for uri #" + count + " for input '" + input + "'");
|
Assert.fail("Scanner should not return empty strings \n "
|
||||||
|
+ "Empty string for uri #" + count + " for input '"
|
||||||
|
+ input + "'");
|
||||||
|
}
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
Assert.assertEquals("Incorrect number of URIs from input '" + input + "'", expectedUris, count);
|
Assert.assertEquals("Incorrect number of URIs from input '" + input
|
||||||
|
+ "'", expectedUris, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -697,6 +697,7 @@ select_existing_collaborator = Select an existing Collaborator for {0}
|
||||||
selected = Selected
|
selected = Selected
|
||||||
change_selection = change selection
|
change_selection = change selection
|
||||||
there_are_no_entries_for_selection = There are no entries in the system from which to select.
|
there_are_no_entries_for_selection = There are no entries in the system from which to select.
|
||||||
|
the_range_class_does_not_exist= The range class for this property does not exist in the system.
|
||||||
editing_prohibited = This property is currently configured to prohibit editing.
|
editing_prohibited = This property is currently configured to prohibit editing.
|
||||||
confirm_entry_deletion_from = Are you sure you want to delete the following entry from
|
confirm_entry_deletion_from = Are you sure you want to delete the following entry from
|
||||||
|
|
||||||
|
@ -752,6 +753,7 @@ custom_template_containing_content = Custom template containing all content
|
||||||
a_menu_page = This is a menu page
|
a_menu_page = This is a menu page
|
||||||
menu_item_name = Menu Item Name
|
menu_item_name = Menu Item Name
|
||||||
if_blank_page_title_used = If left blank, the page title will be used.
|
if_blank_page_title_used = If left blank, the page title will be used.
|
||||||
|
multiple_content_default_template_error = With multiple content types, you must specify a custom template.
|
||||||
|
|
||||||
label = label
|
label = label
|
||||||
no_classes_to_select = There are no Classes in the system from which to select.
|
no_classes_to_select = There are no Classes in the system from which to select.
|
||||||
|
|
|
@ -205,13 +205,15 @@ var pageManagementUtils = {
|
||||||
//Also clear custom template value so as not to submit it
|
//Also clear custom template value so as not to submit it
|
||||||
pageManagementUtils.clearInputs(pageManagementUtils.customTemplate);
|
pageManagementUtils.clearInputs(pageManagementUtils.customTemplate);
|
||||||
pageManagementUtils.rightSideDiv.show();
|
pageManagementUtils.rightSideDiv.show();
|
||||||
|
//Check to see if there is already content on page, in which case save should be enabled
|
||||||
|
var pageContentSections = $("section[class='pageContent']");
|
||||||
|
if(pageContentSections.length == 0) {
|
||||||
pageManagementUtils.disablePageSave();
|
pageManagementUtils.disablePageSave();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.customTemplateRadio.click( function() {
|
this.customTemplateRadio.click( function() {
|
||||||
pageManagementUtils.customTemplate.removeClass('hidden');
|
pageManagementUtils.handleSelectCustomTemplate();
|
||||||
pageManagementUtils.rightSideDiv.show();
|
|
||||||
pageManagementUtils.disablePageSave();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.selfContainedTemplateRadio.click( function() {
|
this.selfContainedTemplateRadio.click( function() {
|
||||||
|
@ -265,6 +267,16 @@ var pageManagementUtils = {
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
|
handleSelectCustomTemplate: function() {
|
||||||
|
pageManagementUtils.customTemplate.removeClass('hidden');
|
||||||
|
pageManagementUtils.rightSideDiv.show();
|
||||||
|
//Check to see if there is already content on page, in which case save should be enabled
|
||||||
|
var pageContentSections = $("section[class='pageContent']");
|
||||||
|
if(pageContentSections.length == 0) {
|
||||||
|
pageManagementUtils.disablePageSave();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
handleClickDone:function() {
|
handleClickDone:function() {
|
||||||
var selectedType = pageManagementUtils.contentTypeSelect.val();
|
var selectedType = pageManagementUtils.contentTypeSelect.val();
|
||||||
var selectedTypeText = $("#typeSelect option:selected").text();
|
var selectedTypeText = $("#typeSelect option:selected").text();
|
||||||
|
@ -392,6 +404,9 @@ var pageManagementUtils = {
|
||||||
pageManagementUtils.adjustSaveButtonHeight();
|
pageManagementUtils.adjustSaveButtonHeight();
|
||||||
//Disable save button until the user has clicked done or cancel from the addition
|
//Disable save button until the user has clicked done or cancel from the addition
|
||||||
pageManagementUtils.disablePageSave();
|
pageManagementUtils.disablePageSave();
|
||||||
|
//If the default template is selected, there is already content on the page, and the user is selecting new content
|
||||||
|
//display alert message that they must select a custom template and select
|
||||||
|
pageManagementUtils.checkTemplateForMultipleContent(_this.contentTypeSelect.val());
|
||||||
},
|
},
|
||||||
disablePageSave:function() {
|
disablePageSave:function() {
|
||||||
pageManagementUtils.pageSaveButton.attr("disabled", "disabled");
|
pageManagementUtils.pageSaveButton.attr("disabled", "disabled");
|
||||||
|
@ -430,6 +445,21 @@ var pageManagementUtils = {
|
||||||
$el.find("select option:eq(0)").attr("selected", "selected");
|
$el.find("select option:eq(0)").attr("selected", "selected");
|
||||||
|
|
||||||
},
|
},
|
||||||
|
checkTemplateForMultipleContent:function(contentTypeSelected) {
|
||||||
|
if(contentTypeSelected != "") {
|
||||||
|
var pageContentSections = $("section[class='pageContent']");
|
||||||
|
var selectedTemplateValue = $('input:radio[name=selectedTemplate]:checked').val();
|
||||||
|
//A new section hasn't been added yet so check to see if there is at least one content type already on page
|
||||||
|
if(selectedTemplateValue == "default" && pageContentSections.length >= 1) {
|
||||||
|
//alert the user that they should be picking custom template instead
|
||||||
|
alert(pageManagementUtils.multipleContentWithDefaultTemplateError);
|
||||||
|
//pick custom template
|
||||||
|
$('input:radio[name=selectedTemplate][value="custom"]').attr("checked", true);
|
||||||
|
pageManagementUtils.handleSelectCustomTemplate();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
//Clone content area
|
//Clone content area
|
||||||
//When adding a new content type, this function will copy the values from the new content form and generate
|
//When adding a new content type, this function will copy the values from the new content form and generate
|
||||||
//the content for the new section containing the content
|
//the content for the new section containing the content
|
||||||
|
@ -874,6 +904,11 @@ var pageManagementUtils = {
|
||||||
if(pageContentSections.length == 0) {
|
if(pageContentSections.length == 0) {
|
||||||
validationErrorMsg = pageManagementUtils.selectContentType + " <br /> ";
|
validationErrorMsg = pageManagementUtils.selectContentType + " <br /> ";
|
||||||
} else {
|
} else {
|
||||||
|
//If there are multiple content types, and the default template option is selected, then display error message
|
||||||
|
var selectedTemplateValue = $('input:radio[name=selectedTemplate]:checked').val();
|
||||||
|
if(selectedTemplateValue == "default") {
|
||||||
|
validationErrorMsg += pageManagementUtils.multipleContentWithDefaultTemplateError;
|
||||||
|
}
|
||||||
//For each, based on type, validate if a validation function exists
|
//For each, based on type, validate if a validation function exists
|
||||||
$.each(pageContentSections, function(i) {
|
$.each(pageContentSections, function(i) {
|
||||||
if(pageManagementUtils.processDataGetterUtils != null) {
|
if(pageManagementUtils.processDataGetterUtils != null) {
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
<#--This is an example of including multiple content types in the same template, this combines the default templates for Fixed HTML, Class groups and Solr Individuals in one template-->
|
||||||
|
<#include "menupage-checkForData.ftl">
|
||||||
|
<#--Fixed HTML portion-->
|
||||||
|
<#--Note that variableName is employed by both the fixed html and sparql query templates, this is used to store the
|
||||||
|
actual name of the variable that is used to store either the fixed html or sparql query results. If combining fixed html
|
||||||
|
and sparql query results in a custom template, the template can utilize the actual variable name e.g. "query results" instead of how
|
||||||
|
variableName is used below.-->
|
||||||
|
<#assign htmlExists = false/>
|
||||||
|
|
||||||
|
<#if variableName?has_content>
|
||||||
|
<#assign htmlExists = true />
|
||||||
|
</#if>
|
||||||
|
<#if htmlExists>
|
||||||
|
${.globals[variableName]}
|
||||||
|
<#else>
|
||||||
|
${i18n().no_html_specified}
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#--Class grou section-->
|
||||||
|
<#if !noData>
|
||||||
|
<section id="menupage-intro" role="region">
|
||||||
|
<h2>${page.title}</h2>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<#include "menupage-browse.ftl">
|
||||||
|
|
||||||
|
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/css/menupage/menupage.css" />')}
|
||||||
|
|
||||||
|
<#include "menupage-scripts.ftl">
|
||||||
|
<#else>
|
||||||
|
${noDataNotification}
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#--Solr Individuals section-->
|
||||||
|
<#import "lib-list.ftl" as l>
|
||||||
|
|
||||||
|
<#include "individualList-checkForData.ftl">
|
||||||
|
|
||||||
|
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/css/browseIndex.css" />')}
|
||||||
|
|
||||||
|
<section class="individualList">
|
||||||
|
<h2>${title}
|
||||||
|
</h2>
|
||||||
|
<#if subtitle?has_content>
|
||||||
|
<h4>${subtitle}</h4>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if (!noData)>
|
||||||
|
<#if errorMessage?has_content>
|
||||||
|
<p>${errorMessage}</p>
|
||||||
|
<#else>
|
||||||
|
<#assign pagination>
|
||||||
|
<#if (pages?has_content && pages?size > 1)>
|
||||||
|
${i18n().pages}:
|
||||||
|
<ul class="pagination">
|
||||||
|
<#list pages as page>
|
||||||
|
<#if page.selected>
|
||||||
|
<li class="selectedNavPage">${page.text}</li>
|
||||||
|
<#else>
|
||||||
|
<#-- RY Ideally the urls would be generated by the controller; see search-pagedResults.ftl -->
|
||||||
|
<li><a href="${urls.base}/individuallist?${page.param}&vclassId=${vclassId?url}" title="${i18n().page_text}">${page.text}</a></li>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</ul>
|
||||||
|
</#if>
|
||||||
|
</#assign>
|
||||||
|
|
||||||
|
${pagination}
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<#list individuals as individual>
|
||||||
|
<li>
|
||||||
|
<@shortView uri=individual.uri viewContext="index" />
|
||||||
|
</li>
|
||||||
|
</#list>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
${pagination}
|
||||||
|
</#if>
|
||||||
|
<#else>
|
||||||
|
${noDataNotification}
|
||||||
|
</#if>
|
||||||
|
</section> <!-- .individualList -->
|
|
@ -12,9 +12,8 @@
|
||||||
<p>This service will update the search index for the list of URIs it
|
<p>This service will update the search index for the list of URIs it
|
||||||
receives. It expectes a POST with an encoding of
|
receives. It expectes a POST with an encoding of
|
||||||
multpart/form-data. The service inspect all parts of this POST for
|
multpart/form-data. The service inspect all parts of this POST for
|
||||||
lists of URIs to reindex. The URIs should be comma or space
|
lists of URIs to reindex. The URIs should be separated by commas and/or white space.
|
||||||
seperated. If no information can be found for a URI it will be
|
If no information can be found for a URI it will be ignored.</p>
|
||||||
ignored.</p>
|
|
||||||
|
|
||||||
<p>The request parameters email and password allow the form to be submitted
|
<p>The request parameters email and password allow the form to be submitted
|
||||||
for a user account. Only internal accounts are supported, external authentication
|
for a user account. Only internal accounts are supported, external authentication
|
||||||
|
@ -33,8 +32,8 @@ is not supported.</p>
|
||||||
<label for="password">Account password</label>
|
<label for="password">Account password</label>
|
||||||
<input type="text" name="password" id="password"/>
|
<input type="text" name="password" id="password"/>
|
||||||
|
|
||||||
<label for="urisToUpdate">List of URIs to update in the search index</label>
|
<label for="urisToUpdate">File of URIs to update in the search index</label>
|
||||||
<textarea name="urisToUpdate" id="urisToUpdate" rows="4" cols="50" ></textarea>
|
<input type="file" name="datafile" size="30" />
|
||||||
|
|
||||||
<button type="submit">submit</button>
|
<button type="submit">submit</button>
|
||||||
</form>
|
</form>
|
|
@ -189,7 +189,8 @@
|
||||||
supplyPrettyUrl: '${i18n().supply_url}',
|
supplyPrettyUrl: '${i18n().supply_url}',
|
||||||
startUrlWithSlash: '${i18n().start_url_with_slash}',
|
startUrlWithSlash: '${i18n().start_url_with_slash}',
|
||||||
supplyTemplate: '${i18n().supply_template}',
|
supplyTemplate: '${i18n().supply_template}',
|
||||||
selectContentType: '${i18n().select_content_type}'
|
selectContentType: '${i18n().select_content_type}',
|
||||||
|
multipleContentWithDefaultTemplateError: '${i18n().multiple_content_default_template_error}'
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue