From 0178beda5b0a45d65d54972662382906957743f3 Mon Sep 17 00:00:00 2001 From: Dragan Ivanovic Date: Fri, 5 Jul 2024 15:52:47 +0200 Subject: [PATCH 1/3] Add faux properties for download and repository link --- .../rdf/display/firsttime/PropertyConfig.n3 | 82 ++++++++++++++ .../resources/rdf/tbox/filegraph/vivo.owl | 100 ++++++++++++++++-- .../rdf/tbox/firsttime/vitroAnnotations.n3 | 12 +++ .../config/listViewConfig-downloadLink.xml | 47 ++++++++ .../config/listViewConfig-repositoryLink.xml | 47 ++++++++ 5 files changed, 279 insertions(+), 9 deletions(-) create mode 100644 webapp/src/main/webapp/config/listViewConfig-downloadLink.xml create mode 100644 webapp/src/main/webapp/config/listViewConfig-repositoryLink.xml diff --git a/home/src/main/resources/rdf/display/firsttime/PropertyConfig.n3 b/home/src/main/resources/rdf/display/firsttime/PropertyConfig.n3 index 6e98de098a..0ae6d4d9cb 100644 --- a/home/src/main/resources/rdf/display/firsttime/PropertyConfig.n3 +++ b/home/src/main/resources/rdf/display/firsttime/PropertyConfig.n3 @@ -646,6 +646,22 @@ local:informationResourceInAuthorshipConfig a :ObjectPropertyDisplayConfig ; vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.AddAuthorsToInformationResourceGenerator"^^ ; :propertyGroup . +local:softwareInAuthorshipContext a :ConfigContext ; + :hasConfiguration local:informationResourceInAuthorshipConfig ; + :configContextFor ; + :qualifiedByDomain ; # Software + :qualifiedBy . + +local:softwareInAuthorshipConfig a :ObjectPropertyDisplayConfig ; + :listViewConfigFile "listViewConfig-informationResourceInAuthorship.xml"^^xsd:string ; + rdfs:label "informationResourceInAuthorship"@en-US; + :displayName "authors" ; + vitro:displayRankAnnot 10; + vitro:hiddenFromDisplayBelowRoleLevelAnnot role:public ; + vitro:prohibitedFromUpdateBelowRoleLevelAnnot role:public ; + vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.AddAuthorsToInformationResourceGenerator"^^ ; + :propertyGroup . + local:informationResourceInEditorshipContext a :ConfigContext ; :hasConfiguration local:informationResourceInEditorshipConfig ; :configContextFor ; @@ -680,6 +696,39 @@ local:editorOfConfig a :ObjectPropertyDisplayConfig ; vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.AddEditorshipToPersonGenerator"^^ ; :propertyGroup . +local:softwareInMaintainershipContext a :ConfigContext ; + :hasConfiguration local:softwareInMaintainershipConfig ; + :configContextFor ; + :qualifiedByDomain ; # Software Entity + :qualifiedBy . + +local:softwareInMaintainershipConfig a :ObjectPropertyDisplayConfig ; + :listViewConfigFile "listViewConfig-softwareInMaintainership.xml"^^xsd:string ; + rdfs:label "softwareInMaintainership"@en-US; + :displayName "maintainers" ; + vitro:displayRankAnnot 12; + vitro:hiddenFromDisplayBelowRoleLevelAnnot role:public ; + vitro:prohibitedFromUpdateBelowRoleLevelAnnot role:public ; + vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.AddMaintainersToSoftwareGenerator"^^ ; + :propertyGroup . + +local:maintainerOfContext a :ConfigContext ; + :hasConfiguration local:maintainerOfConfig ; + :configContextFor ; + :qualifiedByDomain ; + :qualifiedBy . + +local:maintainerOfConfig a :ObjectPropertyDisplayConfig ; + :listViewConfigFile "listViewConfig-maintainership.xml"^^xsd:string ; + rdfs:label "maintainerOf"@en-US; + :displayName "maintainer of" ; + vitro:displayRankAnnot 21; + vitro:hiddenFromDisplayBelowRoleLevelAnnot role:public ; + vitro:prohibitedFromUpdateBelowRoleLevelAnnot role:public ; + vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.AddMaintainorshipsToPersonGenerator"^^ ; + :propertyGroup . + + local:issuedCredentialContext a :ConfigContext ; :hasConfiguration local:issuedCredentialConfig ; :configContextFor ; @@ -1026,6 +1075,39 @@ local:webpageSoftwareConfig a :ObjectPropertyDisplayConfig ; vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.ManageWebpagesForIndividualGenerator"^^ ; :propertyGroup . +local:codeRepositorySoftwareContext a :ConfigContext ; + :hasConfiguration local:codeRepositorySoftwareConfig ; + :configContextFor ; + :qualifiedByDomain ; + :qualifiedByRoot ; + :qualifiedBy . + +local:codeRepositorySoftwareConfig a :ObjectPropertyDisplayConfig ; + :listViewConfigFile "listViewConfig-repositoryLink.xml"^^xsd:string ; + :displayName "code repository" ; + vitro:displayRankAnnot 10; + vitro:hiddenFromDisplayBelowRoleLevelAnnot role:public ; + vitro:prohibitedFromUpdateBelowRoleLevelAnnot role:public ; + vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.ManageWebpagesForIndividualGenerator"^^ ; + :propertyGroup . + +local:downloadUrlSoftwareContext a :ConfigContext ; + :hasConfiguration local:downloadUrlSoftwareConfig ; + :configContextFor ; + :qualifiedByDomain ; + :qualifiedByRoot ; + :qualifiedBy . + +local:downloadUrlSoftwareConfig a :ObjectPropertyDisplayConfig ; + :listViewConfigFile "listViewConfig-downloadLink.xml"^^xsd:string ; + :displayName "download URL" ; + vitro:displayRankAnnot 5; + vitro:hiddenFromDisplayBelowRoleLevelAnnot role:public ; + vitro:prohibitedFromUpdateBelowRoleLevelAnnot role:public ; + vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.ManageWebpagesForIndividualGenerator"^^ ; + :propertyGroup . + + local:webpageFacilityContext a :ConfigContext ; :hasConfiguration local:webpageFacilityConfig ; :configContextFor ; diff --git a/home/src/main/resources/rdf/tbox/filegraph/vivo.owl b/home/src/main/resources/rdf/tbox/filegraph/vivo.owl index 78ccd275d6..226addd31d 100644 --- a/home/src/main/resources/rdf/tbox/filegraph/vivo.owl +++ b/home/src/main/resources/rdf/tbox/filegraph/vivo.owl @@ -4040,7 +4040,53 @@ there is a measurement process p that has specified output m, a measurement datu + + + + has minimum requirement + Java 11 is a minimum requirement for a software. + PERSON: Dragan Ivanovic + Minimum requirements for running a software. It might be linked with memory or processor requirement, or other software dependency. + has minimum requirement + + + + + + + + has minimum memory requirement + + + + + + + + has minimum processor requirement + + + + + + + + + has required software dependency + + + + + + + + + has minimum free storage requirement + + + + @@ -6417,19 +6463,13 @@ To enable other Gender/Sex codes to be used, this dataproperty has range URI. Th - - - - - - - + - + @@ -6442,6 +6482,16 @@ To enable other Gender/Sex codes to be used, this dataproperty has range URI. Th + + + + SWHID + Home page for SoftWare Heritage persistent IDentifiers : https://docs.softwareheritage.org/devel/swh-model/persistent-identifiers.html + SoftWare Heritage persistent IDentifiers, or SWHIDs for short, is a PID for software artifacts. It guarantees to remain stable (persistent) over time. + + + + @@ -8831,7 +8881,7 @@ has super-classes - + @@ -9479,6 +9529,24 @@ This class allows for linking an author to a publication while indicating inform A relationship that represents the recognition of an agent as an editor. + + Maintainership + + + + + + + + + + + + + + A relationship that represents the recognition of a person as a maintainer. + + @@ -9651,7 +9719,21 @@ This class allows for linking an author to a publication while indicating inform F1000 is a place where faculty go to critique papers published in PubMed. Any given record in F1000 might have anywhere from one to dozens of reviews. + + + Download Link + + Download link is an URL for downloading dataset, scholarly output, software, etc. + + + + + + Repository Link + + Repository link is an URL for accessing repository record, e.g. a GitHub repository for a software. + diff --git a/home/src/main/resources/rdf/tbox/firsttime/vitroAnnotations.n3 b/home/src/main/resources/rdf/tbox/firsttime/vitroAnnotations.n3 index 2fcfd609cb..f33e4c0517 100644 --- a/home/src/main/resources/rdf/tbox/firsttime/vitroAnnotations.n3 +++ b/home/src/main/resources/rdf/tbox/firsttime/vitroAnnotations.n3 @@ -1748,6 +1748,18 @@ bibo:doi vitro:selectFromExistingAnnot "true"^^xsd:boolean . +vivo:swhid + vitro:displayLimitAnnot + "1"^^xsd:int ; + vitro:displayRankAnnot + "5"^^xsd:int ; + vitro:hiddenFromDisplayBelowRoleLevelAnnot + ; + vitro:hiddenFromPublishBelowRoleLevelAnnot + ; + vitro:inPropertyGroupAnnot + . + obo:ERO_0000070 ## inverse of ERO_0000031 # vitro:displayLimitAnnot # "2"^^xsd:int ; diff --git a/webapp/src/main/webapp/config/listViewConfig-downloadLink.xml b/webapp/src/main/webapp/config/listViewConfig-downloadLink.xml new file mode 100644 index 0000000000..393da34607 --- /dev/null +++ b/webapp/src/main/webapp/config/listViewConfig-downloadLink.xml @@ -0,0 +1,47 @@ + + + + + + + + + PREFIX core: <http://vivoweb.org/ontology/core#> + PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> + PREFIX vcard: <http://www.w3.org/2006/vcard/ns#> + + SELECT ?vcard ?link + (REPLACE(STR(?link),"^.*(#)(.*)$", "$2") AS ?linkName) + ?label + ?url + ?rank + WHERE { + ?subject ?property ?vcard . + ?vcard vcard:hasURL ?link . + ?link a core:DownloadLink . + OPTIONAL { + ?subject ?property ?vcard . + ?vcard vcard:hasURL ?link . + ?link rdfs:label ?label . + } + OPTIONAL { + ?subject ?property ?vcard . + ?vcard vcard:hasURL ?link . + ?link vcard:url ?url . + } + OPTIONAL { + ?subject ?property ?vcard . + ?vcard vcard:hasURL ?link . + ?link core:rank ?rank . + } + + FILTER ( bound(?link) ) + + } ORDER BY ?rank ?label + + + + edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.MaintainDuplicatesObjectPropertyDataPostProcessor + diff --git a/webapp/src/main/webapp/config/listViewConfig-repositoryLink.xml b/webapp/src/main/webapp/config/listViewConfig-repositoryLink.xml new file mode 100644 index 0000000000..403a729c7f --- /dev/null +++ b/webapp/src/main/webapp/config/listViewConfig-repositoryLink.xml @@ -0,0 +1,47 @@ + + + + + + + + + PREFIX core: <http://vivoweb.org/ontology/core#> + PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> + PREFIX vcard: <http://www.w3.org/2006/vcard/ns#> + + SELECT ?vcard ?link + (REPLACE(STR(?link),"^.*(#)(.*)$", "$2") AS ?linkName) + ?label + ?url + ?rank + WHERE { + ?subject ?property ?vcard . + ?vcard vcard:hasURL ?link . + ?link a core:RepositoryLink . + OPTIONAL { + ?subject ?property ?vcard . + ?vcard vcard:hasURL ?link . + ?link rdfs:label ?label . + } + OPTIONAL { + ?subject ?property ?vcard . + ?vcard vcard:hasURL ?link . + ?link vcard:url ?url . + } + OPTIONAL { + ?subject ?property ?vcard . + ?vcard vcard:hasURL ?link . + ?link core:rank ?rank . + } + + FILTER ( bound(?link) ) + + } ORDER BY ?rank ?label + + + + edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.MaintainDuplicatesObjectPropertyDataPostProcessor + From 9881d95e11c15ffdaf38a6d1506e4070811fffae Mon Sep 17 00:00:00 2001 From: Dragan Ivanovic Date: Fri, 5 Jul 2024 15:53:56 +0200 Subject: [PATCH 2/3] Add maintainer relation via a faux property --- .../AddMaintainersToSoftwareGenerator.java | 517 +++++++++++++ .../AddMaintainershipToPersonGenerator.java | 212 ++++++ .../interface-i18n/firsttime/vivo_UiLabel.ttl | 168 +++++ .../config/listViewConfig-maintainership.xml | 42 ++ ...istViewConfig-softwareInMaintainership.xml | 49 ++ .../propStatement-maintainership.ftl | 27 + ...propStatement-softwareInMaintainership.ftl | 21 + .../edit/forms/addMaintainersToSoftware.ftl | 178 +++++ .../edit/forms/addMaintainershipToPerson.ftl | 157 ++++ .../edit/forms/js/addMaintainersToSoftware.js | 703 ++++++++++++++++++ 10 files changed, 2074 insertions(+) create mode 100644 api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddMaintainersToSoftwareGenerator.java create mode 100644 api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddMaintainershipToPersonGenerator.java create mode 100644 webapp/src/main/webapp/config/listViewConfig-maintainership.xml create mode 100644 webapp/src/main/webapp/config/listViewConfig-softwareInMaintainership.xml create mode 100644 webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-maintainership.ftl create mode 100644 webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-softwareInMaintainership.ftl create mode 100644 webapp/src/main/webapp/templates/freemarker/edit/forms/addMaintainersToSoftware.ftl create mode 100644 webapp/src/main/webapp/templates/freemarker/edit/forms/addMaintainershipToPerson.ftl create mode 100644 webapp/src/main/webapp/templates/freemarker/edit/forms/js/addMaintainersToSoftware.js diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddMaintainersToSoftwareGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddMaintainersToSoftwareGenerator.java new file mode 100644 index 0000000000..dd7df96bd4 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddMaintainersToSoftwareGenerator.java @@ -0,0 +1,517 @@ +/* $This file is distributed under the terms of the license in LICENSE$ */ + +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.servlet.http.HttpSession; + +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.dao.jena.QueryUtils; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.FirstAndLastNameValidator; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.validators.AntiXssValidation; +import edu.cornell.mannlib.vitro.webapp.i18n.I18n; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jena.query.QueryExecution; +import org.apache.jena.query.QueryExecutionFactory; +import org.apache.jena.query.QuerySolution; +import org.apache.jena.query.ResultSet; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.vocabulary.RDF; +import org.apache.jena.vocabulary.RDFS; +import org.apache.jena.vocabulary.XSD; + +/** + * This is a slightly unusual generator that is used by Manage Maintainers on + * information resources. + * + * It is intended to always be an add, and never an update. + */ +public class AddMaintainersToSoftwareGenerator extends VivoBaseGenerator implements EditConfigurationGenerator { + public static Log log = LogFactory.getLog(AddMaintainersToSoftwareGenerator.class); + + @Override + public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, + HttpSession session) { + EditConfigurationVTwo editConfiguration = new EditConfigurationVTwo(); + initBasics(editConfiguration, vreq); + initPropertyParameters(vreq, session, editConfiguration); + + //Overriding URL to return to + setUrlToReturnTo(editConfiguration, vreq); + + //set variable names + editConfiguration.setVarNameForSubject("software"); + editConfiguration.setVarNameForPredicate("predicate"); + editConfiguration.setVarNameForObject("maintainershipUri"); + + // Required N3 + editConfiguration.setN3Required(list(getN3NewMaintainership())); + + // Optional N3 + editConfiguration.setN3Optional(generateN3Optional()); + + editConfiguration.addNewResource("maintainershipUri", DEFAULT_NS_TOKEN); + editConfiguration.addNewResource("newPerson", DEFAULT_NS_TOKEN); + editConfiguration.addNewResource("vcardPerson", DEFAULT_NS_TOKEN); + editConfiguration.addNewResource("vcardName", DEFAULT_NS_TOKEN); + + //In scope + setUrisAndLiteralsInScope(editConfiguration, vreq); + + //on Form + setUrisAndLiteralsOnForm(editConfiguration, vreq); + + //Sparql queries + setSparqlQueries(editConfiguration, vreq); + + //set fields + setFields(editConfiguration, vreq, EditConfigurationUtils.getPredicateUri(vreq)); + + //template file + editConfiguration.setTemplate("addMaintainersToSoftware.ftl"); + //add validators + editConfiguration.addValidator(new FirstAndLastNameValidator("personUri", I18n.bundle(vreq))); + + //Adding additional data, specifically edit mode + addFormSpecificData(editConfiguration, vreq); + + editConfiguration.addValidator(new AntiXssValidation()); + + //NOITCE this generator does not run prepare() since it + //is never an update and has no SPARQL for existing + + return editConfiguration; + } + + private void setUrlToReturnTo(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + editConfiguration.setUrlPatternToReturnTo(EditConfigurationUtils.getFormUrlWithoutContext(vreq)); + } + + /***N3 strings both required and optional***/ + + public String getN3PrefixString() { + return "@prefix core: <" + vivoCore + "> .\n" + + "@prefix foaf: <" + foaf + "> . \n"; + } + + private String getN3NewMaintainership() { + return getN3PrefixString() + + "?maintainershipUri a core:Maintainership ;\n" + + " core:relates ?software .\n" + + "?software core:relatedBy ?maintainershipUri ."; + } + + private String getN3MaintainershipRank() { + return getN3PrefixString() + + "?maintainershipUri core:rank ?rank ."; + } + + //first name, middle name, last name, and new perseon for new maintainer being created, and n3 for existing person + //if existing person selected as maintainer + public List generateN3Optional() { + return list( + getN3NewPersonFirstName(), + getN3NewPersonMiddleName(), + getN3NewPersonLastName(), + getN3NewPerson(), + getN3MaintainershipRank(), + getN3ForExistingPerson()); + } + + + private String getN3NewPersonFirstName() { + return getN3PrefixString() + + "@prefix vcard: . \n" + + "?newPerson ?vcardPerson . \n" + + "?vcardPerson ?newPerson . \n" + + "?vcardPerson a . \n" + + "?vcardPerson vcard:hasName ?vcardName . \n" + + "?vcardName a . \n" + + "?vcardName vcard:givenName ?firstName ."; + } + + private String getN3NewPersonMiddleName() { + return getN3PrefixString() + + "@prefix vcard: . \n" + + "?newPerson ?vcardPerson . \n" + + "?vcardPerson ?newPerson . \n" + + "?vcardPerson a vcard:Individual . \n" + + "?vcardPerson vcard:hasName ?vcardName . \n" + + "?vcardName a vcard:Name . \n" + + "?vcardName ?middleName ."; + } + + private String getN3NewPersonLastName() { + return getN3PrefixString() + + "@prefix vcard: . \n" + + "?newPerson ?vcardPerson . \n" + + "?vcardPerson ?newPerson . \n" + + "?vcardPerson a . \n" + + "?vcardPerson vcard:hasName ?vcardName . \n" + + "?vcardName a . \n" + + "?vcardName vcard:familyName ?lastName ."; + } + + private String getN3NewPerson() { + return getN3PrefixString() + + "?newPerson a foaf:Person ;\n" + + "<" + RDFS.label.getURI() + "> ?label .\n" + + "?maintainershipUri core:relates ?newPerson .\n" + + "?newPerson core:relatedBy ?maintainershipUri . "; + } + + private String getN3ForExistingPerson() { + return getN3PrefixString() + + "?maintainershipUri core:relates ?personUri .\n" + + "?personUri core:relatedBy ?maintainershipUri ."; + } + + /** + * Get new resources + */ + //A new maintainership uri will always be created when an maintainer is added + //A new person may be added if a person not in the system will be added as maintainer + private Map generateNewResources(VitroRequest vreq) { + + + HashMap newResources = new HashMap(); + newResources.put("maintainershipUri", DEFAULT_NS_TOKEN); + newResources.put("newPerson", DEFAULT_NS_TOKEN); + newResources.put("vcardPerson", DEFAULT_NS_TOKEN); + newResources.put("vcardName", DEFAULT_NS_TOKEN); + return newResources; + } + + /** + * Set URIS and Literals In Scope and on form and supporting methods + */ + private void setUrisAndLiteralsInScope(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + //Uris in scope always contain subject and predicate + HashMap> urisInScope = new HashMap>(); + urisInScope.put(editConfiguration.getVarNameForSubject(), + Arrays.asList(new String[] {editConfiguration.getSubjectUri()})); + urisInScope.put(editConfiguration.getVarNameForPredicate(), + Arrays.asList(new String[] {editConfiguration.getPredicateUri()})); + editConfiguration.setUrisInScope(urisInScope); + //no literals in scope + } + + public void setUrisAndLiteralsOnForm(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + List urisOnForm = new ArrayList(); + //If an existing person is being used as an maintainer, need to get the person uri + urisOnForm.add("personUri"); + editConfiguration.setUrisOnform(urisOnForm); + + //for person who is not in system, need to add first name, last name and middle name + //Also need to store maintainership rank and label of maintainer + List literalsOnForm = list("firstName", + "middleName", + "lastName", + "rank", + "label"); + editConfiguration.setLiteralsOnForm(literalsOnForm); + } + + /** + * Set SPARQL Queries and supporting methods. + */ + private void setSparqlQueries(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + //Sparql queries are all empty for existing values + //This form is different from the others that it gets multiple maintainers on the same page + //and that information will be queried and stored in the additional form specific data + HashMap map = new HashMap(); + editConfiguration.setSparqlForExistingUris(new HashMap()); + editConfiguration.setSparqlForExistingLiterals(new HashMap()); + editConfiguration.setSparqlForAdditionalUrisInScope(new HashMap()); + editConfiguration.setSparqlForAdditionalLiteralsInScope(new HashMap()); + } + + /** + * Set Fields and supporting methods + */ + + public void setFields(EditConfigurationVTwo editConfiguration, VitroRequest vreq, String predicateUri) { + setLabelField(editConfiguration); + setFirstNameField(editConfiguration); + setMiddleNameField(editConfiguration); + setLastNameField(editConfiguration); + setRankField(editConfiguration); + setPersonUriField(editConfiguration); + } + + private void setLabelField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("label"). + setValidators(list("datatype:" + RDF.dtLangString.getURI())). + setRangeDatatypeUri(RDF.dtLangString.getURI()) + ); + } + + + private void setFirstNameField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("firstName"). + setValidators(list("datatype:" + RDF.dtLangString.getURI())). + setRangeDatatypeUri(RDF.dtLangString.getURI()) + ); + } + + + private void setMiddleNameField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("middleName"). + setValidators(list("datatype:" + RDF.dtLangString.getURI())). + setRangeDatatypeUri(RDF.dtLangString.getURI()) + ); + } + + private void setLastNameField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("lastName"). + setValidators(list("datatype:" + RDF.dtLangString.getURI())). + setRangeDatatypeUri(RDF.dtLangString.getURI()) + ); + } + + private void setRankField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("rank"). + setValidators(list("nonempty")). + setRangeDatatypeUri(XSD.xint.toString()) + ); + } + + + private void setPersonUriField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("personUri") + //.setObjectClassUri(personClass) + ); + } + + //Form specific data + public void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + HashMap formSpecificData = new HashMap(); + //Get the existing maintainerships + formSpecificData.put("existingMaintainerInfo", + getExistingMaintainerships(editConfiguration.getSubjectUri(), vreq)); + formSpecificData.put("newRank", getMaxRank(editConfiguration.getSubjectUri(), vreq) + 1); + formSpecificData.put("rankPredicate", "http://vivoweb.org/ontology/core#rank"); + editConfiguration.setFormSpecificData(formSpecificData); + } + + private static String MAINTAINERSHIPS_MODEL = "" + + "PREFIX core: \n" + + "PREFIX rdfs: \n" + + "PREFIX foaf: \n" + + "CONSTRUCT\n" + + "{\n" + + " ?subject core:relatedBy ?maintainershipURI .\n" + + " ?maintainershipURI a core:Maintainership .\n" + + " ?maintainershipURI core:relates ?maintainerURI .\n" + + " ?maintainershipURI core:rank ?rank.\n" + + " ?maintainerURI a foaf:Person .\n" + + " ?maintainerURI rdfs:label ?maintainerName .\n" + + "}\n" + + "WHERE\n" + + "{\n" + + " {\n" + + " ?subject core:relatedBy ?maintainershipURI .\n" + + " ?maintainershipURI a core:Maintainership .\n" + + " ?maintainershipURI core:relates ?maintainerURI .\n" + + " ?maintainerURI a foaf:Person .\n" + + " }\n" + + " UNION\n" + + " {\n" + + " ?subject core:relatedBy ?maintainershipURI .\n" + + " ?maintainershipURI a core:Maintainership .\n" + + " ?maintainershipURI core:relates ?maintainerURI .\n" + + " ?maintainerURI a foaf:Person .\n" + + " ?maintainerURI rdfs:label ?maintainerName .\n" + + " }\n" + + " UNION\n" + + " {\n" + + " ?subject core:relatedBy ?maintainershipURI .\n" + + " ?maintainershipURI a core:Maintainership .\n" + + " ?maintainershipURI core:rank ?rank.\n" + + " }\n" + + "}\n"; + + private static String MAINTAINERSHIPS_QUERY = "" + + "PREFIX core: \n" + + "PREFIX rdfs: \n" + + "PREFIX foaf: \n" + + + "SELECT ?maintainershipURI (REPLACE(STR(?maintainershipURI),\"^.*(#)(.*)$\", \"$2\") AS ?maintainershipName) " + + "?maintainerURI ?maintainerName ?rank \n" + + "WHERE { \n" + + "?subject core:relatedBy ?maintainershipURI . \n" + + "?maintainershipURI a core:Maintainership . \n" + + "?maintainershipURI core:relates ?maintainerURI . \n" + + "?maintainerURI a foaf:Person . \n" + + "OPTIONAL { ?maintainerURI rdfs:label ?maintainerName } \n" + + "OPTIONAL { ?maintainershipURI core:rank ?rank } \n" + + "} ORDER BY ?rank"; + + + private List getExistingMaintainerships(String subjectUri, VitroRequest vreq) { + RDFService rdfService = vreq.getRDFService(); + + List> maintainerships = new ArrayList>(); + try { + String constructStr = QueryUtils.subUriForQueryVar(MAINTAINERSHIPS_MODEL, "subject", subjectUri); + + Model constructedModel = ModelFactory.createDefaultModel(); + rdfService.sparqlConstructQuery(constructStr, constructedModel); + + String queryStr = QueryUtils.subUriForQueryVar(this.getMaintainershipsQuery(), "subject", subjectUri); + log.debug("Query string is: " + queryStr); + + QueryExecution qe = QueryExecutionFactory.create(queryStr, constructedModel); + try { + ResultSet results = qe.execSelect(); + while (results.hasNext()) { + QuerySolution soln = results.nextSolution(); + RDFNode node = soln.get("maintainershipURI"); + if (node.isURIResource()) { + maintainerships.add(QueryUtils.querySolutionToStringValueMap(soln)); + } + } + } finally { + qe.close(); + } + } catch (Exception e) { + log.error(e, e); + } + log.debug("maintainerships = " + maintainerships); + return getMaintainershipInfo(maintainerships); + } + + private static String MAX_RANK_QUERY = "" + + "PREFIX core: \n" + + "SELECT DISTINCT ?rank WHERE { \n" + + " ?subject core:relatedBy ?maintainership . \n" + + " ?maintainership a core:Maintainership . \n" + + " ?maintainership core:rank ?rank .\n" + + "} ORDER BY DESC(?rank) LIMIT 1"; + + private int getMaxRank(String subjectUri, VitroRequest vreq) { + + int maxRank = 0; // default value + String queryStr = QueryUtils.subUriForQueryVar(this.getMaxRankQueryStr(), "subject", subjectUri); + log.debug("maxRank query string is: " + queryStr); + try { + ResultSet results = QueryUtils.getQueryResults(queryStr, vreq); + if (results != null && results.hasNext()) { // there is at most one result + QuerySolution soln = results.next(); + RDFNode node = soln.get("rank"); + if (node != null && node.isLiteral()) { + // node.asLiteral().getInt() won't return an xsd:string that + // can be parsed as an int. + int rank = Integer.parseInt(node.asLiteral().getLexicalForm()); + if (rank > maxRank) { + log.debug("setting maxRank to " + rank); + maxRank = rank; + } + } + } + } catch (NumberFormatException e) { + log.error("Invalid rank returned from query: not an integer value."); + } catch (Exception e) { + log.error(e, e); + } + log.debug("maxRank is: " + maxRank); + return maxRank; + } + + private List getMaintainershipInfo( + List> maintainerships) { + List info = new ArrayList(); + String maintainershipUri = ""; + String maintainershipName = ""; + String maintainerUri = ""; + String maintainerName = ""; + + for (Map maintainership : maintainerships) { + for (Entry entry : maintainership.entrySet()) { + if (entry.getKey().equals("maintainershipURI")) { + maintainershipUri = entry.getValue(); + } else if (entry.getKey().equals("maintainershipName")) { + maintainershipName = entry.getValue(); + } else if (entry.getKey().equals("maintainerURI")) { + maintainerUri = entry.getValue(); + } else if (entry.getKey().equals("maintainerName")) { + maintainerName = entry.getValue(); + } + } + + MaintainershipInfo aaInfo = + new MaintainershipInfo(maintainershipUri, maintainershipName, maintainerUri, maintainerName); + info.add(aaInfo); + } + log.debug("info = " + info); + return info; + } + + //This is the information about maintainer the form will require + public class MaintainershipInfo { + //This is the maintainership node information + private String maintainershipUri; + private String maintainershipName; + //Maintainer information for maintainership node + private String maintainerUri; + private String maintainerName; + + public MaintainershipInfo(String inputMaintainershipUri, + String inputMaintainershipName, + String inputMaintainerUri, + String inputMaintainerName) { + maintainershipUri = inputMaintainershipUri; + maintainershipName = inputMaintainershipName; + maintainerUri = inputMaintainerUri; + maintainerName = inputMaintainerName; + + } + + //Getters - specifically required for Freemarker template's access to POJO + public String getMaintainershipUri() { + return maintainershipUri; + } + + public String getMaintainershipName() { + return maintainershipName; + } + + public String getMaintainerUri() { + return maintainerUri; + } + + public String getMaintainerName() { + return maintainerName; + } + } + + static final String DEFAULT_NS_TOKEN = null; //null forces the default NS + + protected String getMaxRankQueryStr() { + return MAX_RANK_QUERY; + } + + protected String getMaintainershipsQuery() { + return MAINTAINERSHIPS_QUERY; + } + +} diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddMaintainershipToPersonGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddMaintainershipToPersonGenerator.java new file mode 100644 index 0000000000..aaa821657c --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddMaintainershipToPersonGenerator.java @@ -0,0 +1,212 @@ +/* $This file is distributed under the terms of the license in LICENSE$ */ +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import javax.servlet.http.HttpSession; + +import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldOptions; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.validators.AntiXssValidation; +import edu.cornell.mannlib.vitro.webapp.i18n.I18n; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; +import edu.cornell.mannlib.vitro.webapp.utils.FrontEndEditingUtils.EditMode; +import edu.cornell.mannlib.vitro.webapp.utils.generators.EditModeUtils; +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.rdf.model.RDFNode; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.sparql.resultset.ResultSetMem; +import org.apache.jena.vocabulary.RDF; +import org.apache.jena.vocabulary.XSD; + +public class AddMaintainershipToPersonGenerator extends VivoBaseGenerator implements + EditConfigurationGenerator { + + public AddMaintainershipToPersonGenerator() { + } + + @Override + public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession session) throws Exception { + + if (EditConfigurationUtils.getObjectUri(vreq) == null) { + return doAddNew(vreq, session); + } else { + return doSkipToSoftware(vreq); + } + } + + private EditConfigurationVTwo doSkipToSoftware(VitroRequest vreq) { + Individual maintainershipNode = EditConfigurationUtils.getObjectIndividual(vreq); + + //try to get the software + String softwareQueryStr = "SELECT ?obj \n" + + "WHERE { <" + maintainershipNode.getURI() + "> ?obj . \n" + + " ?obj a . } \n"; + Query softwareQuery = QueryFactory.create(softwareQueryStr); + QueryExecution qe = QueryExecutionFactory.create(softwareQuery, ModelAccess.on(vreq).getOntModel()); + try { + ResultSetMem rs = new ResultSetMem(qe.execSelect()); + if (!rs.hasNext()) { + return doBadMaintainershipNoPub(vreq); + } else if (rs.size() > 1) { + return doBadMaintainershipMultiplePubs(vreq); + } else { + //skip to software + RDFNode objNode = rs.next().get("obj"); + if (!objNode.isResource() || objNode.isAnon()) { + return doBadMaintainershipNoPub(vreq); + } + EditConfigurationVTwo editConfiguration = new EditConfigurationVTwo(); + editConfiguration.setSkipToUrl(UrlBuilder.getIndividualProfileUrl(((Resource) objNode).getURI(), vreq)); + return editConfiguration; + } + } finally { + qe.close(); + } + } + + protected EditConfigurationVTwo doAddNew(VitroRequest vreq, + HttpSession session) throws Exception { + + EditConfigurationVTwo conf = new EditConfigurationVTwo(); + + initBasics(conf, vreq); + initPropertyParameters(vreq, session, conf); + initObjectPropForm(conf, vreq); + + conf.setTemplate("addMaintainershipToPerson.ftl"); + + conf.setVarNameForSubject("person"); + conf.setVarNameForPredicate("predicate"); + conf.setVarNameForObject("maintainership"); + + conf.setN3Required(Arrays.asList(n3ForNewMaintainership)); + conf.setN3Optional(Arrays.asList(n3ForNewSoftwareAssertion, + n3ForExistingSoftwareAssertion)); + + conf.addNewResource("maintainership", DEFAULT_NS_FOR_NEW_RESOURCE); + conf.addNewResource("newSoftware", DEFAULT_NS_FOR_NEW_RESOURCE); + + conf.setUrisOnform(Arrays.asList("existingSoftware", "softwareType")); + conf.setLiteralsOnForm(Arrays.asList("softwareLabel", "softwareLabelDisplay")); + + conf.addSparqlForExistingLiteral("softwareLabel", softwareLabelQuery); + + conf.addSparqlForExistingUris("softwareType", softwareTypeQuery); + conf.addSparqlForExistingUris("existingSoftware", existingSoftwareQuery); + + conf.addField(new FieldVTwo(). + setName("softwareType"). + setValidators(list("nonempty")). + setOptions(getSoftwareTypeLiteralOptions(vreq))); + + conf.addField(new FieldVTwo(). + setName("softwareLabel"). + setRangeDatatypeUri(RDF.dtLangString.getURI()). + setValidators(list("datatype:" + RDF.dtLangString.getURI())) + ); + + conf.addField(new FieldVTwo(). + setName("softwareLabelDisplay"). + setRangeDatatypeUri(XSD.xstring.toString())); + + conf.addValidator(new AntiXssValidation()); + addFormSpecificData(conf, vreq); + + prepare(vreq, conf); + return conf; + } + + /* N3 assertions */ + + final static String n3ForNewMaintainership = + "@prefix vivo: <" + vivoCore + "> . \n" + + "?person ?predicate ?maintainership . \n" + + "?maintainership a vivo:Maintainership . \n" + + "?maintainership vivo:relates ?person . "; + + final static String n3ForNewSoftwareAssertion = + "@prefix vivo: <" + vivoCore + "> . \n" + + "?maintainership vivo:relates ?newSoftware . \n" + + "?newSoftware a ?softwareType . \n" + + "?newSoftware <" + label + "> ?softwareLabel. "; + + final static String n3ForExistingSoftwareAssertion = + "@prefix vivo: <" + vivoCore + "> . \n" + + "?maintainership vivo:relates ?existingSoftware . \n" + + "?existingSoftware a ?softwareType . "; + + /* Queries for editing an existing entry */ + + final static String softwareTypeQuery = + "PREFIX vitro: <" + VitroVocabulary.vitroURI + "> \n" + + "PREFIX vivo: <" + vivoCore + "> . \n" + + "PREFIX bibo: . \n" + + "SELECT ?softwareType WHERE { \n" + + " ?maintainership vivo:relates ?existingSoftware . \n" + + " ?existingSoftware a . \n" + + " ?existingSoftware vitro:mostSpecificType ?softwareType . \n" + + "}"; + + final static String softwareLabelQuery = + "PREFIX vitro: <" + VitroVocabulary.vitroURI + "> \n" + + "PREFIX vivo: <" + vivoCore + "> . \n" + + "PREFIX bibo: . \n" + + "SELECT ?softwareLabel WHERE { \n" + + " ?maintainership vivo:relates ?existingSoftware . \n" + + " ?existingSoftware a . \n" + + " ?existingSoftware <" + label + "> ?softwareLabel . \n" + + "}"; + + final static String existingSoftwareQuery = + "PREFIX vitro: <" + VitroVocabulary.vitroURI + "> \n" + + "PREFIX vivo: <" + vivoCore + "> . \n" + + "PREFIX bibo: . \n" + + "SELECT ?existingSoftware WHERE { \n" + + " ?maintainership vivo:relates ?existingSoftware . \n" + + " ?existingSoftware a . \n" + + "}"; + + //Adding form specific data such as edit mode + public void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + HashMap formSpecificData = new HashMap(); + formSpecificData.put("editMode", getEditMode(vreq).name().toLowerCase()); + editConfiguration.setFormSpecificData(formSpecificData); + } + + public EditMode getEditMode(VitroRequest vreq) { + List predicates = new ArrayList(); + predicates.add("http://vivoweb.org/ontology/core#relates"); + return EditModeUtils.getEditMode(vreq, predicates); + } + + private EditConfigurationVTwo doBadMaintainershipMultiplePubs(VitroRequest vreq) { + // TODO Auto-generated method stub + return null; + } + + private EditConfigurationVTwo doBadMaintainershipNoPub(VitroRequest vreq) { + // TODO Auto-generated method stub + return null; + } + + private FieldOptions getSoftwareTypeLiteralOptions(VitroRequest vreq) throws Exception { + return GeneratorUtil.buildResourceAndLabelFieldOptions( + vreq.getRDFService(), vreq.getWebappDaoFactory(), "", + I18n.bundle(vreq).text("select_type"), + "http://purl.obolibrary.org/obo/ERO_0000071"); + } + +} diff --git a/home/src/main/resources/rdf/i18n/en_US/interface-i18n/firsttime/vivo_UiLabel.ttl b/home/src/main/resources/rdf/i18n/en_US/interface-i18n/firsttime/vivo_UiLabel.ttl index 4530d5572e..20805b4fbd 100644 --- a/home/src/main/resources/rdf/i18n/en_US/interface-i18n/firsttime/vivo_UiLabel.ttl +++ b/home/src/main/resources/rdf/i18n/en_US/interface-i18n/firsttime/vivo_UiLabel.ttl @@ -206,6 +206,14 @@ uil-data:resource_name.VIVO uil:hasKey "resource_name" ; uil:hasPackage "VIVO-languages" . +uil-data:software_name.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "software name"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "software_name" ; + uil:hasPackage "VIVO-languages" . + uil-data:check_grants_to_exclude.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -421,6 +429,14 @@ uil-data:no_linked_editor.VIVO uil:hasKey "no_linked_editor" ; uil:hasPackage "VIVO-languages" . +uil-data:no_linked_maintainer.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "no linked maintainer"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "no_linked_maintainer" ; + uil:hasPackage "VIVO-languages" . + uil-data:level_undefined_error.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -701,6 +717,14 @@ uil-data:editor_capitalized.VIVO uil:hasKey "editor_capitalized" ; uil:hasPackage "VIVO-languages" . +uil-data:maintainer_capitalized.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Maintainer"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "maintainer_capitalized" ; + uil:hasPackage "VIVO-languages" . + uil-data:create_and_link_type_dataset.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -1524,6 +1548,14 @@ uil-data:editor_of_entry.VIVO uil:hasKey "editor_of_entry" ; uil:hasPackage "VIVO-languages" . +uil-data:maintainer_of_entry.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "maintainer of entry for"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "maintainer_of_entry" ; + uil:hasPackage "VIVO-languages" . + uil-data:principal_investigator_entry_for.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -1692,6 +1724,14 @@ uil-data:reordering_editors_failed.VIVO uil:hasKey "reordering_editors_failed" ; uil:hasPackage "VIVO-languages" . +uil-data:reordering_maintainers_failed.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Reordering of maintainers failed."@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "reordering_maintainers_failed" ; + uil:hasPackage "VIVO-languages" . + uil-data:none_of_the.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -1804,6 +1844,14 @@ uil-data:select_document_type.VIVO uil:hasKey "select_document_type" ; uil:hasPackage "VIVO-languages" . +uil-data:select_software_type.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Please select a value in the Software Type field."@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "select_software_type" ; + uil:hasPackage "VIVO-languages" . + uil-data:reordering_authors_failed.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -1996,6 +2044,14 @@ uil-data:editor_name.VIVO uil:hasKey "editor_name" ; uil:hasPackage "VIVO-languages" . +uil-data:maintainer_name.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "maintainer name"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "maintainer_name" ; + uil:hasPackage "VIVO-languages" . + uil-data:harvest_error_instructions_fiveC.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -2100,6 +2156,14 @@ uil-data:selected_document.VIVO uil:hasKey "selected_document" ; uil:hasPackage "VIVO-languages" . +uil-data:selected_software.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Selected Software"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "selected_software" ; + uil:hasPackage "VIVO-languages" . + uil-data:currently_no_grants_for.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -2196,6 +2260,14 @@ uil-data:missing_editor.VIVO uil:hasKey "missing_editor" ; uil:hasPackage "VIVO-languages" . +uil-data:missing_maintainer.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "missing maintainer"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "missing_maintainer" ; + uil:hasPackage "VIVO-languages" . + uil-data:save_all_as_csv.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -2692,6 +2764,14 @@ uil-data:error_processing_editor_request.VIVO uil:hasKey "error_processing_editor_request" ; uil:hasPackage "VIVO-languages" . +uil-data:error_processing_maintainer_request.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Error processing request: maintainer not removed"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "error_processing_maintainer_request" ; + uil:hasPackage "VIVO-languages" . + uil-data:no_matching_science_areas.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -2988,6 +3068,14 @@ uil-data:add_editor.VIVO uil:hasKey "add_editor" ; uil:hasPackage "VIVO-languages" . +uil-data:add_maintainer.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Add Maintainer"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "add_maintainer" ; + uil:hasPackage "VIVO-languages" . + uil-data:published_in.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -3475,6 +3563,14 @@ uil-data:manage_editors.VIVO uil:hasKey "manage_editors" ; uil:hasPackage "VIVO-languages" . +uil-data:manage_maintainers.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Manage Maintainers"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "manage_maintainers" ; + uil:hasPackage "VIVO-languages" . + uil-data:the_capitalized.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -4099,6 +4195,14 @@ uil-data:drag_drop_reorder_editors.VIVO uil:hasKey "drag_drop_reorder_editors" ; uil:hasPackage "VIVO-languages" . +uil-data:drag_drop_reorder_maintainers.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Drag and drop to reorder maintainers"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "drag_drop_reorder_maintainers" ; + uil:hasPackage "VIVO-languages" . + uil-data:create_and_link_submit_confirm.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -4611,6 +4715,14 @@ uil-data:confirm_editor_removal.VIVO uil:hasKey "confirm_editor_removal" ; uil:hasPackage "VIVO-languages" . +uil-data:confirm_maintainer_removal.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Are you sure you want to remove this maintainer:"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "confirm_maintainer_removal" ; + uil:hasPackage "VIVO-languages" . + uil-data:local_research.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -4787,6 +4899,14 @@ uil-data:select_a_document_name.VIVO uil:hasKey "select_a_document_name" ; uil:hasPackage "VIVO-languages" . +uil-data:select_a_software_name.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Please enter or select a value in the Software Name field."@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "select_a_software_name" ; + uil:hasPackage "VIVO-languages" . + uil-data:view_results.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -4923,6 +5043,14 @@ uil-data:return_to_publication.VIVO uil:hasKey "return_to_publication" ; uil:hasPackage "VIVO-languages" . +uil-data:return_to_software.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Return to software"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "return_to_software" ; + uil:hasPackage "VIVO-languages" . + uil-data:published.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -4963,6 +5091,14 @@ uil-data:missing_info_resource.VIVO uil:hasKey "missing_info_resource" ; uil:hasPackage "VIVO-languages" . +uil-data:missing_software.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "missing software"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "missing_software" ; + uil:hasPackage "VIVO-languages" . + uil-data:orcid_return_to_vivo.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -5075,6 +5211,14 @@ uil-data:document_type_capitalized.VIVO uil:hasKey "document_type_capitalized" ; uil:hasPackage "VIVO-languages" . +uil-data:software_type_capitalized.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Software Type"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "software_type_capitalized" ; + uil:hasPackage "VIVO-languages" . + uil-data:faculty_of_1000.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -5099,6 +5243,14 @@ uil-data:selected_editor.VIVO uil:hasKey "selected_editor" ; uil:hasPackage "VIVO-languages" . +uil-data:selected_maintainer.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Selected Maintainer"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "selected_maintainer" ; + uil:hasPackage "VIVO-languages" . + uil-data:view_all_individuals_in_dept.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -5235,6 +5387,14 @@ uil-data:add_an_editor.VIVO uil:hasKey "add_an_editor" ; uil:hasPackage "VIVO-languages" . +uil-data:add_a_maintainer.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Add a Maintainer"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "add_a_maintainer" ; + uil:hasPackage "VIVO-languages" . + uil-data:create_entry_for_attendee_role.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; @@ -5755,6 +5915,14 @@ uil-data:remove_editor_link.VIVO uil:hasKey "remove_editor_link" ; uil:hasPackage "VIVO-languages" . +uil-data:remove_maintainer_link.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "remove maintainer link"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "remove_maintainer_link" ; + uil:hasPackage "VIVO-languages" . + uil-data:email.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; diff --git a/webapp/src/main/webapp/config/listViewConfig-maintainership.xml b/webapp/src/main/webapp/config/listViewConfig-maintainership.xml new file mode 100644 index 0000000000..92215efbee --- /dev/null +++ b/webapp/src/main/webapp/config/listViewConfig-maintainership.xml @@ -0,0 +1,42 @@ + + + + + + + + PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> + PREFIX core: <http://vivoweb.org/ontology/core#> + PREFIX bibo: <http://purl.org/ontology/bibo/> + PREFIX vitro: <http://vitro.mannlib.cornell.edu/ns/vitro/0.7#> + PREFIX foaf: <http://xmlns.com/foaf/0.1/> + + SELECT DISTINCT ?subclass + ?maintainership + ?software ?softwareName + ?dateTime + WHERE + { + ?subject ?property ?maintainership . + ?maintainership a core:Maintainership . + ?maintainership core:relates ?software . + ?software a <http://purl.obolibrary.org/obo/ERO_0000071> . + ?software rdfs:label ?softwareName . + + OPTIONAL { + ?subject ?property ?maintainership . + ?maintainership a core:Maintainership ; + core:relates ?software . + ?software a <http://purl.obolibrary.org/obo/ERO_0000071> . + ?software core:dateTimeValue ?dateTimeValue . + ?dateTimeValue core:dateTime ?dateTime . + } + + + FILTER ( bound(?software) ) + + } ORDER BY DESC(?dateTime) ?softwareName + + + + diff --git a/webapp/src/main/webapp/config/listViewConfig-softwareInMaintainership.xml b/webapp/src/main/webapp/config/listViewConfig-softwareInMaintainership.xml new file mode 100644 index 0000000000..d9e5379a2a --- /dev/null +++ b/webapp/src/main/webapp/config/listViewConfig-softwareInMaintainership.xml @@ -0,0 +1,49 @@ + + + + + + + + PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> + PREFIX core: <http://vivoweb.org/ontology/core#> + PREFIX foaf: <http://xmlns.com/foaf/0.1/> + PREFIX vitro: <http://vitro.mannlib.cornell.edu/ns/vitro/0.7#> + PREFIX fn: <http://www.w3.org/2005/xpath-functions#> + + SELECT DISTINCT ?subclass + ?maintainership + ?person ?personName + WHERE { + ?subject ?property ?maintainership . + ?maintainership a core:Maintainership . + OPTIONAL { + ?subject ?property ?maintainership . + ?maintainership a core:Maintainership . + ?maintainership core:rank ?rank . + } + OPTIONAL { + ?subject ?property ?maintainership . + ?maintainership a core:Maintainership . + ?maintainership core:relates ?person . + ?person a foaf:Person . + ?person rdfs:label ?personName . + } + + OPTIONAL { + ?subject ?property ?maintainership . + ?maintainership a core:Maintainership . + ?maintainership core:relates ?person . + ?person a foaf:Person . + ?person vitro:mostSpecificType ?subclass . + ?subclass rdfs:subClassOf foaf:Person . + } + + + FILTER ( bound(?person) ) + + } ORDER BY ?subclass ?rank (fn:lower-case(?personName)) + + + + diff --git a/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-maintainership.ftl b/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-maintainership.ftl new file mode 100644 index 0000000000..ababf75041 --- /dev/null +++ b/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-maintainership.ftl @@ -0,0 +1,27 @@ +<#-- $This file is distributed under the terms of the license in LICENSE$ --> + +<#-- Custom object property statement view for faux property "editor of". See the PropertyConfig.n3 file for details. + + This template must be self-contained and not rely on other variables set for the individual page, because it + is also used to generate the property statement during a deletion. + --> + +<#import "lib-sequence.ftl" as s> +<#import "lib-datetime.ftl" as dt> + +<@showMaintainership statement /> + +<#-- Use a macro to keep variable assignments local; otherwise the values carry over to the + next statement --> +<#macro showMaintainership statement> + <#local softwareTitle> + <#if statement.software??> + ${statement.softwareName} + <#else> + <#-- This shouldn't happen, but we must provide for it --> + ${i18n().missing_software} + + + + ${softwareTitle} <@dt.yearSpan "${statement.dateTime!}" /> + diff --git a/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-softwareInMaintainership.ftl b/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-softwareInMaintainership.ftl new file mode 100644 index 0000000000..e05f0fc25c --- /dev/null +++ b/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-softwareInMaintainership.ftl @@ -0,0 +1,21 @@ +<#-- $This file is distributed under the terms of the license in LICENSE$ --> + +<#-- Custom object property statement view for faux property "editors". See the PropertyConfig.n3 file for details. + + This template must be self-contained and not rely on other variables set for the individual page, because it + is also used to generate the property statement during a deletion. + --> + +<#import "lib-sequence.ftl" as s> +<@showMaintainership statement /> + +<#-- Use a macro to keep variable assignments local; otherwise the values carry over to the + next statement --> +<#macro showMaintainership statement> + <#if statement.person??> + ${statement.personName} + <#else> + <#-- This shouldn't happen, but we must provide for it --> + ${i18n().missing_maintainer} + + diff --git a/webapp/src/main/webapp/templates/freemarker/edit/forms/addMaintainersToSoftware.ftl b/webapp/src/main/webapp/templates/freemarker/edit/forms/addMaintainersToSoftware.ftl new file mode 100644 index 0000000000..170f7e48ff --- /dev/null +++ b/webapp/src/main/webapp/templates/freemarker/edit/forms/addMaintainersToSoftware.ftl @@ -0,0 +1,178 @@ +<#-- $This file is distributed under the terms of the license in LICENSE$ --> + +<#-- Custom form for adding maintainers to information resources --> + +<#import "lib-vivo-form.ftl" as lvf> + +<#--Retrieve certain page specific information information--> +<#assign newRank = editConfiguration.pageData.newRank /> +<#assign existingMaintainerInfo = editConfiguration.pageData.existingMaintainerInfo /> +<#assign rankPredicate = editConfiguration.pageData.rankPredicate /> + +<#--If edit submission exists, then retrieve validation errors if they exist--> +<#if editSubmission?has_content && editSubmission.submissionExists = true && editSubmission.validationErrors?has_content> + <#assign submissionErrors = editSubmission.validationErrors/> + + +<#--Submission values for these fields may be returned if user did not fill out fields for new person--> +<#assign lastNameValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "lastName") /> +<#assign firstNameValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "firstName") /> +<#assign middleNameValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "middleName") /> + +<#--UL class based on size of existing maintainers--> +<#assign ulClass = ""/> +<#if (existingMaintainerInfo?size > 0)> + <#assign ulClass = "class='dd'"/> + + +<#assign title="${editConfiguration.subjectName}" /> +<#assign requiredHint=" *" /> +<#assign initialHint="(${i18n().initial_okay})" /> + +<@lvf.unsupportedBrowser urls.base/> + +

${title}

+ +<#if submissionErrors?has_content> + + + +

${i18n().manage_maintainers}

+ +
    + + + + +<#assign maintainerHref="/individual?uri=" /> +<#--This should be a list of java objects where URI and name can be retrieved--> +<#list existingMaintainerInfo as maintainership> + <#assign maintainerUri = maintainership.maintainerUri/> + <#assign maintainerName = maintainership.maintainerName/> + +
  • + <#-- span.maintainer will be used in the next phase, when we display a message that the maintainer has been + removed. That text will replace the a.maintainerName, which will be removed. --> + + <#-- This span is here to assign a width to. We can't assign directly to the a.maintainerName, + for the case when it's followed by an em tag - we want the width to apply to the whole thing. --> + + <#if (maintainerUri?length > 0)> + ${maintainerName} + <#else> + ${maintainership.maintainershipName} (${i18n().no_linked_maintainer}) + + + + ${i18n().remove_capitalized} + +
  • + + + +
+
+
+ + + + ${i18n().or} + ${i18n().return_to_software} + +
+ +
+

${i18n().add_a_maintainer}

+ +
+ <#--These wrapper paragraph elements are important because javascript hides parent of these fields, since last name + should be visible even when first name/middle name are not, the parents should be separate for each field--> +

+ + +

+ +

+ + +

+ +

+ + +

+ +
+

+ + + (${i18n().verify_match_capitalized}) + +

+
+
+ + + + + + +

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

+ +

* ${i18n().required_fields}

+
+ + + +${stylesheets.add('', + '', + '', + '')} + + +${scripts.add('')} +${scripts.add('')} +${scripts.add('')} +${scripts.add('')} diff --git a/webapp/src/main/webapp/templates/freemarker/edit/forms/addMaintainershipToPerson.ftl b/webapp/src/main/webapp/templates/freemarker/edit/forms/addMaintainershipToPerson.ftl new file mode 100644 index 0000000000..4fab498e30 --- /dev/null +++ b/webapp/src/main/webapp/templates/freemarker/edit/forms/addMaintainershipToPerson.ftl @@ -0,0 +1,157 @@ +<#-- $This file is distributed under the terms of the license in LICENSE$ --> + +<#-- this is in request.subject.name --> + +<#-- leaving this edit/add mode code in for reference in case we decide we need it --> + +<#import "lib-vivo-form.ftl" as lvf> + +<#assign subjectName=""/> +<#assign orgLabel="mysteryOrgLabel"/> + +<#--Retrieve certain edit configuration information--> +<#assign editMode = editConfiguration.pageData.editMode /> +<#assign htmlForElements = editConfiguration.pageData.htmlForElements /> + +<#--The blank sentinel indicates what value should be put in a URI when no autocomplete result has been selected. +If the blank value is non-null or non-empty, n3 editing for an existing object will remove the original relationship +if nothing is selected for that object--> +<#assign blankSentinel = "" /> +<#if editConfigurationConstants?has_content && editConfigurationConstants?keys?seq_contains("BLANK_SENTINEL")> + <#assign blankSentinel = editConfigurationConstants["BLANK_SENTINEL"] /> + + +<#--This flag is for clearing the label field on submission for an existing object being selected from autocomplete. +Set this flag on the input acUriReceiver where you would like this behavior to occur. --> +<#assign flagClearLabelForExisting = "flagClearLabelForExisting" /> + +<#--Retrieve variables needed--> +<#assign softwareTypeValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "softwareType")/> +<#assign softwareLabelValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "softwareLabel") /> +<#assign softwareLabelDisplayValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "softwareLabelDisplay") /> +<#assign existingSoftwareValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "existingSoftware") /> + +<#--If edit submission exists, then retrieve validation errors if they exist--> +<#if editSubmission?has_content && editSubmission.submissionExists = true && editSubmission.validationErrors?has_content> + <#assign submissionErrors = editSubmission.validationErrors/> + + +<#if editMode == "edit" || editMode == "repair"> + <#assign titleVerb="${i18n().edit_capitalized}"> + <#assign submitButtonText="${i18n().save_changes}"> + <#assign disabledVal="disabled"> +<#else> + <#assign titleVerb="${i18n().create_capitalized}"> + <#assign submitButtonText="${i18n().create_entry}"> + <#assign disabledVal=""/> + + +<#assign requiredHint = " *" /> +<#assign yearHint = "(${i18n().year_hint_format})" /> + + +

${titleVerb} ${i18n().maintainer_of_entry} ${editConfiguration.subjectName}

+ +<#--Display error messages if any--> +<#if submissionErrors?has_content> + <#if orgLabelDisplayValue?has_content > + <#assign orgLabelValue = orgLabelDisplayValue /> + + + + +<@lvf.unsupportedBrowser urls.base /> + +
+ +
+ + +

+ + <#assign softTypeOpts = editConfiguration.pageData.softwareType /> + +

+ +

+ + + +

+ +
+

+ + + (${i18n().verify_match_capitalized} ${i18n().or} + ${i18n().change_selection}) +

+ +
+ + + <#--End draw elements--> + +

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

+ +

* ${i18n().required_fields}

+ +
+ + + + +
+ +${stylesheets.add('')} +${stylesheets.add('')} +${stylesheets.add('')} + + +${scripts.add('', + '', + '', + '', + '', + '')} + + diff --git a/webapp/src/main/webapp/templates/freemarker/edit/forms/js/addMaintainersToSoftware.js b/webapp/src/main/webapp/templates/freemarker/edit/forms/js/addMaintainersToSoftware.js new file mode 100644 index 0000000000..f521c0bd4d --- /dev/null +++ b/webapp/src/main/webapp/templates/freemarker/edit/forms/js/addMaintainersToSoftware.js @@ -0,0 +1,703 @@ +/* $This file is distributed under the terms of the license in LICENSE$ */ + +var addMaintainerForm = { + + /* *** Initial page setup *** */ + + onLoad: function() { + + if (this.disableFormInUnsupportedBrowsers()) { + return; + } + this.mixIn(); + this.initObjects(); + this.initPage(); + }, + + disableFormInUnsupportedBrowsers: function() { + var disableWrapper = $('#ie67DisableWrapper'); + + // Check for unsupported browsers only if the element exists on the page + if (disableWrapper.length) { + if (vitro.browserUtils.isIELessThan8()) { + disableWrapper.show(); + $('.noIE67').hide(); + return true; + } + } + return false; + }, + + mixIn: function() { + // Mix in the custom form utility methods + $.extend(this, vitro.customFormUtils); + + // Get the custom form data from the page + $.extend(this, customFormData); + + // Get the i18n variables from the page + $.extend(this, i18nStrings); + }, + + // On page load, create references for easy access to form elements. + // NB These must be assigned after the elements have been loaded onto the page. + initObjects: function() { + + this.form = $('#addMaintainerForm'); + this.showFormButtonWrapper = $('#showAddForm'); + this.showFormButton = $('#showAddFormButton'); + this.removeMaintainershipLinks = $('a.remove'); + //this.undoLinks = $('a.undo'); + this.submit = this.form.find(':submit'); + this.cancel = this.form.find('.cancel'); + this.acSelector = this.form.find('.acSelector'); + this.labelField = $('#label'); + this.firstNameField = $('#firstName'); + this.middleNameField = $('#middleName'); + this.lastNameField = $('#lastName'); + this.lastNameLabel = $('label[for=lastName]'); + this.personUriField = $('#personUri'); + this.firstNameWrapper = this.firstNameField.parent(); + this.middleNameWrapper = this.middleNameField.parent(); + this.lastNameWrapper = this.lastNameField.parent(); + this.selectedMaintainer = $('#selectedMaintainer'); + this.selectedMaintainerName = $('#selectedMaintainerName'); + this.acHelpTextClass = 'acSelectorWithHelpText'; + this.verifyMatch = this.form.find('.verifyMatch'); + this.personSection = $('section#personFields'); + this.personLink = $('a#personLink'); + this.returnLink = $('a#returnLink'); + }, + + // Initial page setup. Called only at page load. + initPage: function() { + + this.initMaintainershipData(); + + // Show elements hidden by CSS for the non-JavaScript-enabled version. + // NB The non-JavaScript version of this form is currently not functional. + this.removeMaintainershipLinks.show(); + + //this.undoLinks.hide(); + + this.bindEventListeners(); + + this.initAutocomplete(); + + this.initElementData(); + + this.initMaintainerDD(); + + if (this.findValidationErrors()) { + this.initFormAfterInvalidSubmission(); + } else { + this.initMaintainerListOnlyView(); + } + }, + + + /* *** Set up the various page views *** */ + + // This initialization is done only on page load, not when returning to maintainer list only view + // after hitting 'cancel.' + initMaintainerListOnlyView: function() { + + if ($('.maintainership').length) { // make sure we have at least one maintainer + // Reorder maintainers on page load so that previously unranked maintainers get a rank. Otherwise, + // when we add a new maintainer, it will get put ahead of any previously unranked maintainers, instead + // of at the end of the list. (It is also helpful to normalize the data before we get started.) + this.reorderMaintainers(); + } + this.showMaintainerListOnlyView(); + }, + + // This view shows the list of existing maintainers and hides the form. + // There is a button to show the form. We do this on page load, and after + // hitting 'cancel' from full view. + showMaintainerListOnlyView: function() { + this.hideForm(); + this.showFormButtonWrapper.show(); + }, + + // View of form after returning from an invalid submission. On this form, + // validation errors entail that we were entering a new person, so we show + // all the fields straightaway. + initFormAfterInvalidSubmission: function() { + this.initForm(); + this.showFieldsForNewPerson(); + }, + + // Initial view of add maintainer form. We get here by clicking the show form button, + // or by cancelling out of an autocomplete selection. + initFormView: function() { + + this.initForm(); + + // There's a conflict bewteen the last name fields .blur event and the cancel + // button's click. So display the middle and first names along with the last name tlw72 + //this.hideFieldsForNewPerson(); + + // This shouldn't be needed, because calling this.hideFormFields(this.lastNameWrapper) + // from showSelectedMaintainer should do it. However, it doesn't work from there, + // or in the cancel action, or if referring to this.lastNameField. None of those work, + // however. + $('#lastName').val(''); + // Set the initial autocomplete help text in the acSelector field. + this.addAcHelpText(this.acSelector); + + return false; + + }, + + // Form initialization common to both a 'clean' form view and when + // returning from an invalid submission. + initForm: function() { + + // Hide the button that shows the form + this.showFormButtonWrapper.hide(); + + this.hideSelectedPerson(); + + this.cancel.unbind('click'); + this.cancel.bind('click', function() { + addMaintainerForm.showMaintainerListOnlyView(); + addMaintainerForm.setMaintainerType("person"); + return false; + }); + + // Reset the last name field. It had been hidden if we selected an maintainer from + // the autocomplete field. + this.lastNameWrapper.show(); + this.showFieldsForNewPerson(); + + // Show the form + this.form.show(); + //this.lastNameField.focus(); + }, + + hideSelectedPerson: function() { + this.selectedMaintainer.hide(); + this.selectedMaintainerName.html(''); + this.personUriField.val(''); + }, + + showFieldsForNewPerson: function() { + this.firstNameWrapper.show(); + this.middleNameWrapper.show(); + }, + + hideFieldsForNewPerson: function() { + this.hideFields(this.firstNameWrapper); + this.hideFields(this.middleNameWrapper); + }, + + /* *** Ajax initializations *** */ + + /* Autocomplete */ + initAutocomplete: function() { + + // Make cache a property of this so we can access it after removing + // an maintainer. + this.acCache = {}; + this.setAcFilter(); + var $acField = this.lastNameField; + var urlString = addMaintainerForm.acUrl + addMaintainerForm.personUrl + addMaintainerForm.tokenize; + var authType = "person"; + + $acField.autocomplete({ + minLength: 2, + source: function(request, response) { + if (request.term in addMaintainerForm.acCache) { + // console.log('found term in cache'); + response(addMaintainerForm.acCache[request.term]); + return; + } + // console.log('not getting term from cache'); + + // If the url query params are too long, we could do a post + // here instead of a get. Add the exclude uris to the data + // rather than to the url. + $.ajax({ + url: urlString, + dataType: 'json', + data: { + term: request.term + }, + complete: function(xhr, status) { + // Not sure why, but we need an explicit json parse here. jQuery + // should parse the response text and return a json object. + var results = jQuery.parseJSON(xhr.responseText), + filteredResults = addMaintainerForm.filterAcResults(results); + addMaintainerForm.acCache[request.term] = filteredResults; + response(filteredResults); + } + + }); + }, + // Select event not triggered in IE6/7 when selecting with enter key rather + // than mouse. Thus form is disabled in these browsers. + // jQuery UI bug: when scrolling through the ac suggestions with up/down arrow + // keys, the input element gets filled with the highlighted text, even though no + // select event has been triggered. To trigger a select, the user must hit enter + // or click on the selection with the mouse. This appears to confuse some users. + select: function(event, ui) { + addMaintainerForm.showSelectedMaintainer(ui,authType); + } + }); + + }, + + initElementData: function() { + this.verifyMatch.data('baseHref', this.verifyMatch.attr('href')); + }, + + setAcFilter: function() { + this.acFilter = []; + + $('.maintainership').each(function() { + var uri = $(this).data('maintainerUri'); + addMaintainerForm.acFilter.push(uri); + }); + }, + + removeMaintainerFromAcFilter: function(maintainer) { + var index = $.inArray(maintainer, this.acFilter); + if (index > -1) { // this should always be true + this.acFilter.splice(index, 1); + } + }, + + filterAcResults: function(results) { + var filteredResults = []; + if (!this.acFilter.length) { + return results; + } + $.each(results, function() { + if ($.inArray(this.uri, addMaintainerForm.acFilter) == -1) { + // console.log("adding " + this.label + " to filtered results"); + filteredResults.push(this); + } + else { + // console.log("filtering out " + this.label); + } + }); + return filteredResults; + }, + + // After removing an maintainership, selectively clear matching autocomplete + // cache entries, else the associated maintainer will not be included in + // subsequent autocomplete suggestions. + clearAcCacheEntries: function(name) { + name = name.toLowerCase(); + $.each(this.acCache, function(key, value) { + if (name.indexOf(key) == 0) { + delete addMaintainerForm.acCache[key]; + } + }); + }, + + // Action taken after selecting an maintainer from the autocomplete list + showSelectedMaintainer: function(ui,authType) { + + if ( authType == "person" ) { + this.personUriField.val(ui.item.uri); + this.selectedMaintainer.show(); + + // Transfer the name from the autocomplete to the selected maintainer + // name display, and hide the last name field. + this.selectedMaintainerName.html(ui.item.label); + // NB For some reason this doesn't delete the value from the last name + // field when the form is redisplayed. Thus it's done explicitly in initFormView. + this.hideFields(this.lastNameWrapper); + // These get displayed if the selection was made through an enter keystroke, + // since the keydown event on the last name field is also triggered (and + // executes first). So re-hide them here. + this.hideFieldsForNewPerson(); + this.personLink.attr('href', this.verifyMatch.data('baseHref') + ui.item.uri); + } + + // Cancel restores initial form view + this.cancel.unbind('click'); + this.cancel.bind('click', function() { + addMaintainerForm.initFormView(); + addMaintainerForm.setMaintainerType(authType); + return false; + }); + }, + + /* Drag-and-drop */ + initMaintainerDD: function() { + + var maintainershipList = $('#dragDropList'), + maintainerships = maintainershipList.children('li'); + + if (maintainerships.length < 2) { + return; + } + + $('.maintainerNameWrapper').each(function() { + $(this).attr('title', addMaintainerForm.maintainerNameWrapperTitle); + }); + + maintainershipList.sortable({ + cursor: 'move', + update: function(event, ui) { + addMaintainerForm.reorderMaintainers(event, ui); + } + }); + }, + + // Reorder maintainers. Called on page load and after maintainer drag-and-drop and remove. + // Event and ui parameters are defined only in the case of drag-and-drop. + reorderMaintainers: function(event, ui) { + var maintainerships = $('li.maintainership').map(function(index, el) { + return $(this).data('maintainershipUri'); + }).get(); + + $.ajax({ + url: addMaintainerForm.reorderUrl, + data: { + predicate: addMaintainerForm.rankPredicate, + individuals: maintainerships + }, + traditional: true, // serialize the array of individuals for the server + dataType: 'json', + type: 'POST', + success: function(data, status, request) { + var pos; + $('.maintainership').each(function(index){ + pos = index + 1; + // Set the new position for this element. The only function of this value + // is so we can reset an element to its original position in case reordering fails. + addMaintainerForm.setPosition(this, pos); + }); + // Set the form rank field value. + $('#rank').val(pos + 1); + }, + error: function(request, status, error) { + // ui is undefined on page load and after an maintainership removal. + if (ui) { + // Put the moved item back to its original position. + // Seems we need to do this by hand. Can't see any way to do it with jQuery UI. ?? + var pos = addMaintainerForm.getPosition(ui.item), + nextpos = pos + 1, + maintainerships = $('#dragDropList'), + next = addMaintainerForm.findMaintainership('position', nextpos); + + if (next.length) { + ui.item.insertBefore(next); + } + else { + ui.item.appendTo(maintainerships); + } + + alert(addMaintainerForm.reorderMaintainersAlert); + } + } + }); + }, + + // On page load, associate data with each maintainership element. Then we don't + // have to keep retrieving data from or modifying the DOM as we manipulate the + // maintainerships. + initMaintainershipData: function() { + $('.maintainership').each(function(index) { + $(this).data(maintainershipData[index]); + + // RY We might still need position to put back an element after reordering + // failure. Rank might already have been reset? Check. + // We also may need position to implement undo links: we want the removed maintainership + // to show up in the list, but it has no rank. + $(this).data('position', index+1); + }); + }, + + getPosition: function(maintainership) { + return $(maintainership).data('position'); + }, + + setPosition: function(maintainership, pos) { + $(maintainership).data('position', pos); + }, + + findMaintainership: function(key, value) { + var matchingMaintainership = $(); // if we don't find one, return an empty jQuery set + + $('.maintainership').each(function() { + var maintainership = $(this); + if ( maintainership.data(key) === value ) { + matchingMaintainership = maintainership; + return false; // stop the loop + } + }); + + return matchingMaintainership; + }, + + + /* *** Event listeners *** */ + + bindEventListeners: function() { + + this.showFormButton.click(function() { + addMaintainerForm.initFormView(); + return false; + }); + + this.form.submit(function() { + // NB Important JavaScript scope issue: if we call it this way, this = addMaintainerForm + // in prepareSubmit. If we do this.form.submit(this.prepareSubmit); then + // this != addMaintainerForm in prepareSubmit. + $selectedObj = addMaintainerForm.form.find('input.acSelector'); + addMaintainerForm.deleteAcHelpText($selectedObj); + addMaintainerForm.prepareSubmit(); + }); + + this.lastNameField.blur(function() { + // Cases where this event should be ignored: + // 1. personUri field has a value: the autocomplete select event has already fired. + // 2. The last name field is empty (especially since the field has focus when the form is displayed). + // 3. Autocomplete suggestions are showing. + if ( addMaintainerForm.personUriField.val() || !$(this).val() || $('ul.ui-autocomplete li.ui-menu-item').length ) { + return; + } + addMaintainerForm.onLastNameChange(); + }); + + this.personLink.click(function() { + window.open($(this).attr('href'), 'verifyMatchWindow', 'width=640,height=640,scrollbars=yes,resizable=yes,status=yes,toolbar=no,menubar=no,location=no'); + return false; + }); + + this.acSelector.focus(function() { + addMaintainerForm.deleteAcHelpText(this); + }); + + this.acSelector.blur(function() { + addMaintainerForm.addAcHelpText(this); + }); + + // When hitting enter in last name field, show first and middle name fields. + // NB This event fires when selecting an autocomplete suggestion with the enter + // key. Since it fires first, we undo its effects in the ac select event listener. + this.lastNameField.keydown(function(event) { + if (event.which === 13) { + addMaintainerForm.onLastNameChange(); + return false; // don't submit form + } + }); + + this.removeMaintainershipLinks.click(function() { + addMaintainerForm.removeMaintainership(this); + return false; + }); + + }, + + prepareSubmit: function() { + var firstName, + middleName, + lastName, + name; + + // If selecting an existing person, don't submit name fields + if (this.personUriField.val() != '' ) { + this.firstNameField.attr('disabled', 'disabled'); + this.middleNameField.attr('disabled', 'disabled'); + this.lastNameField.attr('disabled', 'disabled'); + } + else { + firstName = this.firstNameField.val(); + middleName = this.middleNameField.val(); + lastName = this.lastNameField.val(); + + name = lastName; + if (firstName) { + name += ', ' + firstName; + } + if (middleName) { + name += ' ' + middleName; + } + + this.labelField.val(name); + } + + }, + + onLastNameChange: function() { + this.showFieldsForNewPerson(); + this.firstNameField.focus(); + // this.fixNames(); + }, + + removeMaintainership: function(link) { + // RY Upgrade this to a modal window + + maintainerName = $(link).prev().children().text(); + + var removeLast = false, + message = addMaintainerForm.removeMaintainershipMessage + '\n\n' + maintainerName + ' ?\n\n'; + if (!confirm(message)) { + return false; + } + + if ( addMaintainerForm.showFormButtonWrapper.is(':visible') ) { + addMaintainerForm.returnLink.hide(); + $('img#indicatorOne').removeClass('hidden'); + addMaintainerForm.showFormButton.addClass('disabledSubmit'); + addMaintainerForm.showFormButton.attr('disabled','disabled'); + } + else { + addMaintainerForm.cancel.hide(); + $('img#indicatorTwo').removeClass('hidden'); + addMaintainerForm.submit.addClass('disabledSubmit'); + addMaintainerForm.submit.attr('disabled','disabled'); + } + + if ($(link)[0] === $('.remove:last')[0]) { + removeLast = true; + } + + $.ajax({ + url: $(link).attr('href'), + type: 'POST', + data: { + deletion: $(link).parents('.maintainership').data('maintainershipUri') + }, + dataType: 'json', + context: link, // context for callback + complete: function(request, status) { + var maintainership, + maintainerUri; + + if (status === 'success') { + + maintainership = $(this).parents('.maintainership'); + + // Clear autocomplete cache entries matching this maintainer's name, else + // autocomplete will be retrieved from the cache, which excludes the removed maintainer. + addMaintainerForm.clearAcCacheEntries(maintainership.data('maintainerName')); + + // Remove this maintainer from the acFilter so it is included in autocomplete + // results again. + addMaintainerForm.removeMaintainerFromAcFilter(maintainership.data('maintainerUri')); + + maintainership.fadeOut(400, function() { + var numMaintainers; + + // For undo link: add to a deletedMaintainerships array + + // Remove from the DOM + $(this).remove(); + + // Actions that depend on the maintainer having been removed from the DOM: + numMaintainers = $('.maintainership').length; // retrieve the length after removing maintainership from the DOM + + // If removed item not last, reorder to remove any gaps + if (numMaintainers > 0 && ! removeLast) { + addMaintainerForm.reorderMaintainers(); + } + + // If fewer than two maintainers remaining, disable drag-drop + if (numMaintainers < 2) { + addMaintainerForm.disableMaintainerDD(); + } + + if ( $('img#indicatorOne').is(':visible') ) { + $('img#indicatorOne').fadeOut(100, function() { + $(this).addClass('hidden'); + }); + + addMaintainerForm.returnLink.fadeIn(100, function() { + $(this).show(); + }); + addMaintainerForm.showFormButton.removeClass('disabledSubmit'); + addMaintainerForm.showFormButton.attr('disabled',false); + } + else { + $('img#indicatorTwo').fadeOut(100, function() { + $(this).addClass('hidden'); + }); + + addMaintainerForm.cancel.fadeIn(100, function() { + $(this).show(); + }); + addMaintainerForm.submit.removeClass('disabledSubmit'); + addMaintainerForm.submit.attr('disabled',false); + } + }); + + } else { + alert(addMaintainerForm.removeMaintainershipAlert); + + } + } + }); + }, + + // Disable DD and associated cues if only one maintainer remains + disableMaintainerDD: function() { + var maintainerships = $('#dragDropList'), + maintainerNameWrapper = $('.maintainerNameWrapper'); + + maintainerships.sortable({ disable: true } ); + + // Use class dd rather than jQuery UI's class ui-sortable, so that we can remove + // the class if there's fewer than one maintainer. We don't want to remove the ui-sortable + // class, in case we want to re-enable DD without a page reload (e.g., if implementing + // adding an maintainer via Ajax request). + maintainerships.removeClass('dd'); + + maintainerNameWrapper.removeAttr('title'); + }, + + // RY To be implemented later. + toggleRemoveLink: function() { + // when clicking remove: remove the maintainer, and change link text to 'undo' + // when clicking undo: add the maintainer back, and change link text to 'remove' + }, + + // Set the initial help text in the lastName field and change the class name. + addAcHelpText: function(selectedObj) { + var typeText; + if ( $(selectedObj).attr('id') == "lastName" ) { + typeText = addMaintainerForm.maintainerTypeText; + } + + if (!$(selectedObj).val()) { + $(selectedObj).val(addMaintainerForm.helpTextSelect + " " + typeText + " " + addMaintainerForm.helpTextAdd) + .addClass(this.acHelpTextClass); + } + }, + + deleteAcHelpText: function(selectedObj) { + if ($(selectedObj).hasClass(this.acHelpTextClass)) { + $(selectedObj).val('') + .removeClass(this.acHelpTextClass); + } + }, + + // we need to set the correct class names for fields like the acSelector, acSelection, etc. + // as well as clear and disable fields, call other functions ... + setMaintainerType: function(authType) { + if ( authType == "person" ) { + this.personSection.show(); + this.acSelector.addClass("acSelector"); + this.personRadio.prop('checked', true); // needed for reset when cancel button is clicked + this.selectedMaintainer.addClass("acSelection"); + this.selectedMaintainerName.addClass("acSelectionInfo"); + this.personLink.addClass("verifyMatch"); + this.acSelector.attr('disabled', false); + this.firstNameField.attr('disabled', false); + this.middleNameField.attr('disabled', false); + this.lastNameField.attr('disabled', false); + + addMaintainerForm.addAcHelpText(this.acSelector); + addMaintainerForm.initAutocomplete(); + } + } +}; + +$(document).ready(function() { + addMaintainerForm.onLoad(); +}); From 11c030d4dd180d606d29da18400b805b82758fa3 Mon Sep 17 00:00:00 2001 From: Dragan Ivanovic Date: Mon, 8 Jul 2024 13:17:51 +0200 Subject: [PATCH 3/3] Some bugs fixed for Maintainers of Software --- .../AddMaintainershipToPersonGenerator.java | 12 ++-- .../rdf/display/firsttime/PropertyConfig.n3 | 69 ++++++++++--------- .../interface-i18n/firsttime/vivo_UiLabel.ttl | 8 +++ .../resources/rdf/tbox/filegraph/vivo.owl | 32 ++++----- .../rdf/tbox/firsttime/vitroAnnotations.n3 | 42 +++++++++++ ...propStatement-softwareInMaintainership.ftl | 2 +- 6 files changed, 107 insertions(+), 58 deletions(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddMaintainershipToPersonGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddMaintainershipToPersonGenerator.java index aaa821657c..47baa6e1a9 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddMaintainershipToPersonGenerator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddMaintainershipToPersonGenerator.java @@ -59,14 +59,14 @@ private EditConfigurationVTwo doSkipToSoftware(VitroRequest vreq) { try { ResultSetMem rs = new ResultSetMem(qe.execSelect()); if (!rs.hasNext()) { - return doBadMaintainershipNoPub(vreq); + return doBadMaintainershipNoSoftware(vreq); } else if (rs.size() > 1) { - return doBadMaintainershipMultiplePubs(vreq); + return doBadMaintainershipMultipleSoftware(vreq); } else { //skip to software RDFNode objNode = rs.next().get("obj"); if (!objNode.isResource() || objNode.isAnon()) { - return doBadMaintainershipNoPub(vreq); + return doBadMaintainershipNoSoftware(vreq); } EditConfigurationVTwo editConfiguration = new EditConfigurationVTwo(); editConfiguration.setSkipToUrl(UrlBuilder.getIndividualProfileUrl(((Resource) objNode).getURI(), vreq)); @@ -192,13 +192,11 @@ public EditMode getEditMode(VitroRequest vreq) { return EditModeUtils.getEditMode(vreq, predicates); } - private EditConfigurationVTwo doBadMaintainershipMultiplePubs(VitroRequest vreq) { - // TODO Auto-generated method stub + private EditConfigurationVTwo doBadMaintainershipMultipleSoftware(VitroRequest vreq) { return null; } - private EditConfigurationVTwo doBadMaintainershipNoPub(VitroRequest vreq) { - // TODO Auto-generated method stub + private EditConfigurationVTwo doBadMaintainershipNoSoftware(VitroRequest vreq) { return null; } diff --git a/home/src/main/resources/rdf/display/firsttime/PropertyConfig.n3 b/home/src/main/resources/rdf/display/firsttime/PropertyConfig.n3 index 0ae6d4d9cb..be724ba303 100644 --- a/home/src/main/resources/rdf/display/firsttime/PropertyConfig.n3 +++ b/home/src/main/resources/rdf/display/firsttime/PropertyConfig.n3 @@ -725,7 +725,7 @@ local:maintainerOfConfig a :ObjectPropertyDisplayConfig ; vitro:displayRankAnnot 21; vitro:hiddenFromDisplayBelowRoleLevelAnnot role:public ; vitro:prohibitedFromUpdateBelowRoleLevelAnnot role:public ; - vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.AddMaintainorshipsToPersonGenerator"^^ ; + vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.AddMaintainershipToPersonGenerator"^^ ; :propertyGroup . @@ -1075,39 +1075,6 @@ local:webpageSoftwareConfig a :ObjectPropertyDisplayConfig ; vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.ManageWebpagesForIndividualGenerator"^^ ; :propertyGroup . -local:codeRepositorySoftwareContext a :ConfigContext ; - :hasConfiguration local:codeRepositorySoftwareConfig ; - :configContextFor ; - :qualifiedByDomain ; - :qualifiedByRoot ; - :qualifiedBy . - -local:codeRepositorySoftwareConfig a :ObjectPropertyDisplayConfig ; - :listViewConfigFile "listViewConfig-repositoryLink.xml"^^xsd:string ; - :displayName "code repository" ; - vitro:displayRankAnnot 10; - vitro:hiddenFromDisplayBelowRoleLevelAnnot role:public ; - vitro:prohibitedFromUpdateBelowRoleLevelAnnot role:public ; - vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.ManageWebpagesForIndividualGenerator"^^ ; - :propertyGroup . - -local:downloadUrlSoftwareContext a :ConfigContext ; - :hasConfiguration local:downloadUrlSoftwareConfig ; - :configContextFor ; - :qualifiedByDomain ; - :qualifiedByRoot ; - :qualifiedBy . - -local:downloadUrlSoftwareConfig a :ObjectPropertyDisplayConfig ; - :listViewConfigFile "listViewConfig-downloadLink.xml"^^xsd:string ; - :displayName "download URL" ; - vitro:displayRankAnnot 5; - vitro:hiddenFromDisplayBelowRoleLevelAnnot role:public ; - vitro:prohibitedFromUpdateBelowRoleLevelAnnot role:public ; - vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.ManageWebpagesForIndividualGenerator"^^ ; - :propertyGroup . - - local:webpageFacilityContext a :ConfigContext ; :hasConfiguration local:webpageFacilityConfig ; :configContextFor ; @@ -1293,6 +1260,40 @@ local:documentPartOfConfig a :ObjectPropertyDisplayConfig ; vitro:offerCreateNewOptionAnnot "true"^^xsd:boolean ; :propertyGroup . +local:softwareHasPartContext a :ConfigContext ; + :hasConfiguration local:softwareHasPartConfig ; + :configContextFor ; + :qualifiedByDomain ; + :qualifiedBy . + +local:softwareHasPartConfig a :ObjectPropertyDisplayConfig ; + :listViewConfigFile "listViewConfig-fauxPropertyDefault.xml"^^xsd:string ; + rdfs:label "softwareHasPart"@en-US; + :displayName "has software part" ; + vitro:displayRankAnnot 51; + vitro:hiddenFromDisplayBelowRoleLevelAnnot role:public ; + vitro:prohibitedFromUpdateBelowRoleLevelAnnot role:public ; + vitro:selectFromExistingAnnot "true"^^xsd:boolean ; + vitro:offerCreateNewOptionAnnot "true"^^xsd:boolean ; + :propertyGroup . + +local:softwarePartOfContext a :ConfigContext ; + :hasConfiguration local:softwarePartOfConfig ; + :configContextFor ; + :qualifiedByDomain ; + :qualifiedBy . + +local:softwarePartOfConfig a :ObjectPropertyDisplayConfig ; + :listViewConfigFile "listViewConfig-fauxPropertyDefault.xml"^^xsd:string ; + rdfs:label "softwarePartOf"@en-US; + :displayName "part of other software" ; + vitro:displayRankAnnot 52; + vitro:hiddenFromDisplayBelowRoleLevelAnnot role:public ; + vitro:prohibitedFromUpdateBelowRoleLevelAnnot role:public ; + vitro:selectFromExistingAnnot "true"^^xsd:boolean ; + vitro:offerCreateNewOptionAnnot "true"^^xsd:boolean ; + :propertyGroup . + local:geographicLocationContainsLocationContext a :ConfigContext ; :hasConfiguration local:geographicLocationContainsLocationConfig ; :configContextFor ; diff --git a/home/src/main/resources/rdf/i18n/en_US/interface-i18n/firsttime/vivo_UiLabel.ttl b/home/src/main/resources/rdf/i18n/en_US/interface-i18n/firsttime/vivo_UiLabel.ttl index 20805b4fbd..ee4454b399 100644 --- a/home/src/main/resources/rdf/i18n/en_US/interface-i18n/firsttime/vivo_UiLabel.ttl +++ b/home/src/main/resources/rdf/i18n/en_US/interface-i18n/firsttime/vivo_UiLabel.ttl @@ -2596,6 +2596,14 @@ uil-data:document_name_capitalized.VIVO uil:hasKey "document_name_capitalized" ; uil:hasPackage "VIVO-languages" . +uil-data:software_name_capitalized.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Software Name"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "software_name_capitalized" ; + uil:hasPackage "VIVO-languages" . + uil-data:add_author.VIVO rdf:type owl:NamedIndividual ; rdf:type uil:UILabel ; diff --git a/home/src/main/resources/rdf/tbox/filegraph/vivo.owl b/home/src/main/resources/rdf/tbox/filegraph/vivo.owl index 226addd31d..1b63619763 100644 --- a/home/src/main/resources/rdf/tbox/filegraph/vivo.owl +++ b/home/src/main/resources/rdf/tbox/filegraph/vivo.owl @@ -6492,7 +6492,23 @@ To enable other Gender/Sex codes to be used, this dataproperty has range URI. Th + + download URL + + + + + code repository URL + + + + + + license URL + + + @@ -9719,22 +9735,6 @@ This class allows for linking an author to a publication while indicating inform F1000 is a place where faculty go to critique papers published in PubMed. Any given record in F1000 might have anywhere from one to dozens of reviews. - - - - Download Link - - Download link is an URL for downloading dataset, scholarly output, software, etc. - - - - - - Repository Link - - Repository link is an URL for accessing repository record, e.g. a GitHub repository for a software. - - diff --git a/home/src/main/resources/rdf/tbox/firsttime/vitroAnnotations.n3 b/home/src/main/resources/rdf/tbox/firsttime/vitroAnnotations.n3 index f33e4c0517..b0654ac370 100644 --- a/home/src/main/resources/rdf/tbox/firsttime/vitroAnnotations.n3 +++ b/home/src/main/resources/rdf/tbox/firsttime/vitroAnnotations.n3 @@ -2533,6 +2533,48 @@ vivo:Relationship vitro:prohibitedFromUpdateBelowRoleLevelAnnot . +vivo:downloadURL + vitro:displayLimitAnnot + "1"^^xsd:int ; + vitro:displayRankAnnot + "25"^^xsd:int ; + vitro:hiddenFromDisplayBelowRoleLevelAnnot + ; + vitro:hiddenFromPublishBelowRoleLevelAnnot + ; + vitro:prohibitedFromUpdateBelowRoleLevelAnnot + ; + vitro:inPropertyGroupAnnot + . + +vivo:codeRepositoryURL + vitro:displayLimitAnnot + "1"^^xsd:int ; + vitro:displayRankAnnot + "26"^^xsd:int ; + vitro:hiddenFromDisplayBelowRoleLevelAnnot + ; + vitro:hiddenFromPublishBelowRoleLevelAnnot + ; + vitro:prohibitedFromUpdateBelowRoleLevelAnnot + ; + vitro:inPropertyGroupAnnot + . + +vivo:licenseURL + vitro:displayLimitAnnot + "1"^^xsd:int ; + vitro:displayRankAnnot + "27"^^xsd:int ; + vitro:hiddenFromDisplayBelowRoleLevelAnnot + ; + vitro:hiddenFromPublishBelowRoleLevelAnnot + ; + vitro:prohibitedFromUpdateBelowRoleLevelAnnot + ; + vitro:inPropertyGroupAnnot + . + obo:ERO_0000045 vitro:displayLimitAnnot "1"^^xsd:int ; diff --git a/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-softwareInMaintainership.ftl b/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-softwareInMaintainership.ftl index e05f0fc25c..9b58c8ce31 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-softwareInMaintainership.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-softwareInMaintainership.ftl @@ -16,6 +16,6 @@ ${statement.personName} <#else> <#-- This shouldn't happen, but we must provide for it --> - ${i18n().missing_maintainer} + ${i18n().missing_maintainer}