Merge branch 'rel-1.12.0-RC' into main
This commit is contained in:
commit
5a4648554a
57 changed files with 620 additions and 689 deletions
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-api</artifactId>
|
<artifactId>vitro-api</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-project</artifactId>
|
<artifactId>vitro-project</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<relativePath>..</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-dependencies</artifactId>
|
<artifactId>vitro-dependencies</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -24,7 +24,6 @@ import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableModel
|
||||||
*/
|
*/
|
||||||
public class ApplicationSetup implements ServletContextListener {
|
public class ApplicationSetup implements ServletContextListener {
|
||||||
private static final String APPLICATION_SETUP_PATH = "config/applicationSetup.n3";
|
private static final String APPLICATION_SETUP_PATH = "config/applicationSetup.n3";
|
||||||
private static final String APPLICATION_SETUP_DEFAULT_PATH = "config/default.applicationSetup.n3";
|
|
||||||
|
|
||||||
private ServletContext ctx;
|
private ServletContext ctx;
|
||||||
private StartupStatus ss;
|
private StartupStatus ss;
|
||||||
|
@ -46,8 +45,6 @@ public class ApplicationSetup implements ServletContextListener {
|
||||||
this.vitroHomeDir = VitroHomeDirectory.find(ctx);
|
this.vitroHomeDir = VitroHomeDirectory.find(ctx);
|
||||||
ss.info(this, vitroHomeDir.getDiscoveryMessage());
|
ss.info(this, vitroHomeDir.getDiscoveryMessage());
|
||||||
|
|
||||||
this.vitroHomeDir.populate();
|
|
||||||
|
|
||||||
locateApplicationConfigFile();
|
locateApplicationConfigFile();
|
||||||
loadApplicationConfigFile();
|
loadApplicationConfigFile();
|
||||||
createConfigurationBeanLoader();
|
createConfigurationBeanLoader();
|
||||||
|
@ -66,19 +63,11 @@ public class ApplicationSetup implements ServletContextListener {
|
||||||
private void locateApplicationConfigFile() {
|
private void locateApplicationConfigFile() {
|
||||||
Path path = this.vitroHomeDir.getPath().resolve(APPLICATION_SETUP_PATH);
|
Path path = this.vitroHomeDir.getPath().resolve(APPLICATION_SETUP_PATH);
|
||||||
|
|
||||||
if (!Files.exists(path) || !Files.isReadable(path)) {
|
|
||||||
path = this.vitroHomeDir.getPath().resolve(APPLICATION_SETUP_DEFAULT_PATH);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Files.exists(path)) {
|
if (!Files.exists(path)) {
|
||||||
throw new IllegalStateException("Neither '" + APPLICATION_SETUP_PATH + "' nor '" +
|
throw new IllegalStateException("'" + path + "' does not exist.");
|
||||||
APPLICATION_SETUP_DEFAULT_PATH + "' were found in " +
|
|
||||||
this.vitroHomeDir.getPath());
|
|
||||||
}
|
}
|
||||||
if (!Files.isReadable(path)) {
|
if (!Files.isReadable(path)) {
|
||||||
throw new IllegalStateException("No readable '" + APPLICATION_SETUP_PATH + "' nor '" +
|
throw new IllegalStateException("Can't read '" + path + "'");
|
||||||
APPLICATION_SETUP_DEFAULT_PATH + "' files were found in " +
|
|
||||||
this.vitroHomeDir.getPath());
|
|
||||||
}
|
}
|
||||||
this.configFile = path;
|
this.configFile = path;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,46 +4,25 @@ package edu.cornell.mannlib.vitro.webapp.application;
|
||||||
|
|
||||||
import static edu.cornell.mannlib.vitro.webapp.application.BuildProperties.WEBAPP_PATH_BUILD_PROPERTIES;
|
import static edu.cornell.mannlib.vitro.webapp.application.BuildProperties.WEBAPP_PATH_BUILD_PROPERTIES;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
|
import javax.naming.InitialContext;
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
|
|
||||||
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
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.config.ContextProperties;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates some of the info relating to and initializes the Vitro home directory.
|
* Encapsulates some of the info relating to the Vitro home directory.
|
||||||
*/
|
*/
|
||||||
public class VitroHomeDirectory {
|
public class VitroHomeDirectory {
|
||||||
private static final Log log = LogFactory.getLog(VitroHomeDirectory.class);
|
private static final Log log = LogFactory.getLog(VitroHomeDirectory.class);
|
||||||
|
|
||||||
private static final String DIGEST_FILE_NAME = "digest.md5";
|
|
||||||
|
|
||||||
private static final Pattern CHECKSUM_PATTERN = Pattern.compile("^[a-f0-9]{32} \\*.+$");
|
|
||||||
|
|
||||||
public static VitroHomeDirectory find(ServletContext ctx) {
|
public static VitroHomeDirectory find(ServletContext ctx) {
|
||||||
HomeDirectoryFinder finder = new HomeDirectoryFinder(ctx);
|
HomeDirectoryFinder finder = new HomeDirectoryFinder(ctx);
|
||||||
return new VitroHomeDirectory(ctx, finder.getPath(),
|
return new VitroHomeDirectory(ctx, finder.getPath(),
|
||||||
|
@ -73,219 +52,6 @@ public class VitroHomeDirectory {
|
||||||
return discoveryMessage;
|
return discoveryMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Populates VIVO home directory with files required to run.
|
|
||||||
*
|
|
||||||
* NOTE: Will not overwrite any modified files on redeploy.
|
|
||||||
*/
|
|
||||||
public void populate() {
|
|
||||||
File vhdDir = getPath().toFile();
|
|
||||||
|
|
||||||
if (!vhdDir.isDirectory() || vhdDir.list() == null) {
|
|
||||||
throw new RuntimeException("Application home dir is not a directory! " + vhdDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> digest = untar(vhdDir);
|
|
||||||
|
|
||||||
writeDigest(digest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A non-destructive untar process that returns checksum digest of tarred files.
|
|
||||||
*
|
|
||||||
* Checksum digest can be manually created with the following command.
|
|
||||||
*
|
|
||||||
* `find /vivo/home -type f | cut -c3- | grep -E '^bin/|^config/|^rdf/' | xargs md5sum > /vivo/home/digest.md5`
|
|
||||||
*
|
|
||||||
* @param destination VIVO home directory
|
|
||||||
* @return digest of each files checksum
|
|
||||||
*/
|
|
||||||
private Map<String, String> untar(File destination) {
|
|
||||||
log.info("Syncing VIVO home at: " + destination.getPath());
|
|
||||||
|
|
||||||
Map<String, String> digest = new HashMap<>();
|
|
||||||
Map<String, String> storedDigest = loadDigest();
|
|
||||||
|
|
||||||
TarArchiveEntry tarEntry;
|
|
||||||
try (
|
|
||||||
InputStream homeDirTar = getHomeDirTar();
|
|
||||||
TarArchiveInputStream tarInput = new TarArchiveInputStream(homeDirTar);
|
|
||||||
) {
|
|
||||||
while ((tarEntry = tarInput.getNextTarEntry()) != null) {
|
|
||||||
|
|
||||||
// Use the example configurations
|
|
||||||
String outFilename = tarEntry.getName().replace("example.", "");
|
|
||||||
File outFile = new File(destination, outFilename);
|
|
||||||
|
|
||||||
// Is the entry a directory?
|
|
||||||
if (tarEntry.isDirectory()) {
|
|
||||||
if (!outFile.exists()) {
|
|
||||||
outFile.mkdirs();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Entry is a File
|
|
||||||
boolean write = true;
|
|
||||||
|
|
||||||
// reading bytes into memory to avoid having to unreliably reset stream
|
|
||||||
byte[] bytes = IOUtils.toByteArray(tarInput);
|
|
||||||
String newFileChecksum = checksum(bytes);
|
|
||||||
digest.put(outFilename, newFileChecksum);
|
|
||||||
|
|
||||||
// if file already exists and stored digest contains the file,
|
|
||||||
// check to determine if it has changed
|
|
||||||
if (outFile.exists() && storedDigest.containsKey(outFilename)) {
|
|
||||||
String existingFileChecksum = checksum(outFile);
|
|
||||||
// if file has not changed in home and is not the same as new file, overwrite
|
|
||||||
write = storedDigest.get(outFilename).equals(existingFileChecksum)
|
|
||||||
&& !existingFileChecksum.equals(newFileChecksum);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (write) {
|
|
||||||
outFile.getParentFile().mkdirs();
|
|
||||||
try (
|
|
||||||
InputStream is = new ByteArrayInputStream(bytes);
|
|
||||||
FileOutputStream fos = new FileOutputStream(outFile);
|
|
||||||
) {
|
|
||||||
IOUtils.copy(is, fos);
|
|
||||||
log.info(outFile.getAbsolutePath() + " source has changed and has not been "
|
|
||||||
+ "edited in home, updated file has been copied to home directory.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.debug(outFile.getAbsolutePath() + " has been preserved.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException | NoSuchAlgorithmException e) {
|
|
||||||
throw new RuntimeException("Error creating home directory!", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return digest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load checksum digest of VIVO home directory.
|
|
||||||
*
|
|
||||||
* @return checksum digest
|
|
||||||
*/
|
|
||||||
private Map<String, String> loadDigest() {
|
|
||||||
File storedDigest = new File(getPath().toFile(), DIGEST_FILE_NAME);
|
|
||||||
if (storedDigest.exists() && storedDigest.isFile()) {
|
|
||||||
log.info("Reading VIVO home digest: " + storedDigest.getPath());
|
|
||||||
try {
|
|
||||||
return FileUtils
|
|
||||||
.readLines(storedDigest, StandardCharsets.UTF_8)
|
|
||||||
.stream()
|
|
||||||
.filter(CHECKSUM_PATTERN.asPredicate())
|
|
||||||
.map(this::split)
|
|
||||||
.collect(Collectors.toMap(this::checksumFile, this::checksumValue));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Error reading VIVO home checksum digest!", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.info("VIVO home digest not found: " + storedDigest.getPath());
|
|
||||||
|
|
||||||
return new HashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write VIVO home checksum digest following md5 format; `<checksum> *<file>`.
|
|
||||||
*
|
|
||||||
* @param digest checksum digest to write
|
|
||||||
*/
|
|
||||||
private void writeDigest(Map<String, String> digest) {
|
|
||||||
File storedDigest = new File(getPath().toFile(), DIGEST_FILE_NAME);
|
|
||||||
try (
|
|
||||||
FileOutputStream fos = new FileOutputStream(storedDigest);
|
|
||||||
OutputStreamWriter osw = new OutputStreamWriter(fos);
|
|
||||||
) {
|
|
||||||
for (Map.Entry<String, String> entry : digest.entrySet()) {
|
|
||||||
String filename = entry.getKey();
|
|
||||||
String checksum = entry.getValue();
|
|
||||||
osw.write(String.format("%s *%s\n", checksum, filename));
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Error writing home directory checksum digest!", e);
|
|
||||||
}
|
|
||||||
log.info("VIVO home digest created: " + storedDigest.getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Split checksum.
|
|
||||||
*
|
|
||||||
* @param checksum checksum delimited by space and asterisks `<checksum> *<file>`
|
|
||||||
* @return split checksum
|
|
||||||
*/
|
|
||||||
private String[] split(String checksum) {
|
|
||||||
return checksum.split("\\s+");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get value from split checksum.
|
|
||||||
*
|
|
||||||
* @param checksum split checksum
|
|
||||||
* @return checksum value
|
|
||||||
*/
|
|
||||||
private String checksumValue(String[] checksum) {
|
|
||||||
return checksum[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return file from split checksum.
|
|
||||||
*
|
|
||||||
* @param checksum split checksum
|
|
||||||
* @return filename
|
|
||||||
*/
|
|
||||||
private String checksumFile(String[] checksum) {
|
|
||||||
return checksum[1].substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get md5 checksum from file.
|
|
||||||
*
|
|
||||||
* @param file file
|
|
||||||
* @return md5 checksum as string
|
|
||||||
* @throws IOException
|
|
||||||
* @throws NoSuchAlgorithmException
|
|
||||||
*/
|
|
||||||
private String checksum(File file) throws IOException, NoSuchAlgorithmException {
|
|
||||||
return checksum(FileUtils.readFileToByteArray(file));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get md5 checksum from bytes.
|
|
||||||
*
|
|
||||||
* @param bytes bytes from file
|
|
||||||
* @return md5 checksum as string
|
|
||||||
* @throws NoSuchAlgorithmException
|
|
||||||
*/
|
|
||||||
private String checksum(byte[] bytes) throws NoSuchAlgorithmException {
|
|
||||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
|
||||||
md.update(bytes);
|
|
||||||
// bytes to hex
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
for (byte b : md.digest()) {
|
|
||||||
result.append(String.format("%02x", b));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get prepacked VIVO home tar file as input stream.
|
|
||||||
*
|
|
||||||
* @return input stream of VIVO home tar file
|
|
||||||
*/
|
|
||||||
private InputStream getHomeDirTar() {
|
|
||||||
String tarLocation = "/WEB-INF/resources/home-files/vivo-home.tar";
|
|
||||||
InputStream tar = ctx.getResourceAsStream(tarLocation);
|
|
||||||
if (tar == null) {
|
|
||||||
log.error("Application home tar not found in: " + tarLocation);
|
|
||||||
throw new RuntimeException("Application home tar not found in: " + tarLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tar;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find something that specifies the location of the Vitro home directory.
|
* Find something that specifies the location of the Vitro home directory.
|
||||||
* Look in the JDNI environment, the system properties, and the
|
* Look in the JDNI environment, the system properties, and the
|
||||||
|
@ -326,13 +92,24 @@ public class VitroHomeDirectory {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getVhdFromJndi() {
|
public void getVhdFromJndi() {
|
||||||
String vhdPath = ContextProperties.findJndiProperty(VHD_JNDI_PATH);
|
try {
|
||||||
log.debug("'" + VHD_JNDI_PATH + "' as specified by JNDI: " + vhdPath);
|
String vhdPath = (String) new InitialContext()
|
||||||
|
.lookup(VHD_JNDI_PATH);
|
||||||
|
if (vhdPath == null) {
|
||||||
|
log.debug("Didn't find a JNDI value at '" + VHD_JNDI_PATH
|
||||||
|
+ "'.");
|
||||||
|
} else {
|
||||||
|
log.debug("'" + VHD_JNDI_PATH + "' as specified by JNDI: "
|
||||||
|
+ vhdPath);
|
||||||
String message = String.format(
|
String message = String.format(
|
||||||
"JNDI environment '%s' was set to '%s'",
|
"JNDI environment '%s' was set to '%s'",
|
||||||
VHD_JNDI_PATH, vhdPath);
|
VHD_JNDI_PATH, vhdPath);
|
||||||
foundLocations.add(new Found(Paths.get(vhdPath), message));
|
foundLocations.add(new Found(Paths.get(vhdPath), message));
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("JNDI lookup failed. " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void getVhdFromSystemProperties() {
|
private void getVhdFromSystemProperties() {
|
||||||
String vhdPath = System.getProperty(VHD_SYSTEM_PROPERTY);
|
String vhdPath = System.getProperty(VHD_SYSTEM_PROPERTY);
|
||||||
|
|
|
@ -7,17 +7,11 @@ import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about the account of a user. URI, email, password, etc.
|
* Information about the account of a user. URI, email, password, etc.
|
||||||
*
|
*
|
||||||
* The "password link expires hash" is just a string that is derived from the
|
|
||||||
* value in the passwordLinkExpires field. It doesn't have to be a hash, and
|
|
||||||
* there is no need for it to be cryptographic, but it seems embarrassing to
|
|
||||||
* just send the value as a clear string. There is no real need for security
|
|
||||||
* here, except that a brute force attack would allow someone to change the
|
|
||||||
* password on an account that they know has a password change pending.
|
|
||||||
*/
|
*/
|
||||||
public class UserAccount {
|
public class UserAccount {
|
||||||
public static final int MIN_PASSWORD_LENGTH = 6;
|
public static final int MIN_PASSWORD_LENGTH = 6;
|
||||||
|
@ -52,6 +46,7 @@ public class UserAccount {
|
||||||
private String md5Password = ""; // Never null.
|
private String md5Password = ""; // Never null.
|
||||||
private String oldPassword = ""; // Never null.
|
private String oldPassword = ""; // Never null.
|
||||||
private long passwordLinkExpires = 0L; // Never negative.
|
private long passwordLinkExpires = 0L; // Never negative.
|
||||||
|
private String emailKey = "";
|
||||||
private boolean passwordChangeRequired = false;
|
private boolean passwordChangeRequired = false;
|
||||||
|
|
||||||
private int loginCount = 0; // Never negative.
|
private int loginCount = 0; // Never negative.
|
||||||
|
@ -133,15 +128,27 @@ public class UserAccount {
|
||||||
return passwordLinkExpires;
|
return passwordLinkExpires;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPasswordLinkExpiresHash() {
|
|
||||||
return limitStringLength(8, Authenticator.applyArgon2iEncoding(String
|
|
||||||
.valueOf(passwordLinkExpires)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPasswordLinkExpires(long passwordLinkExpires) {
|
public void setPasswordLinkExpires(long passwordLinkExpires) {
|
||||||
this.passwordLinkExpires = Math.max(0, passwordLinkExpires);
|
this.passwordLinkExpires = Math.max(0, passwordLinkExpires);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void generateEmailKey() {
|
||||||
|
boolean useLetters = true;
|
||||||
|
boolean useNumbers = true;
|
||||||
|
int length = 64;
|
||||||
|
emailKey = RandomStringUtils.random(length, useLetters, useNumbers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmailKey(String emailKey) {
|
||||||
|
if (emailKey != null) {
|
||||||
|
this.emailKey = emailKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmailKey() {
|
||||||
|
return emailKey;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isPasswordChangeRequired() {
|
public boolean isPasswordChangeRequired() {
|
||||||
return passwordChangeRequired;
|
return passwordChangeRequired;
|
||||||
}
|
}
|
||||||
|
@ -247,6 +254,7 @@ public class UserAccount {
|
||||||
+ (", oldPassword=" + oldPassword)
|
+ (", oldPassword=" + oldPassword)
|
||||||
+ (", argon2password=" + argon2Password)
|
+ (", argon2password=" + argon2Password)
|
||||||
+ (", passwordLinkExpires=" + passwordLinkExpires)
|
+ (", passwordLinkExpires=" + passwordLinkExpires)
|
||||||
|
+ (", emailKey =" + emailKey)
|
||||||
+ (", passwordChangeRequired=" + passwordChangeRequired)
|
+ (", passwordChangeRequired=" + passwordChangeRequired)
|
||||||
+ (", externalAuthOnly=" + externalAuthOnly)
|
+ (", externalAuthOnly=" + externalAuthOnly)
|
||||||
+ (", loginCount=" + loginCount) + (", status=" + status)
|
+ (", loginCount=" + loginCount) + (", status=" + status)
|
||||||
|
|
|
@ -109,7 +109,7 @@ public abstract class ConfigurationProperties {
|
||||||
throw new NullPointerException("bean may not be null.");
|
throw new NullPointerException("bean may not be null.");
|
||||||
}
|
}
|
||||||
context.setAttribute(ATTRIBUTE_NAME, bean);
|
context.setAttribute(ATTRIBUTE_NAME, bean);
|
||||||
log.info(bean);
|
log.debug(bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Package access, so unit tests can call it. */
|
/** Package access, so unit tests can call it. */
|
||||||
|
|
|
@ -32,10 +32,8 @@ public class ConfigurationPropertiesImpl extends ConfigurationProperties {
|
||||||
|
|
||||||
public ConfigurationPropertiesImpl(InputStream stream,
|
public ConfigurationPropertiesImpl(InputStream stream,
|
||||||
Map<String, String> preemptiveProperties,
|
Map<String, String> preemptiveProperties,
|
||||||
Map<String, String> buildProperties,
|
Map<String, String> buildProperties) throws IOException {
|
||||||
Map<String, String> contextProperties) throws IOException {
|
|
||||||
Map<String, String> map = new HashMap<>(buildProperties);
|
Map<String, String> map = new HashMap<>(buildProperties);
|
||||||
map.putAll(contextProperties);
|
|
||||||
|
|
||||||
Properties props = loadFromPropertiesFile(stream);
|
Properties props = loadFromPropertiesFile(stream);
|
||||||
for (String key: props.stringPropertyNames()) {
|
for (String key: props.stringPropertyNames()) {
|
||||||
|
|
|
@ -49,12 +49,12 @@ public class ConfigurationPropertiesSetup implements ServletContextListener {
|
||||||
/** Name of the file that contains runtime properties. */
|
/** Name of the file that contains runtime properties. */
|
||||||
private static final String FILE_RUNTIME_PROPERTIES = "runtime.properties";
|
private static final String FILE_RUNTIME_PROPERTIES = "runtime.properties";
|
||||||
|
|
||||||
/** Fall-back name of the file that contains runtime properties. */
|
|
||||||
private static final String FILE_DEFAULT_RUNTIME_PROPERTIES = "default.runtime.properties";
|
|
||||||
|
|
||||||
/** Configuration property to store the Vitro home directory */
|
/** Configuration property to store the Vitro home directory */
|
||||||
private static final String VHD_CONFIGURATION_PROPERTY = "vitro.home";
|
private static final String VHD_CONFIGURATION_PROPERTY = "vitro.home";
|
||||||
|
|
||||||
|
/** Configuration property used to determine if there are runtime.properties files in multiple locations **/
|
||||||
|
static final String RP_MULTIPLE = "rp.multiple";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contextInitialized(ServletContextEvent sce) {
|
public void contextInitialized(ServletContextEvent sce) {
|
||||||
ServletContext ctx = sce.getServletContext();
|
ServletContext ctx = sce.getServletContext();
|
||||||
|
@ -69,17 +69,18 @@ public class ConfigurationPropertiesSetup implements ServletContextListener {
|
||||||
File vitroHomeDirConfig = new File(vitroHomeDir.getPath()
|
File vitroHomeDirConfig = new File(vitroHomeDir.getPath()
|
||||||
.concat(File.separator).concat("config"));
|
.concat(File.separator).concat("config"));
|
||||||
|
|
||||||
|
String rpfLocation = findMultipleRuntimePropertiesFiles(
|
||||||
|
vitroHomeDir, vitroHomeDirConfig);
|
||||||
|
|
||||||
File runtimePropertiesFile = locateRuntimePropertiesFile(
|
File runtimePropertiesFile = locateRuntimePropertiesFile(
|
||||||
vitroHomeDirConfig, ss);
|
vitroHomeDir, vitroHomeDirConfig, ss);
|
||||||
stream = new FileInputStream(runtimePropertiesFile);
|
stream = new FileInputStream(runtimePropertiesFile);
|
||||||
|
|
||||||
Map<String, String> preempts = createPreemptiveProperties(
|
Map<String, String> preempts = createPreemptiveProperties(
|
||||||
VHD_CONFIGURATION_PROPERTY, vitroHomeDir);
|
VHD_CONFIGURATION_PROPERTY, vitroHomeDir, RP_MULTIPLE, rpfLocation);
|
||||||
|
|
||||||
ConfigurationPropertiesImpl bean = new ConfigurationPropertiesImpl(
|
ConfigurationPropertiesImpl bean = new ConfigurationPropertiesImpl(
|
||||||
stream, preempts,
|
stream, preempts, new BuildProperties(ctx).getMap());
|
||||||
new BuildProperties(ctx).getMap(),
|
|
||||||
new ContextProperties().getMap());
|
|
||||||
|
|
||||||
ConfigurationProperties.setBean(ctx, bean);
|
ConfigurationProperties.setBean(ctx, bean);
|
||||||
ss.info(this, "Loaded " + bean.getPropertyMap().size()
|
ss.info(this, "Loaded " + bean.getPropertyMap().size()
|
||||||
|
@ -98,36 +99,53 @@ public class ConfigurationPropertiesSetup implements ServletContextListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private File locateRuntimePropertiesFile(File vitroHomeDirConfig, StartupStatus ss) {
|
private String findMultipleRuntimePropertiesFiles(File vitroHomeDir,
|
||||||
|
File vitroHomeDirConfig) {
|
||||||
|
|
||||||
// First look for the user-customized runtime.properties
|
File rpf = new File(vitroHomeDir, FILE_RUNTIME_PROPERTIES);
|
||||||
File rpf = new File(vitroHomeDirConfig, FILE_RUNTIME_PROPERTIES);
|
File rpfc = new File(vitroHomeDirConfig, FILE_RUNTIME_PROPERTIES);
|
||||||
|
|
||||||
// Have we found a suitable runtime.properties file?
|
if (rpf.exists() && !rpfc.exists()) {
|
||||||
if (!rpf.exists() || !rpf.isFile() || !rpf.canRead()) {
|
return "home";
|
||||||
|
} else if (rpf.exists() && rpfc.exists()) {
|
||||||
// If not... look for the default runtime.properties
|
return "both";
|
||||||
rpf = new File(vitroHomeDirConfig, FILE_DEFAULT_RUNTIME_PROPERTIES);
|
} else if (rpfc.exists()) {
|
||||||
|
return "config";
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Did not find '"
|
||||||
|
+ FILE_RUNTIME_PROPERTIES + "' in vitro home directory '"
|
||||||
|
+ vitroHomeDir + "' or config directory '" + vitroHomeDirConfig + "'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rpf.exists() || !rpf.isFile()) {
|
private File locateRuntimePropertiesFile(File vitroHomeDir,
|
||||||
throw new IllegalStateException("Neither '" + FILE_RUNTIME_PROPERTIES + "' nor '" +
|
File vitroHomeDirConfig, StartupStatus ss) {
|
||||||
FILE_DEFAULT_RUNTIME_PROPERTIES + "' were found in " +
|
|
||||||
vitroHomeDirConfig.getAbsolutePath());
|
File rpf = new File(vitroHomeDir, FILE_RUNTIME_PROPERTIES);
|
||||||
|
File rpfc = new File(vitroHomeDirConfig, FILE_RUNTIME_PROPERTIES);
|
||||||
|
|
||||||
|
if (!rpf.exists()) {
|
||||||
|
rpf = rpfc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rpf.isFile()) {
|
||||||
|
throw new IllegalStateException("'" + rpf.getPath()
|
||||||
|
+ "' is not a file.");
|
||||||
}
|
}
|
||||||
if (!rpf.canRead()) {
|
if (!rpf.canRead()) {
|
||||||
throw new IllegalStateException("No readable '" + FILE_RUNTIME_PROPERTIES + "' nor '" +
|
throw new IllegalStateException("Cannot read '" + rpf.getPath()
|
||||||
FILE_DEFAULT_RUNTIME_PROPERTIES + "' files were found in " +
|
+ "'.");
|
||||||
vitroHomeDirConfig.getAbsolutePath());
|
|
||||||
}
|
}
|
||||||
ss.info(this, "Loading runtime properties from '" + rpf.getPath() + "'");
|
ss.info(this, "Loading runtime properties from '" + rpf.getPath() + "'");
|
||||||
return rpf;
|
return rpf;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, String> createPreemptiveProperties(
|
private Map<String, String> createPreemptiveProperties(
|
||||||
String propertyVitroHome, File vitroHomeDir) {
|
String propertyVitroHome, File vitroHomeDir, String propertyRpfMultiple,
|
||||||
|
String rpfLocation) {
|
||||||
Map<String, String> map = new HashMap<String, String>();
|
Map<String, String> map = new HashMap<String, String>();
|
||||||
map.put(propertyVitroHome, vitroHomeDir.getAbsolutePath());
|
map.put(propertyVitroHome, vitroHomeDir.getAbsolutePath());
|
||||||
|
map.put(propertyRpfMultiple, rpfLocation);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ public class ConfigurationPropertiesSmokeTests implements
|
||||||
StartupStatus ss = StartupStatus.getBean(ctx);
|
StartupStatus ss = StartupStatus.getBean(ctx);
|
||||||
|
|
||||||
checkDefaultNamespace(ctx, props, ss);
|
checkDefaultNamespace(ctx, props, ss);
|
||||||
|
checkMultipleRPFs(ctx, props, ss);
|
||||||
checkLanguages(ctx, props, ss);
|
checkLanguages(ctx, props, ss);
|
||||||
checkEncryptionParameters(props, ss);
|
checkEncryptionParameters(props, ss);
|
||||||
|
|
||||||
|
@ -85,6 +86,32 @@ public class ConfigurationPropertiesSmokeTests implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warn if runtime.properties exists in multiple locations
|
||||||
|
* or is located vivo.home instead of vivo.home/config
|
||||||
|
*/
|
||||||
|
private void checkMultipleRPFs(ServletContext ctx,
|
||||||
|
ConfigurationProperties props, StartupStatus ss) {
|
||||||
|
String rpfStatus = props.getProperty(ConfigurationPropertiesSetup.RP_MULTIPLE);
|
||||||
|
|
||||||
|
if (rpfStatus.equals("both")) {
|
||||||
|
ss.warning(this,
|
||||||
|
"Deprecation warning: Files matching the name 'runtime.properties' "
|
||||||
|
+ "were found in both vivo.home and vivo.home/config. Using "
|
||||||
|
+ "the file in vivo.home. Future releases may require "
|
||||||
|
+ "runtime.properties be placed in vivo.home/config.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rpfStatus.equals("home")) {
|
||||||
|
ss.warning(this,
|
||||||
|
"Deprecation warning: runtime.properties was found in the "
|
||||||
|
+ "vivo.home directory. The recommended directory for "
|
||||||
|
+ "runtime.properties is now vivo.home/config. Future releases "
|
||||||
|
+ "may require runtime.properties be placed in "
|
||||||
|
+ "vivo.home/config.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Warn if we set up the languages incorrectly:
|
* Warn if we set up the languages incorrectly:
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
/* $This file is distributed under the terms of the license in LICENSE$ */
|
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.config;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.naming.InitialContext;
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtains and provides the properties from the web application's context.xml
|
|
||||||
*
|
|
||||||
* @author awoods
|
|
||||||
* @since 2020-10-23
|
|
||||||
*/
|
|
||||||
public class ContextProperties {
|
|
||||||
private static final Log log = LogFactory.getLog(ContextProperties.class);
|
|
||||||
|
|
||||||
private static final String DEFAULT_NAMESPACE_JNDI_PATH = "java:comp/env/vitro/defaultNamespace";
|
|
||||||
private static final String ROOT_USER_ADDRESS_JNDI_PATH = "java:comp/env/vitro/rootUserAddress";
|
|
||||||
private static final String APP_NAME_JNDI_PATH = "java:comp/env/vitro/appName";
|
|
||||||
|
|
||||||
private static final String DEFAULT_NAMESPACE_KEY = "Vitro.defaultNamespace";
|
|
||||||
private static final String ROOT_USER_ADDRESS_KEY = "rootUser.emailAddress";
|
|
||||||
private static final String APP_NAME_KEY = "app-name";
|
|
||||||
|
|
||||||
private final Map<String, String> propertyMap;
|
|
||||||
|
|
||||||
public ContextProperties() {
|
|
||||||
Map<String, String> map = new HashMap<>();
|
|
||||||
|
|
||||||
// Find default namespace
|
|
||||||
map.put(DEFAULT_NAMESPACE_KEY, findJndiProperty(DEFAULT_NAMESPACE_JNDI_PATH));
|
|
||||||
|
|
||||||
// Find root user email address
|
|
||||||
map.put(ROOT_USER_ADDRESS_KEY, findJndiProperty(ROOT_USER_ADDRESS_JNDI_PATH));
|
|
||||||
|
|
||||||
// Find application name
|
|
||||||
map.put(APP_NAME_KEY, findJndiProperty(APP_NAME_JNDI_PATH));
|
|
||||||
|
|
||||||
propertyMap = Collections.unmodifiableMap(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String findJndiProperty(String jndiProperty) {
|
|
||||||
try {
|
|
||||||
return (String) new InitialContext().lookup(jndiProperty);
|
|
||||||
|
|
||||||
} catch (NamingException e) {
|
|
||||||
log.error("Unable to find name in JNDI: " + jndiProperty, e);
|
|
||||||
|
|
||||||
StringBuilder msg = new StringBuilder("\n====================\n");
|
|
||||||
msg.append("Error loading JNDI property: ");
|
|
||||||
msg.append(jndiProperty);
|
|
||||||
msg.append("\n");
|
|
||||||
msg.append("\tAn application context XML file (named after deployed war file, e.g. vivo.xml) ");
|
|
||||||
msg.append("must be placed in servlet container.\n");
|
|
||||||
msg.append("\tFor Tomcat, see documentation for location of file: \n");
|
|
||||||
msg.append("\t\thttps://tomcat.apache.org/tomcat-9.0-doc/config/context.html#Defining_a_context \n");
|
|
||||||
msg.append("\tThe common location on the server is: $CATALINA_BASE/conf/[enginename]/[hostname]/ \n");
|
|
||||||
msg.append("\t\te.g. /var/lib/tomcat9/conf/Catalina/localhost/vivo.xml\n");
|
|
||||||
msg.append("\tAn example 'context.xml' file is in the META-INF directory of this project.\n");
|
|
||||||
msg.append("====================\n");
|
|
||||||
throw new RuntimeException(msg.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getMap() {
|
|
||||||
return this.propertyMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -249,6 +249,7 @@ public class UserAccountsSelector {
|
||||||
user.setMd5Password(ifLiteralPresent(solution, "md5pwd", ""));
|
user.setMd5Password(ifLiteralPresent(solution, "md5pwd", ""));
|
||||||
user.setArgon2Password(ifLiteralPresent(solution, "a2pwd", ""));
|
user.setArgon2Password(ifLiteralPresent(solution, "a2pwd", ""));
|
||||||
user.setPasswordLinkExpires(ifLongPresent(solution, "expire", 0L));
|
user.setPasswordLinkExpires(ifLongPresent(solution, "expire", 0L));
|
||||||
|
user.setEmailKey(ifLiteralPresent(solution, "emailKey", ""));
|
||||||
user.setLoginCount(ifIntPresent(solution, "count", 0));
|
user.setLoginCount(ifIntPresent(solution, "count", 0));
|
||||||
user.setLastLoginTime(ifLongPresent(solution, "lastLogin", 0));
|
user.setLastLoginTime(ifLongPresent(solution, "lastLogin", 0));
|
||||||
user.setStatus(parseStatus(solution, "status", null));
|
user.setStatus(parseStatus(solution, "status", null));
|
||||||
|
|
|
@ -156,6 +156,7 @@ public class UserAccountsAddPage extends UserAccountsPage {
|
||||||
u.setOldPassword("");
|
u.setOldPassword("");
|
||||||
u.setPasswordChangeRequired(false);
|
u.setPasswordChangeRequired(false);
|
||||||
u.setPasswordLinkExpires(0);
|
u.setPasswordLinkExpires(0);
|
||||||
|
u.setEmailKey("");
|
||||||
u.setLoginCount(0);
|
u.setLoginCount(0);
|
||||||
u.setLastLoginTime(0L);
|
u.setLastLoginTime(0L);
|
||||||
u.setStatus(Status.INACTIVE);
|
u.setStatus(Status.INACTIVE);
|
||||||
|
|
|
@ -84,6 +84,7 @@ public abstract class UserAccountsAddPageStrategy extends UserAccountsPage {
|
||||||
u.setStatus(Status.ACTIVE);
|
u.setStatus(Status.ACTIVE);
|
||||||
} else {
|
} else {
|
||||||
u.setPasswordLinkExpires(figureExpirationDate().getTime());
|
u.setPasswordLinkExpires(figureExpirationDate().getTime());
|
||||||
|
u.generateEmailKey();
|
||||||
u.setStatus(Status.INACTIVE);
|
u.setStatus(Status.INACTIVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,10 +120,8 @@ public abstract class UserAccountsAddPageStrategy extends UserAccountsPage {
|
||||||
private String buildCreatePasswordLink() {
|
private String buildCreatePasswordLink() {
|
||||||
try {
|
try {
|
||||||
String email = page.getAddedAccount().getEmailAddress();
|
String email = page.getAddedAccount().getEmailAddress();
|
||||||
String hash = page.getAddedAccount()
|
String key = page.getAddedAccount().getEmailKey();
|
||||||
.getPasswordLinkExpiresHash();
|
String relativeUrl = UrlBuilder.getUrl(CREATE_PASSWORD_URL, "user", email, "key", key);
|
||||||
String relativeUrl = UrlBuilder.getUrl(CREATE_PASSWORD_URL,
|
|
||||||
"user", email, "key", hash);
|
|
||||||
|
|
||||||
URL context = new URL(vreq.getRequestURL().toString());
|
URL context = new URL(vreq.getRequestURL().toString());
|
||||||
URL url = new URL(context, relativeUrl);
|
URL url = new URL(context, relativeUrl);
|
||||||
|
|
|
@ -274,6 +274,7 @@ public class UserAccountsEditPage extends UserAccountsPage {
|
||||||
userAccount.setOldPassword("");
|
userAccount.setOldPassword("");
|
||||||
userAccount.setPasswordChangeRequired(false);
|
userAccount.setPasswordChangeRequired(false);
|
||||||
userAccount.setPasswordLinkExpires(0L);
|
userAccount.setPasswordLinkExpires(0L);
|
||||||
|
userAccount.setEmailKey("");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRootUser()) {
|
if (isRootUser()) {
|
||||||
|
|
|
@ -82,6 +82,7 @@ public abstract class UserAccountsEditPageStrategy extends UserAccountsPage {
|
||||||
protected void setAdditionalProperties(UserAccount u) {
|
protected void setAdditionalProperties(UserAccount u) {
|
||||||
if (resetPassword && !page.isExternalAuthOnly()) {
|
if (resetPassword && !page.isExternalAuthOnly()) {
|
||||||
u.setPasswordLinkExpires(figureExpirationDate().getTime());
|
u.setPasswordLinkExpires(figureExpirationDate().getTime());
|
||||||
|
u.generateEmailKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,10 +122,8 @@ public abstract class UserAccountsEditPageStrategy extends UserAccountsPage {
|
||||||
private String buildResetPasswordLink() {
|
private String buildResetPasswordLink() {
|
||||||
try {
|
try {
|
||||||
String email = page.getUpdatedAccount().getEmailAddress();
|
String email = page.getUpdatedAccount().getEmailAddress();
|
||||||
String hash = page.getUpdatedAccount()
|
String key = page.getUpdatedAccount().getEmailKey();
|
||||||
.getPasswordLinkExpiresHash();
|
String relativeUrl = UrlBuilder.getUrl(RESET_PASSWORD_URL, "user", email, "key", key);
|
||||||
String relativeUrl = UrlBuilder.getUrl(RESET_PASSWORD_URL,
|
|
||||||
"user", email, "key", hash);
|
|
||||||
|
|
||||||
URL context = new URL(vreq.getRequestURL().toString());
|
URL context = new URL(vreq.getRequestURL().toString());
|
||||||
URL url = new URL(context, relativeUrl);
|
URL url = new URL(context, relativeUrl);
|
||||||
|
|
|
@ -36,6 +36,7 @@ public class UserAccountsCreatePasswordPage extends
|
||||||
userAccount.setArgon2Password(Authenticator.applyArgon2iEncoding(newPassword));
|
userAccount.setArgon2Password(Authenticator.applyArgon2iEncoding(newPassword));
|
||||||
userAccount.setMd5Password("");
|
userAccount.setMd5Password("");
|
||||||
userAccount.setPasswordLinkExpires(0L);
|
userAccount.setPasswordLinkExpires(0L);
|
||||||
|
userAccount.setEmailKey("");
|
||||||
userAccount.setPasswordChangeRequired(false);
|
userAccount.setPasswordChangeRequired(false);
|
||||||
userAccount.setStatus(Status.ACTIVE);
|
userAccount.setStatus(Status.ACTIVE);
|
||||||
userAccountsDao.updateUserAccount(userAccount);
|
userAccountsDao.updateUserAccount(userAccount);
|
||||||
|
@ -54,6 +55,11 @@ public class UserAccountsCreatePasswordPage extends
|
||||||
return i18n.text("account_already_activated", userEmail);
|
return i18n.text("account_already_activated", userEmail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String passwordChangeInavlidKeyMessage() {
|
||||||
|
return i18n.text("password_change_invalid_key", userEmail);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String templateName() {
|
protected String templateName() {
|
||||||
return TEMPLATE_NAME;
|
return TEMPLATE_NAME;
|
||||||
|
|
|
@ -195,6 +195,7 @@ public class UserAccountsFirstTimeExternalPage extends UserAccountsPage {
|
||||||
u.setExternalAuthId(externalAuthId);
|
u.setExternalAuthId(externalAuthId);
|
||||||
u.setPasswordChangeRequired(false);
|
u.setPasswordChangeRequired(false);
|
||||||
u.setPasswordLinkExpires(0);
|
u.setPasswordLinkExpires(0);
|
||||||
|
u.setEmailKey("");
|
||||||
u.setExternalAuthOnly(true);
|
u.setExternalAuthOnly(true);
|
||||||
u.setLoginCount(0);
|
u.setLoginCount(0);
|
||||||
u.setStatus(Status.ACTIVE);
|
u.setStatus(Status.ACTIVE);
|
||||||
|
|
|
@ -159,6 +159,7 @@ public abstract class UserAccountsMyAccountPageStrategy extends
|
||||||
userAccount.setMd5Password("");
|
userAccount.setMd5Password("");
|
||||||
userAccount.setPasswordChangeRequired(false);
|
userAccount.setPasswordChangeRequired(false);
|
||||||
userAccount.setPasswordLinkExpires(0L);
|
userAccount.setPasswordLinkExpires(0L);
|
||||||
|
userAccount.setEmailKey("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,12 +103,12 @@ public abstract class UserAccountsPasswordBasePage extends UserAccountsPage {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String expectedKey = userAccount.getPasswordLinkExpiresHash();
|
String expectedKey = userAccount.getEmailKey();
|
||||||
if (!key.equals(expectedKey)) {
|
if (key.isEmpty() || !key.equals(expectedKey)) {
|
||||||
log.warn("Password request for '" + userEmail + "' is bogus: key ("
|
log.warn("Password request for '" + userEmail + "' is bogus: key ("
|
||||||
+ key + ") doesn't match expected key (" + expectedKey
|
+ key + ") doesn't match expected key (" + expectedKey
|
||||||
+ ")");
|
+ ")");
|
||||||
bogusMessage = passwordChangeNotPendingMessage();
|
bogusMessage = passwordChangeInavlidKeyMessage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ public abstract class UserAccountsPasswordBasePage extends UserAccountsPage {
|
||||||
body.put("minimumLength", UserAccount.MIN_PASSWORD_LENGTH);
|
body.put("minimumLength", UserAccount.MIN_PASSWORD_LENGTH);
|
||||||
body.put("maximumLength", UserAccount.MAX_PASSWORD_LENGTH);
|
body.put("maximumLength", UserAccount.MAX_PASSWORD_LENGTH);
|
||||||
body.put("userAccount", userAccount);
|
body.put("userAccount", userAccount);
|
||||||
body.put("key", userAccount.getPasswordLinkExpiresHash());
|
body.put("key", userAccount.getEmailKey());
|
||||||
body.put("newPassword", newPassword);
|
body.put("newPassword", newPassword);
|
||||||
body.put("confirmPassword", confirmPassword);
|
body.put("confirmPassword", confirmPassword);
|
||||||
body.put("formUrls", buildUrlsMap());
|
body.put("formUrls", buildUrlsMap());
|
||||||
|
@ -177,5 +177,7 @@ public abstract class UserAccountsPasswordBasePage extends UserAccountsPage {
|
||||||
|
|
||||||
protected abstract String passwordChangeNotPendingMessage();
|
protected abstract String passwordChangeNotPendingMessage();
|
||||||
|
|
||||||
|
protected abstract String passwordChangeInavlidKeyMessage();
|
||||||
|
|
||||||
protected abstract String templateName();
|
protected abstract String templateName();
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,11 @@ public class UserAccountsResetPasswordPage extends UserAccountsPasswordBasePage
|
||||||
return i18n.text("password_change_not_pending", userEmail);
|
return i18n.text("password_change_not_pending", userEmail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String passwordChangeInavlidKeyMessage() {
|
||||||
|
return i18n.text("password_change_invalid_key", userEmail);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String templateName() {
|
protected String templateName() {
|
||||||
return TEMPLATE_NAME;
|
return TEMPLATE_NAME;
|
||||||
|
|
|
@ -134,6 +134,7 @@ public class BasicAuthenticator extends Authenticator {
|
||||||
userAccount.setMd5Password("");
|
userAccount.setMd5Password("");
|
||||||
userAccount.setPasswordChangeRequired(false);
|
userAccount.setPasswordChangeRequired(false);
|
||||||
userAccount.setPasswordLinkExpires(0L);
|
userAccount.setPasswordLinkExpires(0L);
|
||||||
|
userAccount.setEmailKey("");
|
||||||
getUserAccountsDao().updateUserAccount(userAccount);
|
getUserAccountsDao().updateUserAccount(userAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,9 @@ public class LoginRedirector {
|
||||||
throws IOException {
|
throws IOException {
|
||||||
try {
|
try {
|
||||||
DisplayMessage.setMessage(request, assembleWelcomeMessage());
|
DisplayMessage.setMessage(request, assembleWelcomeMessage());
|
||||||
response.sendRedirect(getRedirectionUriForLoggedInUser());
|
String redirectUrl = getRedirectionUriForLoggedInUser();
|
||||||
|
log.debug("Sending redirect to path: " + redirectUrl);
|
||||||
|
response.sendRedirect(redirectUrl);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.debug("Problem with re-direction", e);
|
log.debug("Problem with re-direction", e);
|
||||||
response.sendRedirect(getApplicationHomePageUrl());
|
response.sendRedirect(getApplicationHomePageUrl());
|
||||||
|
@ -175,21 +177,13 @@ public class LoginRedirector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The application home page can be overridden by an attribute in the
|
|
||||||
* ServletContext. Further, it can either be an absolute URL, or it can be
|
|
||||||
* relative to the application. Weird.
|
|
||||||
*/
|
|
||||||
private String getApplicationHomePageUrl() {
|
private String getApplicationHomePageUrl() {
|
||||||
String contextRedirect = (String) session.getServletContext()
|
String contextPath = request.getContextPath();
|
||||||
.getAttribute("postLoginRequest");
|
if (contextPath.equals("")) {
|
||||||
if (contextRedirect != null) {
|
return "/";
|
||||||
if (contextRedirect.indexOf(":") == -1) {
|
}
|
||||||
return request.getContextPath() + contextRedirect;
|
else {
|
||||||
} else {
|
return contextPath;
|
||||||
return contextRedirect;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return request.getContextPath();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,28 +11,29 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.annotation.WebServlet;
|
import javax.servlet.annotation.WebServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.LocaleUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
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 org.apache.jena.query.QuerySolution;
|
import org.apache.jena.query.QuerySolution;
|
||||||
import org.apache.jena.query.ResultSet;
|
import org.apache.jena.query.ResultSet;
|
||||||
import org.apache.jena.rdf.model.Literal;
|
import org.apache.jena.rdf.model.Literal;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
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.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.dao.jena.QueryUtils;
|
import edu.cornell.mannlib.vitro.webapp.dao.jena.QueryUtils;
|
||||||
import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale;
|
import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.filter.LanguageFilteringUtils;
|
||||||
|
|
||||||
|
|
||||||
/*Servlet to view all labels in various languages for individual*/
|
/*Servlet to view all labels in various languages for individual*/
|
||||||
|
@ -47,12 +48,13 @@ public class ViewLabelsServlet extends FreemarkerHttpServlet{
|
||||||
String subjectUri = vreq.getParameter("subjectUri");
|
String subjectUri = vreq.getParameter("subjectUri");
|
||||||
body.put("subjectUri", subjectUri);
|
body.put("subjectUri", subjectUri);
|
||||||
try {
|
try {
|
||||||
//Get all language codes/labels in the system, and this list is sorted by language name
|
|
||||||
List<HashMap<String, String>> locales = this.getLocales(vreq);
|
|
||||||
//Get code to label hashmap - we use this to get the language name for the language code returned in the rdf literal
|
|
||||||
HashMap<String, String> localeCodeToNameMap = this.getFullCodeToLanguageNameMap(locales);
|
|
||||||
//the labels already added by the user
|
//the labels already added by the user
|
||||||
ArrayList<Literal> existingLabels = this.getExistingLabels(subjectUri, vreq);
|
ArrayList<Literal> existingLabels = this.getExistingLabels(subjectUri, vreq);
|
||||||
|
//Get all language codes/labels used in the list of existing labels
|
||||||
|
List<HashMap<String, String>> locales = this.getLocales(vreq, existingLabels);
|
||||||
|
//Get code to label hashmap - we use this to get the language name for the language code returned in the rdf literal
|
||||||
|
HashMap<String, String> localeCodeToNameMap = this.getFullCodeToLanguageNameMap(locales);
|
||||||
|
|
||||||
//existing labels keyed by language name and each of the list of labels is sorted by language name
|
//existing labels keyed by language name and each of the list of labels is sorted by language name
|
||||||
HashMap<String, List<LabelInformation>> existingLabelsByLanguageName = this.getLabelsSortedByLanguageName(existingLabels, localeCodeToNameMap, vreq, subjectUri);
|
HashMap<String, List<LabelInformation>> existingLabelsByLanguageName = this.getLabelsSortedByLanguageName(existingLabels, localeCodeToNameMap, vreq, subjectUri);
|
||||||
//Get available locales for the drop down for adding a new label, also sorted by language name
|
//Get available locales for the drop down for adding a new label, also sorted by language name
|
||||||
|
@ -137,20 +139,26 @@ public class ViewLabelsServlet extends FreemarkerHttpServlet{
|
||||||
doGet(request, response);
|
doGet(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
//get locales
|
//get locales present in list of literals
|
||||||
public List<HashMap<String, String>> getLocales(VitroRequest vreq) {
|
public List<HashMap<String, String>> getLocales(VitroRequest vreq,
|
||||||
List<Locale> selectables = SelectedLocale.getSelectableLocales(vreq);
|
List<Literal> existingLiterals) {
|
||||||
if (selectables.isEmpty()) {
|
Set<Locale> locales = new HashSet<Locale>();
|
||||||
|
for(Literal literal : existingLiterals) {
|
||||||
|
String language = literal.getLanguage();
|
||||||
|
if(!StringUtils.isEmpty(language)) {
|
||||||
|
locales.add(LanguageFilteringUtils.languageToLocale(language));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (locales.isEmpty()) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
|
List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
|
||||||
Locale currentLocale = SelectedLocale.getCurrentLocale(vreq);
|
Locale currentLocale = SelectedLocale.getCurrentLocale(vreq);
|
||||||
for (Locale locale : selectables) {
|
for (Locale locale : locales) {
|
||||||
try {
|
try {
|
||||||
list.add(buildLocaleMap(locale, currentLocale));
|
list.add(buildLocaleMap(locale, currentLocale));
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
log.warn("Can't show the Locale selector for '" + locale
|
log.warn("Can't show locale '" + locale + "': " + e);
|
||||||
+ "': " + e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,8 +196,8 @@ public class ViewLabelsServlet extends FreemarkerHttpServlet{
|
||||||
|
|
||||||
ArrayList<Literal> labels = new ArrayList<Literal>();
|
ArrayList<Literal> labels = new ArrayList<Literal>();
|
||||||
try {
|
try {
|
||||||
//We want to get the labels for all the languages, not just the display language
|
// Show only labels with current language filtering
|
||||||
ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq);
|
ResultSet results = QueryUtils.getQueryResults(queryStr, vreq);
|
||||||
while (results.hasNext()) {
|
while (results.hasNext()) {
|
||||||
QuerySolution soln = results.nextSolution();
|
QuerySolution soln = results.nextSolution();
|
||||||
Literal nodeLiteral = soln.get("label").asLiteral();
|
Literal nodeLiteral = soln.get("label").asLiteral();
|
||||||
|
|
|
@ -6,14 +6,13 @@ import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.jena.rdf.model.RDFNode;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModelBuilder;
|
|
||||||
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 org.apache.jena.query.QuerySolution;
|
import org.apache.jena.query.QuerySolution;
|
||||||
import org.apache.jena.query.ResultSet;
|
import org.apache.jena.query.ResultSet;
|
||||||
|
|
||||||
|
@ -36,6 +35,7 @@ import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.ExecuteDataRetrieval;
|
import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.ExecuteDataRetrieval;
|
||||||
import edu.cornell.mannlib.vitro.webapp.web.beanswrappers.ReadOnlyBeansWrapper;
|
import edu.cornell.mannlib.vitro.webapp.web.beanswrappers.ReadOnlyBeansWrapper;
|
||||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModel;
|
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModel;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModelBuilder;
|
||||||
import edu.ucsf.vitro.opensocial.OpenSocialManager;
|
import edu.ucsf.vitro.opensocial.OpenSocialManager;
|
||||||
import freemarker.ext.beans.BeansWrapper;
|
import freemarker.ext.beans.BeansWrapper;
|
||||||
import freemarker.template.TemplateModel;
|
import freemarker.template.TemplateModel;
|
||||||
|
@ -123,8 +123,10 @@ class IndividualResponseBuilder {
|
||||||
* into the data model: no real data can be modified.
|
* into the data model: no real data can be modified.
|
||||||
*/
|
*/
|
||||||
// body.put("individual", wrap(itm, BeansWrapper.EXPOSE_SAFE));
|
// body.put("individual", wrap(itm, BeansWrapper.EXPOSE_SAFE));
|
||||||
body.put("labelCount", getLabelCount(itm.getUri(), vreq));
|
LabelAndLanguageCount labelAndLanguageCount = getLabelAndLanguageCount(
|
||||||
body.put("languageCount", getLanguagesRepresentedCount(itm.getUri(), vreq));
|
itm.getUri(), vreq);
|
||||||
|
body.put("labelCount", labelAndLanguageCount.getLabelCount());
|
||||||
|
body.put("languageCount", labelAndLanguageCount.getLanguageCount());
|
||||||
//We also need to know the number of available locales
|
//We also need to know the number of available locales
|
||||||
body.put("localesCount", SelectedLocale.getSelectableLocales(vreq).size());
|
body.put("localesCount", SelectedLocale.getSelectableLocales(vreq).size());
|
||||||
body.put("profileType", getProfileType(itm.getUri(), vreq));
|
body.put("profileType", getProfileType(itm.getUri(), vreq));
|
||||||
|
@ -282,61 +284,103 @@ class IndividualResponseBuilder {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String LABEL_COUNT_QUERY = ""
|
private static String LABEL_QUERY = ""
|
||||||
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
|
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
|
||||||
+ "SELECT ( str(COUNT(?label)) AS ?labelCount ) WHERE { \n"
|
+ "SELECT ?label WHERE { \n"
|
||||||
+ " ?subject rdfs:label ?label \n"
|
+ " ?subject rdfs:label ?label \n"
|
||||||
+ " FILTER isLiteral(?label) \n"
|
+ " FILTER isLiteral(?label) \n"
|
||||||
+ "}" ;
|
+ "}" ;
|
||||||
|
|
||||||
private static String DISTINCT_LANGUAGE_QUERY = ""
|
// Queries that were previously used for counts via RDFService that didn't
|
||||||
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
|
// filter results by language. With language filtering, aggregate
|
||||||
+ "SELECT ( str(COUNT(DISTINCT lang(?label))) AS ?languageCount ) WHERE { \n"
|
// functions like COUNT() cannot be used.
|
||||||
+ " ?subject rdfs:label ?label \n"
|
|
||||||
+ " FILTER isLiteral(?label) \n"
|
|
||||||
+ "}" ;
|
|
||||||
|
|
||||||
private static Integer getLabelCount(String subjectUri, VitroRequest vreq) {
|
// private static String LABEL_COUNT_QUERY = ""
|
||||||
String queryStr = QueryUtils.subUriForQueryVar(LABEL_COUNT_QUERY, "subject", subjectUri);
|
// + "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
|
||||||
|
// + "SELECT ( str(COUNT(?label)) AS ?labelCount ) WHERE { \n"
|
||||||
|
// + " ?subject rdfs:label ?label \n"
|
||||||
|
// + " FILTER isLiteral(?label) \n"
|
||||||
|
// + "}" ;
|
||||||
|
|
||||||
|
// private static String DISTINCT_LANGUAGE_QUERY = ""
|
||||||
|
// + "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
|
||||||
|
// + "SELECT ( str(COUNT(DISTINCT lang(?label))) AS ?languageCount ) WHERE { \n"
|
||||||
|
// + " ?subject rdfs:label ?label \n"
|
||||||
|
// + " FILTER isLiteral(?label) \n"
|
||||||
|
// + "}" ;
|
||||||
|
|
||||||
|
private static LabelAndLanguageCount getLabelAndLanguageCount(
|
||||||
|
String subjectUri, VitroRequest vreq) {
|
||||||
|
// 1.12.0 Now filtering to only the labels for the current locale so as
|
||||||
|
// to be consistent with other editing forms. Because the language
|
||||||
|
// filter can only act on a result set containing actual literals,
|
||||||
|
// we can't do the counting with a COUNT() in the query itself. So
|
||||||
|
// we will now use the LABEL_QUERY instead of LABEL_COUNT_QUERY and
|
||||||
|
// count the rows and the number of distinct languages represented.
|
||||||
|
Set<String> distinctLanguages = new HashSet<String>();
|
||||||
|
String queryStr = QueryUtils.subUriForQueryVar(LABEL_QUERY, "subject", subjectUri);
|
||||||
log.debug("queryStr = " + queryStr);
|
log.debug("queryStr = " + queryStr);
|
||||||
int theCount = 0;
|
int labelCount = 0;
|
||||||
try {
|
try {
|
||||||
//ResultSet results = QueryUtils.getQueryResults(queryStr, vreq);
|
ResultSet results = QueryUtils.getQueryResults(queryStr, vreq);
|
||||||
//Get query results across all languages in order for template to show manage labels link correctly
|
while(results.hasNext()) {
|
||||||
ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq);
|
QuerySolution qsoln = results.next();
|
||||||
if (results.hasNext()) {
|
labelCount++;
|
||||||
QuerySolution soln = results.nextSolution();
|
String lang = qsoln.getLiteral("label").getLanguage();
|
||||||
RDFNode labelCount = soln.get("labelCount");
|
if(lang == null) {
|
||||||
if (labelCount != null && labelCount.isLiteral()) {
|
lang = "";
|
||||||
theCount = labelCount.asLiteral().getInt();
|
|
||||||
}
|
}
|
||||||
|
distinctLanguages.add(lang);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error(e, e);
|
log.error(e, e);
|
||||||
}
|
}
|
||||||
return theCount;
|
return new LabelAndLanguageCount(labelCount, distinctLanguages.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class LabelAndLanguageCount {
|
||||||
|
|
||||||
|
private Integer labelCount;
|
||||||
|
private Integer languageCount;
|
||||||
|
|
||||||
|
public LabelAndLanguageCount(Integer labelCount, Integer languageCount) {
|
||||||
|
this.labelCount = labelCount;
|
||||||
|
this.languageCount = languageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getLabelCount() {
|
||||||
|
return this.labelCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getLanguageCount() {
|
||||||
|
return this.languageCount;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//what is the number of languages represented across the labels
|
//what is the number of languages represented across the labels
|
||||||
private static Integer getLanguagesRepresentedCount(String subjectUri, VitroRequest vreq) {
|
// This version not compatible with language-filtering RDF services
|
||||||
String queryStr = QueryUtils.subUriForQueryVar(DISTINCT_LANGUAGE_QUERY, "subject", subjectUri);
|
// private static Integer getLanguagesRepresentedCount(String subjectUri, VitroRequest vreq) {
|
||||||
log.debug("queryStr = " + queryStr);
|
// String queryStr = QueryUtils.subUriForQueryVar(DISTINCT_LANGUAGE_QUERY, "subject", subjectUri);
|
||||||
int theCount = 0;
|
// log.debug("queryStr = " + queryStr);
|
||||||
try {
|
// int theCount = 0;
|
||||||
|
// try {
|
||||||
ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq);
|
//
|
||||||
if (results.hasNext()) {
|
// ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq);
|
||||||
QuerySolution soln = results.nextSolution();
|
// if (results.hasNext()) {
|
||||||
RDFNode languageCount = soln.get("languageCount");
|
// QuerySolution soln = results.nextSolution();
|
||||||
if (languageCount != null && languageCount.isLiteral()) {
|
// RDFNode languageCount = soln.get("languageCount");
|
||||||
theCount = languageCount.asLiteral().getInt();
|
// if (languageCount != null && languageCount.isLiteral()) {
|
||||||
}
|
// theCount = languageCount.asLiteral().getInt();
|
||||||
}
|
// log.info("Language count is " + theCount);
|
||||||
} catch (Exception e) {
|
// }
|
||||||
log.error(e, e);
|
// }
|
||||||
}
|
// } catch (Exception e) {
|
||||||
return theCount;
|
// log.error(e, e);
|
||||||
}
|
// }
|
||||||
|
// log.info("Returning language count " + theCount);
|
||||||
|
// return theCount;
|
||||||
|
// }
|
||||||
|
|
||||||
private static String PROFILE_TYPE_QUERY = ""
|
private static String PROFILE_TYPE_QUERY = ""
|
||||||
+ "PREFIX display: <http://vitro.mannlib.cornell.edu/ontologies/display/1.1#> \n"
|
+ "PREFIX display: <http://vitro.mannlib.cornell.edu/ontologies/display/1.1#> \n"
|
||||||
|
|
|
@ -155,6 +155,7 @@ public class VitroVocabulary {
|
||||||
public static final String USERACCOUNT_LAST_LOGIN_TIME = VITRO_AUTH + "lastLoginTime";
|
public static final String USERACCOUNT_LAST_LOGIN_TIME = VITRO_AUTH + "lastLoginTime";
|
||||||
public static final String USERACCOUNT_STATUS = VITRO_AUTH + "status";
|
public static final String USERACCOUNT_STATUS = VITRO_AUTH + "status";
|
||||||
public static final String USERACCOUNT_PASSWORD_LINK_EXPIRES = VITRO_AUTH + "passwordLinkExpires";
|
public static final String USERACCOUNT_PASSWORD_LINK_EXPIRES = VITRO_AUTH + "passwordLinkExpires";
|
||||||
|
public static final String USERACCOUNT_EMAIL_KEY = VITRO_AUTH + "emailKey";
|
||||||
public static final String USERACCOUNT_PASSWORD_CHANGE_REQUIRED = VITRO_AUTH + "passwordChangeRequired";
|
public static final String USERACCOUNT_PASSWORD_CHANGE_REQUIRED = VITRO_AUTH + "passwordChangeRequired";
|
||||||
public static final String USERACCOUNT_EXTERNAL_AUTH_ID = VITRO_AUTH + "externalAuthId";
|
public static final String USERACCOUNT_EXTERNAL_AUTH_ID = VITRO_AUTH + "externalAuthId";
|
||||||
public static final String USERACCOUNT_EXTERNAL_AUTH_ONLY = VITRO_AUTH + "externalAuthOnly";
|
public static final String USERACCOUNT_EXTERNAL_AUTH_ONLY = VITRO_AUTH + "externalAuthOnly";
|
||||||
|
|
|
@ -121,6 +121,7 @@ public class JenaBaseDaoCon {
|
||||||
protected DatatypeProperty USERACCOUNT_LAST_LOGIN_TIME = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_LAST_LOGIN_TIME);
|
protected DatatypeProperty USERACCOUNT_LAST_LOGIN_TIME = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_LAST_LOGIN_TIME);
|
||||||
protected DatatypeProperty USERACCOUNT_STATUS = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_STATUS);
|
protected DatatypeProperty USERACCOUNT_STATUS = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_STATUS);
|
||||||
protected DatatypeProperty USERACCOUNT_PASSWORD_LINK_EXPIRES = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_PASSWORD_LINK_EXPIRES);
|
protected DatatypeProperty USERACCOUNT_PASSWORD_LINK_EXPIRES = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_PASSWORD_LINK_EXPIRES);
|
||||||
|
protected DatatypeProperty USERACCOUNT_EMAIL_KEY = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_EMAIL_KEY);
|
||||||
protected DatatypeProperty USERACCOUNT_PASSWORD_CHANGE_REQUIRED = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_PASSWORD_CHANGE_REQUIRED);
|
protected DatatypeProperty USERACCOUNT_PASSWORD_CHANGE_REQUIRED = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_PASSWORD_CHANGE_REQUIRED);
|
||||||
protected DatatypeProperty USERACCOUNT_EXTERNAL_AUTH_ID = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_EXTERNAL_AUTH_ID);
|
protected DatatypeProperty USERACCOUNT_EXTERNAL_AUTH_ID = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_EXTERNAL_AUTH_ID);
|
||||||
protected DatatypeProperty USERACCOUNT_EXTERNAL_AUTH_ONLY = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_EXTERNAL_AUTH_ONLY);
|
protected DatatypeProperty USERACCOUNT_EXTERNAL_AUTH_ONLY = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_EXTERNAL_AUTH_ONLY);
|
||||||
|
|
|
@ -12,10 +12,10 @@ import java.util.function.Supplier;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
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 org.apache.jena.graph.Capabilities;
|
import org.apache.jena.graph.Capabilities;
|
||||||
import org.apache.jena.graph.Graph;
|
import org.apache.jena.graph.Graph;
|
||||||
import org.apache.jena.graph.GraphEventManager;
|
import org.apache.jena.graph.GraphEventManager;
|
||||||
|
import org.apache.jena.graph.GraphListener;
|
||||||
import org.apache.jena.graph.GraphStatisticsHandler;
|
import org.apache.jena.graph.GraphStatisticsHandler;
|
||||||
import org.apache.jena.graph.Node;
|
import org.apache.jena.graph.Node;
|
||||||
import org.apache.jena.graph.TransactionHandler;
|
import org.apache.jena.graph.TransactionHandler;
|
||||||
|
@ -23,7 +23,6 @@ import org.apache.jena.graph.Triple;
|
||||||
import org.apache.jena.graph.impl.GraphWithPerform;
|
import org.apache.jena.graph.impl.GraphWithPerform;
|
||||||
import org.apache.jena.graph.impl.SimpleEventManager;
|
import org.apache.jena.graph.impl.SimpleEventManager;
|
||||||
import org.apache.jena.query.QuerySolution;
|
import org.apache.jena.query.QuerySolution;
|
||||||
import org.apache.jena.rdf.listeners.StatementListener;
|
|
||||||
import org.apache.jena.rdf.model.Model;
|
import org.apache.jena.rdf.model.Model;
|
||||||
import org.apache.jena.rdf.model.ModelFactory;
|
import org.apache.jena.rdf.model.ModelFactory;
|
||||||
import org.apache.jena.rdf.model.StmtIterator;
|
import org.apache.jena.rdf.model.StmtIterator;
|
||||||
|
@ -409,7 +408,18 @@ public class RDFServiceGraph implements GraphWithPerform {
|
||||||
@Override
|
@Override
|
||||||
public GraphEventManager getEventManager() {
|
public GraphEventManager getEventManager() {
|
||||||
if (eventManager == null) {
|
if (eventManager == null) {
|
||||||
eventManager = new SimpleEventManager(this);
|
eventManager = new SimpleEventManager() {
|
||||||
|
@Override
|
||||||
|
public void notifyEvent(Graph g, Object event) {
|
||||||
|
ChangeSet changeSet = rdfService.manufactureChangeSet();
|
||||||
|
changeSet.addPreChangeEvent(event);
|
||||||
|
try {
|
||||||
|
rdfService.changeSetUpdate(changeSet);
|
||||||
|
} catch (RDFServiceException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return eventManager;
|
return eventManager;
|
||||||
}
|
}
|
||||||
|
@ -595,21 +605,7 @@ public class RDFServiceGraph implements GraphWithPerform {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Model createRDFServiceModel(final RDFServiceGraph g) {
|
public static Model createRDFServiceModel(final RDFServiceGraph g) {
|
||||||
Model m = VitroModelFactory.createModelForGraph(g);
|
return VitroModelFactory.createModelForGraph(g);
|
||||||
m.register(new StatementListener() {
|
|
||||||
@Override
|
|
||||||
public void notifyEvent(Model m, Object event) {
|
|
||||||
ChangeSet changeSet = g.getRDFService().manufactureChangeSet();
|
|
||||||
changeSet.addPreChangeEvent(event);
|
|
||||||
try {
|
|
||||||
g.getRDFService().changeSetUpdate(changeSet);
|
|
||||||
} catch (RDFServiceException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
return m;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,7 +4,6 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
@ -98,6 +97,8 @@ public class UserAccountsDaoJena extends JenaBaseDao implements UserAccountsDao
|
||||||
u.setOldPassword(getPropertyStringValue(r, USERACCOUNT_OLD_PASSWORD));
|
u.setOldPassword(getPropertyStringValue(r, USERACCOUNT_OLD_PASSWORD));
|
||||||
u.setPasswordLinkExpires(getPropertyLongValue(r,
|
u.setPasswordLinkExpires(getPropertyLongValue(r,
|
||||||
USERACCOUNT_PASSWORD_LINK_EXPIRES));
|
USERACCOUNT_PASSWORD_LINK_EXPIRES));
|
||||||
|
u.setEmailKey(getPropertyStringValue(r,USERACCOUNT_EMAIL_KEY));
|
||||||
|
|
||||||
u.setPasswordChangeRequired(getPropertyBooleanValue(r,
|
u.setPasswordChangeRequired(getPropertyBooleanValue(r,
|
||||||
USERACCOUNT_PASSWORD_CHANGE_REQUIRED));
|
USERACCOUNT_PASSWORD_CHANGE_REQUIRED));
|
||||||
u.setExternalAuthOnly(getPropertyBooleanValue(r,
|
u.setExternalAuthOnly(getPropertyBooleanValue(r,
|
||||||
|
@ -240,6 +241,8 @@ public class UserAccountsDaoJena extends JenaBaseDao implements UserAccountsDao
|
||||||
userAccount.getLoginCount(), model);
|
userAccount.getLoginCount(), model);
|
||||||
addPropertyLongValue(res, USERACCOUNT_LAST_LOGIN_TIME,
|
addPropertyLongValue(res, USERACCOUNT_LAST_LOGIN_TIME,
|
||||||
userAccount.getLastLoginTime(), model);
|
userAccount.getLastLoginTime(), model);
|
||||||
|
addPropertyStringValue(res, USERACCOUNT_EMAIL_KEY,
|
||||||
|
userAccount.getEmailKey(), model);
|
||||||
if (userAccount.getStatus() != null) {
|
if (userAccount.getStatus() != null) {
|
||||||
addPropertyStringValue(res, USERACCOUNT_STATUS, userAccount
|
addPropertyStringValue(res, USERACCOUNT_STATUS, userAccount
|
||||||
.getStatus().toString(), model);
|
.getStatus().toString(), model);
|
||||||
|
@ -306,6 +309,8 @@ public class UserAccountsDaoJena extends JenaBaseDao implements UserAccountsDao
|
||||||
userAccount.getLoginCount(), model);
|
userAccount.getLoginCount(), model);
|
||||||
updatePropertyLongValue(res, USERACCOUNT_LAST_LOGIN_TIME,
|
updatePropertyLongValue(res, USERACCOUNT_LAST_LOGIN_TIME,
|
||||||
userAccount.getLastLoginTime(), model);
|
userAccount.getLastLoginTime(), model);
|
||||||
|
updatePropertyStringValue(res, USERACCOUNT_EMAIL_KEY,
|
||||||
|
userAccount.getEmailKey(), model);
|
||||||
if (userAccount.getStatus() == null) {
|
if (userAccount.getStatus() == null) {
|
||||||
updatePropertyStringValue(res, USERACCOUNT_STATUS, null, model);
|
updatePropertyStringValue(res, USERACCOUNT_STATUS, null, model);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTw
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.IdModelSelector;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.IdModelSelector;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.StandardModelSelector;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.StandardModelSelector;
|
||||||
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
|
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.LanguageOption;
|
||||||
|
|
||||||
public abstract class BaseEditConfigurationGenerator implements EditConfigurationGenerator {
|
public abstract class BaseEditConfigurationGenerator implements EditConfigurationGenerator {
|
||||||
|
|
||||||
|
@ -63,6 +64,7 @@ public abstract class BaseEditConfigurationGenerator implements EditConfiguratio
|
||||||
setupModelSelectorsFromVitroRequest(vreq, editConfig);
|
setupModelSelectorsFromVitroRequest(vreq, editConfig);
|
||||||
|
|
||||||
OntModel queryModel = ModelAccess.on(vreq).getOntModel();
|
OntModel queryModel = ModelAccess.on(vreq).getOntModel();
|
||||||
|
OntModel languageNeutralModel = vreq.getLanguageNeutralUnionFullModel();
|
||||||
|
|
||||||
if( editConfig.getSubjectUri() == null)
|
if( editConfig.getSubjectUri() == null)
|
||||||
editConfig.setSubjectUri( EditConfigurationUtils.getSubjectUri(vreq));
|
editConfig.setSubjectUri( EditConfigurationUtils.getSubjectUri(vreq));
|
||||||
|
@ -78,7 +80,10 @@ public abstract class BaseEditConfigurationGenerator implements EditConfiguratio
|
||||||
editConfig.prepareForObjPropUpdate(queryModel);
|
editConfig.prepareForObjPropUpdate(queryModel);
|
||||||
} else if( dataKey != null ) { // edit of a data prop statement
|
} else if( dataKey != null ) { // edit of a data prop statement
|
||||||
//do nothing since the data prop form generator must take care of it
|
//do nothing since the data prop form generator must take care of it
|
||||||
editConfig.prepareForDataPropUpdate(queryModel, vreq.getWebappDaoFactory().getDataPropertyDao());
|
// Use language-neutral model to ensure that a data property statement
|
||||||
|
// is found for any literal hash, even if the UI locale is changed.
|
||||||
|
editConfig.prepareForDataPropUpdate(languageNeutralModel,
|
||||||
|
vreq.getWebappDaoFactory().getDataPropertyDao());
|
||||||
} else{
|
} else{
|
||||||
//this might be a create new or a form
|
//this might be a create new or a form
|
||||||
editConfig.prepareForNonUpdate(queryModel);
|
editConfig.prepareForNonUpdate(queryModel);
|
||||||
|
|
|
@ -15,6 +15,7 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.FoafNameToRdfsLabelPreprocessor;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.FoafNameToRdfsLabelPreprocessor;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.ManageLabelsForIndividualPreprocessor;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.ManageLabelsForIndividualPreprocessor;
|
||||||
import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale;
|
import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.filter.LanguageFilteringUtils;
|
||||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DataPropertyStatementTemplateModel;
|
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DataPropertyStatementTemplateModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -202,12 +204,12 @@ public class ManageLabelsForIndividualGenerator extends BaseEditConfigurationGen
|
||||||
|
|
||||||
private void addFormSpecificData(EditConfigurationVTwo config,
|
private void addFormSpecificData(EditConfigurationVTwo config,
|
||||||
VitroRequest vreq) {
|
VitroRequest vreq) {
|
||||||
//Get all language codes/labels in the system, and this list is sorted by language name
|
|
||||||
List<HashMap<String, String>> locales = this.getLocales(vreq);
|
|
||||||
//Get code to label hashmap - we use this to get the language name for the language code returned in the rdf literal
|
|
||||||
HashMap<String, String> localeCodeToNameMap = this.getFullCodeToLanguageNameMap(locales);
|
|
||||||
//the labels already added by the user
|
//the labels already added by the user
|
||||||
ArrayList<Literal> existingLabels = this.getExistingLabels(config.getSubjectUri(), vreq);
|
ArrayList<Literal> existingLabels = this.getExistingLabels(config.getSubjectUri(), vreq);
|
||||||
|
//Get language codes/labels for languages present in the existing labels
|
||||||
|
List<HashMap<String, String>> locales = this.getLocales(vreq, existingLabels);
|
||||||
|
//Get code to label hashmap - we use this to get the language name for the language code returned in the rdf literal
|
||||||
|
HashMap<String, String> localeCodeToNameMap = this.getFullCodeToLanguageNameMap(locales);
|
||||||
int numberExistingLabels = existingLabels.size();
|
int numberExistingLabels = existingLabels.size();
|
||||||
//existing labels keyed by language name and each of the list of labels is sorted by language name
|
//existing labels keyed by language name and each of the list of labels is sorted by language name
|
||||||
HashMap<String, List<LabelInformation>> existingLabelsByLanguageName = this.getLabelsSortedByLanguageName(existingLabels, localeCodeToNameMap, config, vreq);
|
HashMap<String, List<LabelInformation>> existingLabelsByLanguageName = this.getLabelsSortedByLanguageName(existingLabels, localeCodeToNameMap, config, vreq);
|
||||||
|
@ -373,8 +375,9 @@ public class ManageLabelsForIndividualGenerator extends BaseEditConfigurationGen
|
||||||
|
|
||||||
ArrayList<Literal> labels = new ArrayList<Literal>();
|
ArrayList<Literal> labels = new ArrayList<Literal>();
|
||||||
try {
|
try {
|
||||||
//We want to get the labels for all the languages, not just the display language
|
// Get results filtered to current locale so as to be consistent
|
||||||
ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq);
|
// with other editing forms.
|
||||||
|
ResultSet results = QueryUtils.getQueryResults(queryStr, vreq);
|
||||||
while (results.hasNext()) {
|
while (results.hasNext()) {
|
||||||
QuerySolution soln = results.nextSolution();
|
QuerySolution soln = results.nextSolution();
|
||||||
Literal nodeLiteral = soln.get("label").asLiteral();
|
Literal nodeLiteral = soln.get("label").asLiteral();
|
||||||
|
@ -401,30 +404,32 @@ public class ManageLabelsForIndividualGenerator extends BaseEditConfigurationGen
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//get locales present in list of literals
|
||||||
|
public List<HashMap<String, String>> getLocales(VitroRequest vreq,
|
||||||
//get locales
|
List<Literal> existingLiterals) {
|
||||||
public List<HashMap<String, String>> getLocales(VitroRequest vreq) {
|
Set<Locale> locales = new HashSet<Locale>();
|
||||||
List<Locale> selectables = SelectedLocale.getSelectableLocales(vreq);
|
for(Literal literal : existingLiterals) {
|
||||||
if (selectables.isEmpty()) {
|
String language = literal.getLanguage();
|
||||||
|
if(!StringUtils.isEmpty(language)) {
|
||||||
|
locales.add(LanguageFilteringUtils.languageToLocale(language));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (locales.isEmpty()) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
|
List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
|
||||||
Locale currentLocale = SelectedLocale.getCurrentLocale(vreq);
|
Locale currentLocale = SelectedLocale.getCurrentLocale(vreq);
|
||||||
for (Locale locale : selectables) {
|
for (Locale locale : locales) {
|
||||||
try {
|
try {
|
||||||
list.add(buildLocaleMap(locale, currentLocale));
|
list.add(buildLocaleMap(locale, currentLocale));
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
log.warn("Can't show the Locale selector for '" + locale
|
log.warn("Can't show locale '" + locale + "': " + e);
|
||||||
+ "': " + e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public HashMap<String, String> getFullCodeToLanguageNameMap(List<HashMap<String, String>> localesList) {
|
public HashMap<String, String> getFullCodeToLanguageNameMap(List<HashMap<String, String>> localesList) {
|
||||||
HashMap<String, String> codeToLanguageMap = new HashMap<String, String>();
|
HashMap<String, String> codeToLanguageMap = new HashMap<String, String>();
|
||||||
for(Map<String, String> locale: localesList) {
|
for(Map<String, String> locale: localesList) {
|
||||||
|
|
|
@ -68,12 +68,15 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet {
|
||||||
//TODO: Create this generator
|
//TODO: Create this generator
|
||||||
final String RDFS_LABEL_FORM = "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.RDFSLabelGenerator";
|
final String RDFS_LABEL_FORM = "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.RDFSLabelGenerator";
|
||||||
final String DEFAULT_DELETE_FORM = "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.DefaultDeleteGenerator";
|
final String DEFAULT_DELETE_FORM = "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.DefaultDeleteGenerator";
|
||||||
|
final String MANAGE_MENUS_FORM = "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.ManagePageGenerator";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthorizationRequest requiredActions(VitroRequest vreq) {
|
protected AuthorizationRequest requiredActions(VitroRequest vreq) {
|
||||||
// If request is for new individual, return simple do back end editing action permission
|
// If request is for new individual, return simple do back end editing action permission
|
||||||
if (StringUtils.isNotEmpty(EditConfigurationUtils.getTypeOfNew(vreq))) {
|
if (StringUtils.isNotEmpty(EditConfigurationUtils.getTypeOfNew(vreq))) {
|
||||||
return SimplePermission.DO_BACK_END_EDITING.ACTION;
|
return SimplePermission.DO_BACK_END_EDITING.ACTION;
|
||||||
|
} else if(MANAGE_MENUS_FORM.equals(vreq.getParameter("editForm"))) {
|
||||||
|
return SimplePermission.MANAGE_MENUS.ACTION;
|
||||||
}
|
}
|
||||||
// Check if this statement can be edited here and return unauthorized if not
|
// Check if this statement can be edited here and return unauthorized if not
|
||||||
String subjectUri = EditConfigurationUtils.getSubjectUri(vreq);
|
String subjectUri = EditConfigurationUtils.getSubjectUri(vreq);
|
||||||
|
|
|
@ -202,7 +202,7 @@ public class RequestModelAccessImpl implements RequestModelAccess {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OntModel getOntModel(String name, LanguageOption... options) {
|
public OntModel getOntModel(String name, LanguageOption... options) {
|
||||||
return addLanguageAwareness(getOntModel(new OntModelKey(name, options)));
|
return getOntModel(new OntModelKey(name, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
private OntModel getOntModel(OntModelKey key) {
|
private OntModel getOntModel(OntModelKey key) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.apache.jena.query.QuerySolution;
|
||||||
import org.apache.jena.query.ResultSet;
|
import org.apache.jena.query.ResultSet;
|
||||||
import org.apache.jena.rdf.model.Model;
|
import org.apache.jena.rdf.model.Model;
|
||||||
import org.apache.jena.sparql.engine.binding.Binding;
|
import org.apache.jena.sparql.engine.binding.Binding;
|
||||||
|
import org.apache.jena.sparql.engine.binding.BindingUtils;
|
||||||
|
|
||||||
public class FilteredResultSet implements ResultSet {
|
public class FilteredResultSet implements ResultSet {
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ public class FilteredResultSet implements ResultSet {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Binding nextBinding() {
|
public Binding nextBinding() {
|
||||||
throw new UnsupportedOperationException("Can we ignore this?");
|
return BindingUtils.asBinding(nextSolution());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -36,8 +36,14 @@ public class LangSort {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int compareLangs(String t1lang, String t2lang) {
|
protected int compareLangs(String t1lang, String t2lang) {
|
||||||
|
int index1 = languageIndex(t1lang);
|
||||||
|
int index2 = languageIndex(t2lang);
|
||||||
|
if(index1 == index2) {
|
||||||
|
return t1lang.compareTo(t2lang);
|
||||||
|
} else {
|
||||||
return languageIndex(t1lang) - languageIndex(t2lang);
|
return languageIndex(t1lang) - languageIndex(t2lang);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return index of exact match, or index of partial match, or
|
* Return index of exact match, or index of partial match, or
|
||||||
|
|
|
@ -201,8 +201,8 @@ public abstract class RDFServiceJena extends RDFServiceImpl implements RDFServic
|
||||||
log.debug("blank node model size " + blankNodeModel.size());
|
log.debug("blank node model size " + blankNodeModel.size());
|
||||||
|
|
||||||
if (blankNodeModel.size() == 1) {
|
if (blankNodeModel.size() == 1) {
|
||||||
log.warn("Deleting single triple with blank node: " + blankNodeModel);
|
log.debug("Deleting single triple with blank node: " + blankNodeModel);
|
||||||
log.warn("This likely indicates a problem; excessive data may be deleted.");
|
log.debug("This could result in the deletion of multiple triples if multiple blank nodes match the same triple pattern.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Query rootFinderQuery = QueryFactory.create(BNODE_ROOT_QUERY);
|
Query rootFinderQuery = QueryFactory.create(BNODE_ROOT_QUERY);
|
||||||
|
|
|
@ -13,6 +13,8 @@ import java.nio.file.Paths;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.jena.rdf.model.Model;
|
import org.apache.jena.rdf.model.Model;
|
||||||
|
import org.apache.jena.rdf.model.RDFNode;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
@ -75,9 +77,17 @@ public class RDFServiceTDB extends RDFServiceJena {
|
||||||
notifyListenersOfPreChangeEvents(changeSet);
|
notifyListenersOfPreChangeEvents(changeSet);
|
||||||
|
|
||||||
dataset.begin(ReadWrite.WRITE);
|
dataset.begin(ReadWrite.WRITE);
|
||||||
|
try {
|
||||||
|
boolean committed = false;
|
||||||
try {
|
try {
|
||||||
applyChangeSetToModel(changeSet, dataset);
|
applyChangeSetToModel(changeSet, dataset);
|
||||||
dataset.commit();
|
dataset.commit();
|
||||||
|
committed = true;
|
||||||
|
} finally {
|
||||||
|
if(!committed) {
|
||||||
|
dataset.abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
dataset.end();
|
dataset.end();
|
||||||
}
|
}
|
||||||
|
@ -93,6 +103,10 @@ public class RDFServiceTDB extends RDFServiceJena {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preferPreciseOptionals() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
@ -232,6 +246,28 @@ public class RDFServiceTDB extends RDFServiceJena {
|
||||||
return isEquivalentGraph(graphURI, inStream, ModelSerializationFormat.NTRIPLE);
|
return isEquivalentGraph(graphURI, inStream, ModelSerializationFormat.NTRIPLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countTriples(RDFNode subject, RDFNode predicate, RDFNode object)
|
||||||
|
throws RDFServiceException {
|
||||||
|
dataset.begin(ReadWrite.READ);
|
||||||
|
try {
|
||||||
|
return super.countTriples(subject, predicate, object);
|
||||||
|
} finally {
|
||||||
|
dataset.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model getTriples(RDFNode subject, RDFNode predicate, RDFNode object,
|
||||||
|
long limit, long offset) throws RDFServiceException {
|
||||||
|
dataset.begin(ReadWrite.READ);
|
||||||
|
try {
|
||||||
|
return super.getTriples(subject, predicate, object, limit, offset);
|
||||||
|
} finally {
|
||||||
|
dataset.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert all of the references to integer compatible type to "integer" in the serialized graph.
|
* Convert all of the references to integer compatible type to "integer" in the serialized graph.
|
||||||
*
|
*
|
||||||
|
|
|
@ -202,23 +202,18 @@ public class DeveloperSettings {
|
||||||
File dsFile = homeDir.resolve("config/developer.properties")
|
File dsFile = homeDir.resolve("config/developer.properties")
|
||||||
.toFile();
|
.toFile();
|
||||||
|
|
||||||
if (!dsFile.exists()) {
|
|
||||||
dsFile = homeDir.resolve("config/default.developer.properties").toFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
try (FileReader reader = new FileReader(dsFile)) {
|
try (FileReader reader = new FileReader(dsFile)) {
|
||||||
Properties dsProps = new Properties();
|
Properties dsProps = new Properties();
|
||||||
dsProps.load(reader);
|
dsProps.load(reader);
|
||||||
devSettings.updateFromProperties(dsProps);
|
devSettings.updateFromProperties(dsProps);
|
||||||
log.info(devSettings);
|
log.info(devSettings);
|
||||||
ss.info(this, "Loaded the '" + dsFile.getName() + "' file: "
|
ss.info(this, "Loaded the 'developer.properties' file: "
|
||||||
+ devSettings);
|
+ devSettings);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
ss.info(this, "Neither 'developer.properties' nor 'default.developer.properties' " +
|
ss.info(this, "'developer.properties' file does not exist.");
|
||||||
"files exist.");
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ss.warning(this,
|
ss.warning(this,
|
||||||
"Failed to load the '" + dsFile.getAbsolutePath() + "' file.", e);
|
"Failed to load the 'developer.properties' file.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,24 @@
|
||||||
package org.vivoweb.linkeddatafragments.servlet;
|
package org.vivoweb.linkeddatafragments.servlet;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import java.io.IOException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.beans.Ontology;
|
import java.io.InputStream;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
|
import java.io.StringReader;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.OntologyDao;
|
import java.util.HashMap;
|
||||||
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
|
import java.util.List;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
import java.util.Map.Entry;
|
||||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
|
||||||
|
import javax.servlet.ServletConfig;
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.annotation.WebServlet;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.jena.riot.Lang;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.apache.jena.riot.Lang;
|
||||||
import org.linkeddatafragments.config.ConfigReader;
|
import org.linkeddatafragments.config.ConfigReader;
|
||||||
import org.linkeddatafragments.datasource.DataSourceFactory;
|
import org.linkeddatafragments.datasource.DataSourceFactory;
|
||||||
import org.linkeddatafragments.datasource.DataSourceTypesRegistry;
|
import org.linkeddatafragments.datasource.DataSourceTypesRegistry;
|
||||||
|
@ -22,26 +31,19 @@ import org.linkeddatafragments.fragments.ILinkedDataFragment;
|
||||||
import org.linkeddatafragments.fragments.ILinkedDataFragmentRequest;
|
import org.linkeddatafragments.fragments.ILinkedDataFragmentRequest;
|
||||||
import org.linkeddatafragments.util.MIMEParse;
|
import org.linkeddatafragments.util.MIMEParse;
|
||||||
import org.linkeddatafragments.views.ILinkedDataFragmentWriter;
|
import org.linkeddatafragments.views.ILinkedDataFragmentWriter;
|
||||||
import org.vivoweb.linkeddatafragments.views.HtmlTriplePatternFragmentWriterImpl;
|
|
||||||
import org.vivoweb.linkeddatafragments.views.LinkedDataFragmentWriterFactory;
|
|
||||||
import org.vivoweb.linkeddatafragments.datasource.rdfservice.RDFServiceBasedRequestProcessorForTPFs;
|
import org.vivoweb.linkeddatafragments.datasource.rdfservice.RDFServiceBasedRequestProcessorForTPFs;
|
||||||
import org.vivoweb.linkeddatafragments.datasource.rdfservice.RDFServiceDataSourceType;
|
import org.vivoweb.linkeddatafragments.datasource.rdfservice.RDFServiceDataSourceType;
|
||||||
|
import org.vivoweb.linkeddatafragments.views.HtmlTriplePatternFragmentWriterImpl;
|
||||||
|
import org.vivoweb.linkeddatafragments.views.LinkedDataFragmentWriterFactory;
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import javax.servlet.ServletContext;
|
|
||||||
import javax.servlet.ServletException;
|
import edu.cornell.mannlib.vitro.webapp.beans.Ontology;
|
||||||
import javax.servlet.annotation.WebServlet;
|
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import edu.cornell.mannlib.vitro.webapp.dao.OntologyDao;
|
||||||
import java.io.File;
|
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
|
||||||
import java.io.IOException;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Servlet that responds with a Linked Data Fragment.
|
* Servlet that responds with a Linked Data Fragment.
|
||||||
|
@ -52,29 +54,13 @@ public class VitroLinkedDataFragmentServlet extends VitroHttpServlet {
|
||||||
private final static long serialVersionUID = 1L;
|
private final static long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static final String PROPERTY_TPF_ACTIVE_FLAG = "tpf.activeFlag";
|
private static final String PROPERTY_TPF_ACTIVE_FLAG = "tpf.activeFlag";
|
||||||
|
private static final Log log = LogFactory.getLog(VitroLinkedDataFragmentServlet.class);
|
||||||
|
|
||||||
private ConfigReader config;
|
private ConfigReader config;
|
||||||
private final HashMap<String, IDataSource> dataSources = new HashMap<>();
|
private final HashMap<String, IDataSource> dataSources = new HashMap<>();
|
||||||
private final Collection<String> mimeTypes = new ArrayList<>();
|
|
||||||
private ConfigurationProperties configProps;
|
private ConfigurationProperties configProps;
|
||||||
private String tpfActiveFlag;
|
private String tpfActiveFlag;
|
||||||
|
|
||||||
private File getConfigFile(ServletConfig config) throws IOException {
|
|
||||||
String path = config.getServletContext().getRealPath("/");
|
|
||||||
if (path == null) {
|
|
||||||
// this can happen when running standalone
|
|
||||||
path = System.getProperty("user.dir");
|
|
||||||
}
|
|
||||||
File cfg = new File(path, "config-example.json");
|
|
||||||
if (!cfg.exists()) {
|
|
||||||
throw new IOException("Configuration file " + cfg + " not found.");
|
|
||||||
}
|
|
||||||
if (!cfg.isFile()) {
|
|
||||||
throw new IOException("Configuration file " + cfg + " is not a file.");
|
|
||||||
}
|
|
||||||
return cfg;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(ServletConfig servletConfig) throws ServletException {
|
public void init(ServletConfig servletConfig) throws ServletException {
|
||||||
try {
|
try {
|
||||||
|
@ -82,11 +68,11 @@ public class VitroLinkedDataFragmentServlet extends VitroHttpServlet {
|
||||||
configProps = ConfigurationProperties.getBean(ctx);
|
configProps = ConfigurationProperties.getBean(ctx);
|
||||||
|
|
||||||
if (!configurationPresent()) {
|
if (!configurationPresent()) {
|
||||||
throw new ServletException("TPF is currently disabled. To enable, add 'tpfActive.flag=true' to the runtime.properties.");
|
throw new ServletException("TPF is currently disabled. To enable, add '"
|
||||||
} else {
|
+ PROPERTY_TPF_ACTIVE_FLAG + " = true' to runtime.properties.");
|
||||||
if (!tpfActiveFlag.equalsIgnoreCase("true")) {
|
} else if (!tpfActiveFlag.equalsIgnoreCase("true")) {
|
||||||
throw new ServletException("TPF is currently disabled. To enable, set 'tpfActive.flag=true' in runtime.properties.");
|
throw new ServletException("TPF is currently disabled. To enable, set '"
|
||||||
}
|
+ PROPERTY_TPF_ACTIVE_FLAG + " = true' in runtime.properties.");
|
||||||
}
|
}
|
||||||
|
|
||||||
RDFService rdfService = ModelAccess.on(ctx).getRDFService();
|
RDFService rdfService = ModelAccess.on(ctx).getRDFService();
|
||||||
|
@ -215,18 +201,18 @@ public class VitroLinkedDataFragmentServlet extends VitroHttpServlet {
|
||||||
writer.writeFragment(response.getOutputStream(), dataSource, fragment, ldfRequest);
|
writer.writeFragment(response.getOutputStream(), dataSource, fragment, ldfRequest);
|
||||||
|
|
||||||
} catch (DataSourceNotFoundException ex) {
|
} catch (DataSourceNotFoundException ex) {
|
||||||
|
log.error(ex, ex);
|
||||||
try {
|
try {
|
||||||
response.setStatus(404);
|
response.setStatus(404);
|
||||||
writer.writeNotFound(response.getOutputStream(), request);
|
writer.writeNotFound(response.getOutputStream(), request);
|
||||||
} catch (Exception ex1) {
|
} catch (Exception ex1) {
|
||||||
|
log.error(ex1, ex1);
|
||||||
throw new ServletException(ex1);
|
throw new ServletException(ex1);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
response.setStatus(500);
|
|
||||||
writer.writeError(response.getOutputStream(), e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
log.error(e, e);
|
||||||
throw new ServletException(e);
|
throw new ServletException(e);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.dao.jena;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.apache.jena.rdf.model.Model;
|
||||||
|
import org.apache.jena.rdf.model.ModelFactory;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.ModelChange;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.model.RDFServiceModel;
|
||||||
|
|
||||||
|
|
||||||
|
public class RDFServiceGraphTest extends AbstractTestClass {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
/**
|
||||||
|
* Test that creating a new model with the same underlying RDFServiceGraph
|
||||||
|
* does not result in a new listener registered on that graph. No matter
|
||||||
|
* how many models have been created using a given RDFServiceGraph, an event
|
||||||
|
* sent to the last-created model should be heard only once by the
|
||||||
|
* RDFService.
|
||||||
|
* @throws RDFServiceException
|
||||||
|
*/
|
||||||
|
public void testEventListening() throws RDFServiceException {
|
||||||
|
Model m = ModelFactory.createDefaultModel();
|
||||||
|
RDFService rdfService = new RDFServiceModel(m);
|
||||||
|
EventsCounter counter = new EventsCounter();
|
||||||
|
rdfService.registerListener(counter);
|
||||||
|
RDFServiceGraph g = new RDFServiceGraph(rdfService);
|
||||||
|
Model model = null;
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
model = RDFServiceGraph.createRDFServiceModel(g);
|
||||||
|
}
|
||||||
|
model.notifyEvent("event");
|
||||||
|
assertEquals(1, counter.getCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class EventsCounter implements ChangeListener {
|
||||||
|
|
||||||
|
private int count = 0;
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyModelChange(ModelChange modelChange) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyEvent(String graphURI, Object event) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
4
dependencies/pom.xml
vendored
4
dependencies/pom.xml
vendored
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-dependencies</artifactId>
|
<artifactId>vitro-dependencies</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-project</artifactId>
|
<artifactId>vitro-project</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<relativePath>..</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-home</artifactId>
|
<artifactId>vitro-home</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-project</artifactId>
|
<artifactId>vitro-project</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<relativePath>..</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
:hasSearchIndexer :basicSearchIndexer ;
|
:hasSearchIndexer :basicSearchIndexer ;
|
||||||
:hasImageProcessor :iioImageProcessor ;
|
:hasImageProcessor :iioImageProcessor ;
|
||||||
:hasFileStorage :ptiFileStorage ;
|
:hasFileStorage :ptiFileStorage ;
|
||||||
:hasContentTripleSource :sdbContentTripleSource ;
|
:hasContentTripleSource :tdbContentTripleSource ;
|
||||||
:hasConfigurationTripleSource :tdbConfigurationTripleSource ;
|
:hasConfigurationTripleSource :tdbConfigurationTripleSource ;
|
||||||
:hasTBoxReasonerModule :jfactTBoxReasonerModule .
|
:hasTBoxReasonerModule :jfactTBoxReasonerModule .
|
||||||
|
|
||||||
|
@ -82,22 +82,22 @@
|
||||||
# ----------------------------
|
# ----------------------------
|
||||||
#
|
#
|
||||||
# Content triples source module: holds data contents
|
# Content triples source module: holds data contents
|
||||||
# The SDB-based implementation is the default option. It reads its parameters
|
# The TDB-based implementation is the default option. It reads its parameters
|
||||||
# from the runtime.properties file, for backward compatibility.
|
# from the runtime.properties file, for backward compatibility.
|
||||||
#
|
#
|
||||||
# Other implementations are based on a local TDB instance, a "standard" SPARQL
|
# Other implementations are based on an SDB instance, a "standard" SPARQL
|
||||||
# endpoint, or a Virtuoso endpoint, with parameters as shown.
|
# endpoint, or a Virtuoso endpoint, with parameters as shown.
|
||||||
#
|
#
|
||||||
|
|
||||||
:sdbContentTripleSource
|
#:sdbContentTripleSource
|
||||||
a vitroWebapp:triplesource.impl.sdb.ContentTripleSourceSDB ,
|
# a vitroWebapp:triplesource.impl.sdb.ContentTripleSourceSDB ,
|
||||||
vitroWebapp:modules.tripleSource.ContentTripleSource .
|
# vitroWebapp:modules.tripleSource.ContentTripleSource .
|
||||||
|
|
||||||
#:tdbContentTripleSource
|
:tdbContentTripleSource
|
||||||
# a vitroWebapp:triplesource.impl.tdb.ContentTripleSourceTDB ,
|
a vitroWebapp:triplesource.impl.tdb.ContentTripleSourceTDB ,
|
||||||
# vitroWebapp:modules.tripleSource.ContentTripleSource ;
|
vitroWebapp:modules.tripleSource.ContentTripleSource ;
|
||||||
# # May be an absolute path, or relative to the Vitro home directory.
|
# May be an absolute path, or relative to the Vitro home directory.
|
||||||
# :hasTdbDirectory "tdbContentModels" .
|
:hasTdbDirectory "tdbContentModels" .
|
||||||
|
|
||||||
#:sparqlContentTripleSource
|
#:sparqlContentTripleSource
|
||||||
# a vitroWebapp:triplesource.impl.virtuoso.ContentTripleSourceSPARQL ,
|
# a vitroWebapp:triplesource.impl.virtuoso.ContentTripleSourceSPARQL ,
|
|
@ -9,53 +9,92 @@
|
||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#
|
||||||
|
# This namespace will be used when generating URIs for objects created in the
|
||||||
|
# editor. In order to serve linked data, the default namespace must be composed
|
||||||
|
# as follows (optional elements in parentheses):
|
||||||
|
#
|
||||||
|
# scheme + server_name (+ port) (+ servlet_context) + "/individual/"
|
||||||
|
#
|
||||||
|
# For example, Cornell's default namespace is:
|
||||||
|
#
|
||||||
|
# http://vivo.cornell.edu/individual/
|
||||||
|
#
|
||||||
|
Vitro.defaultNamespace = http://vivo.mydomain.edu/individual/
|
||||||
|
|
||||||
#
|
#
|
||||||
# URL of Solr context used in local Vitro search. This will usually consist of:
|
# URL of Solr context used in local Vitro search. This will usually consist of:
|
||||||
# scheme + server_name + port + vitro_webapp_name + "solr"
|
# scheme + server_name + port + "solr" + solr_core_name
|
||||||
# In the standard installation, the Solr context will be on the same server as Vitro,
|
# In a standard Solr installation, the Solr service will be available on port
|
||||||
# and in the same Tomcat instance. The path will be the Vitro webapp.name (specified
|
# 8983. The path will be /solr followed by the name used when adding a core
|
||||||
# above) + "solr"
|
# for Vitro.
|
||||||
# Example:
|
# Example:
|
||||||
# vitro.local.solr.url = http://localhost:8080/vitrosolr
|
# vitro.local.solr.url = http://localhost:8983/solr/vitrocore
|
||||||
vitro.local.solr.url = http://localhost:8080/vitrosolr
|
#
|
||||||
|
vitro.local.solr.url = http://localhost:8983/solr/vitrocore
|
||||||
|
|
||||||
#
|
#
|
||||||
# Email parameters which VIVO can use to send mail. If these are left empty,
|
# Email parameters which VIVO can use to send mail. If these are left empty,
|
||||||
# the "Contact Us" form will be disabled and users will not be notified of
|
# the "Contact Us" form will be disabled and users will not be notified of
|
||||||
# changes to their accounts.
|
# changes to their accounts.
|
||||||
|
# Example:
|
||||||
|
# email.smtpHost = smtp.mydomain.edu
|
||||||
|
# email.replyTo = vitroAdmin@mydomain.edu
|
||||||
#
|
#
|
||||||
email.smtpHost = smtp.my.domain.edu
|
email.smtpHost =
|
||||||
email.replyTo = vivoAdmin@my.domain.edu
|
email.replyTo =
|
||||||
|
|
||||||
#
|
#
|
||||||
# The basic parameters for a MySQL database connection. Change the end of the
|
# NOTE: VitroConnection.DataSource.* properties are only used in conjuction with
|
||||||
# URL to reflect your database name (if it is not "vitro"). Change the username
|
# an SDB triple store.
|
||||||
# and password to match the authorized user you created in MySQL.
|
|
||||||
#
|
#
|
||||||
VitroConnection.DataSource.url = jdbc:mysql://localhost/vitro
|
# The basic parameters for a database connection. Change the end of the
|
||||||
VitroConnection.DataSource.username = vitroweb
|
# URL to reflect your database name (if it is not "vitrodb"). Change the username
|
||||||
VitroConnection.DataSource.password = vitrovitro
|
# and password to match the authorized database user you created.
|
||||||
|
#
|
||||||
|
# VitroConnection.DataSource.url = jdbc:mysql://localhost/vitrodb
|
||||||
|
# VitroConnection.DataSource.username = vitrodbUsername
|
||||||
|
# VitroConnection.DataSource.password = vitrodbPassword
|
||||||
|
|
||||||
#
|
#
|
||||||
# The maximum number of active connections in the database connection pool.
|
# The maximum number of active connections in the database connection pool.
|
||||||
# Increase this value to support a greater number of concurrent page requests.
|
# Increase this value to support a greater number of concurrent page requests.
|
||||||
#
|
#
|
||||||
VitroConnection.DataSource.pool.maxActive = 40
|
# VitroConnection.DataSource.pool.maxActive = 40
|
||||||
|
|
||||||
#
|
#
|
||||||
# The maximum number of database connections that will be allowed
|
# The maximum number of database connections that will be allowed
|
||||||
# to remain idle in the connection pool. Default is 25%
|
# to remain idle in the connection pool. Default is 25%
|
||||||
# of the maximum number of active connections.
|
# of the maximum number of active connections.
|
||||||
#
|
#
|
||||||
VitroConnection.DataSource.pool.maxIdle = 10
|
# VitroConnection.DataSource.pool.maxIdle = 10
|
||||||
|
|
||||||
#
|
#
|
||||||
# Parameters to change in order to use VIVO with a database other than
|
# Parameters to change in order to use Vitro with a database other than
|
||||||
# MySQL.
|
# MySQL.
|
||||||
#
|
#
|
||||||
VitroConnection.DataSource.dbtype = MySQL
|
# VitroConnection.DataSource.dbtype = MySQL
|
||||||
VitroConnection.DataSource.driver = com.mysql.jdbc.Driver
|
# VitroConnection.DataSource.driver = com.mysql.jdbc.Driver
|
||||||
VitroConnection.DataSource.validationQuery = SELECT 1
|
# VitroConnection.DataSource.validationQuery = SELECT 1
|
||||||
|
|
||||||
|
#
|
||||||
|
# Include sections between <precise-subquery></precise-subquery>
|
||||||
|
# tags when executing 'list view' queries that retrieve data
|
||||||
|
# for property lists on profile pages.
|
||||||
|
#
|
||||||
|
# Including these optional sections does not change the query
|
||||||
|
# semantics, but may improve performance.
|
||||||
|
#
|
||||||
|
# Default is true if not set.
|
||||||
|
#
|
||||||
|
# listview.usePreciseSubquery = true
|
||||||
|
|
||||||
|
#
|
||||||
|
# The email address of the root user for the VIVO application. The password
|
||||||
|
# for this user is initially set to "rootPassword", but you will be asked to
|
||||||
|
# change the password the first time you log in.
|
||||||
|
#
|
||||||
|
rootUser.emailAddress = root@myDomain.com
|
||||||
|
|
||||||
#
|
#
|
||||||
# Argon2 password hashing parameters for time, memory and parallelism required to
|
# Argon2 password hashing parameters for time, memory and parallelism required to
|
||||||
|
@ -134,7 +173,15 @@ proxy.eligibleTypeList = http://www.w3.org/2002/07/owl#Thing
|
||||||
#
|
#
|
||||||
# languages.selectableLocales = en, es, fr
|
# languages.selectableLocales = en, es, fr
|
||||||
|
|
||||||
# Triple pattern fragments is a very fast, very simple means for querying a triple store.
|
# Triple Pattern Fragments is a very fast, very simple means for querying a
|
||||||
# The triple pattern fragments API in VIVO puts little load on the server, providing a simple means for getting data from the triple store. The API has a web interface for manual use, can be used from the command line via curl, and can be used by programs.
|
# triple store. The Triple Pattern Fragments API in VIVO puts little load on
|
||||||
|
# the server, providing a simple means for getting data from the triple store.
|
||||||
|
# The API has a web interface for manual use, can be used from the command line
|
||||||
|
# via curl, and can be used by programs.
|
||||||
|
#
|
||||||
|
# Vitro's Triple Pattern Fragments API does not require authentication and
|
||||||
|
# makes the full RDF graph available regardless of display or publish levels
|
||||||
|
# set on particular properties. Enable Triple Pattern Fragments only if your
|
||||||
|
# Vitro does not contain restricted data that should not be shared with others.
|
||||||
|
#
|
||||||
# tpf.activeFlag = true
|
# tpf.activeFlag = true
|
21
installer/example-settings.xml
Normal file
21
installer/example-settings.xml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<settings xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd">
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>defaults</id>
|
||||||
|
<properties>
|
||||||
|
<app-name>vitro</app-name>
|
||||||
|
|
||||||
|
<vitro-dir>/usr/local/vitro/home</vitro-dir>
|
||||||
|
<tomcat-dir>/usr/local/tomcat</tomcat-dir>
|
||||||
|
|
||||||
|
<default-theme>vitro</default-theme>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
|
||||||
|
<activeProfiles>
|
||||||
|
<activeProfile>defaults</activeProfile>
|
||||||
|
</activeProfiles>
|
||||||
|
</settings>
|
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-installer-home</artifactId>
|
<artifactId>vitro-installer-home</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-installer</artifactId>
|
<artifactId>vitro-installer</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<relativePath>..</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-installer</artifactId>
|
<artifactId>vitro-installer</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-project</artifactId>
|
<artifactId>vitro-project</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<relativePath>..</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-installer-solr</artifactId>
|
<artifactId>vitro-installer-solr</artifactId>
|
||||||
<version>1.11.0-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<packaging>war</packaging>
|
<packaging>war</packaging>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-installer</artifactId>
|
<artifactId>vitro-installer</artifactId>
|
||||||
<version>1.11.0-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<relativePath>..</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-installer-webapp</artifactId>
|
<artifactId>vitro-installer-webapp</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<packaging>war</packaging>
|
<packaging>war</packaging>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-installer</artifactId>
|
<artifactId>vitro-installer</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<relativePath>..</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -1,51 +1,8 @@
|
||||||
<Context> <!-- useHttpOnly="false" -->
|
<Context> <!-- useHttpOnly="false" -->
|
||||||
|
|
||||||
<!--
|
|
||||||
# The 'home' property specifies the location of Vitro HOME.
|
|
||||||
# The system user used to run the Vitro web application must have write access
|
|
||||||
# to the parent directory of the directory defined in this property, if Vitro HOME
|
|
||||||
# does not already exist.
|
|
||||||
# If this directory already exists, the system user used to run the Vitro web application
|
|
||||||
# must have write access to this directory.
|
|
||||||
-->
|
|
||||||
<Environment
|
<Environment
|
||||||
type="java.lang.String"
|
type="java.lang.String"
|
||||||
name="vitro/home"
|
name="vitro/home"
|
||||||
value="${vivo-dir}" override="true"/>
|
value="${vitro-dir}" override="true"/>
|
||||||
|
|
||||||
<!--
|
|
||||||
# The name of the application (possibly not used).
|
|
||||||
-->
|
|
||||||
<Environment
|
|
||||||
type="java.lang.String"
|
|
||||||
name="vitro/appName"
|
|
||||||
value="vivo" override="true"/>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
# The email address of the root user for the Vitro application. The password
|
|
||||||
# for this user is initially set to "rootPassword", but you will be asked to
|
|
||||||
# change the password the first time you log in.
|
|
||||||
-->
|
|
||||||
<Environment
|
|
||||||
type="java.lang.String"
|
|
||||||
name="vitro/rootUserAddress"
|
|
||||||
value="vivo_root@mydomain.edu" override="true"/>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
# This namespace will be used when generating URIs for objects created in the
|
|
||||||
# editor. In order to serve linked data, the default namespace must be composed
|
|
||||||
# as follows (optional elements in parentheses):
|
|
||||||
#
|
|
||||||
# scheme + server_name (+ port) (+ servlet_context) + "/individual/"
|
|
||||||
#
|
|
||||||
# For example, Cornell's default namespace is:
|
|
||||||
#
|
|
||||||
# http://vivo.cornell.edu/individual/
|
|
||||||
-->
|
|
||||||
<Environment
|
|
||||||
type="java.lang.String"
|
|
||||||
name="vitro/defaultNamespace"
|
|
||||||
value="http://vivo.mydomain.edu/individual/" override="true"/>
|
|
||||||
|
|
||||||
<!-- Disable persist sessions on shut down.-->
|
<!-- Disable persist sessions on shut down.-->
|
||||||
<Manager pathname="" />
|
<Manager pathname="" />
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-project</artifactId>
|
<artifactId>vitro-project</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<name>Vitro</name>
|
<name>Vitro</name>
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-webapp</artifactId>
|
<artifactId>vitro-webapp</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<packaging>war</packaging>
|
<packaging>war</packaging>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-project</artifactId>
|
<artifactId>vitro-project</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
<relativePath>..</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.vivoweb</groupId>
|
<groupId>org.vivoweb</groupId>
|
||||||
<artifactId>vitro-api</artifactId>
|
<artifactId>vitro-api</artifactId>
|
||||||
<version>1.11.2-SNAPSHOT</version>
|
<version>1.12.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
<form method="POST" action="${formUrls.createPassword}" class="customForm" role="create password">
|
<form method="POST" action="${formUrls.createPassword}" class="customForm" role="create password">
|
||||||
<input type="hidden" name="user" value="${userAccount.emailAddress}" role="input" />
|
<input type="hidden" name="user" value="${userAccount.emailAddress}" role="input" />
|
||||||
<input type="hidden" name="key" value="${userAccount.passwordLinkExpiresHash}" role="input" />
|
<input type="hidden" name="key" value="${userAccount.emailKey}" role="input" />
|
||||||
|
|
||||||
<label for="new-password">${strings.new_password}<span class="requiredHint"> *</span></label>
|
<label for="new-password">${strings.new_password}<span class="requiredHint"> *</span></label>
|
||||||
<input type="password" name="newPassword" value="${newPassword}" id="new-password" role="input" />
|
<input type="password" name="newPassword" value="${newPassword}" id="new-password" role="input" />
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<section id="reset-password" role="region">
|
<section id="reset-password" role="region">
|
||||||
<form method="POST" action="${formUrls.resetPassword}" class="customForm" role="create password">
|
<form method="POST" action="${formUrls.resetPassword}" class="customForm" role="create password">
|
||||||
<input type="hidden" name="user" value="${userAccount.emailAddress}" />
|
<input type="hidden" name="user" value="${userAccount.emailAddress}" />
|
||||||
<input type="hidden" name="key" value="${userAccount.passwordLinkExpiresHash}" />
|
<input type="hidden" name="key" value="${userAccount.emailKey}" />
|
||||||
|
|
||||||
<label for="new-password">${strings.new_password}<span class="requiredHint"> *</span></label>
|
<label for="new-password">${strings.new_password}<span class="requiredHint"> *</span></label>
|
||||||
<input type="password" name="newPassword" value="${newPassword}" id="new-password" role="input" />
|
<input type="password" name="newPassword" value="${newPassword}" id="new-password" role="input" />
|
||||||
|
|
|
@ -183,16 +183,16 @@ name will be used as the label. -->
|
||||||
<#local url = statement.editUrl>
|
<#local url = statement.editUrl>
|
||||||
<#if url?has_content>
|
<#if url?has_content>
|
||||||
<#if propertyLocalName?contains("ARG_2000028")>
|
<#if propertyLocalName?contains("ARG_2000028")>
|
||||||
<#if rangeUri?contains("Address")>
|
<#if rangeUri?contains("Address") && statement.address??>
|
||||||
<#local url = url + "&addressUri=" + "${statement.address!}">
|
<#local url = url + "&addressUri=" + "${statement.address?url}">
|
||||||
<#elseif rangeUri?contains("Telephone") || rangeUri?contains("Fax")>
|
<#elseif (rangeUri?contains("Telephone") || rangeUri?contains("Fax")) && statement.phone??>
|
||||||
<#local url = url + "&phoneUri=" + "${statement.phone!}">
|
<#local url = url + "&phoneUri=" + "${statement.phone?url}">
|
||||||
<#elseif rangeUri?contains("Work") || rangeUri?contains("Email")>
|
<#elseif (rangeUri?contains("Work") || rangeUri?contains("Email")) && statement.email??>
|
||||||
<#local url = url + "&emailUri=" + "${statement.email!}">
|
<#local url = url + "&emailUri=" + "${statement.email?url}">
|
||||||
<#elseif rangeUri?contains("Name")>
|
<#elseif rangeUri?contains("Name") && statement.fullName??>
|
||||||
<#local url = url + "&fullNameUri=" + "${statement.fullName!}">
|
<#local url = url + "&fullNameUri=" + "${statement.fullName?url}">
|
||||||
<#elseif rangeUri?contains("Title")>
|
<#elseif rangeUri?contains("Title") && statement.title??>
|
||||||
<#local url = url + "&titleUri=" + "${statement.title!}">
|
<#local url = url + "&titleUri=" + "${statement.title?url}">
|
||||||
</#if>
|
</#if>
|
||||||
</#if>
|
</#if>
|
||||||
<@showEditLink propertyLocalName rangeUri url />
|
<@showEditLink propertyLocalName rangeUri url />
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="${country}" lang="${country}">
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<#import "lib-home-page.ftl" as lh>
|
<#import "lib-home-page.ftl" as lh>
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="${country}">
|
||||||
<head>
|
<head>
|
||||||
<#include "head.ftl">
|
<#include "head.ftl">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<#import "lib-list.ftl" as l>
|
<#import "lib-list.ftl" as l>
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="${country}">
|
||||||
<head>
|
<head>
|
||||||
<#include "head.ftl">
|
<#include "head.ftl">
|
||||||
</head>
|
</head>
|
||||||
|
|
Loading…
Add table
Reference in a new issue