From 4fdbb71fee96d87ed9a124fba00a47bbaea67f8d Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Wed, 17 Feb 2021 14:15:10 +0100 Subject: [PATCH 01/27] Added code for deleting individuals --- .../DeleteIndividualController.java | 201 ++++++++++++++++++ .../generators/DefaultDeleteGenerator.java | 18 +- .../edit/EditConfigurationTemplateModel.java | 4 + .../rdf/display/firsttime/application.owl | 1 + .../rdf/displayTbox/everytime/displayTBOX.n3 | 3 + webapp/src/main/webapp/i18n/all.properties | 1 + .../forms/confirmDeleteIndividualForm.ftl | 26 +++ 7 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java create mode 100644 webapp/src/main/webapp/templates/freemarker/edit/forms/confirmDeleteIndividualForm.ftl diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java new file mode 100644 index 000000000..f7bdaaa41 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java @@ -0,0 +1,201 @@ +package edu.cornell.mannlib.vitro.webapp.controller.freemarker; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jena.query.Query; +import org.apache.jena.query.QueryExecution; +import org.apache.jena.query.QueryExecutionFactory; +import org.apache.jena.query.QueryFactory; +import org.apache.jena.query.QuerySolution; +import org.apache.jena.query.QuerySolutionMap; +import org.apache.jena.query.ResultSet; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ResourceFactory; +import org.apache.jena.shared.Lock; + +import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.AuthorizationRequest; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.RedirectResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; +import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.jena.QueryUtils; +import edu.cornell.mannlib.vitro.webapp.dao.jena.event.BulkUpdateEvent; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; + +@WebServlet(name="DeleteIndividualController",urlPatterns="/deleteIndividualController") +public class DeleteIndividualController extends FreemarkerHttpServlet{ + + private static final Log log = LogFactory.getLog(DeleteIndividualController.class); + private static final boolean BEGIN = true; + private static final boolean END = !BEGIN; + + private static String TYPE_QUERY_START = "" + + "PREFIX vitro: " + + "SELECT ?type " + + "WHERE" + + "{ <"; + private static String TYPE_QUERY_END = "> vitro:mostSpecificType ?type ." + + "}"; + private static String queryForDeleteQuery = + "PREFIX display: <" + DisplayVocabulary.DISPLAY_NS +"> \n" + + "SELECT ?deleteQueryText WHERE { ?associatedURI display:hasDeleteQuery ?deleteQueryText }"; + + private static final String DEFAULT_DELETE_QUERY_TEXT = "DESCRIBE ?associatedURI"; + + @Override + protected AuthorizationRequest requiredActions(VitroRequest vreq) { + return SimplePermission.DO_FRONT_END_EDITING.ACTION; + } + + protected ResponseValues processRequest(VitroRequest vreq) { + String errorMessage = handleErrors(vreq); + if (!errorMessage.isEmpty()) { + return prepareErrorMessage(errorMessage); + } + String individualUri = vreq.getParameter("individualUri"); + String type = getObjectMostSpecificType(individualUri, vreq); + Model displayModel = vreq.getDisplayModel(); + + String delteQueryText = getDeleteQueryForType(type, displayModel); + byte[] toRemove = getIndividualsToDelete(individualUri, delteQueryText, vreq); + if (toRemove.length > 0) { + deleteIndividuals(toRemove,vreq); + } + String redirectUrl = getRedirectUrl(vreq); + + return new RedirectResponseValues(redirectUrl, HttpServletResponse.SC_SEE_OTHER); + } + + private String getRedirectUrl(VitroRequest vreq) { + String redirectUrl = vreq.getParameter("redirectUrl"); + if (redirectUrl != null) { + return redirectUrl; + } + return "/"; + } + + + private TemplateResponseValues prepareErrorMessage(String errorMessage) { + HashMap map = new HashMap(); + map.put("errorMessage", errorMessage); + return new TemplateResponseValues("error-message.ftl", map); + } + + private String handleErrors(VitroRequest vreq) { + String uri = vreq.getParameter("individualUri"); + if ( uri == null) { + return "Individual uri is null. No object to delete."; + } + if (uri.contains(">")) { + return "Individual uri shouldn't contain >"; + } + return ""; + } + + private static String getDeleteQueryForType(String typeURI,Model displayModel) { + + String deleteQueryText = DEFAULT_DELETE_QUERY_TEXT; + + Query queryForTypeSpecificDeleteQuery = QueryFactory.create(queryForDeleteQuery); + + QuerySolutionMap initialBindings = new QuerySolutionMap(); + initialBindings.add("associatedURI", ResourceFactory.createResource( typeURI )); + + displayModel.enterCriticalSection(Lock.READ); + try{ + QueryExecution qexec = QueryExecutionFactory.create(queryForTypeSpecificDeleteQuery,displayModel,initialBindings ); + try{ + ResultSet results = qexec.execSelect(); + while (results.hasNext()) { + QuerySolution solution = results.nextSolution(); + deleteQueryText = solution.get("deleteQueryText").toString(); + } + }finally{ qexec.close(); } + }finally{ displayModel.leaveCriticalSection(); } + + if (!deleteQueryText.equals(DEFAULT_DELETE_QUERY_TEXT)) { + log.debug("For " + typeURI + " found delete query \n" + deleteQueryText); + } else { + log.debug("For " + typeURI + " delete query not found. Using defalut query \n" + deleteQueryText); + } + return deleteQueryText; + } + + private String getObjectMostSpecificType(String individualURI, VitroRequest vreq) { + String type = ""; + try { + ResultSet results = QueryUtils.getLanguageNeutralQueryResults(makeTypeQuery(individualURI), vreq); + while (results.hasNext()) { + QuerySolution solution = results.nextSolution(); + type = solution.get("type").toString(); + log.debug(type); + } + } catch (Exception e) { + log.error("Failed to get type for individual URI " + individualURI); + log.error(e, e); + } + return type; + } + + private byte[] getIndividualsToDelete(String targetIndividual, String deleteQuery,VitroRequest vreq) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Query queryForTypeSpecificDeleteQuery = QueryFactory.create(deleteQuery); + QuerySolutionMap initialBindings = new QuerySolutionMap(); + initialBindings.add("individualURI", ResourceFactory.createResource( targetIndividual )); + Model ontModel = vreq.getJenaOntModel(); + try { + QueryExecution qexec = QueryExecutionFactory.create(queryForTypeSpecificDeleteQuery,ontModel,initialBindings ); + Model results = qexec.execDescribe(); + results.write(out,"N3"); + + } catch (Exception e) { + log.error("Query raised an error \n" + deleteQuery); + log.error(e, e); + } + return out.toByteArray(); + } + + private String makeTypeQuery(String objectURI) { + return TYPE_QUERY_START + objectURI + TYPE_QUERY_END; + } + + private void deleteIndividuals(byte[] toRemove, VitroRequest vreq) { + String removingString = new String(toRemove, StandardCharsets.UTF_8); + RDFService rdfService = vreq.getRDFService(); + ChangeSet cs = makeChangeSet(rdfService); + InputStream in = new ByteArrayInputStream(toRemove); + cs.addRemoval(in, RDFServiceUtils.getSerializationFormatFromJenaString("N3"), ModelNames.ABOX_ASSERTIONS); + try { + rdfService.changeSetUpdate(cs); + } catch (RDFServiceException e) { + log.error("Got error while removing\n" + removingString); + throw new RuntimeException(e); + } + } + + private ChangeSet makeChangeSet(RDFService rdfService) { + ChangeSet cs = rdfService.manufactureChangeSet(); + cs.addPreChangeEvent(new BulkUpdateEvent(null, BEGIN)); + cs.addPostChangeEvent(new BulkUpdateEvent(null, END)); + return cs; +} + + + + +} diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java index 7b77786d4..11ef2d455 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java @@ -28,7 +28,9 @@ public class DefaultDeleteGenerator extends BaseEditConfigurationGenerator imple private Integer dataHash = 0; private DataPropertyStatement dps = null; private String dataLiteral = null; - private String template = "confirmDeletePropertyForm.ftl"; + private String propertyTemplate = "confirmDeletePropertyForm.ftl"; + private String individualTemplate = "confirmDeleteIndividualForm.ftl"; + //In this case, simply return the edit configuration currently saved in session //Since this is forwarding from another form, an edit configuration should already exist in session @@ -43,12 +45,24 @@ public class DefaultDeleteGenerator extends BaseEditConfigurationGenerator imple if(editConfiguration == null) { editConfiguration = setupEditConfiguration(vreq, session); } - editConfiguration.setTemplate(template); //prepare update? prepare(vreq, editConfiguration); + if (editConfiguration.getPredicateUri() == null && editConfiguration.getSubjectUri() == null) { + editConfiguration.setTemplate(individualTemplate); + addRedirectUrl(vreq, editConfiguration); + }else { + editConfiguration.setTemplate(propertyTemplate); + } return editConfiguration; } + private void addRedirectUrl(VitroRequest vreq, EditConfigurationVTwo editConfiguration) { + String redirectUrl = vreq.getParameter("redirectUrl"); + if (redirectUrl != null) { + editConfiguration.addFormSpecificData("redirectUrl", redirectUrl); + } + } + private EditConfigurationVTwo setupEditConfiguration(VitroRequest vreq, HttpSession session) { EditConfigurationVTwo editConfiguration = new EditConfigurationVTwo(); initProcessParameters(vreq, session, editConfiguration); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java index 7f88848ec..05a9c676f 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java @@ -705,6 +705,10 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { public String getDeleteProcessingUrl() { return vreq.getContextPath() + "/deletePropertyController"; } + + public String getDeleteIndividualProcessingUrl() { + return vreq.getContextPath() + "/deleteIndividualController"; + } //TODO: Check if this logic is correct and delete prohibited does not expect a specific value public boolean isDeleteProhibited() { diff --git a/home/src/main/resources/rdf/display/firsttime/application.owl b/home/src/main/resources/rdf/display/firsttime/application.owl index 02dbd5736..3a48d3ef5 100644 --- a/home/src/main/resources/rdf/display/firsttime/application.owl +++ b/home/src/main/resources/rdf/display/firsttime/application.owl @@ -128,6 +128,7 @@ + diff --git a/home/src/main/resources/rdf/displayTbox/everytime/displayTBOX.n3 b/home/src/main/resources/rdf/displayTbox/everytime/displayTBOX.n3 index d5fcf9ec2..07478b771 100644 --- a/home/src/main/resources/rdf/displayTbox/everytime/displayTBOX.n3 +++ b/home/src/main/resources/rdf/displayTbox/everytime/displayTBOX.n3 @@ -204,6 +204,9 @@ vitro:additionalLink display:hasElement a owl:ObjectProperty . +display:hasDeleteQuery + a owl:DataProperty . + display:excludeClass a owl:ObjectProperty . diff --git a/webapp/src/main/webapp/i18n/all.properties b/webapp/src/main/webapp/i18n/all.properties index 1909545ad..5f7be8861 100644 --- a/webapp/src/main/webapp/i18n/all.properties +++ b/webapp/src/main/webapp/i18n/all.properties @@ -720,6 +720,7 @@ there_are_no_entries_for_selection = There are no entries in the system from whi the_range_class_does_not_exist= The range class for this property does not exist in the system. editing_prohibited = This property is currently configured to prohibit editing. confirm_entry_deletion_from = Are you sure you want to delete the following entry from +confirm_individual_deletion = Are you sure you want to delete the following individual? edit_date_time_value = Edit Date/Time Value create_date_time_value = Create Date/Time Value diff --git a/webapp/src/main/webapp/templates/freemarker/edit/forms/confirmDeleteIndividualForm.ftl b/webapp/src/main/webapp/templates/freemarker/edit/forms/confirmDeleteIndividualForm.ftl new file mode 100644 index 000000000..01d28ec62 --- /dev/null +++ b/webapp/src/main/webapp/templates/freemarker/edit/forms/confirmDeleteIndividualForm.ftl @@ -0,0 +1,26 @@ +<#-- $This file is distributed under the terms of the license in LICENSE$ --> +<#if editConfiguration.pageData.redirectUrl??> + <#assign redirectUrl = editConfiguration.pageData.redirectUrl /> +<#else> + <#assign redirectUrl = "/" /> + +<#assign statement = editConfiguration.objectStatementDisplay /> +<#assign deletionTemplateName = editConfiguration.deleteTemplate/> + +
+

${i18n().confirm_individual_deletion}

+ + + + <#assign deletionTemplateName = editConfiguration.deleteTemplate/> + + <#if statement?has_content> + <#include deletionTemplateName /> + +
+

+ + or + ${i18n().cancel_link} +

+
From 2e0b3f0f05305dc4ed3eebd55ab5f1ea49d39225 Mon Sep 17 00:00:00 2001 From: William Welling Date: Tue, 2 Feb 2021 14:10:40 -0600 Subject: [PATCH 02/27] VIVO-1929: patch authorizing create individual form (#206) * patch authorizing create individual form Resolves: https://jira.lyrasis.org/browse/VIVO-1929 --- .../edit/n3editing/VTwo/EditConfigurationUtils.java | 4 ++++ .../controller/EditRequestDispatchController.java | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java index e72e172c1..da3f9be3e 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java @@ -61,6 +61,10 @@ public class EditConfigurationUtils { return vreq.getParameter("rangeUri"); } + public static String getTypeOfNew(VitroRequest vreq) { + return vreq.getParameter("typeOfNew"); + } + public static VClass getRangeVClass(VitroRequest vreq) { // This needs a WebappDaoFactory with no filtering/RDFService // funny business because it needs to be able to retrieve anonymous union diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java index 96d6556b8..529db4d45 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java @@ -11,6 +11,7 @@ import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.jena.ontology.OntModel; @@ -68,9 +69,13 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { 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"; - @Override - protected AuthorizationRequest requiredActions(VitroRequest vreq) { - //Check if this statement can be edited here and return unauthorized if not + @Override + 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; + } + // Check if this statement can be edited here and return unauthorized if not String subjectUri = EditConfigurationUtils.getSubjectUri(vreq); String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); String objectUri = EditConfigurationUtils.getObjectUri(vreq); From af9820b7f3f970d4890fce518ec98923a5042e32 Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Thu, 18 Feb 2021 18:33:23 +0100 Subject: [PATCH 03/27] Added template model, freemarker macro and pass checks in EditRequestDispatchController for individual deletion --- .../EditRequestDispatchController.java | 2 +- .../BaseIndividualTemplateModel.java | 20 +++++++++++++++++++ .../freemarker/lib/lib-properties.ftl | 10 ++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java index 529db4d45..bb6f8292a 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java @@ -360,7 +360,7 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); String formParam = getFormParam(vreq); //if no form parameter, then predicate uri and subject uri must both be populated - if (formParam == null || "".equals(formParam)) { + if ((formParam == null || "".equals(formParam)) && !isDeleteForm(vreq)) { if ((predicateUri == null || predicateUri.trim().length() == 0)) { return true; } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java index 8c25395ff..a4d3509a6 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java @@ -7,6 +7,7 @@ import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAct import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction.SOME_URI; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -27,6 +28,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; @@ -37,6 +39,7 @@ import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel; public abstract class BaseIndividualTemplateModel extends BaseTemplateModel { private static final Log log = LogFactory.getLog(BaseIndividualTemplateModel.class); + private static final String EDIT_PATH = "editRequestDispatch"; protected final Individual individual; protected final LoginStatusBean loginStatusBean; @@ -148,6 +151,23 @@ public abstract class BaseIndividualTemplateModel extends BaseTemplateModel { public String getName() { return individual.getName(); } + + public String getDeleteUrl() { + Collection types = getMostSpecificTypes(); + ParamMap params = new ParamMap( + "objectUri", individual.getURI(), + "cmd", "delete", + "statement_label",getNameStatement().getValue(), + "statement_object",individual.getURI() + ); + Iterator typesIterator = types.iterator(); + if (types.iterator().hasNext()) { + String type = typesIterator.next(); + params.put("statement_type", type); + } + + return UrlBuilder.getUrl(EDIT_PATH, params); + } public Collection getMostSpecificTypes() { ObjectPropertyStatementDao opsDao = vreq.getWebappDaoFactory().getObjectPropertyStatementDao(); diff --git a/webapp/src/main/webapp/templates/freemarker/lib/lib-properties.ftl b/webapp/src/main/webapp/templates/freemarker/lib/lib-properties.ftl index 3e5223fc6..34b00e51c 100644 --- a/webapp/src/main/webapp/templates/freemarker/lib/lib-properties.ftl +++ b/webapp/src/main/webapp/templates/freemarker/lib/lib-properties.ftl @@ -203,6 +203,16 @@ name will be used as the label. --> ${i18n().edit_entry} +<#macro deleteIndividualLink individual redirectUrl="/"> + <#local url = individual.deleteUrl + "&redirectUrl=" + "${redirectUrl}"> + <@showDeleteIndividualLink url /> + + + +<#macro showDeleteIndividualLink url> + ${i18n().delete_entry} + + <#macro deleteLink propertyLocalName propertyName statement rangeUri=""> <#local url = statement.deleteUrl> <#if url?has_content> From d6eb01de9c2a6c66d68534d5cb4a9f1a75267025 Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Thu, 18 Feb 2021 18:53:07 +0100 Subject: [PATCH 04/27] Fix naming mistake in describe query --- .../controller/freemarker/DeleteIndividualController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java index f7bdaaa41..1a61ef980 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java @@ -55,7 +55,7 @@ public class DeleteIndividualController extends FreemarkerHttpServlet{ "PREFIX display: <" + DisplayVocabulary.DISPLAY_NS +"> \n" + "SELECT ?deleteQueryText WHERE { ?associatedURI display:hasDeleteQuery ?deleteQueryText }"; - private static final String DEFAULT_DELETE_QUERY_TEXT = "DESCRIBE ?associatedURI"; + private static final String DEFAULT_DELETE_QUERY_TEXT = "DESCRIBE ?individualURI"; @Override protected AuthorizationRequest requiredActions(VitroRequest vreq) { From 595e122043300da41135d8a4ea3eeff064cdf68d Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Wed, 17 Feb 2021 14:15:10 +0100 Subject: [PATCH 05/27] Added code for deleting individuals --- .../DeleteIndividualController.java | 201 ++++++++++++++++++ .../generators/DefaultDeleteGenerator.java | 18 +- .../EditRequestDispatchController.java | 2 +- .../edit/EditConfigurationTemplateModel.java | 4 + .../BaseIndividualTemplateModel.java | 20 ++ .../rdf/display/firsttime/application.owl | 1 + .../rdf/displayTbox/everytime/displayTBOX.n3 | 3 + webapp/src/main/webapp/i18n/all.properties | 1 + .../forms/confirmDeleteIndividualForm.ftl | 26 +++ .../freemarker/lib/lib-properties.ftl | 10 + 10 files changed, 283 insertions(+), 3 deletions(-) create mode 100644 api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java create mode 100644 webapp/src/main/webapp/templates/freemarker/edit/forms/confirmDeleteIndividualForm.ftl diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java new file mode 100644 index 000000000..1a61ef980 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java @@ -0,0 +1,201 @@ +package edu.cornell.mannlib.vitro.webapp.controller.freemarker; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jena.query.Query; +import org.apache.jena.query.QueryExecution; +import org.apache.jena.query.QueryExecutionFactory; +import org.apache.jena.query.QueryFactory; +import org.apache.jena.query.QuerySolution; +import org.apache.jena.query.QuerySolutionMap; +import org.apache.jena.query.ResultSet; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ResourceFactory; +import org.apache.jena.shared.Lock; + +import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.AuthorizationRequest; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.RedirectResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; +import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.jena.QueryUtils; +import edu.cornell.mannlib.vitro.webapp.dao.jena.event.BulkUpdateEvent; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; + +@WebServlet(name="DeleteIndividualController",urlPatterns="/deleteIndividualController") +public class DeleteIndividualController extends FreemarkerHttpServlet{ + + private static final Log log = LogFactory.getLog(DeleteIndividualController.class); + private static final boolean BEGIN = true; + private static final boolean END = !BEGIN; + + private static String TYPE_QUERY_START = "" + + "PREFIX vitro: " + + "SELECT ?type " + + "WHERE" + + "{ <"; + private static String TYPE_QUERY_END = "> vitro:mostSpecificType ?type ." + + "}"; + private static String queryForDeleteQuery = + "PREFIX display: <" + DisplayVocabulary.DISPLAY_NS +"> \n" + + "SELECT ?deleteQueryText WHERE { ?associatedURI display:hasDeleteQuery ?deleteQueryText }"; + + private static final String DEFAULT_DELETE_QUERY_TEXT = "DESCRIBE ?individualURI"; + + @Override + protected AuthorizationRequest requiredActions(VitroRequest vreq) { + return SimplePermission.DO_FRONT_END_EDITING.ACTION; + } + + protected ResponseValues processRequest(VitroRequest vreq) { + String errorMessage = handleErrors(vreq); + if (!errorMessage.isEmpty()) { + return prepareErrorMessage(errorMessage); + } + String individualUri = vreq.getParameter("individualUri"); + String type = getObjectMostSpecificType(individualUri, vreq); + Model displayModel = vreq.getDisplayModel(); + + String delteQueryText = getDeleteQueryForType(type, displayModel); + byte[] toRemove = getIndividualsToDelete(individualUri, delteQueryText, vreq); + if (toRemove.length > 0) { + deleteIndividuals(toRemove,vreq); + } + String redirectUrl = getRedirectUrl(vreq); + + return new RedirectResponseValues(redirectUrl, HttpServletResponse.SC_SEE_OTHER); + } + + private String getRedirectUrl(VitroRequest vreq) { + String redirectUrl = vreq.getParameter("redirectUrl"); + if (redirectUrl != null) { + return redirectUrl; + } + return "/"; + } + + + private TemplateResponseValues prepareErrorMessage(String errorMessage) { + HashMap map = new HashMap(); + map.put("errorMessage", errorMessage); + return new TemplateResponseValues("error-message.ftl", map); + } + + private String handleErrors(VitroRequest vreq) { + String uri = vreq.getParameter("individualUri"); + if ( uri == null) { + return "Individual uri is null. No object to delete."; + } + if (uri.contains(">")) { + return "Individual uri shouldn't contain >"; + } + return ""; + } + + private static String getDeleteQueryForType(String typeURI,Model displayModel) { + + String deleteQueryText = DEFAULT_DELETE_QUERY_TEXT; + + Query queryForTypeSpecificDeleteQuery = QueryFactory.create(queryForDeleteQuery); + + QuerySolutionMap initialBindings = new QuerySolutionMap(); + initialBindings.add("associatedURI", ResourceFactory.createResource( typeURI )); + + displayModel.enterCriticalSection(Lock.READ); + try{ + QueryExecution qexec = QueryExecutionFactory.create(queryForTypeSpecificDeleteQuery,displayModel,initialBindings ); + try{ + ResultSet results = qexec.execSelect(); + while (results.hasNext()) { + QuerySolution solution = results.nextSolution(); + deleteQueryText = solution.get("deleteQueryText").toString(); + } + }finally{ qexec.close(); } + }finally{ displayModel.leaveCriticalSection(); } + + if (!deleteQueryText.equals(DEFAULT_DELETE_QUERY_TEXT)) { + log.debug("For " + typeURI + " found delete query \n" + deleteQueryText); + } else { + log.debug("For " + typeURI + " delete query not found. Using defalut query \n" + deleteQueryText); + } + return deleteQueryText; + } + + private String getObjectMostSpecificType(String individualURI, VitroRequest vreq) { + String type = ""; + try { + ResultSet results = QueryUtils.getLanguageNeutralQueryResults(makeTypeQuery(individualURI), vreq); + while (results.hasNext()) { + QuerySolution solution = results.nextSolution(); + type = solution.get("type").toString(); + log.debug(type); + } + } catch (Exception e) { + log.error("Failed to get type for individual URI " + individualURI); + log.error(e, e); + } + return type; + } + + private byte[] getIndividualsToDelete(String targetIndividual, String deleteQuery,VitroRequest vreq) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Query queryForTypeSpecificDeleteQuery = QueryFactory.create(deleteQuery); + QuerySolutionMap initialBindings = new QuerySolutionMap(); + initialBindings.add("individualURI", ResourceFactory.createResource( targetIndividual )); + Model ontModel = vreq.getJenaOntModel(); + try { + QueryExecution qexec = QueryExecutionFactory.create(queryForTypeSpecificDeleteQuery,ontModel,initialBindings ); + Model results = qexec.execDescribe(); + results.write(out,"N3"); + + } catch (Exception e) { + log.error("Query raised an error \n" + deleteQuery); + log.error(e, e); + } + return out.toByteArray(); + } + + private String makeTypeQuery(String objectURI) { + return TYPE_QUERY_START + objectURI + TYPE_QUERY_END; + } + + private void deleteIndividuals(byte[] toRemove, VitroRequest vreq) { + String removingString = new String(toRemove, StandardCharsets.UTF_8); + RDFService rdfService = vreq.getRDFService(); + ChangeSet cs = makeChangeSet(rdfService); + InputStream in = new ByteArrayInputStream(toRemove); + cs.addRemoval(in, RDFServiceUtils.getSerializationFormatFromJenaString("N3"), ModelNames.ABOX_ASSERTIONS); + try { + rdfService.changeSetUpdate(cs); + } catch (RDFServiceException e) { + log.error("Got error while removing\n" + removingString); + throw new RuntimeException(e); + } + } + + private ChangeSet makeChangeSet(RDFService rdfService) { + ChangeSet cs = rdfService.manufactureChangeSet(); + cs.addPreChangeEvent(new BulkUpdateEvent(null, BEGIN)); + cs.addPostChangeEvent(new BulkUpdateEvent(null, END)); + return cs; +} + + + + +} diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java index 7b77786d4..11ef2d455 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java @@ -28,7 +28,9 @@ public class DefaultDeleteGenerator extends BaseEditConfigurationGenerator imple private Integer dataHash = 0; private DataPropertyStatement dps = null; private String dataLiteral = null; - private String template = "confirmDeletePropertyForm.ftl"; + private String propertyTemplate = "confirmDeletePropertyForm.ftl"; + private String individualTemplate = "confirmDeleteIndividualForm.ftl"; + //In this case, simply return the edit configuration currently saved in session //Since this is forwarding from another form, an edit configuration should already exist in session @@ -43,12 +45,24 @@ public class DefaultDeleteGenerator extends BaseEditConfigurationGenerator imple if(editConfiguration == null) { editConfiguration = setupEditConfiguration(vreq, session); } - editConfiguration.setTemplate(template); //prepare update? prepare(vreq, editConfiguration); + if (editConfiguration.getPredicateUri() == null && editConfiguration.getSubjectUri() == null) { + editConfiguration.setTemplate(individualTemplate); + addRedirectUrl(vreq, editConfiguration); + }else { + editConfiguration.setTemplate(propertyTemplate); + } return editConfiguration; } + private void addRedirectUrl(VitroRequest vreq, EditConfigurationVTwo editConfiguration) { + String redirectUrl = vreq.getParameter("redirectUrl"); + if (redirectUrl != null) { + editConfiguration.addFormSpecificData("redirectUrl", redirectUrl); + } + } + private EditConfigurationVTwo setupEditConfiguration(VitroRequest vreq, HttpSession session) { EditConfigurationVTwo editConfiguration = new EditConfigurationVTwo(); initProcessParameters(vreq, session, editConfiguration); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java index 96d6556b8..960f64add 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java @@ -355,7 +355,7 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); String formParam = getFormParam(vreq); //if no form parameter, then predicate uri and subject uri must both be populated - if (formParam == null || "".equals(formParam)) { + if ((formParam == null || "".equals(formParam)) && !isDeleteForm(vreq)) { if ((predicateUri == null || predicateUri.trim().length() == 0)) { return true; } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java index 7f88848ec..05a9c676f 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java @@ -705,6 +705,10 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { public String getDeleteProcessingUrl() { return vreq.getContextPath() + "/deletePropertyController"; } + + public String getDeleteIndividualProcessingUrl() { + return vreq.getContextPath() + "/deleteIndividualController"; + } //TODO: Check if this logic is correct and delete prohibited does not expect a specific value public boolean isDeleteProhibited() { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java index 8c25395ff..a4d3509a6 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java @@ -7,6 +7,7 @@ import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAct import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction.SOME_URI; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -27,6 +28,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; @@ -37,6 +39,7 @@ import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel; public abstract class BaseIndividualTemplateModel extends BaseTemplateModel { private static final Log log = LogFactory.getLog(BaseIndividualTemplateModel.class); + private static final String EDIT_PATH = "editRequestDispatch"; protected final Individual individual; protected final LoginStatusBean loginStatusBean; @@ -148,6 +151,23 @@ public abstract class BaseIndividualTemplateModel extends BaseTemplateModel { public String getName() { return individual.getName(); } + + public String getDeleteUrl() { + Collection types = getMostSpecificTypes(); + ParamMap params = new ParamMap( + "objectUri", individual.getURI(), + "cmd", "delete", + "statement_label",getNameStatement().getValue(), + "statement_object",individual.getURI() + ); + Iterator typesIterator = types.iterator(); + if (types.iterator().hasNext()) { + String type = typesIterator.next(); + params.put("statement_type", type); + } + + return UrlBuilder.getUrl(EDIT_PATH, params); + } public Collection getMostSpecificTypes() { ObjectPropertyStatementDao opsDao = vreq.getWebappDaoFactory().getObjectPropertyStatementDao(); diff --git a/home/src/main/resources/rdf/display/firsttime/application.owl b/home/src/main/resources/rdf/display/firsttime/application.owl index 02dbd5736..3a48d3ef5 100644 --- a/home/src/main/resources/rdf/display/firsttime/application.owl +++ b/home/src/main/resources/rdf/display/firsttime/application.owl @@ -128,6 +128,7 @@ + diff --git a/home/src/main/resources/rdf/displayTbox/everytime/displayTBOX.n3 b/home/src/main/resources/rdf/displayTbox/everytime/displayTBOX.n3 index d5fcf9ec2..07478b771 100644 --- a/home/src/main/resources/rdf/displayTbox/everytime/displayTBOX.n3 +++ b/home/src/main/resources/rdf/displayTbox/everytime/displayTBOX.n3 @@ -204,6 +204,9 @@ vitro:additionalLink display:hasElement a owl:ObjectProperty . +display:hasDeleteQuery + a owl:DataProperty . + display:excludeClass a owl:ObjectProperty . diff --git a/webapp/src/main/webapp/i18n/all.properties b/webapp/src/main/webapp/i18n/all.properties index 1909545ad..5f7be8861 100644 --- a/webapp/src/main/webapp/i18n/all.properties +++ b/webapp/src/main/webapp/i18n/all.properties @@ -720,6 +720,7 @@ there_are_no_entries_for_selection = There are no entries in the system from whi the_range_class_does_not_exist= The range class for this property does not exist in the system. editing_prohibited = This property is currently configured to prohibit editing. confirm_entry_deletion_from = Are you sure you want to delete the following entry from +confirm_individual_deletion = Are you sure you want to delete the following individual? edit_date_time_value = Edit Date/Time Value create_date_time_value = Create Date/Time Value diff --git a/webapp/src/main/webapp/templates/freemarker/edit/forms/confirmDeleteIndividualForm.ftl b/webapp/src/main/webapp/templates/freemarker/edit/forms/confirmDeleteIndividualForm.ftl new file mode 100644 index 000000000..01d28ec62 --- /dev/null +++ b/webapp/src/main/webapp/templates/freemarker/edit/forms/confirmDeleteIndividualForm.ftl @@ -0,0 +1,26 @@ +<#-- $This file is distributed under the terms of the license in LICENSE$ --> +<#if editConfiguration.pageData.redirectUrl??> + <#assign redirectUrl = editConfiguration.pageData.redirectUrl /> +<#else> + <#assign redirectUrl = "/" /> + +<#assign statement = editConfiguration.objectStatementDisplay /> +<#assign deletionTemplateName = editConfiguration.deleteTemplate/> + +
+

${i18n().confirm_individual_deletion}

+ + + + <#assign deletionTemplateName = editConfiguration.deleteTemplate/> + + <#if statement?has_content> + <#include deletionTemplateName /> + +
+

+ + or + ${i18n().cancel_link} +

+
diff --git a/webapp/src/main/webapp/templates/freemarker/lib/lib-properties.ftl b/webapp/src/main/webapp/templates/freemarker/lib/lib-properties.ftl index 3e5223fc6..34b00e51c 100644 --- a/webapp/src/main/webapp/templates/freemarker/lib/lib-properties.ftl +++ b/webapp/src/main/webapp/templates/freemarker/lib/lib-properties.ftl @@ -203,6 +203,16 @@ name will be used as the label. --> ${i18n().edit_entry} +<#macro deleteIndividualLink individual redirectUrl="/"> + <#local url = individual.deleteUrl + "&redirectUrl=" + "${redirectUrl}"> + <@showDeleteIndividualLink url /> + + + +<#macro showDeleteIndividualLink url> + ${i18n().delete_entry} + + <#macro deleteLink propertyLocalName propertyName statement rangeUri=""> <#local url = statement.deleteUrl> <#if url?has_content> From a6fa88bd1ffccaf30930ded64532c7273fed5f67 Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Tue, 23 Feb 2021 20:39:55 +0100 Subject: [PATCH 06/27] Cleaned custom search controller --- .../controller/CustomSearchController.java | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/search/controller/CustomSearchController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/search/controller/CustomSearchController.java index 0575746ec..2de8bb6ae 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/search/controller/CustomSearchController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/search/controller/CustomSearchController.java @@ -10,10 +10,8 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; @@ -41,7 +39,6 @@ import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupDao; import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupsForRequest; 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.i18n.I18n; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine; @@ -56,9 +53,6 @@ import edu.cornell.mannlib.vitro.webapp.web.templatemodels.LinkTemplateModel; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.searchresult.IndividualSearchResult; 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 */ @@ -80,18 +74,6 @@ public class CustomSearchController extends FreemarkerHttpServlet { private static final String PARAM_RDFTYPE = "type"; private static final String PARAM_QUERY_TEXT = "querytext"; - private static String FILTERS_QUERY = "" - + "PREFIX rdf: " - + "PREFIX rdfs: " - + "PREFIX search: " - + "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> templateTable; protected enum Format { @@ -217,10 +199,6 @@ public class CustomSearchController extends FreemarkerHttpServlet { for (SearchResultDocument doc : docs) { try { String uri = doc.getStringValue(VitroSearchTermNames.URI); - /* - * if(possibleExcerpts.contains(uri)) { log.info("FOUND AVAILIBLE URI " + uri); - * } - */ Individual ind = iDao.getIndividualByURI(uri); if (ind != null) { ind.setSearchSnippet(getSnippet(doc, response)); @@ -336,26 +314,6 @@ public class CustomSearchController extends FreemarkerHttpServlet { } } - private Set getExistingExcerpts( VitroRequest vreq) { - Set labels = new HashSet(); - try { - //We want to get the labels for all the languages, not just the display language - ResultSet results = QueryUtils.getLanguageNeutralQueryResults(FILTERS_QUERY, vreq); - while (results.hasNext()) { - QuerySolution solution = results.nextSolution(); - String nodeLiteral = solution.get("individualUri").toString(); - log.debug(nodeLiteral.toString()); - labels.add(nodeLiteral); - } - } catch (Exception e) { - log.error(e, e); - } - return labels; -} - - - - private int getHitsPerPage(VitroRequest vreq) { int hitsPerPage = DEFAULT_HITS_PER_PAGE; try{ From 1590d5883024fe4d643aca38b4d19509fab58033 Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Wed, 24 Feb 2021 01:17:53 +0100 Subject: [PATCH 07/27] Process query builder rules in custom search controller --- .../controller/CustomSearchController.java | 50 ++++++++++++++++++- .../body/search/search-pagedResults.ftl | 7 +++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/search/controller/CustomSearchController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/search/controller/CustomSearchController.java index 2de8bb6ae..23af21f0d 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/search/controller/CustomSearchController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/search/controller/CustomSearchController.java @@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.search.controller; import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Base64; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -126,6 +127,39 @@ 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 protected ResponseValues processRequest(VitroRequest vreq) { @@ -156,6 +190,8 @@ public class CustomSearchController extends FreemarkerHttpServlet { int startIndex = getStartIndex(vreq); int hitsPerPage = getHitsPerPage( vreq ); + String queryBuilderRules = getQueryBuilderRules(vreq); + String queryText = vreq.getParameter(PARAM_QUERY_TEXT); log.debug("Query text is \""+ queryText + "\""); @@ -281,7 +317,9 @@ public class CustomSearchController extends FreemarkerHttpServlet { body.put("nextPage", getNextPageLink(startIndex, hitsPerPage, vreq.getServletPath(), pagingLinkParams)); } - + if (queryBuilderRules != null) { + body.put("queryBuilderRules", queryBuilderRules); + } // VIVO OpenSocial Extension by UCSF try { OpenSocialManager openSocialManager = new OpenSocialManager(vreq, "search"); @@ -314,6 +352,16 @@ public class CustomSearchController extends FreemarkerHttpServlet { } } + private String getQueryBuilderRules(VitroRequest vreq) { + String rules = null; + try { + rules = vreq.getParameter("queryBuilderRules"); + } catch (Throwable e) { + log.error(e); + } + return rules; + } + private int getHitsPerPage(VitroRequest vreq) { int hitsPerPage = DEFAULT_HITS_PER_PAGE; try{ diff --git a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl index d9c940758..981e4d626 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl @@ -152,8 +152,15 @@ $('input[type=checkbox]').removeAttr('checked'); fillOutForm(compilationName); }); } + function fillOutForm(compilationName){ var iframeDoc = document.getElementById('newCompilationIframe').contentWindow.document; + var rules = $('#builder').queryBuilder('getRules'); + var query = format_query_string(rules,""); + iframeDoc.getElementById('queryBuilderRules').value = JSON.stringify(rules); + iframeDoc.getElementById('rawQueryString').value = query; + + iframeDoc.getElementById('newCompilationLabel').value = compilationName; var excerpts = $('.virtualArticlePart').toArray(); for (i = 0;i < excerpts.length;i++){ From 75841b9fb2029946789de529ef1f71661ab56cff Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Thu, 25 Feb 2021 21:48:19 +0100 Subject: [PATCH 08/27] Do not create compilation with no excerpts --- .../templates/freemarker/body/search/search-pagedResults.ftl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl index 981e4d626..cb22923c5 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl @@ -135,6 +135,11 @@ $('input[type=checkbox]').removeAttr('checked'); } } function createNewCompilation() { + var excerpts = $('.virtualArticlePart').toArray(); + if (excerpts.length == 0){ + alert("Отрывков не найдено."); + return; + } var compilationName = window.prompt("Введите название подборки."); if (!compilationName){ alert("Для создания подоборки необходимо ввести её название."); From 2f8fa040db4a2facead275f64d65479335137435 Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Thu, 25 Feb 2021 23:17:32 +0100 Subject: [PATCH 09/27] Allow admins delete individuals --- .../controller/EditRequestDispatchController.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java index bb6f8292a..f8bf9eca4 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java @@ -75,6 +75,9 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { if (StringUtils.isNotEmpty(EditConfigurationUtils.getTypeOfNew(vreq))) { return SimplePermission.DO_BACK_END_EDITING.ACTION; } + if (isIndividualDeletion(vreq)) { + return SimplePermission.DO_BACK_END_EDITING.ACTION; + } // Check if this statement can be edited here and return unauthorized if not String subjectUri = EditConfigurationUtils.getSubjectUri(vreq); String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); @@ -103,6 +106,16 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { 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 protected ResponseValues processRequest(VitroRequest vreq) { From cb35b5f6478a502eb040cbcbde55b603ebb1975b Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Mon, 1 Mar 2021 12:32:21 +0100 Subject: [PATCH 10/27] Open try block before creating query --- .../freemarker/DeleteIndividualController.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java index 1a61ef980..c6939fb77 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeleteIndividualController.java @@ -154,14 +154,14 @@ public class DeleteIndividualController extends FreemarkerHttpServlet{ private byte[] getIndividualsToDelete(String targetIndividual, String deleteQuery,VitroRequest vreq) { ByteArrayOutputStream out = new ByteArrayOutputStream(); - Query queryForTypeSpecificDeleteQuery = QueryFactory.create(deleteQuery); - QuerySolutionMap initialBindings = new QuerySolutionMap(); - initialBindings.add("individualURI", ResourceFactory.createResource( targetIndividual )); - Model ontModel = vreq.getJenaOntModel(); - try { + try { + Query queryForTypeSpecificDeleteQuery = QueryFactory.create(deleteQuery); + QuerySolutionMap initialBindings = new QuerySolutionMap(); + initialBindings.add("individualURI", ResourceFactory.createResource( targetIndividual )); + Model ontModel = vreq.getJenaOntModel(); QueryExecution qexec = QueryExecutionFactory.create(queryForTypeSpecificDeleteQuery,ontModel,initialBindings ); - Model results = qexec.execDescribe(); - results.write(out,"N3"); + Model results = qexec.execDescribe(); + results.write(out,"N3"); } catch (Exception e) { log.error("Query raised an error \n" + deleteQuery); From 63f15a90ef14a04f271077aa6cb7ff82e75bc38d Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Mon, 1 Mar 2021 21:56:42 +0100 Subject: [PATCH 11/27] Fixed delete individual url params --- .../generators/DefaultDeleteGenerator.java | 12 +++++++++-- .../BaseIndividualTemplateModel.java | 5 ++--- .../forms/confirmDeleteIndividualForm.ftl | 21 +++++++++++++------ 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java index 11ef2d455..c329543fe 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java @@ -49,18 +49,26 @@ public class DefaultDeleteGenerator extends BaseEditConfigurationGenerator imple prepare(vreq, editConfiguration); if (editConfiguration.getPredicateUri() == null && editConfiguration.getSubjectUri() == null) { editConfiguration.setTemplate(individualTemplate); - addRedirectUrl(vreq, editConfiguration); + addDeleteParams(vreq, editConfiguration); }else { editConfiguration.setTemplate(propertyTemplate); } return editConfiguration; } - private void addRedirectUrl(VitroRequest vreq, EditConfigurationVTwo editConfiguration) { + private void addDeleteParams(VitroRequest vreq, EditConfigurationVTwo editConfiguration) { String redirectUrl = vreq.getParameter("redirectUrl"); if (redirectUrl != null) { 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) { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java index a4d3509a6..efaa8396f 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java @@ -157,13 +157,12 @@ public abstract class BaseIndividualTemplateModel extends BaseTemplateModel { ParamMap params = new ParamMap( "objectUri", individual.getURI(), "cmd", "delete", - "statement_label",getNameStatement().getValue(), - "statement_object",individual.getURI() + "individualName",getNameStatement().getValue() ); Iterator typesIterator = types.iterator(); if (types.iterator().hasNext()) { String type = typesIterator.next(); - params.put("statement_type", type); + params.put("individualType", type); } return UrlBuilder.getUrl(EDIT_PATH, params); diff --git a/webapp/src/main/webapp/templates/freemarker/edit/forms/confirmDeleteIndividualForm.ftl b/webapp/src/main/webapp/templates/freemarker/edit/forms/confirmDeleteIndividualForm.ftl index 01d28ec62..22bb8bea1 100644 --- a/webapp/src/main/webapp/templates/freemarker/edit/forms/confirmDeleteIndividualForm.ftl +++ b/webapp/src/main/webapp/templates/freemarker/edit/forms/confirmDeleteIndividualForm.ftl @@ -4,19 +4,28 @@ <#else> <#assign redirectUrl = "/" /> -<#assign statement = editConfiguration.objectStatementDisplay /> -<#assign deletionTemplateName = editConfiguration.deleteTemplate/> +<#if editConfiguration.pageData.individualName??> + <#assign individualName = editConfiguration.pageData.individualName /> + +<#if editConfiguration.pageData.individualType??> + <#assign individualType = editConfiguration.pageData.individualType /> +

${i18n().confirm_individual_deletion}

- <#assign deletionTemplateName = editConfiguration.deleteTemplate/> - <#if statement?has_content> - <#include deletionTemplateName /> - +

+ <#if individualType??> + ${individualType} + + <#if individualName??> + ${individualName} + +

+

From caa1bc84127af12917ab84d80932401e3a3572aa Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Mon, 22 Mar 2021 13:17:12 +0100 Subject: [PATCH 12/27] Hide literature and bibliography by default --- .../templates/freemarker/body/search/search-pagedResults.ftl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl index cb22923c5..147c8fe0e 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl @@ -206,13 +206,13 @@ $('input[type=checkbox]').removeAttr('checked'); var biblioArr = Array.from(biblioSet); biblioArr.sort(); if (workArr.length > 0 ) { - $('

').insertAfter($('.virtualArticlePart').last()); + $('
').insertAfter($('.virtualArticlePart').last()); for (let value of workArr){ $('.virtualWorks').last().append( '

' + value + '

' ); } } if (biblioArr.length > 0 ) { - $('
').insertAfter($('.virtualArticlePart').last()); + $('
').insertAfter($('.virtualArticlePart').last()); for (let value of biblioArr){ $('.virtualBibliography').last().append( '

' + value + '

' ); } From e2d37bbb759a37514ce0ec596c5c90f3b02b7486 Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Mon, 22 Mar 2021 13:29:42 +0100 Subject: [PATCH 13/27] Moved create new compilation button inside container --- .../freemarker/body/search/search-pagedResults.ftl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl index 147c8fe0e..e869d1ec9 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl @@ -61,12 +61,11 @@ + <#if user.loggedIn> + + - <#if user.loggedIn> -
- -
- + <#-- Search results -->
    From 8e3a98cc56809196ad7afd836c67d6ad52c22044 Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Mon, 22 Mar 2021 19:20:00 +0100 Subject: [PATCH 14/27] Collapse all results on virtual article display --- .../body/search/search-pagedResults.ftl | 118 +++++++++--------- 1 file changed, 61 insertions(+), 57 deletions(-) diff --git a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl index e869d1ec9..9da58b472 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl @@ -57,6 +57,7 @@ +
    + <#-- Search results -->
      @@ -122,17 +124,20 @@ - - - ${stylesheets.add('', '', '')} From 0bdfe65d42cc947434eccec7de699fa4fb840d0a Mon Sep 17 00:00:00 2001 From: Svetlana Rastegina Date: Mon, 22 Mar 2021 19:43:53 +0100 Subject: [PATCH 15/27] Removed margin top in search results. --- .../templates/freemarker/body/search/search-pagedResults.ftl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl index 9da58b472..285604cda 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl @@ -208,13 +208,13 @@ var biblioArr = Array.from(biblioSet); biblioArr.sort(); if (workArr.length > 0 ) { - $('
      ').insertAfter($('.virtualArticlePart').last()); + $('
      ').insertAfter($('.virtualArticlePart').last()); for (let value of workArr){ $('.virtualWorks').last().append( '

      ' + value + '

      ' ); } } if (biblioArr.length > 0 ) { - $('
      ').insertAfter($('.virtualArticlePart').last()); + $('
      ').insertAfter($('.virtualArticlePart').last()); for (let value of biblioArr){ $('.virtualBibliography').last().append( '

      ' + value + '

      ' ); } From 64cd06fbbb4059f9ad483f69d707c7f681aa7c02 Mon Sep 17 00:00:00 2001 From: Svetlana Rastegina Date: Mon, 22 Mar 2021 23:08:22 +0100 Subject: [PATCH 16/27] Removed collapsible buttons paddings. --- .../templates/freemarker/body/search/search-pagedResults.ftl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl index 285604cda..cf4a75de4 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl @@ -208,13 +208,13 @@ var biblioArr = Array.from(biblioSet); biblioArr.sort(); if (workArr.length > 0 ) { - $('
      ').insertAfter($('.virtualArticlePart').last()); + $('
      ').insertAfter($('.virtualArticlePart').last()); for (let value of workArr){ $('.virtualWorks').last().append( '

      ' + value + '

      ' ); } } if (biblioArr.length > 0 ) { - $('
      ').insertAfter($('.virtualArticlePart').last()); + $('
      ').insertAfter($('.virtualArticlePart').last()); for (let value of biblioArr){ $('.virtualBibliography').last().append( '

      ' + value + '

      ' ); } From c2429a6768bfe8410c2049d8bd5730249e3a3a2a Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Thu, 25 Mar 2021 12:40:40 +0100 Subject: [PATCH 17/27] Allow table tags in TinyMCE --- .../templates/freemarker/edit/forms/defaultFormScripts.ftl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/main/webapp/templates/freemarker/edit/forms/defaultFormScripts.ftl b/webapp/src/main/webapp/templates/freemarker/edit/forms/defaultFormScripts.ftl index cc11a4930..b623485af 100644 --- a/webapp/src/main/webapp/templates/freemarker/edit/forms/defaultFormScripts.ftl +++ b/webapp/src/main/webapp/templates/freemarker/edit/forms/defaultFormScripts.ftl @@ -39,7 +39,7 @@ theme_advanced_resizing : true, height : "${height}", width : "${width}", - 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]", + 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]", fix_list_elements : true, fix_nesting : true, cleanup_on_startup : true, From 4ab94d59afafbe87fd9a45eda9511e752b210a19 Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Fri, 26 Mar 2021 14:11:30 +0100 Subject: [PATCH 18/27] Fix compilation creation --- .../freemarker/body/search/search-pagedResults.ftl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl index cf4a75de4..9bcdedc09 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl @@ -139,7 +139,7 @@ } function createNewCompilation() { - var excerpts = $('.virtualArticlePart').toArray(); + var excerpts = $('.compilationDraftExcerpt').toArray(); if (excerpts.length == 0){ alert("Отрывков не найдено."); return; @@ -150,7 +150,7 @@ return; } var iframe = document.createElement("iframe"); - var excerptsCounter = $('.virtualArticlePart').length; + var excerptsCounter = $('.compilationDraftExcerpt').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"; @@ -171,7 +171,7 @@ iframeDoc.getElementById('newCompilationLabel').value = compilationName; - var excerpts = $('.virtualArticlePart').toArray(); + var excerpts = $('.compilationDraftExcerpt').toArray(); for (i = 0;i < excerpts.length;i++){ var excerptUri = excerpts[i].getAttribute('parturi'); var excerptName = $(excerpts[i]).children('button').html(); From 1dbbe6ed4cb2bcbd3a56ea786dee5ae5f417b84c Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Tue, 30 Mar 2021 15:41:59 +0200 Subject: [PATCH 19/27] Renamed works to sources --- .../templates/freemarker/body/search/search-pagedResults.ftl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl index 9bcdedc09..16820d282 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/search/search-pagedResults.ftl @@ -208,7 +208,7 @@ var biblioArr = Array.from(biblioSet); biblioArr.sort(); if (workArr.length > 0 ) { - $('
      ').insertAfter($('.virtualArticlePart').last()); + $('
      ').insertAfter($('.virtualArticlePart').last()); for (let value of workArr){ $('.virtualWorks').last().append( '

      ' + value + '

      ' ); } From a9a89d220bd275048fc7f29476cb32684d6298d3 Mon Sep 17 00:00:00 2001 From: Svetlana Rastegina Date: Wed, 31 Mar 2021 14:21:04 +0200 Subject: [PATCH 20/27] Added classes for titles. --- .../freemarker/body/search/search-error.ftl | 13 ++++++++----- .../freemarker/body/search/search-help.ftl | 6 ++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/webapp/src/main/webapp/templates/freemarker/body/search/search-error.ftl b/webapp/src/main/webapp/templates/freemarker/body/search/search-error.ftl index 451174d95..3f08f55db 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/search/search-error.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/search/search-error.ftl @@ -3,11 +3,14 @@ <#-- Template for displaying search error message --> <#if title??> -

      ${title?html}

      +
      +

      ${title?html}

      +
      - -

      -${message?html} -

      +
      +

      + ${message?html} +

      +
      <#include "searchSelector.ftl"> <#include "search-help.ftl" > diff --git a/webapp/src/main/webapp/templates/freemarker/body/search/search-help.ftl b/webapp/src/main/webapp/templates/freemarker/body/search/search-help.ftl index b69e4a57f..e892f96df 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/search/search-help.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/search/search-help.ftl @@ -1,12 +1,16 @@ <#-- $This file is distributed under the terms of the license in LICENSE$ --> <#if origination?has_content && origination == "helpLink"> +

      Search Tips

      +
      Back to results <#else> +

      Search Tips

      +
      • Keep it simple! Use short, single terms unless your searches are returning too many results.
      • @@ -15,7 +19,9 @@
      • If you are unsure of the correct spelling, put ~ at the end of your search term -- e.g., cabage~ finds cabbage, steven~ finds Stephen and Stefan (as well as other similar names).
      +