Compare commits
1 commit
texts
...
del_indivi
Author | SHA1 | Date | |
---|---|---|---|
595e122043 |
31 changed files with 259 additions and 253 deletions
|
@ -7,11 +7,17 @@ import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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;
|
||||||
|
@ -46,7 +52,6 @@ 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.
|
||||||
|
@ -128,27 +133,15 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -254,7 +247,6 @@ 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)
|
||||||
|
|
|
@ -249,7 +249,6 @@ 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,7 +156,6 @@ 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,7 +84,6 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,8 +119,10 @@ 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 key = page.getAddedAccount().getEmailKey();
|
String hash = page.getAddedAccount()
|
||||||
String relativeUrl = UrlBuilder.getUrl(CREATE_PASSWORD_URL, "user", email, "key", key);
|
.getPasswordLinkExpiresHash();
|
||||||
|
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,7 +274,6 @@ 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,7 +82,6 @@ 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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,8 +121,10 @@ 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 key = page.getUpdatedAccount().getEmailKey();
|
String hash = page.getUpdatedAccount()
|
||||||
String relativeUrl = UrlBuilder.getUrl(RESET_PASSWORD_URL, "user", email, "key", key);
|
.getPasswordLinkExpiresHash();
|
||||||
|
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,7 +36,6 @@ 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);
|
||||||
|
@ -55,11 +54,6 @@ 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,7 +195,6 @@ 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,7 +159,6 @@ 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.getEmailKey();
|
String expectedKey = userAccount.getPasswordLinkExpiresHash();
|
||||||
if (key.isEmpty() || !key.equals(expectedKey)) {
|
if (!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 = passwordChangeInavlidKeyMessage();
|
bogusMessage = passwordChangeNotPendingMessage();
|
||||||
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.getEmailKey());
|
body.put("key", userAccount.getPasswordLinkExpiresHash());
|
||||||
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,7 +177,5 @@ 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,11 +56,6 @@ 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,7 +134,6 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,11 +154,11 @@ public class DeleteIndividualController extends FreemarkerHttpServlet{
|
||||||
|
|
||||||
private byte[] getIndividualsToDelete(String targetIndividual, String deleteQuery,VitroRequest vreq) {
|
private byte[] getIndividualsToDelete(String targetIndividual, String deleteQuery,VitroRequest vreq) {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
try {
|
|
||||||
Query queryForTypeSpecificDeleteQuery = QueryFactory.create(deleteQuery);
|
Query queryForTypeSpecificDeleteQuery = QueryFactory.create(deleteQuery);
|
||||||
QuerySolutionMap initialBindings = new QuerySolutionMap();
|
QuerySolutionMap initialBindings = new QuerySolutionMap();
|
||||||
initialBindings.add("individualURI", ResourceFactory.createResource( targetIndividual ));
|
initialBindings.add("individualURI", ResourceFactory.createResource( targetIndividual ));
|
||||||
Model ontModel = vreq.getJenaOntModel();
|
Model ontModel = vreq.getJenaOntModel();
|
||||||
|
try {
|
||||||
QueryExecution qexec = QueryExecutionFactory.create(queryForTypeSpecificDeleteQuery,ontModel,initialBindings );
|
QueryExecution qexec = QueryExecutionFactory.create(queryForTypeSpecificDeleteQuery,ontModel,initialBindings );
|
||||||
Model results = qexec.execDescribe();
|
Model results = qexec.execDescribe();
|
||||||
results.write(out,"N3");
|
results.write(out,"N3");
|
||||||
|
|
|
@ -155,7 +155,6 @@ 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,7 +121,6 @@ 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,6 +23,7 @@ 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;
|
||||||
|
@ -403,18 +404,7 @@ public class RDFServiceGraph implements GraphWithPerform {
|
||||||
@Override
|
@Override
|
||||||
public GraphEventManager getEventManager() {
|
public GraphEventManager getEventManager() {
|
||||||
if (eventManager == null) {
|
if (eventManager == null) {
|
||||||
eventManager = new SimpleEventManager() {
|
eventManager = new SimpleEventManager(this);
|
||||||
@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;
|
||||||
}
|
}
|
||||||
|
@ -600,7 +590,21 @@ public class RDFServiceGraph implements GraphWithPerform {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Model createRDFServiceModel(final RDFServiceGraph g) {
|
public static Model createRDFServiceModel(final RDFServiceGraph g) {
|
||||||
return VitroModelFactory.createModelForGraph(g);
|
Model m = 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,6 +4,7 @@ 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;
|
||||||
|
@ -97,8 +98,6 @@ 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,
|
||||||
|
@ -241,8 +240,6 @@ 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);
|
||||||
|
@ -309,8 +306,6 @@ 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 {
|
||||||
|
|
|
@ -61,10 +61,6 @@ public class EditConfigurationUtils {
|
||||||
return vreq.getParameter("rangeUri");
|
return vreq.getParameter("rangeUri");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getTypeOfNew(VitroRequest vreq) {
|
|
||||||
return vreq.getParameter("typeOfNew");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static VClass getRangeVClass(VitroRequest vreq) {
|
public static VClass getRangeVClass(VitroRequest vreq) {
|
||||||
// This needs a WebappDaoFactory with no filtering/RDFService
|
// This needs a WebappDaoFactory with no filtering/RDFService
|
||||||
// funny business because it needs to be able to retrieve anonymous union
|
// funny business because it needs to be able to retrieve anonymous union
|
||||||
|
|
|
@ -49,26 +49,18 @@ public class DefaultDeleteGenerator extends BaseEditConfigurationGenerator imple
|
||||||
prepare(vreq, editConfiguration);
|
prepare(vreq, editConfiguration);
|
||||||
if (editConfiguration.getPredicateUri() == null && editConfiguration.getSubjectUri() == null) {
|
if (editConfiguration.getPredicateUri() == null && editConfiguration.getSubjectUri() == null) {
|
||||||
editConfiguration.setTemplate(individualTemplate);
|
editConfiguration.setTemplate(individualTemplate);
|
||||||
addDeleteParams(vreq, editConfiguration);
|
addRedirectUrl(vreq, editConfiguration);
|
||||||
}else {
|
}else {
|
||||||
editConfiguration.setTemplate(propertyTemplate);
|
editConfiguration.setTemplate(propertyTemplate);
|
||||||
}
|
}
|
||||||
return editConfiguration;
|
return editConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addDeleteParams(VitroRequest vreq, EditConfigurationVTwo editConfiguration) {
|
private void addRedirectUrl(VitroRequest vreq, EditConfigurationVTwo editConfiguration) {
|
||||||
String redirectUrl = vreq.getParameter("redirectUrl");
|
String redirectUrl = vreq.getParameter("redirectUrl");
|
||||||
if (redirectUrl != null) {
|
if (redirectUrl != null) {
|
||||||
editConfiguration.addFormSpecificData("redirectUrl", redirectUrl);
|
editConfiguration.addFormSpecificData("redirectUrl", redirectUrl);
|
||||||
}
|
}
|
||||||
String individualName = vreq.getParameter("individualName");
|
|
||||||
if (redirectUrl != null) {
|
|
||||||
editConfiguration.addFormSpecificData("individualName", individualName);
|
|
||||||
}
|
|
||||||
String individualType = vreq.getParameter("individualType");
|
|
||||||
if (redirectUrl != null) {
|
|
||||||
editConfiguration.addFormSpecificData("individualType", individualType);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private EditConfigurationVTwo setupEditConfiguration(VitroRequest vreq, HttpSession session) {
|
private EditConfigurationVTwo setupEditConfiguration(VitroRequest vreq, HttpSession session) {
|
||||||
|
|
|
@ -11,7 +11,6 @@ import javax.servlet.annotation.WebServlet;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
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.ontology.OntModel;
|
import org.apache.jena.ontology.OntModel;
|
||||||
|
@ -68,19 +67,9 @@ 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 (StringUtils.isNotEmpty(EditConfigurationUtils.getTypeOfNew(vreq))) {
|
|
||||||
return SimplePermission.DO_BACK_END_EDITING.ACTION;
|
|
||||||
} else if(MANAGE_MENUS_FORM.equals(vreq.getParameter("editForm"))) {
|
|
||||||
return SimplePermission.MANAGE_MENUS.ACTION;
|
|
||||||
}
|
|
||||||
if (isIndividualDeletion(vreq)) {
|
|
||||||
return SimplePermission.DO_BACK_END_EDITING.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);
|
||||||
String predicateUri = EditConfigurationUtils.getPredicateUri(vreq);
|
String predicateUri = EditConfigurationUtils.getPredicateUri(vreq);
|
||||||
|
@ -109,16 +98,6 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet {
|
||||||
return isAuthorized? SimplePermission.DO_FRONT_END_EDITING.ACTION: AuthorizationRequest.UNAUTHORIZED;
|
return isAuthorized? SimplePermission.DO_FRONT_END_EDITING.ACTION: AuthorizationRequest.UNAUTHORIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isIndividualDeletion(VitroRequest vreq) {
|
|
||||||
String subjectUri = EditConfigurationUtils.getSubjectUri(vreq);
|
|
||||||
String predicateUri = EditConfigurationUtils.getPredicateUri(vreq);
|
|
||||||
String objectUri = EditConfigurationUtils.getObjectUri(vreq);
|
|
||||||
if (objectUri != null && subjectUri == null && predicateUri == null && isDeleteForm(vreq)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResponseValues processRequest(VitroRequest vreq) {
|
protected ResponseValues processRequest(VitroRequest vreq) {
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,15 @@ package edu.cornell.mannlib.vitro.webapp.search.controller;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
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;
|
||||||
|
@ -40,6 +41,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.VClassDao;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupDao;
|
import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupDao;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupsForRequest;
|
import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupsForRequest;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.jena.QueryUtils;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.VClassGroupCache;
|
import edu.cornell.mannlib.vitro.webapp.dao.jena.VClassGroupCache;
|
||||||
import edu.cornell.mannlib.vitro.webapp.i18n.I18n;
|
import edu.cornell.mannlib.vitro.webapp.i18n.I18n;
|
||||||
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine;
|
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine;
|
||||||
|
@ -54,6 +56,9 @@ import edu.cornell.mannlib.vitro.webapp.web.templatemodels.LinkTemplateModel;
|
||||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.searchresult.IndividualSearchResult;
|
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.searchresult.IndividualSearchResult;
|
||||||
import edu.ucsf.vitro.opensocial.OpenSocialManager;
|
import edu.ucsf.vitro.opensocial.OpenSocialManager;
|
||||||
|
|
||||||
|
import org.apache.jena.query.QuerySolution;
|
||||||
|
import org.apache.jena.query.ResultSet;
|
||||||
|
import org.apache.jena.rdf.model.Literal;
|
||||||
/**
|
/**
|
||||||
* Paged search controller that uses the search engine
|
* Paged search controller that uses the search engine
|
||||||
*/
|
*/
|
||||||
|
@ -75,6 +80,18 @@ public class CustomSearchController extends FreemarkerHttpServlet {
|
||||||
private static final String PARAM_RDFTYPE = "type";
|
private static final String PARAM_RDFTYPE = "type";
|
||||||
private static final String PARAM_QUERY_TEXT = "querytext";
|
private static final String PARAM_QUERY_TEXT = "querytext";
|
||||||
|
|
||||||
|
private static String FILTERS_QUERY = ""
|
||||||
|
+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>"
|
||||||
|
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>"
|
||||||
|
+ "PREFIX search: <https://dideside.com/searchOntology#>"
|
||||||
|
+ "SELECT ?filterID ?fieldField ?filterLabel"
|
||||||
|
+ "WHERE"
|
||||||
|
+ "{ ?filterStatement rdf:type search:filter ."
|
||||||
|
+ " ?filterStatement search:field ?fieldField ."
|
||||||
|
+ " ?filterStatement search:id ?filterID ."
|
||||||
|
+ " ?filterStatement rdfs:label ?filterLabel ."
|
||||||
|
+ "} ORDER BY ?fileterLabel";
|
||||||
|
|
||||||
protected static final Map<Format,Map<Result,String>> templateTable;
|
protected static final Map<Format,Map<Result,String>> templateTable;
|
||||||
|
|
||||||
protected enum Format {
|
protected enum Format {
|
||||||
|
@ -128,39 +145,6 @@ public class CustomSearchController extends FreemarkerHttpServlet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
|
||||||
throws IOException, ServletException {
|
|
||||||
VitroRequest vreq = new VitroRequest(request);
|
|
||||||
boolean wasXmlRequested = isRequestedFormatXml(vreq);
|
|
||||||
boolean wasCSVRequested = isRequestedFormatCSV(vreq);
|
|
||||||
if( !wasXmlRequested && !wasCSVRequested){
|
|
||||||
super.doGet(vreq,response);
|
|
||||||
}else if (wasXmlRequested){
|
|
||||||
try {
|
|
||||||
ResponseValues rvalues = processRequest(vreq);
|
|
||||||
|
|
||||||
response.setCharacterEncoding("UTF-8");
|
|
||||||
response.setContentType("text/xml;charset=UTF-8");
|
|
||||||
response.setHeader("Content-Disposition", "attachment; filename=search.xml");
|
|
||||||
writeTemplate(rvalues.getTemplateName(), rvalues.getMap(), request, response);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error(e, e);
|
|
||||||
}
|
|
||||||
}else if (wasCSVRequested){
|
|
||||||
try {
|
|
||||||
ResponseValues rvalues = processRequest(vreq);
|
|
||||||
|
|
||||||
response.setCharacterEncoding("UTF-8");
|
|
||||||
response.setContentType("text/csv;charset=UTF-8");
|
|
||||||
response.setHeader("Content-Disposition", "attachment; filename=search.csv");
|
|
||||||
writeTemplate(rvalues.getTemplateName(), rvalues.getMap(), request, response);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error(e, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResponseValues processRequest(VitroRequest vreq) {
|
protected ResponseValues processRequest(VitroRequest vreq) {
|
||||||
|
|
||||||
|
@ -190,8 +174,6 @@ public class CustomSearchController extends FreemarkerHttpServlet {
|
||||||
|
|
||||||
int startIndex = getStartIndex(vreq);
|
int startIndex = getStartIndex(vreq);
|
||||||
int hitsPerPage = getHitsPerPage( vreq );
|
int hitsPerPage = getHitsPerPage( vreq );
|
||||||
String queryBuilderRules = getQueryBuilderRules(vreq);
|
|
||||||
|
|
||||||
|
|
||||||
String queryText = vreq.getParameter(PARAM_QUERY_TEXT);
|
String queryText = vreq.getParameter(PARAM_QUERY_TEXT);
|
||||||
log.debug("Query text is \""+ queryText + "\"");
|
log.debug("Query text is \""+ queryText + "\"");
|
||||||
|
@ -235,6 +217,10 @@ public class CustomSearchController extends FreemarkerHttpServlet {
|
||||||
for (SearchResultDocument doc : docs) {
|
for (SearchResultDocument doc : docs) {
|
||||||
try {
|
try {
|
||||||
String uri = doc.getStringValue(VitroSearchTermNames.URI);
|
String uri = doc.getStringValue(VitroSearchTermNames.URI);
|
||||||
|
/*
|
||||||
|
* if(possibleExcerpts.contains(uri)) { log.info("FOUND AVAILIBLE URI " + uri);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
Individual ind = iDao.getIndividualByURI(uri);
|
Individual ind = iDao.getIndividualByURI(uri);
|
||||||
if (ind != null) {
|
if (ind != null) {
|
||||||
ind.setSearchSnippet(getSnippet(doc, response));
|
ind.setSearchSnippet(getSnippet(doc, response));
|
||||||
|
@ -317,10 +303,6 @@ public class CustomSearchController extends FreemarkerHttpServlet {
|
||||||
body.put("nextPage", getNextPageLink(startIndex, hitsPerPage,
|
body.put("nextPage", getNextPageLink(startIndex, hitsPerPage,
|
||||||
vreq.getServletPath(), pagingLinkParams));
|
vreq.getServletPath(), pagingLinkParams));
|
||||||
}
|
}
|
||||||
if (queryBuilderRules != null) {
|
|
||||||
body.put("queryBuilderRules", queryBuilderRules);
|
|
||||||
}
|
|
||||||
body.put(PARAM_HITS_PER_PAGE, hitsPerPage);
|
|
||||||
|
|
||||||
// VIVO OpenSocial Extension by UCSF
|
// VIVO OpenSocial Extension by UCSF
|
||||||
try {
|
try {
|
||||||
|
@ -354,15 +336,25 @@ public class CustomSearchController extends FreemarkerHttpServlet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getQueryBuilderRules(VitroRequest vreq) {
|
private Set<String> getExistingExcerpts( VitroRequest vreq) {
|
||||||
String rules = null;
|
Set<String> labels = new HashSet<String>();
|
||||||
try {
|
try {
|
||||||
rules = vreq.getParameter("queryBuilderRules");
|
//We want to get the labels for all the languages, not just the display language
|
||||||
} catch (Throwable e) {
|
ResultSet results = QueryUtils.getLanguageNeutralQueryResults(FILTERS_QUERY, vreq);
|
||||||
log.error(e);
|
while (results.hasNext()) {
|
||||||
|
QuerySolution solution = results.nextSolution();
|
||||||
|
String nodeLiteral = solution.get("individualUri").toString();
|
||||||
|
log.debug(nodeLiteral.toString());
|
||||||
|
labels.add(nodeLiteral);
|
||||||
}
|
}
|
||||||
return rules;
|
} catch (Exception e) {
|
||||||
|
log.error(e, e);
|
||||||
}
|
}
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private int getHitsPerPage(VitroRequest vreq) {
|
private int getHitsPerPage(VitroRequest vreq) {
|
||||||
int hitsPerPage = DEFAULT_HITS_PER_PAGE;
|
int hitsPerPage = DEFAULT_HITS_PER_PAGE;
|
||||||
|
|
|
@ -157,12 +157,13 @@ public abstract class BaseIndividualTemplateModel extends BaseTemplateModel {
|
||||||
ParamMap params = new ParamMap(
|
ParamMap params = new ParamMap(
|
||||||
"objectUri", individual.getURI(),
|
"objectUri", individual.getURI(),
|
||||||
"cmd", "delete",
|
"cmd", "delete",
|
||||||
"individualName",getNameStatement().getValue()
|
"statement_label",getNameStatement().getValue(),
|
||||||
|
"statement_object",individual.getURI()
|
||||||
);
|
);
|
||||||
Iterator<String> typesIterator = types.iterator();
|
Iterator<String> typesIterator = types.iterator();
|
||||||
if (types.iterator().hasNext()) {
|
if (types.iterator().hasNext()) {
|
||||||
String type = typesIterator.next();
|
String type = typesIterator.next();
|
||||||
params.put("individualType", type);
|
params.put("statement_type", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UrlBuilder.getUrl(EDIT_PATH, params);
|
return UrlBuilder.getUrl(EDIT_PATH, params);
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -11,3 +11,31 @@
|
||||||
# Find out how to use this file at
|
# Find out how to use this file at
|
||||||
# https://wiki.duraspace.org/display/VIVO/Using+Short+Views+in+Release+1.5
|
# https://wiki.duraspace.org/display/VIVO/Using+Short+Views+in+Release+1.5
|
||||||
#
|
#
|
||||||
|
@prefix ts_: <https://litvinovg.pro/text_structures#> .
|
||||||
|
@prefix display: <http://vitro.mannlib.cornell.edu/ontologies/display/1.1#> .
|
||||||
|
@prefix mydomain: <http://vivo.mydomain.edu/individual/> .
|
||||||
|
|
||||||
|
ts_:elenphExcerpt display:hasCustomView mydomain:elenphExcerptShortView .
|
||||||
|
|
||||||
|
mydomain:elenphExcerptShortView
|
||||||
|
a display:customViewForIndividual ;
|
||||||
|
display:appliesToContext "SEARCH" ;
|
||||||
|
display:hasTemplate "elenphExcerptShortView.ftl" ;
|
||||||
|
display:hasDataGetter mydomain:elenphExcerptShortViewDataGetter .
|
||||||
|
|
||||||
|
mydomain:elenphExcerptShortViewDataGetter
|
||||||
|
a <java:edu.cornell.mannlib.vitro.webapp.utils.dataGetter.SparqlQueryDataGetter>;
|
||||||
|
display:saveToVar "excerptInfo";
|
||||||
|
display:query
|
||||||
|
"""
|
||||||
|
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||||
|
PREFIX vivo: <http://vivoweb.org/ontology/core#>
|
||||||
|
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
||||||
|
PREFIX ts_: <https://litvinovg.pro/text_structures#>
|
||||||
|
SELECT ?property ?value
|
||||||
|
WHERE {
|
||||||
|
?individualUri ?property ?value .
|
||||||
|
?individualUri rdf:type ts_:elenphExcerpt .
|
||||||
|
}
|
||||||
|
""" .
|
||||||
|
|
||||||
|
|
|
@ -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.emailKey}" role="input" />
|
<input type="hidden" name="key" value="${userAccount.passwordLinkExpiresHash}" 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.emailKey}" />
|
<input type="hidden" name="key" value="${userAccount.passwordLinkExpiresHash}" />
|
||||||
|
|
||||||
<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 @@
|
||||||
</ul>
|
</ul>
|
||||||
<nav id="alpha-browse-container" role="navigation">
|
<nav id="alpha-browse-container" role="navigation">
|
||||||
<h3 class="selected-class"></h3>
|
<h3 class="selected-class"></h3>
|
||||||
<#assign alphabet = ["A", "B", "C", "D", "E", "F", "G" "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] />
|
<#assign alphabet = ["А", "Б", "В", "Г", "Д", "Е", "Ё" "Ж", "З", "И", "Й", "К", "Л", "М", "Н", "О", "П", "Р", "С", "Т", "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Э", "Ю", "Я" ] />
|
||||||
<ul id="alpha-browse-individuals">
|
<ul id="alpha-browse-individuals">
|
||||||
<li><a href="#" class="selected" data-alpha="all" title="${i18n().select_all}">${i18n().all}</a></li>
|
<li><a href="#" class="selected" data-alpha="all" title="${i18n().select_all}">${i18n().all}</a></li>
|
||||||
<#list alphabet as letter>
|
<#list alphabet as letter>
|
||||||
|
|
|
@ -9,4 +9,5 @@
|
||||||
<p>
|
<p>
|
||||||
${message?html}
|
${message?html}
|
||||||
</p>
|
</p>
|
||||||
|
<#include "searchSelector.ftl">
|
||||||
<#include "search-help.ftl" >
|
<#include "search-help.ftl" >
|
||||||
|
|
|
@ -3,10 +3,13 @@
|
||||||
<#-- Template for displaying paged search results -->
|
<#-- Template for displaying paged search results -->
|
||||||
|
|
||||||
<h2 class="searchResultsHeader">
|
<h2 class="searchResultsHeader">
|
||||||
|
|
||||||
|
<#include "searchSelector.ftl">
|
||||||
|
|
||||||
<#escape x as x?html>
|
<#escape x as x?html>
|
||||||
${i18n().search_results_for} '${querytext}'
|
<div id='searchQueryResults'> ${i18n().search_results_for} '${querytext}'</div>
|
||||||
<#if classGroupName?has_content>${i18n().limited_to_type} '${classGroupName}'</#if>
|
<div id='limitedToClassGroup'> <#if classGroupName?has_content>${i18n().limited_to_type} '${classGroupName}'</#if> </div>
|
||||||
<#if typeName?has_content>${i18n().limited_to_type} '${typeName}'</#if>
|
<div id='limitedToType'> <#if typeName?has_content>${i18n().limited_to_type} '${typeName}'</#if> </div>
|
||||||
</#escape>
|
</#escape>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var url = window.location.toString();
|
var url = window.location.toString();
|
||||||
|
@ -28,7 +31,7 @@
|
||||||
<div class="contentsBrowseGroup">
|
<div class="contentsBrowseGroup">
|
||||||
|
|
||||||
<#-- Refinement links -->
|
<#-- Refinement links -->
|
||||||
<#if classGroupLinks?has_content>
|
<#if classGroupLinks?has_content && classGroupLinks?size gt 1>
|
||||||
<div class="searchTOC">
|
<div class="searchTOC">
|
||||||
<h4>${i18n().display_only}</h4>
|
<h4>${i18n().display_only}</h4>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -39,7 +42,7 @@
|
||||||
</div>
|
</div>
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
<#if classLinks?has_content>
|
<#if classLinks?has_content && classLinks?size gt 1 >
|
||||||
<div class="searchTOC">
|
<div class="searchTOC">
|
||||||
<#if classGroupName?has_content>
|
<#if classGroupName?has_content>
|
||||||
<h4>${i18n().limit} ${classGroupName} ${i18n().to}</h4>
|
<h4>${i18n().limit} ${classGroupName} ${i18n().to}</h4>
|
||||||
|
@ -54,6 +57,17 @@
|
||||||
</div>
|
</div>
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
|
<div class="virtualArticleSwitch">
|
||||||
|
<label class="switch">Показать виртуальную статью
|
||||||
|
<input id="virtualArticleCheck" type="checkbox" checked="false" onclick="showVirtualArticles();">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<#if user.loggedIn>
|
||||||
|
<div>
|
||||||
|
<button onclick="createNewCompilation()">Сохранить</button>
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
|
||||||
<#-- Search results -->
|
<#-- Search results -->
|
||||||
<ul class="searchhits">
|
<ul class="searchhits">
|
||||||
<#list individuals as individual>
|
<#list individuals as individual>
|
||||||
|
@ -108,6 +122,108 @@
|
||||||
|
|
||||||
</div> <!-- end contentsBrowseGroup -->
|
</div> <!-- end contentsBrowseGroup -->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$('input[type=checkbox]').removeAttr('checked');
|
||||||
|
function showVirtualArticles(){
|
||||||
|
var checkBox = document.getElementById("virtualArticleCheck");
|
||||||
|
if (checkBox.checked == true){
|
||||||
|
$('.excerptSearchResult').hide();
|
||||||
|
$('.virtualArticlePart').show();
|
||||||
|
} else {
|
||||||
|
$('.excerptSearchResult').show();
|
||||||
|
$('.virtualArticlePart').hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function createNewCompilation() {
|
||||||
|
var compilationName = window.prompt("Введите название подборки.");
|
||||||
|
if (!compilationName){
|
||||||
|
alert("Для создания подоборки необходимо ввести её название.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var iframe = document.createElement("iframe");
|
||||||
|
var excerptsCounter = $('.virtualArticlePart').length;
|
||||||
|
iframe.setAttribute("src", "${urls.base}/editRequestDispatch?typeOfNew=https%3A%2F%2Flitvinovg.pro%2Ftext_structures%23compilation&editForm=edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.CompilationGenerator&excerptsCount=" + excerptsCounter);
|
||||||
|
iframe.style.width = "1px";
|
||||||
|
iframe.style.height = "1px";
|
||||||
|
iframe.id="newCompilationIframe";
|
||||||
|
//iframe.style.display="none";
|
||||||
|
document.body.appendChild(iframe);
|
||||||
|
$('#newCompilationIframe').on('load', function(){
|
||||||
|
fillOutForm(compilationName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function fillOutForm(compilationName){
|
||||||
|
var iframeDoc = document.getElementById('newCompilationIframe').contentWindow.document;
|
||||||
|
iframeDoc.getElementById('newCompilationLabel').value = compilationName;
|
||||||
|
var excerpts = $('.virtualArticlePart').toArray();
|
||||||
|
for (i = 0;i < excerpts.length;i++){
|
||||||
|
var excerptUri = excerpts[i].getAttribute('parturi');
|
||||||
|
var excerptName = $(excerpts[i]).children('button').html();
|
||||||
|
var number = i + 1;
|
||||||
|
iframeDoc.getElementById("tocLevel" + number + "Name").value = excerptName + " (" + compilationName + ")";
|
||||||
|
iframeDoc.getElementById("tocItem" + number + "Name").value = excerptName + " (" + compilationName + ")";
|
||||||
|
iframeDoc.getElementById("excerpt" + number).value = excerptUri;
|
||||||
|
}
|
||||||
|
$('#newCompilationIframe').off('load');
|
||||||
|
iframeDoc.getElementById('submit').click();
|
||||||
|
$('#newCompilationIframe').on('load', function(){
|
||||||
|
redirectToNewCompilation();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
function redirectToNewCompilation(){
|
||||||
|
var newURL = document.getElementById('newCompilationIframe').contentWindow.location.href;
|
||||||
|
window.open(newURL,"_self");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
let workSet = new Set();
|
||||||
|
let biblioSet = new Set();
|
||||||
|
var workDivs = $('.virtualArticleWork');
|
||||||
|
var biblioDivs = $('.virtualArticleBibliography');
|
||||||
|
biblioDivs.each(function() {
|
||||||
|
biblioSet.add($(this).html());
|
||||||
|
});
|
||||||
|
workDivs.each(function() {
|
||||||
|
workSet.add($(this).html());
|
||||||
|
});
|
||||||
|
var workArr = Array.from(workSet);
|
||||||
|
workArr.sort();
|
||||||
|
var biblioArr = Array.from(biblioSet);
|
||||||
|
biblioArr.sort();
|
||||||
|
if (workArr.length > 0 ) {
|
||||||
|
$('<div class="virtualArticleWorks"><button type="button" style="margin-top:16px;border:none;padding: 18px;width: 100%; text-align:left;" class="collapsible">Работы</button><div class="virtualWorks"></div></div>').insertAfter($('.virtualArticlePart').last());
|
||||||
|
for (let value of workArr){
|
||||||
|
$('.virtualWorks').last().append( '<div class="work"><p>' + value + '</p></div>' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (biblioArr.length > 0 ) {
|
||||||
|
$('<div class="virtualArticleBiblio"><button type="button" style="margin-top:16px;border:none;padding: 18px;width: 100%; text-align:left;" class="collapsible">Литература</button><div class="virtualBibliography"></div></div>').insertAfter($('.virtualArticlePart').last());
|
||||||
|
for (let value of biblioArr){
|
||||||
|
$('.virtualBibliography').last().append( '<div class="bibliography"><p>' + value + '</p></div>' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
$('.virtualWorks').hide();
|
||||||
|
$('.virtualBibliography').hide();
|
||||||
|
$('.virtualArticlePart').hide();
|
||||||
|
var coll = document.getElementsByClassName("collapsible");
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < coll.length; i++) {
|
||||||
|
coll[i].addEventListener("click", function() {
|
||||||
|
this.classList.toggle("active");
|
||||||
|
var content = this.nextElementSibling;
|
||||||
|
if (content.style.display === "block") {
|
||||||
|
content.style.display = "none";
|
||||||
|
} else {
|
||||||
|
content.style.display = "block";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
${stylesheets.add('<link rel="stylesheet" href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />',
|
${stylesheets.add('<link rel="stylesheet" href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />',
|
||||||
'<link rel="stylesheet" href="${urls.base}/css/search.css" />',
|
'<link rel="stylesheet" href="${urls.base}/css/search.css" />',
|
||||||
'<link rel="stylesheet" type="text/css" href="${urls.base}/css/jquery_plugins/qtip/jquery.qtip.min.css" />')}
|
'<link rel="stylesheet" type="text/css" href="${urls.base}/css/jquery_plugins/qtip/jquery.qtip.min.css" />')}
|
||||||
|
|
|
@ -4,28 +4,19 @@
|
||||||
<#else>
|
<#else>
|
||||||
<#assign redirectUrl = "/" />
|
<#assign redirectUrl = "/" />
|
||||||
</#if>
|
</#if>
|
||||||
<#if editConfiguration.pageData.individualName??>
|
<#assign statement = editConfiguration.objectStatementDisplay />
|
||||||
<#assign individualName = editConfiguration.pageData.individualName />
|
<#assign deletionTemplateName = editConfiguration.deleteTemplate/>
|
||||||
</#if>
|
|
||||||
<#if editConfiguration.pageData.individualType??>
|
|
||||||
<#assign individualType = editConfiguration.pageData.individualType />
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
<form action="${editConfiguration.deleteIndividualProcessingUrl}" method="get">
|
<form action="${editConfiguration.deleteIndividualProcessingUrl}" method="get">
|
||||||
<h2>${i18n().confirm_individual_deletion} </h2>
|
<h2>${i18n().confirm_individual_deletion} </h2>
|
||||||
|
|
||||||
<input type="hidden" name="individualUri" value="${editConfiguration.objectUri}" role="input" />
|
<input type="hidden" name="individualUri" value="${editConfiguration.objectUri}" role="input" />
|
||||||
<input type="hidden" name="redirectUrl" value="${redirectUrl}" role="input" />
|
<input type="hidden" name="redirectUrl" value="${redirectUrl}" role="input" />
|
||||||
|
<#assign deletionTemplateName = editConfiguration.deleteTemplate/>
|
||||||
|
|
||||||
<p>
|
<#if statement?has_content>
|
||||||
<#if individualType??>
|
<#include deletionTemplateName />
|
||||||
${individualType}
|
|
||||||
</#if>
|
</#if>
|
||||||
<#if individualName??>
|
|
||||||
${individualName}
|
|
||||||
</#if>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<p class="submit">
|
<p class="submit">
|
||||||
<input type="submit" id="submit" value="${i18n().delete_button}" role="button"/>
|
<input type="submit" id="submit" value="${i18n().delete_button}" role="button"/>
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
theme_advanced_resizing : true,
|
theme_advanced_resizing : true,
|
||||||
height : "${height}",
|
height : "${height}",
|
||||||
width : "${width}",
|
width : "${width}",
|
||||||
valid_elements : "tr[*],td[*],tbody[*],table[*],a[href|name|title],br,p[style],i,em,cite,strong/b,u,sub,sup,ul,ol,li,h1[dir|style|id],h2[dir|style|id],h3[dir|style|id],h4,h5,h6,div[style|class],span[dir|style|class]",
|
valid_elements : "a[href|name|title],br,p[style],i,em,cite,strong/b,u,sub,sup,ul,ol,li,h1[dir|style|id],h2[dir|style|id],h3[dir|style|id],h4,h5,h6,div[style|class],span[dir|style|class]",
|
||||||
fix_list_elements : true,
|
fix_list_elements : true,
|
||||||
fix_nesting : true,
|
fix_nesting : true,
|
||||||
cleanup_on_startup : true,
|
cleanup_on_startup : true,
|
||||||
|
|
Loading…
Add table
Reference in a new issue