diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddAuthorsToInformationResourceGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddAuthorsToInformationResourceGenerator.java index 1fc93f697a..49db16e8d1 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddAuthorsToInformationResourceGenerator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddAuthorsToInformationResourceGenerator.java @@ -41,7 +41,14 @@ * It is intended to always be an add, and never an update. */ public class AddAuthorsToInformationResourceGenerator extends VivoBaseGenerator implements EditConfigurationGenerator { - public static Log log = LogFactory.getLog(AddAuthorsToInformationResourceGenerator.class); + + private static Log log = LogFactory.getLog(AddAuthorsToInformationResourceGenerator.class); + + private static final String prefixes = + "@prefix core: <" + vivoCore + "> .\n" + + "@prefix foaf: <" + foaf + "> . \n"; + private static final String vcardFailPattern = "@prefix fail_pattern: ?createVCard .\n"; + private static final String personInstanceFailPattern = "@prefix fail_pattern: ?createPersonInstance .\n"; @Override public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, @@ -59,7 +66,7 @@ public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, editConfiguration.setVarNameForObject("authorshipUri"); // Required N3 - editConfiguration.setN3Required( list( getN3NewAuthorship() ) ); + editConfiguration.setN3Required( list( newAuthorship ) ); // Optional N3 editConfiguration.setN3Optional( generateN3Optional()); @@ -98,47 +105,39 @@ public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, 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 void setUrlToReturnTo(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + editConfiguration.setUrlPatternToReturnTo(EditConfigurationUtils.getFormUrlWithoutContext(vreq)); + } - private String getN3NewAuthorship() { - return getN3PrefixString() + - "?authorshipUri a core:Authorship ;\n" + + private static final String newAuthorship = prefixes + + "?authorshipUri a core:Authorship ;\n" + " core:relates ?infoResource .\n" + "?infoResource core:relatedBy ?authorshipUri ."; - } - private String getN3AuthorshipRank() { - return getN3PrefixString() + + private static final String authorshipRank = prefixes + "?authorshipUri core:rank ?rank ."; - } - - //first name, middle name, last name, and new perseon for new author being created, and n3 for existing person - //if existing person selected as author - public List generateN3Optional() { - return list( - getN3NewPersonFirstName() , - getN3NewPersonMiddleName(), - getN3NewPersonLastName(), - getN3NewPerson(), - getN3AuthorshipRank(), - getN3ForExistingPerson(), - getN3NewOrg(), - getN3ForExistingOrg()); - - } - - - private String getN3NewPersonFirstName() { - return getN3PrefixString() + + + //first name, middle name, last name, and new perseon for new author being created, and n3 for existing person + //if existing person selected as author + private List generateN3Optional() { + return list( + newPersonFirstName , + newPersonMiddleName, + newPersonLastName, + newPerson, + + newPersonVCardFirstName , + newPersonVCardMiddleName, + newPersonVCardLastName, + newPersonVCard, + + authorshipRank, + existingPerson, + newOrg, + existingOrg); + } + + private static final String newPersonFirstName = prefixes + personInstanceFailPattern + "@prefix vcard: . \n" + "?newPerson ?vcardPerson . \n" + "?vcardPerson ?newPerson . \n" + @@ -146,10 +145,8 @@ private String getN3NewPersonFirstName() { "?vcardPerson vcard:hasName ?vcardName . \n" + "?vcardName a . \n" + "?vcardName vcard:givenName ?firstName ."; - } - private String getN3NewPersonMiddleName() { - return getN3PrefixString() + + private static final String newPersonMiddleName = prefixes + personInstanceFailPattern + "@prefix vcard: . \n" + "?newPerson ?vcardPerson . \n" + "?vcardPerson ?newPerson . \n" + @@ -157,10 +154,8 @@ private String getN3NewPersonMiddleName() { "?vcardPerson vcard:hasName ?vcardName . \n" + "?vcardName a vcard:Name . \n" + "?vcardName ?middleName ."; - } - private String getN3NewPersonLastName() { - return getN3PrefixString() + + private static final String newPersonLastName = prefixes + personInstanceFailPattern + "@prefix vcard: . \n" + "?newPerson ?vcardPerson . \n" + "?vcardPerson ?newPerson . \n" + @@ -168,247 +163,260 @@ private String getN3NewPersonLastName() { "?vcardPerson vcard:hasName ?vcardName . \n" + "?vcardName a . \n" + "?vcardName vcard:familyName ?lastName ."; - } - private String getN3NewPerson() { - return getN3PrefixString() + + private static final String newPerson = prefixes + personInstanceFailPattern + "?newPerson a foaf:Person ;\n" + "<" + RDFS.label.getURI() + "> ?label .\n" + "?authorshipUri core:relates ?newPerson .\n" + "?newPerson core:relatedBy ?authorshipUri . "; - } - private String getN3ForExistingPerson() { - return getN3PrefixString() + - "?authorshipUri core:relates ?personUri .\n" + - "?personUri core:relatedBy ?authorshipUri ."; - } + // Changes here for creating vcards for external authors + private static final String newPersonVCardFirstName = prefixes + vcardFailPattern + + "@prefix vcard: . \n" + + "?vcardPerson a . \n" + + "?vcardPerson vcard:hasName ?vcardName . \n" + + "?vcardName a . \n" + + "?vcardName vcard:givenName ?firstName ."; + + private static final String newPersonVCardMiddleName = prefixes + vcardFailPattern + + "@prefix vcard: . \n" + + "?vcardPerson a vcard:Individual . \n" + + "?vcardPerson vcard:hasName ?vcardName . \n" + + "?vcardName a vcard:Name . \n" + + "?vcardName ?middleName ."; + + private static final String newPersonVCardLastName = prefixes + vcardFailPattern + + "@prefix vcard: . \n" + + "?vcardPerson a . \n" + + "?vcardPerson vcard:hasName ?vcardName . \n" + + "?vcardName a . \n" + + "?vcardName vcard:familyName ?lastName ."; + + // Changes here for creating vcards for external authors + private static final String newPersonVCard = prefixes + vcardFailPattern + + "@prefix vcard: . \n" + + "?vcardPerson a vcard:Individual ;\n" + + "<" + RDFS.label.getURI() + "> ?label .\n" + + "?authorshipUri core:relates ?vcardPerson .\n" + + "?vcardPerson core:relatedBy ?authorshipUri . "; - private String getN3NewOrg() { - return getN3PrefixString() + + private static final String existingPerson = prefixes + + "?authorshipUri core:relates ?personUri .\n" + + "?personUri core:relatedBy ?authorshipUri ."; + + private static final String newOrg = prefixes + "?newOrg a foaf:Organization ;\n" + "<" + RDFS.label.getURI() + "> ?orgName .\n" + "?authorshipUri core:relates ?newOrg .\n" + "?newOrg core:relatedBy ?authorshipUri . "; - } - - private String getN3ForExistingOrg() { - return getN3PrefixString() + - "?authorshipUri core:relates ?orgUri .\n" + - "?orgUri core:relatedBy ?authorshipUri ."; - } - /** Get new resources */ - //A new authorship uri will always be created when an author is added - //A new person may be added if a person not in the system will be added as author - private Map generateNewResources(VitroRequest vreq) { - - - HashMap newResources = new HashMap(); - newResources.put("authorshipUri", DEFAULT_NS_TOKEN); - newResources.put("newPerson", DEFAULT_NS_TOKEN); - newResources.put("vcardPerson", DEFAULT_NS_TOKEN); - newResources.put("vcardName", DEFAULT_NS_TOKEN); - newResources.put("newOrg", DEFAULT_NS_TOKEN); - return newResources; - } - - /** Set URIS and Literals In Scope and on form and supporting methods */ + + private static final String existingOrg = prefixes + + "?authorshipUri core:relates ?orgUri .\n" + + "?orgUri core:relatedBy ?authorshipUri ."; + + /** 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 + //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 author, need to get the person uri - urisOnForm.add("personUri"); - urisOnForm.add("orgUri"); - editConfiguration.setUrisOnform(urisOnForm); - - //for person who is not in system, need to add first name, last name and middle name - //Also need to store authorship rank and label of author - List literalsOnForm = list("firstName", - "middleName", - "lastName", - "rank", - "orgName", - "label"); - editConfiguration.setLiteralsOnForm(literalsOnForm); + private void setUrisAndLiteralsOnForm(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + List urisOnForm = new ArrayList(); + //If an existing person is being used as an author, need to get the person uri + urisOnForm.add("personUri"); + urisOnForm.add("orgUri"); + + urisOnForm.add("createPersonInstance"); + urisOnForm.add("createVCard"); + editConfiguration.setUrisOnform(urisOnForm); + + //for person who is not in system, need to add first name, last name and middle name + //Also need to store authorship rank and label of author + List literalsOnForm = list("firstName", + "middleName", + "lastName", + "rank", + "orgName", + "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 authors 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()); + //This form is different from the others that it gets multiple authors on the same page + //and that information will be queried and stored in the additional form specific data + 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); - setOrgUriField(editConfiguration); - setOrgNameField(editConfiguration); + * + * Set Fields and supporting methods + */ + + private void setFields(EditConfigurationVTwo editConfiguration, VitroRequest vreq, String predicateUri) { + setLabelField(editConfiguration); + setFirstNameField(editConfiguration); + setMiddleNameField(editConfiguration); + setLastNameField(editConfiguration); + setRankField(editConfiguration); + setPersonUriField(editConfiguration); + setOrgUriField(editConfiguration); + setOrgNameField(editConfiguration); + setPatternFailFields(editConfiguration); + } + + private void setLabelField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("label"). + setValidators(list("datatype:" + RDF.dtLangString.getURI())). + setRangeDatatypeUri(RDF.dtLangString.getURI()) + ); } - 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) - ); - } - - private void setOrgUriField(EditConfigurationVTwo editConfiguration) { - editConfiguration.addField(new FieldVTwo(). - setName("orgUri") - //.setObjectClassUri(personClass) - ); - } - - private void setOrgNameField(EditConfigurationVTwo editConfiguration) { - editConfiguration.addField(new FieldVTwo(). - setName("orgName"). - setValidators(list("datatype:" + RDF.dtLangString.getURI())). - setRangeDatatypeUri(RDF.dtLangString.getURI()) - ); - } - - //Form specific data - public void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { - HashMap formSpecificData = new HashMap(); - //Get the existing authorships - formSpecificData.put("existingAuthorInfo", getExistingAuthorships(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 AUTHORSHIPS_MODEL = " \n" - + "PREFIX core: \n" - + "PREFIX rdfs: \n" - + "PREFIX foaf: \n" - + "PREFIX vcard: \n" - + "CONSTRUCT\n" - + "{\n" - + " ?subject core:relatedBy ?authorshipURI .\n" - + " ?authorshipURI a core:Authorship .\n" - + " ?authorshipURI core:relates ?authorURI .\n" - + " ?authorshipURI core:rank ?rank .\n" - + " ?authorURI a ?type .\n" - + " ?authorURI rdfs:label ?authorName .\n" - + " ?authorURI vcard:hasName ?vName .\n" - + " ?vName vcard:givenName ?firstName .\n" - + " ?vName vcard:familyName ?lastName .\n" - + " ?vName core:middleName ?middleName .\n" - + "}\n" - + "WHERE\n" - + "{\n" - + " {\n" - + " ?subject core:relatedBy ?authorshipURI .\n" - + " ?authorshipURI a core:Authorship .\n" - + " ?authorshipURI core:relates ?authorURI .\n" - + " ?authorURI a foaf:Agent .\n" - + " ?authorURI a ?type .\n" - + " }\n" - + " UNION\n" - + " {\n" - + " ?subject core:relatedBy ?authorshipURI .\n" - + " ?authorshipURI a core:Authorship .\n" - + " ?authorshipURI core:relates ?authorURI .\n" - + " ?authorURI a foaf:Agent .\n" - + " ?authorURI rdfs:label ?authorName\n" - + " }\n" - + " UNION\n" - + " {\n" - + " ?subject core:relatedBy ?authorshipURI .\n" - + " ?authorshipURI a core:Authorship .\n" - + " ?authorshipURI core:rank ?rank\n" - + " }\n" - + " UNION\n" - + " {\n" - + " ?subject core:relatedBy ?authorshipURI .\n" - + " ?authorshipURI a core:Authorship .\n" - + " ?authorshipURI core:relates ?authorURI .\n" - + " ?authorURI a vcard:Individual .\n" - + " ?authorURI a ?type .\n" - + " ?authorURI vcard:hasName ?vName .\n" - + " ?vName vcard:givenName ?firstName .\n" - + " ?vName vcard:familyName ?lastName .\n" - + " }\n" - + " UNION\n" - + " {\n" - + " ?subject core:relatedBy ?authorshipURI .\n" - + " ?authorshipURI a core:Authorship .\n" - + " ?authorshipURI core:relates ?authorURI .\n" - + " ?authorURI a vcard:Individual .\n" - + " ?authorURI a ?type .\n" - + " ?authorURI vcard:hasName ?vName .\n" - + " ?vName core:middleName ?middleName .\n" - + " }\n" - + "}\n" - ; + + private void setFirstNameField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("firstName"). + setValidators(list("datatype:" + RDF.dtLangString.getURI())). + setRangeDatatypeUri(RDF.dtLangString.getURI()) + ); + } + + private void setPatternFailFields(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo().setName("createVCard")); + editConfiguration.addField(new FieldVTwo().setName("createPersonInstance")); + } + + 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) + ); + } + + private void setOrgUriField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("orgUri") + //.setObjectClassUri(personClass) + ); + } + + private void setOrgNameField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("orgName"). + setValidators(list("datatype:" + RDF.dtLangString.getURI())). + setRangeDatatypeUri(RDF.dtLangString.getURI()) + ); + } + + //Form specific data + public void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + HashMap formSpecificData = new HashMap(); + //Get the existing authorships + formSpecificData.put("existingAuthorInfo", getExistingAuthorships(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 AUTHORSHIPS_MODEL = " \n" + + "PREFIX core: \n" + + "PREFIX rdfs: \n" + + "PREFIX foaf: \n" + + "PREFIX vcard: \n" + + "CONSTRUCT\n" + + "{\n" + + " ?subject core:relatedBy ?authorshipURI .\n" + + " ?authorshipURI a core:Authorship .\n" + + " ?authorshipURI core:relates ?authorURI .\n" + + " ?authorshipURI core:rank ?rank .\n" + + " ?authorURI a ?type .\n" + + " ?authorURI rdfs:label ?authorName .\n" + + " ?authorURI vcard:hasName ?vName .\n" + + " ?vName vcard:givenName ?firstName .\n" + + " ?vName vcard:familyName ?lastName .\n" + + " ?vName core:middleName ?middleName .\n" + + "}\n" + + "WHERE\n" + + "{\n" + + " {\n" + + " ?subject core:relatedBy ?authorshipURI .\n" + + " ?authorshipURI a core:Authorship .\n" + + " ?authorshipURI core:relates ?authorURI .\n" + + " ?authorURI a foaf:Agent .\n" + + " ?authorURI a ?type .\n" + + " }\n" + + " UNION\n" + + " {\n" + + " ?subject core:relatedBy ?authorshipURI .\n" + + " ?authorshipURI a core:Authorship .\n" + + " ?authorshipURI core:relates ?authorURI .\n" + + " ?authorURI a foaf:Agent .\n" + + " ?authorURI rdfs:label ?authorName\n" + + " }\n" + + " UNION\n" + + " {\n" + + " ?subject core:relatedBy ?authorshipURI .\n" + + " ?authorshipURI a core:Authorship .\n" + + " ?authorshipURI core:rank ?rank\n" + + " }\n" + + " UNION\n" + + " {\n" + + " ?subject core:relatedBy ?authorshipURI .\n" + + " ?authorshipURI a core:Authorship .\n" + + " ?authorshipURI core:relates ?authorURI .\n" + + " ?authorURI a vcard:Individual .\n" + + " ?authorURI a ?type .\n" + + " ?authorURI vcard:hasName ?vName .\n" + + " ?vName vcard:givenName ?firstName .\n" + + " ?vName vcard:familyName ?lastName .\n" + + " }\n" + + " UNION\n" + + " {\n" + + " ?subject core:relatedBy ?authorshipURI .\n" + + " ?authorshipURI a core:Authorship .\n" + + " ?authorshipURI core:relates ?authorURI .\n" + + " ?authorURI a vcard:Individual .\n" + + " ?authorURI a ?type .\n" + + " ?authorURI vcard:hasName ?vName .\n" + + " ?vName core:middleName ?middleName .\n" + + " }\n" + + "}\n"; private static String AUTHORSHIPS_QUERY = " \n" + "PREFIX core: \n" @@ -423,49 +431,49 @@ public void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRe + " ?authorURI a foaf:Agent . \n" + " OPTIONAL { ?authorURI rdfs:label ?authorName } \n" + " OPTIONAL { ?authorshipURI core:rank ?rank } \n" - + "} UNION { \n" - + " ?subject core:relatedBy ?authorshipURI . \n" - + " ?authorshipURI a core:Authorship . \n" - + " ?authorshipURI core:relates ?authorURI . \n" - + " ?authorURI a vcard:Individual . \n" - + " ?authorURI vcard:hasName ?vName . \n" - + " ?vName vcard:givenName ?firstName . \n" - + " ?vName vcard:familyName ?lastName . \n" - + " OPTIONAL { ?vName core:middleName ?middleName . } \n" - + " OPTIONAL { ?authorshipURI core:rank ?rank } \n" - + " bind ( COALESCE(?firstName, \"\") As ?firstName1) . \n" - + " bind ( COALESCE(?middleName, \"\") As ?middleName1) . \n" - + " bind ( COALESCE(?lastName, \"\") As ?lastName1) . \n" - + " bind (concat(str(?lastName1 + \", \"),str(?middleName1 + \" \"),str(?firstName1)) as ?authorName) . \n" + + "} UNION { \n" + + " ?subject core:relatedBy ?authorshipURI . \n" + + " ?authorshipURI a core:Authorship . \n" + + " ?authorshipURI core:relates ?authorURI . \n" + + " ?authorURI a vcard:Individual . \n" + + " ?authorURI vcard:hasName ?vName . \n" + + " ?vName vcard:givenName ?firstName . \n" + + " ?vName vcard:familyName ?lastName . \n" + + " OPTIONAL { ?vName core:middleName ?middleName . } \n" + + " OPTIONAL { ?authorshipURI core:rank ?rank } \n" + + " bind ( COALESCE(?firstName, \"\") As ?firstName1) . \n" + + " bind ( COALESCE(?middleName, \"\") As ?middleName1) . \n" + + " bind ( COALESCE(?lastName, \"\") As ?lastName1) . \n" + + " bind (concat(str(str(?lastName1) + \", \"),str(str(?middleName1) + \" \"),str(?firstName1)) as ?authorName) . \n" + "} } ORDER BY ?rank"; private List getExistingAuthorships(String subjectUri, VitroRequest vreq) { - RDFService rdfService = vreq.getRDFService(); - - List> authorships = new ArrayList>(); - try { - String constructStr = QueryUtils.subUriForQueryVar(AUTHORSHIPS_MODEL, "subject", subjectUri); - - Model constructedModel = ModelFactory.createDefaultModel(); - rdfService.sparqlConstructQuery(constructStr, constructedModel); - - String queryStr = QueryUtils.subUriForQueryVar(this.getAuthorshipsQuery(), "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("authorshipURI"); - if (node.isURIResource()) { - authorships.add(QueryUtils.querySolutionToStringValueMap(soln)); - } - } - } finally { - qe.close(); - } + RDFService rdfService = vreq.getRDFService(); + + List> authorships = new ArrayList>(); + try { + String constructStr = QueryUtils.subUriForQueryVar(AUTHORSHIPS_MODEL, "subject", subjectUri); + + Model constructedModel = ModelFactory.createDefaultModel(); + rdfService.sparqlConstructQuery(constructStr, constructedModel); + + String queryStr = QueryUtils.subUriForQueryVar(getAuthorshipsQuery, "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("authorshipURI"); + if (node.isURIResource()) { + authorships.add(QueryUtils.querySolutionToStringValueMap(soln)); + } + } + } finally { + qe.close(); + } } catch (Exception e) { log.error(e, e); } @@ -485,7 +493,7 @@ private List getExistingAuthorships(String subjectUri, VitroRequ private int getMaxRank(String subjectUri, VitroRequest vreq) { int maxRank = 0; // default value - String queryStr = QueryUtils.subUriForQueryVar(this.getMaxRankQueryStr(), "subject", subjectUri); + String queryStr = QueryUtils.subUriForQueryVar(getMaxRankQueryStr, "subject", subjectUri); log.debug("maxRank query string is: " + queryStr); try { ResultSet results = QueryUtils.getQueryResults(queryStr, vreq); @@ -511,83 +519,77 @@ private int getMaxRank(String subjectUri, VitroRequest vreq) { return maxRank; } - private List getAuthorshipInfo( - List> authorships) { - List info = new ArrayList(); - String authorshipUri = ""; - String authorshipName = ""; - String authorUri = ""; - String authorName = ""; - - for ( Map authorship : authorships ) { - for (Entry entry : authorship.entrySet() ) { - if ( entry.getKey().equals("authorshipURI") ) { - authorshipUri = entry.getValue(); - } - else if ( entry.getKey().equals("authorshipName") ) { - authorshipName = entry.getValue(); - } - else if ( entry.getKey().equals("authorURI") ) { - authorUri = entry.getValue(); - } - else if ( entry.getKey().equals("authorName") ) { - authorName = entry.getValue(); - } - } - - AuthorshipInfo aaInfo = new AuthorshipInfo(authorshipUri, authorshipName, authorUri, authorName); - info.add(aaInfo); - } - log.debug("info = " + info); - return info; - } - - //This is the information about authors the form will require - public class AuthorshipInfo { - //This is the authorship node information - private String authorshipUri; - private String authorshipName; - //Author information for authorship node - private String authorUri; - private String authorName; - - public AuthorshipInfo(String inputAuthorshipUri, - String inputAuthorshipName, - String inputAuthorUri, - String inputAuthorName) { - authorshipUri = inputAuthorshipUri; - authorshipName = inputAuthorshipName; - authorUri = inputAuthorUri; - authorName = inputAuthorName; - - } - - //Getters - specifically required for Freemarker template's access to POJO - public String getAuthorshipUri() { - return authorshipUri; - } - - public String getAuthorshipName() { - return authorshipName; - } - - public String getAuthorUri() { - return authorUri; - } - - public String getAuthorName() { - return authorName; - } - } - - static final String DEFAULT_NS_TOKEN=null; //null forces the default NS - - protected String getMaxRankQueryStr() { - return MAX_RANK_QUERY; + private List getAuthorshipInfo( + List> authorships) { + List info = new ArrayList(); + String authorshipUri = ""; + String authorshipName = ""; + String authorUri = ""; + String authorName = ""; + + for ( Map authorship : authorships ) { + for (Entry entry : authorship.entrySet() ) { + if ( entry.getKey().equals("authorshipURI") ) { + authorshipUri = entry.getValue(); + } + else if ( entry.getKey().equals("authorshipName") ) { + authorshipName = entry.getValue(); + } + else if ( entry.getKey().equals("authorURI") ) { + authorUri = entry.getValue(); + } + else if ( entry.getKey().equals("authorName") ) { + authorName = entry.getValue(); + } + } + + AuthorshipInfo aaInfo = new AuthorshipInfo(authorshipUri, authorshipName, authorUri, authorName); + info.add(aaInfo); + } + log.debug("info = " + info); + return info; } - protected String getAuthorshipsQuery() { - return AUTHORSHIPS_QUERY; + // This is the information about authors the form will require + public class AuthorshipInfo { + // This is the authorship node information + private String authorshipUri; + private String authorshipName; + // Author information for authorship node + private String authorUri; + private String authorName; + + public AuthorshipInfo(String inputAuthorshipUri, String inputAuthorshipName, String inputAuthorUri, + String inputAuthorName) { + authorshipUri = inputAuthorshipUri; + authorshipName = inputAuthorshipName; + authorUri = inputAuthorUri; + authorName = inputAuthorName; + + } + + // Getters - specifically required for Freemarker template's access to POJO + public String getAuthorshipUri() { + return authorshipUri; + } + + public String getAuthorshipName() { + return authorshipName; + } + + public String getAuthorUri() { + return authorUri; + } + + public String getAuthorName() { + return authorName; + } } + private static final String DEFAULT_NS_TOKEN = null; // null forces the default NS + + private String getMaxRankQueryStr = MAX_RANK_QUERY; + + private String getAuthorshipsQuery = AUTHORSHIPS_QUERY; + } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddEditorsToInformationResourceGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddEditorsToInformationResourceGenerator.java index de1c0a8614..fcfe0424bd 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddEditorsToInformationResourceGenerator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddEditorsToInformationResourceGenerator.java @@ -28,12 +28,11 @@ 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.PublicationHasAuthorValidator; 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; /** * This is a slightly unusual generator that is used by Manage Editors on @@ -42,100 +41,105 @@ * It is intended to always be an add, and never an update. */ public class AddEditorsToInformationResourceGenerator extends VivoBaseGenerator implements EditConfigurationGenerator { - public static Log log = LogFactory.getLog(AddEditorsToInformationResourceGenerator.class); + + private static Log log = LogFactory.getLog(AddEditorsToInformationResourceGenerator.class); + private static final String DEFAULT_NS_TOKEN = null; // null forces the default NS + private static final String prefixes = + "@prefix core: <" + vivoCore + "> .\n" + + "@prefix foaf: <" + foaf + "> . \n"; + + private static final String vcardFailPattern = "@prefix fail_pattern: ?createVCard .\n"; + private static final String personInstanceFailPattern = "@prefix fail_pattern: ?createPersonInstance .\n"; + private String maxRankQueryStr = MAX_RANK_QUERY; + private String editorshipsQuery = EDITORSHIPS_QUERY; @Override - public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, - HttpSession session) { + public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession session) { EditConfigurationVTwo editConfiguration = new EditConfigurationVTwo(); initBasics(editConfiguration, vreq); initPropertyParameters(vreq, session, editConfiguration); - //Overriding URL to return to + // Overriding URL to return to setUrlToReturnTo(editConfiguration, vreq); - //set variable names + // set variable names editConfiguration.setVarNameForSubject("infoResource"); editConfiguration.setVarNameForPredicate("predicate"); editConfiguration.setVarNameForObject("editorshipUri"); // Required N3 - editConfiguration.setN3Required( list( getN3NewEditorship() ) ); + editConfiguration.setN3Required(list(newEditorship)); // Optional N3 - editConfiguration.setN3Optional( generateN3Optional()); + editConfiguration.setN3Optional(generateN3Optional()); editConfiguration.addNewResource("editorshipUri", DEFAULT_NS_TOKEN); editConfiguration.addNewResource("newPerson", DEFAULT_NS_TOKEN); + editConfiguration.addNewResource("newOrg", DEFAULT_NS_TOKEN); editConfiguration.addNewResource("vcardPerson", DEFAULT_NS_TOKEN); editConfiguration.addNewResource("vcardName", DEFAULT_NS_TOKEN); - //In scope + // In scope setUrisAndLiteralsInScope(editConfiguration, vreq); - //on Form + // on Form setUrisAndLiteralsOnForm(editConfiguration, vreq); - //Sparql queries + // Sparql queries setSparqlQueries(editConfiguration, vreq); - //set fields + // set fields setFields(editConfiguration, vreq, EditConfigurationUtils.getPredicateUri(vreq)); - //template file + // template file editConfiguration.setTemplate("addEditorsToInformationResource.ftl"); - //add validators - editConfiguration.addValidator(new FirstAndLastNameValidator("personUri", I18n.bundle(vreq))); + // add validators + editConfiguration.addValidator(new PublicationHasAuthorValidator()); - //Adding additional data, specifically edit mode + // 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 + // 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 getN3NewEditorship() { - return getN3PrefixString() + - "?editorshipUri a core:Editorship ;\n" + - " core:relates ?infoResource .\n" + - "?infoResource core:relatedBy ?editorshipUri ."; - } - - private String getN3EditorshipRank() { - return getN3PrefixString() + - "?editorshipUri core:editorRank ?rank ."; - } - - //first name, middle name, last name, and new perseon for new editor being created, and n3 for existing person - //if existing person selected as editor - public List generateN3Optional() { - return list( - getN3NewPersonFirstName() , - getN3NewPersonMiddleName(), - getN3NewPersonLastName(), - getN3NewPerson(), - getN3EditorshipRank(), - getN3ForExistingPerson()); - } - - - private String getN3NewPersonFirstName() { - return getN3PrefixString() + + private void setUrlToReturnTo(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + editConfiguration.setUrlPatternToReturnTo(EditConfigurationUtils.getFormUrlWithoutContext(vreq)); + } + + private String newEditorship = prefixes + + "?editorshipUri a core:Editorship ;\n" + + "core:relates ?infoResource .\n" + + "?infoResource core:relatedBy ?editorshipUri ."; + + private String editorshipRank = prefixes + + "?editorshipUri core:rank ?rank ."; + + // first name, middle name, last name, and new perseon for new editor being created, and n3 for existing person + // if existing person selected as editor + private List generateN3Optional() { + return list( + newPersonFirstName , + newPersonMiddleName, + newPersonLastName, + newPerson, + + newVCardPersonFirstName , + newVCardPersonMiddleName, + newVCardPersonLastName, + newVCardPerson, + + editorshipRank, + existingPerson, + newOrg, + existingOrg); + } + + private static final String newPersonFirstName = prefixes + personInstanceFailPattern + "@prefix vcard: . \n" + "?newPerson ?vcardPerson . \n" + "?vcardPerson ?newPerson . \n" + @@ -143,10 +147,8 @@ private String getN3NewPersonFirstName() { "?vcardPerson vcard:hasName ?vcardName . \n" + "?vcardName a . \n" + "?vcardName vcard:givenName ?firstName ."; - } - private String getN3NewPersonMiddleName() { - return getN3PrefixString() + + private static final String newPersonMiddleName = prefixes + personInstanceFailPattern + "@prefix vcard: . \n" + "?newPerson ?vcardPerson . \n" + "?vcardPerson ?newPerson . \n" + @@ -154,10 +156,8 @@ private String getN3NewPersonMiddleName() { "?vcardPerson vcard:hasName ?vcardName . \n" + "?vcardName a vcard:Name . \n" + "?vcardName ?middleName ."; - } - private String getN3NewPersonLastName() { - return getN3PrefixString() + + private static final String newPersonLastName = prefixes + personInstanceFailPattern + "@prefix vcard: . \n" + "?newPerson ?vcardPerson . \n" + "?vcardPerson ?newPerson . \n" + @@ -165,236 +165,329 @@ private String getN3NewPersonLastName() { "?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" + - "?editorshipUri core:relates ?newPerson .\n" + - "?newPerson core:relatedBy ?editorshipUri . "; - } - - private String getN3ForExistingPerson() { - return getN3PrefixString() + - "?editorshipUri core:relates ?personUri .\n" + - "?personUri core:relatedBy ?editorshipUri ."; - } - - /** Get new resources */ - //A new editorship uri will always be created when an editor is added - //A new person may be added if a person not in the system will be added as editor - private Map generateNewResources(VitroRequest vreq) { - - - HashMap newResources = new HashMap(); - newResources.put("editorshipUri", 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 static final String newPerson = prefixes + personInstanceFailPattern + + "?newPerson a foaf:Person ;\n" + + "<" + RDFS.label.getURI() + "> ?label .\n" + + "?editorshipUri core:relates ?newPerson .\n" + + "?newPerson core:relatedBy ?editorshipUri . "; + + // Changes here for creating vcards for external editors + private static final String newVCardPersonFirstName = prefixes + vcardFailPattern + + "@prefix vcard: . \n" + + "?vcardPerson a . \n" + + "?vcardPerson vcard:hasName ?vcardName . \n" + + "?vcardName a . \n" + + "?vcardName vcard:givenName ?firstName ."; + + private static final String newVCardPersonMiddleName = prefixes + vcardFailPattern + + "@prefix vcard: . \n" + + "?vcardPerson a vcard:Individual . \n" + + "?vcardPerson vcard:hasName ?vcardName . \n" + + "?vcardName a vcard:Name . \n" + + "?vcardName ?middleName ."; + + private static final String newVCardPersonLastName = prefixes + vcardFailPattern + + "@prefix vcard: . \n" + + "?vcardPerson a . \n" + + "?vcardPerson vcard:hasName ?vcardName . \n" + + "?vcardName a . \n" + + "?vcardName vcard:familyName ?lastName ."; + + // Changes here for creating vcards for external editors + private static final String newVCardPerson = prefixes + vcardFailPattern + + "@prefix vcard: . \n" + + "?vcardPerson a vcard:Individual ;\n" + + "<" + RDFS.label.getURI() + "> ?label .\n" + + "?editorshipUri core:relates ?vcardPerson .\n" + + "?vcardPerson core:relatedBy ?editorshipUri . "; + + private static final String existingPerson = prefixes + + "?editorshipUri core:relates ?personUri .\n" + + "?personUri core:relatedBy ?editorshipUri ."; + + private static final String newOrg = prefixes + + "?newOrg a foaf:Organization ;\n" + + "<" + RDFS.label.getURI() + "> ?orgName .\n" + + "?editorshipUri core:relates ?newOrg .\n" + + "?newOrg core:relatedBy ?editorshipUri . "; + + private static final String existingOrg = prefixes + + "?editorshipUri core:relates ?orgUri .\n" + + "?orgUri core:relatedBy ?editorshipUri ."; + + /** 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 + //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 editor, 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 editorship rank and label of editor - List literalsOnForm = list("firstName", - "middleName", - "lastName", - "rank", - "label"); - editConfiguration.setLiteralsOnForm(literalsOnForm); + private void setUrisAndLiteralsOnForm(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + List urisOnForm = new ArrayList(); + //If an existing person is being used as an editor, need to get the person uri + urisOnForm.add("personUri"); + + urisOnForm.add("createPersonInstance"); + urisOnForm.add("createVCard"); + urisOnForm.add("orgUri"); + editConfiguration.setUrisOnform(urisOnForm); + + //for person who is not in system, need to add first name, last name and middle name + //Also need to store editorship rank and label of editor + List literalsOnForm = list("firstName", + "middleName", + "lastName", + "rank", + "orgName", + "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 editors 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()); + //This form is different from the others that it gets multiple editors on the same page + //and that information will be queried and stored in the additional form specific data + 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); + * + * Set Fields and supporting methods + */ + + private void setFields(EditConfigurationVTwo editConfiguration, VitroRequest vreq, String predicateUri) { + setLabelField(editConfiguration); + setFirstNameField(editConfiguration); + setMiddleNameField(editConfiguration); + setLastNameField(editConfiguration); + setRankField(editConfiguration); + setPersonUriField(editConfiguration); + setPatternFailFields(editConfiguration); + setOrgUriField(editConfiguration); + setOrgNameField(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 editorships - formSpecificData.put("existingEditorInfo", getExistingEditorships(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 EDITORSHIPS_MODEL = "" - + "PREFIX core: \n" - + "PREFIX rdfs: \n" - + "PREFIX foaf: \n" - + "CONSTRUCT\n" - + "{\n" - + " ?subject core:relatedBy ?editorshipURI .\n" - + " ?editorshipURI a core:Editorship .\n" - + " ?editorshipURI core:relates ?editorURI .\n" - + " ?editorshipURI core:rank ?rank.\n" - + " ?editorURI a foaf:Person .\n" - + " ?editorURI rdfs:label ?editorName .\n" - + "}\n" - + "WHERE\n" - + "{\n" - + " {\n" - + " ?subject core:relatedBy ?editorshipURI .\n" - + " ?editorshipURI a core:Editorship .\n" - + " ?editorshipURI core:relates ?editorURI .\n" - + " ?editorURI a foaf:Person .\n" - + " }\n" - + " UNION\n" - + " {\n" - + " ?subject core:relatedBy ?editorshipURI .\n" - + " ?editorshipURI a core:Editorship .\n" - + " ?editorshipURI core:relates ?editorURI .\n" - + " ?editorURI a foaf:Person .\n" - + " ?editorURI rdfs:label ?editorName .\n" - + " }\n" - + " UNION\n" - + " {\n" - + " ?subject core:relatedBy ?editorshipURI .\n" - + " ?editorshipURI a core:Editorship .\n" - + " ?editorshipURI core:rank ?rank.\n" - + " }\n" - + "}\n"; - - private static String EDITORSHIPS_QUERY = "" + private void setPatternFailFields(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo().setName("createVCard")); + editConfiguration.addField(new FieldVTwo().setName("createPersonInstance")); + } + + 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) + ); + } + + private void setOrgUriField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("orgUri") + ); + } + + private void setOrgNameField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("orgName"). + setValidators(list("datatype:" + XSD.xstring.toString())). + setRangeDatatypeUri(XSD.xstring.toString()) + ); + } + + //Form specific data + private void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + HashMap formSpecificData = new HashMap(); + //Get the existing editorships + formSpecificData.put("existingEditorInfo", getExistingEditorships(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 final String EDITORSHIPS_MODEL = "" + + "PREFIX core: \n" + + "PREFIX rdfs: \n" + + "PREFIX foaf: \n" + + "PREFIX vcard: \n" + + "CONSTRUCT\n" + + "{\n" + + " ?subject core:relatedBy ?editorshipURI .\n" + + " ?editorshipURI a core:Editorship .\n" + + " ?editorshipURI core:relates ?editorURI .\n" + + " ?editorshipURI core:rank ?rank.\n" + + " ?editorURI a ?type .\n" + + " ?editorURI rdfs:label ?editorName .\n" + + " ?editorURI vcard:hasName ?vName .\n" + + " ?vName vcard:givenName ?firstName .\n" + + " ?vName vcard:familyName ?lastName .\n" + + " ?vName core:middleName ?middleName .\n" + + "}\n" + + "WHERE\n" + + "{\n" + + " {\n" + + " ?subject core:relatedBy ?editorshipURI .\n" + + " ?editorshipURI a core:Editorship .\n" + + " ?editorshipURI core:relates ?editorURI .\n" + + " ?editorURI a foaf:Agent .\n" + + " ?editorURI a ?type .\n" + + " }\n" + + " UNION\n" + + " {\n" + + " ?subject core:relatedBy ?editorshipURI .\n" + + " ?editorshipURI a core:Editorship .\n" + + " ?editorshipURI core:relates ?editorURI .\n" + + " ?editorURI a foaf:Agent .\n" + + " ?editorURI rdfs:label ?editorName .\n" + + " }\n" + + " UNION\n" + + " {\n" + + " ?subject core:relatedBy ?editorshipURI .\n" + + " ?editorshipURI a core:Editorship .\n" + + " ?editorshipURI core:rank ?rank .\n" + + " }\n" + + " UNION\n" + + " {\n" + + " ?subject core:relatedBy ?editorshipURI .\n" + + " ?editorshipURI a core:Editorship .\n" + + " ?editorshipURI core:relates ?editorURI .\n" + + " ?editorURI a vcard:Individual .\n" + + " ?editorURI a ?type .\n" + + " ?editorURI vcard:hasName ?vName .\n" + + " ?vName vcard:givenName ?firstName .\n" + + " ?vName vcard:familyName ?lastName .\n" + + " }\n" + + " UNION\n" + + " {\n" + + " ?subject core:relatedBy ?editorshipURI .\n" + + " ?editorshipURI a core:Editorship .\n" + + " ?editorshipURI core:relates ?editorURI .\n" + + " ?editorURI a vcard:Individual .\n" + + " ?editorURI a ?type .\n" + + " ?editorURI vcard:hasName ?vName .\n" + + " ?vName core:middleName ?middleName .\n" + + " }\n" + + "}\n"; + + private static final String EDITORSHIPS_QUERY = " \n" + "PREFIX core: \n" + "PREFIX rdfs: \n" + "PREFIX foaf: \n" - + "SELECT ?editorshipURI (REPLACE(STR(?editorshipURI),\"^.*(#)(.*)$\", \"$2\") AS ?editorshipName) ?editorURI ?editorName ?rank \n" - + "WHERE { \n" + + "PREFIX vcard: \n" + + "SELECT ?editorshipURI (REPLACE(STR(?editorshipURI),\"^.*(#)(.*)$\", \"$2\") AS ?editorshipName)" + + "?editorURI ?editorName ?rank \n" + + "WHERE { { \n" + "?subject core:relatedBy ?editorshipURI . \n" + "?editorshipURI a core:Editorship . \n" + "?editorshipURI core:relates ?editorURI . \n" - + "?editorURI a foaf:Person . \n" + + "?editorURI a foaf:Agent . \n" + "OPTIONAL { ?editorURI rdfs:label ?editorName } \n" + "OPTIONAL { ?editorshipURI core:rank ?rank } \n" - + "} ORDER BY ?rank"; + + "} UNION { \n" + + " ?subject core:relatedBy ?editorshipURI . \n" + + " ?editorshipURI a core:Editorship . \n" + + " ?editorshipURI core:relates ?editorURI . \n" + + " ?editorURI a vcard:Individual . \n" + + " ?editorURI vcard:hasName ?vName . \n" + + " ?vName vcard:givenName ?firstName . \n" + + " ?vName vcard:familyName ?lastName . \n" + + " OPTIONAL { ?vName core:middleName ?middleName . } \n" + + " OPTIONAL { ?editorshipURI core:rank ?rank } \n" + + " bind ( COALESCE(?firstName, \"\") As ?firstName1) . \n" + + " bind ( COALESCE(?middleName, \"\") As ?middleName1) . \n" + + " bind ( COALESCE(?lastName, \"\") As ?lastName1) . \n" + + " bind (concat(str(str(?lastName1) + \", \"),str(str(?middleName1) + \" \"),str(?firstName1))" + + " as ?editorName) . \n" + + "} } ORDER BY ?rank"; private List getExistingEditorships(String subjectUri, VitroRequest vreq) { - RDFService rdfService = vreq.getRDFService(); - - List> editorships = new ArrayList>(); - try { - String constructStr = QueryUtils.subUriForQueryVar(EDITORSHIPS_MODEL, "subject", subjectUri); - - Model constructedModel = ModelFactory.createDefaultModel(); - rdfService.sparqlConstructQuery(constructStr, constructedModel); - - String queryStr = QueryUtils.subUriForQueryVar(this.getEditorshipsQuery(), "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("editorshipURI"); - if (node.isURIResource()) { - editorships.add(QueryUtils.querySolutionToStringValueMap(soln)); - } - } - } finally { - qe.close(); - } + RDFService rdfService = vreq.getRDFService(); + + List> editorships = new ArrayList>(); + try { + String constructStr = QueryUtils.subUriForQueryVar(EDITORSHIPS_MODEL, "subject", subjectUri); + + Model constructedModel = ModelFactory.createDefaultModel(); + rdfService.sparqlConstructQuery(constructStr, constructedModel); + + String queryStr = QueryUtils.subUriForQueryVar(editorshipsQuery, "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("editorshipURI"); + if (node.isURIResource()) { + editorships.add(QueryUtils.querySolutionToStringValueMap(soln)); + } + } + } finally { + qe.close(); + } } catch (Exception e) { log.error(e, e); } + // Added QueryUtils.removeDuplicatesMapsFromList ... + editorships = QueryUtils.removeDuplicatesMapsFromList(editorships, "editorshipURI", "editorURI"); log.debug("editorships = " + editorships); return getEditorshipInfo(editorships); } - private static String MAX_RANK_QUERY = "" + private static final String MAX_RANK_QUERY = "" + "PREFIX core: \n" + "SELECT DISTINCT ?rank WHERE { \n" + " ?subject core:relatedBy ?editorship . \n" @@ -405,7 +498,7 @@ private List getExistingEditorships(String subjectUri, VitroRequ private int getMaxRank(String subjectUri, VitroRequest vreq) { int maxRank = 0; // default value - String queryStr = QueryUtils.subUriForQueryVar(this.getMaxRankQueryStr(), "subject", subjectUri); + String queryStr = QueryUtils.subUriForQueryVar(maxRankQueryStr, "subject", subjectUri); log.debug("maxRank query string is: " + queryStr); try { ResultSet results = QueryUtils.getQueryResults(queryStr, vreq); @@ -431,83 +524,72 @@ private int getMaxRank(String subjectUri, VitroRequest vreq) { return maxRank; } - private List getEditorshipInfo( - List> editorships) { - List info = new ArrayList(); - String editorshipUri = ""; - String editorshipName = ""; - String editorUri = ""; - String editorName = ""; - - for ( Map editorship : editorships ) { - for (Entry entry : editorship.entrySet() ) { - if ( entry.getKey().equals("editorshipURI") ) { - editorshipUri = entry.getValue(); - } - else if ( entry.getKey().equals("editorshipName") ) { - editorshipName = entry.getValue(); - } - else if ( entry.getKey().equals("editorURI") ) { - editorUri = entry.getValue(); - } - else if ( entry.getKey().equals("editorName") ) { - editorName = entry.getValue(); - } - } - - EditorshipInfo aaInfo = new EditorshipInfo(editorshipUri, editorshipName, editorUri, editorName); - info.add(aaInfo); - } - log.debug("info = " + info); - return info; - } - - //This is the information about editors the form will require - public class EditorshipInfo { - //This is the editorship node information - private String editorshipUri; - private String editorshipName; - //Editor information for editorship node - private String editorUri; - private String editorName; - - public EditorshipInfo(String inputEditorshipUri, - String inputEditorshipName, - String inputEditorUri, - String inputEditorName) { - editorshipUri = inputEditorshipUri; - editorshipName = inputEditorshipName; - editorUri = inputEditorUri; - editorName = inputEditorName; - - } - - //Getters - specifically required for Freemarker template's access to POJO - public String getEditorshipUri() { - return editorshipUri; - } - - public String getEditorshipName() { - return editorshipName; - } - - public String getEditorUri() { - return editorUri; - } - - public String getEditorName() { - return editorName; - } - } - - static final String DEFAULT_NS_TOKEN=null; //null forces the default NS - - protected String getMaxRankQueryStr() { - return MAX_RANK_QUERY; + private List getEditorshipInfo(List> editorships) { + List info = new ArrayList(); + String editorshipUri = ""; + String editorshipName = ""; + String editorUri = ""; + String editorName = ""; + + for ( Map editorship : editorships ) { + for (Entry entry : editorship.entrySet() ) { + if ( entry.getKey().equals("editorshipURI") ) { + editorshipUri = entry.getValue(); + } + else if ( entry.getKey().equals("editorshipName") ) { + editorshipName = entry.getValue(); + } + else if ( entry.getKey().equals("editorURI") ) { + editorUri = entry.getValue(); + } + else if ( entry.getKey().equals("editorName") ) { + editorName = entry.getValue(); + } + } + + EditorshipInfo aaInfo = new EditorshipInfo(editorshipUri, editorshipName, editorUri, editorName); + info.add(aaInfo); + } + log.debug("info = " + info); + return info; } - protected String getEditorshipsQuery() { - return EDITORSHIPS_QUERY; + //This is the information about editors the form will require + public class EditorshipInfo { + //This is the editorship node information + private String editorshipUri; + private String editorshipName; + //Editor information for editorship node + private String editorUri; + private String editorName; + + public EditorshipInfo(String inputEditorshipUri, + String inputEditorshipName, + String inputEditorUri, + String inputEditorName) { + editorshipUri = inputEditorshipUri; + editorshipName = inputEditorshipName; + editorUri = inputEditorUri; + editorName = inputEditorName; + + } + + //Getters - specifically required for Freemarker template's access to POJO + public String getEditorshipUri() { + return editorshipUri; + } + + public String getEditorshipName() { + return editorshipName; + } + + public String getEditorUri() { + return editorUri; + } + + public String getEditorName() { + return editorName; + } } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ProjectHasParticipantGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ProjectHasParticipantGenerator.java index 5ac776f4fd..ddda61531c 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ProjectHasParticipantGenerator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ProjectHasParticipantGenerator.java @@ -38,7 +38,15 @@ public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession conf.setVarNameForObject("projectRole"); conf.setN3Required( Arrays.asList( n3ForNewProjectRole ) ); - conf.setN3Optional(Arrays.asList( n3ForNewPerson, n3ForExistingPerson, firstNameAssertion, lastNameAssertion ) ); + conf.setN3Optional(Arrays.asList( + n3ForNewPerson, + n3ForExistingPerson, + firstNameAssertion, + lastNameAssertion, + n3ForNewVCardPerson, + firstNameVCardAssertion, + lastNameVCardAssertion + )); conf.addNewResource("projectRole", DEFAULT_NS_FOR_NEW_RESOURCE); conf.addNewResource("newPerson",DEFAULT_NS_FOR_NEW_RESOURCE); @@ -48,7 +56,7 @@ public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession //uris in scope: none //literals in scope: none - conf.setUrisOnform( Arrays.asList( "existingPerson")); + conf.setUrisOnform(Arrays.asList("existingPerson", "createPersonInstance", "createVCard")); conf.setLiteralsOnForm( Arrays.asList("personLabel", "personLabelDisplay", "roleLabel", "roleLabeldisplay", "firstName", "lastName")); @@ -92,6 +100,9 @@ public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession setValidators( list("datatype:" + RDF.dtLangString.getURI()) ) ); + conf.addField(new FieldVTwo().setName("createVCard")); + conf.addField(new FieldVTwo().setName("createPersonInstance")); + //Add validator conf.addValidator(new AntiXssValidation()); conf.addValidator(new FirstAndLastNameValidator("existingPerson", I18n.bundle(vreq))); @@ -102,28 +113,34 @@ public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession return conf; } + private static final String vcardFailPattern = "@prefix fail_pattern: ?createVCard .\n"; + + private static final String personInstanceFailPattern = "@prefix fail_pattern: ?createPersonInstance .\n"; + /* N3 assertions for working with educational training */ - final static String n3ForNewProjectRole = + private static final String n3ForNewProjectRole = "@prefix core: <"+ vivoCore +"> .\n" + - "@prefix rdfs: <"+ rdfs +"> . \n"+ + "@prefix rdfs: <"+ rdfs +"> . \n"+ "?project ?projectRole .\n" + "?projectRole a .\n" + "?projectRole ?project . \n" + "?projectRole <"+ label +"> ?roleLabel . \n" ; - final static String n3ForNewPerson = + private static final String n3ForNewPerson = + personInstanceFailPattern + "?projectRole ?newPerson . \n" + "?newPerson ?projectRole . \n" + "?newPerson a . \n" + "?newPerson <"+ label +"> ?personLabel . "; - final static String n3ForExistingPerson = + private static final String n3ForExistingPerson = "?projectRole ?existingPerson . \n" + "?existingPerson ?projectRole . \n" + " "; - final static String firstNameAssertion = + private static final String firstNameAssertion = + personInstanceFailPattern + "@prefix vcard: . \n" + "?newPerson ?vcardPerson . \n" + "?vcardPerson ?newPerson . \n" + @@ -132,7 +149,8 @@ public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession "?vcardName a . \n" + "?vcardName vcard:givenName ?firstName ."; - final static String lastNameAssertion = + private static final String lastNameAssertion = + personInstanceFailPattern + "@prefix vcard: . \n" + "?newPerson ?vcardPerson . \n" + "?vcardPerson ?newPerson . \n" + @@ -141,40 +159,61 @@ public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession "?vcardName a . \n" + "?vcardName vcard:familyName ?lastName ."; + private static final String n3ForNewVCardPerson = + vcardFailPattern + + "?projectRole ?vcardPerson . \n" + + "?vcardPerson ?projectRole . \n" + + "?vcardPerson a . \n" + + "?vcardPerson <"+ label +"> ?personLabel . "; + + private static final String firstNameVCardAssertion = + vcardFailPattern + + "@prefix vcard: . \n" + + "?vcardPerson a . \n" + + "?vcardPerson vcard:hasName ?vcardName . \n" + + "?vcardName a . \n" + + "?vcardName vcard:givenName ?firstName ."; + + private static final String lastNameVCardAssertion = + vcardFailPattern + + "@prefix vcard: . \n" + + "?vcardPerson a . \n" + + "?vcardPerson vcard:hasName ?vcardName . \n" + + "?vcardName a . \n" + + "?vcardName vcard:familyName ?lastName ."; + /* Queries for editing an existing educational training entry */ - final static String roleLabelQuery = + private static final String roleLabelQuery = "SELECT ?roleLabel WHERE {\n"+ "?projectRole <"+ label +"> ?roleLabel }\n"; - final static String existingPersonQuery = + private static final String existingPersonQuery = "PREFIX rdfs: <"+ rdfs +"> \n"+ "SELECT ?existingPerson WHERE {\n"+ "?projectRole ?existingPerson . \n" + "?existingPerson ?projectRole . \n" + - "?existingPerson a . \n " + " }"; - final static String personLabelQuery = + private static final String personLabelQuery = "PREFIX rdfs: <"+ rdfs +"> \n"+ "SELECT ?existingPersonLabel WHERE {\n"+ "?projectRole ?existingPerson . \n" + "?existingPerson ?projectRole .\n"+ "?existingPerson <"+ label +"> ?existingPersonLabel .\n"+ - "?existingPerson 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://purl.obolibrary.org/obo/RO_0000053"); - return EditModeUtils.getEditMode(vreq, predicates); - } + private void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + HashMap formSpecificData = new HashMap(); + formSpecificData.put("editMode", getEditMode(vreq).name().toLowerCase()); + editConfiguration.setFormSpecificData(formSpecificData); + } + + private EditMode getEditMode(VitroRequest vreq) { + List predicates = new ArrayList(); + predicates.add("http://purl.obolibrary.org/obo/RO_0000053"); + return EditModeUtils.getEditMode(vreq, predicates); + } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/extensions/VCardsAcrossContextNodes.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/extensions/VCardsAcrossContextNodes.java new file mode 100644 index 0000000000..d5d4a855e3 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/searchindex/extensions/VCardsAcrossContextNodes.java @@ -0,0 +1,437 @@ +/* $This file is distributed under the terms of the license in LICENSE$ */ + +package edu.cornell.mannlib.vitro.webapp.searchindex.extensions; + +import static edu.cornell.mannlib.vitro.webapp.search.VitroSearchTermNames.ALLTEXT; +import static edu.cornell.mannlib.vitro.webapp.search.VitroSearchTermNames.ALLTEXTUNSTEMMED; +import static edu.cornell.mannlib.vitro.webapp.utils.sparqlrunner.SparqlQueryRunner.createSelectQueryContext; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.beans.VClass; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ContextModelAccess; +import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchInputDocument; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; +import edu.cornell.mannlib.vitro.webapp.searchindex.documentBuilding.DocumentModifier; +import edu.cornell.mannlib.vitro.webapp.searchindex.indexing.IndexingUriFinder; +import edu.cornell.mannlib.vitro.webapp.utils.configuration.ContextModelsUser; +import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property; +import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jena.query.ParameterizedSparqlString; +import org.apache.jena.query.QuerySolution; +import org.apache.jena.query.ResultSet; +import org.apache.jena.rdf.model.Literal; +import org.apache.jena.rdf.model.ResourceFactory; +import org.apache.jena.rdf.model.Statement; +import org.apache.jena.vocabulary.RDFS; + +/** + * If an individual has context nodes then the search document for that individual should include the labels of the + * partners across those nodes. The labels will be added to the ALLTEXT and ALLTEXTUNSTEMMED fields. + * + * We must specify what property leads to a context node (incoming), and what property leads from a context node + * (outgoing). We may add restrictions to say that this only applies to individuals of certain types. We may also + * restrict the type of the applicable context nodes. + * + * An instance of this class acts as both a DocumentModifier and an IndexingUriFinder: + * + * As a DocumentModifier, it looks across approved context nodes to fetch the labels of the partners. + * + * As an IndexingUriFinder, it recognizes that this relationship can be changed by a change to a "label" statement, or + * to a "relates" property, and finds all partners as candidates for reindexing. + * + *
+ * Configuration:
+ *     rdfs:label -- Optional. Appears in the timings and debug statements.
+ *     :hasIncomingProperty -- Required. Property leading to the context node.
+ *     :hasOutgoingProperty -- Required. Property leading from the context node.
+ *     :hasTypeRestriction -- Optional. Match any. If none, then no restriction.
+ *     :appliesToContextNodeType -- Optional. Match any. If none, then no restriction.
+ * 
+ */ +public class VCardsAcrossContextNodes implements IndexingUriFinder, DocumentModifier, ContextModelsUser { + private static final Log log = LogFactory.getLog(VCardsAcrossContextNodes.class); + + private RDFService rdfService; + + /** + * A name to be used in logging, to identify this instance. If not provided, then a descriptive label will be + * created. + */ + private String label; + + /** + * The URI of the property that leads into the context node. Required. + */ + private String incomingPropertyUri; + + /** + * The URI of the property that leads from the context node. Required. + */ + private String outgoingPropertyUri; + + /** + * URIs of the types of individuals to whom this instance applies. + * + * If this is not empty and an individual does not have any of these types, then skip that individual. + */ + private Set typeRestrictions = new HashSet<>(); + + /** + * URIs of the types of acceptable context nodes. + * + * If this is not empty and a context node does not have any of these types, then skip that context node's label. + */ + private Set contextNodeClasses = new HashSet<>(); + + @Override + public void setContextModels(ContextModelAccess models) { + this.rdfService = models.getRDFService(); + } + + @Property(uri = "http://www.w3.org/2000/01/rdf-schema#label", maxOccurs = 1) + public void setLabel(String l) { + label = l; + } + + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasIncomingProperty", minOccurs = 1, + maxOccurs = 1) + public void setIncomingProperty(String incomingUri) { + incomingPropertyUri = incomingUri; + } + + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasOutgoingProperty", minOccurs = 1, + maxOccurs = 1) + public void setOutgoingProperty(String outgoingUri) { + outgoingPropertyUri = outgoingUri; + } + + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTypeRestriction") + public void addTypeRestriction(String typeUri) { + typeRestrictions.add(typeUri); + } + + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#appliesToContextNodeType") + public void addContextNodeClass(String cnc) { + contextNodeClasses.add(cnc); + } + + @Validation + public void validate() { + if (label == null) { + label = String.format("%s[types=%s, contextNodeTypes=%s]", this + .getClass().getSimpleName(), + formatRestrictions(typeRestrictions), + formatRestrictions(contextNodeClasses)); + } + } + + private String formatRestrictions(Set uris) { + if (uris.isEmpty()) { + return "ALL"; + } else { + return localNames(uris).toString(); + } + } + + private Set localNames(Set uris) { + Set names = new HashSet<>(); + for (String uri : uris) { + try { + names.add(ResourceFactory.createResource(uri).getLocalName()); + } catch (Exception e) { + log.warn("Failed to parse URI: " + uri, e); + names.add(uri); + } + } + return names; + } + + @Override + public String toString() { + return (label == null) ? super.toString() : label; + } + + // ---------------------------------------------------------------------- + // DocumentModifier + // ---------------------------------------------------------------------- + + private static final String LABELS_WITHOUT_RESTRICTION = "" + + "PREFIX vcard: \n" + + "PREFIX rdfs: \n" + + "SELECT ?vName \n" + + "WHERE { \n" + + " ?uri ?incoming ?contextNode . \n" + + " ?contextNode ?outgoing ?partner . \n" + + " ?partner vcard:hasName ?vName . \n" + + " FILTER( ?uri != ?partner ) \n" + + "} \n"; + private static final String LABELS_FOR_SPECIFIC_CONTEXT_NODE_TYPE = "" + + "PREFIX vcard: \n" + + "PREFIX rdfs: \n" + + "SELECT ?vName \n" + + "WHERE { \n" + + " ?uri ?incoming ?contextNode .\n" + + " ?contextNode a ?nodeType .\n" + + " ?contextNode ?outgoing ?partner .\n" + + " ?partner vcard:hasName ?vName .\n" + + " FILTER( ?uri != ?partner ) \n" + + "} \n"; + + /** + * If this individual is acceptable, locate the labels of any context partners across acceptable context nodes. Add + * those labels to the text fields of the search document. + */ + @Override + public void modifyDocument(Individual ind, SearchInputDocument doc) { + if (passesTypeRestriction(ind)) { + if (contextNodeClasses.isEmpty()) { + addVCardsFromAllContextNodeClasses(ind, doc); + } else { + for (String contextNodeClass : contextNodeClasses) { + addVCardsFromContextNodeClass(ind, doc, contextNodeClass); + } + } + } + } + + private boolean passesTypeRestriction(Individual ind) { + if (typeRestrictions.isEmpty()) { + return true; + } else { + for (VClass type : ind.getVClasses()) { + if (typeRestrictions.contains(type.getURI())) { + return true; + } + } + } + return false; + } + + private void addVCardsFromAllContextNodeClasses(Individual ind, SearchInputDocument doc) { + addVCardsToTextFields( + doc, + createSelectQueryContext(rdfService, LABELS_WITHOUT_RESTRICTION) + .bindVariableToUri("uri", ind.getURI()) + .bindVariableToUri("incoming", incomingPropertyUri) + .bindVariableToUri("outgoing", outgoingPropertyUri) + .execute().toStringFields("vName").flatten()); + } + + private void addVCardsFromContextNodeClass(Individual ind, SearchInputDocument doc, String contextNodeClass) { + addVCardsToTextFields( + doc, + createSelectQueryContext(rdfService, + LABELS_FOR_SPECIFIC_CONTEXT_NODE_TYPE) + .bindVariableToUri("uri", ind.getURI()) + .bindVariableToUri("nodeType", contextNodeClass) + .bindVariableToUri("incoming", incomingPropertyUri) + .bindVariableToUri("outgoing", outgoingPropertyUri) + .execute().toStringFields("vName").flatten()); + } + + private void addVCardsToTextFields(SearchInputDocument doc, List vcardUris) { + for (String vcardUri : vcardUris) { + String name = getNameForVCard(vcardUri); + if (StringUtils.isNotEmpty(name)) { + doc.addField(ALLTEXT, name); + doc.addField(ALLTEXTUNSTEMMED, name); + } + } + } + + private static final String SELECT_NAME_QUERY = "" + + "PREFIX vcard: \n" + + "PREFIX rdfs: \n" + + "SELECT ?familyName ?givenName \n" + + "WHERE { \n" + + " OPTIONAL { ?uri vcard:familyName ?familyName . } \n" + + " OPTIONAL { ?uri vcard:givenName ?givenName . } \n" + + "} \n"; + + private String getNameForVCard(String vcardUri) { + ParameterizedSparqlString pss = new ParameterizedSparqlString(SELECT_NAME_QUERY); + pss.setIri("uri", vcardUri); + ResultSet results = RDFServiceUtils.sparqlSelectQuery(pss.toString(), rdfService); + if (results == null || !results.hasNext()) { + return ""; + } + QuerySolution sol = results.next(); + String familyName = getLiteralStringValue(sol.getLiteral("familyName")); + String givenName = getLiteralStringValue(sol.getLiteral("givenName")); + if (familyName.isEmpty()) { + return givenName; + } + if (givenName.isEmpty()) { + return familyName; + } + return familyName + ", " + givenName; + } + + private String getLiteralStringValue(Literal literal) { + if (literal == null) { + return ""; + } + return literal.getLexicalForm(); + } + + @Override + public void shutdown() { + // Nothing to shut down. + } + + // ---------------------------------------------------------------------- + // IndexingUriFinder + // ---------------------------------------------------------------------- + + private static final String LOCATE_PARTNERS_WITHOUT_RESTRICTION = "" + + "SELECT ?partner \n" // + + "WHERE { \n" // + + " ?partner ?incoming ?contextNode . \n" // + + " ?contextNode ?outgoing ?uri . \n" // + + " FILTER( ?uri != ?partner ) \n" // + + "} \n"; + private static final String LOCATE_PARTNERS_ON_CONTEXT_NODE_TYPE = "" + + "SELECT ?partner \n" // + + "WHERE { \n" // + + " ?partner ?incoming ?contextNode . \n" // + + " ?contextNode ?outgoing ?uri . \n" // + + " ?contextNode a ?nodeType . \n" // + + " FILTER( ?uri != ?partner ) \n" // + + "} \n"; + private static final String LOCATE_OTHER_PARTNERS_ON_THIS_NODE = "" + + "SELECT ?partner \n" // + + "WHERE { \n" // + + " ?contextNode ?outgoing ?partner . \n" // + + " FILTER( ?uri != ?partner ) \n" // + + "} \n"; + private static final String GET_TYPES = "" // + + "SELECT ?type \n" // + + "WHERE { \n" // + + " ?uri a ?type . \n" // + + "} \n"; + + @Override + public void startIndexing() { + // Nothing to do. + } + + /** + * If this is a "label" statement, check to see if the subject has any acceptable partners across acceptable context + * nodes. + * + * If this is a statement that involves the specified incoming property on an acceptable context node, check to see + * if there are any acceptable partners on this node. + */ + @Override + public List findAdditionalURIsToIndex(Statement stmt) { + if (isLabelStatement(stmt)) { + return filterByType(locatePartners(stmt)); + } else if (isIncomingStatementOnAcceptableContextNode(stmt)) { + return filterByType(locateOtherPartners(stmt)); + } + return Collections.emptyList(); + } + + private boolean isLabelStatement(Statement stmt) { + return RDFS.label.getURI().equals(stmt.getPredicate().getURI()); + } + + private Set locatePartners(Statement stmt) { + String uri = stmt.getSubject().getURI(); + if (contextNodeClasses.isEmpty()) { + return locatePartnersWithoutRestriction(uri); + } else { + Set uris = new HashSet<>(); + for (String contextNodeClass : contextNodeClasses) { + uris.addAll(locatePartnersAcrossContextNodeClass(uri, contextNodeClass)); + } + return uris; + } + } + + private Set locatePartnersWithoutRestriction(String uri) { + return createSelectQueryContext(rdfService, + LOCATE_PARTNERS_WITHOUT_RESTRICTION) + .bindVariableToUri("uri", uri) + .bindVariableToUri("incoming", incomingPropertyUri) + .bindVariableToUri("outgoing", outgoingPropertyUri).execute() + .toStringFields("partner").flattenToSet(); + } + + private Collection locatePartnersAcrossContextNodeClass( + String uri, String contextNodeClass) { + return createSelectQueryContext(rdfService, + LOCATE_PARTNERS_ON_CONTEXT_NODE_TYPE) + .bindVariableToUri("uri", uri) + .bindVariableToUri("nodeType", contextNodeClass) + .bindVariableToUri("incoming", incomingPropertyUri) + .bindVariableToUri("outgoing", outgoingPropertyUri).execute() + .toStringFields("partner").flattenToSet(); + } + + private boolean isIncomingStatementOnAcceptableContextNode(Statement stmt) { + String subjectUri = stmt.getSubject().getURI(); + String predicateUri = stmt.getPredicate().getURI(); + + return incomingPropertyUri.equals(predicateUri) && (contextNodeClasses.isEmpty() || isAnyMatch( + contextNodeClasses, getTypes(subjectUri))); + } + + private boolean isAnyMatch(Set set1, Set set2) { + Set matches = new HashSet<>(set1); + matches.retainAll(set2); + return !matches.isEmpty(); + } + + private Set getTypes(String uri) { + return createSelectQueryContext(rdfService, GET_TYPES).bindVariableToUri("uri", uri).execute().toStringFields( + "type").flattenToSet(); + } + + private Set locateOtherPartners(Statement stmt) { + if (!stmt.getSubject().isURIResource()) { + return Collections.emptySet(); + } + + String nodeUri = stmt.getSubject().getURI(); + String objectUri = (stmt.getObject().isURIResource()) ? stmt.getObject().asResource().getURI() : "NO_MATCH"; + + return createSelectQueryContext(rdfService, + LOCATE_OTHER_PARTNERS_ON_THIS_NODE) + .bindVariableToUri("contextNode", nodeUri) + .bindVariableToUri("uri", objectUri) + .bindVariableToUri("outgoing", outgoingPropertyUri).execute() + .toStringFields("partner").flattenToSet(); + } + + private List filterByType(Collection uris) { + if (typeRestrictions.isEmpty()) { + return new ArrayList<>(uris); + } else { + List filtered = new ArrayList<>(); + for (String uri : uris) { + if (isAnyMatch(typeRestrictions, getTypes(uri))) { + filtered.add(uri); + } + } + return filtered; + } + } + + @Override + public void endIndexing() { + // Nothing to do. + } + +} diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/CoAuthorshipQueryRunner.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/CoAuthorshipQueryRunner.java index bfb64a9808..71c755a9dc 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/CoAuthorshipQueryRunner.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/CoAuthorshipQueryRunner.java @@ -3,7 +3,6 @@ package edu.cornell.mannlib.vitro.webapp.visualization.coauthorship; import java.util.ArrayList; -import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -12,36 +11,34 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import org.apache.jena.query.QueryExecution; -import org.apache.jena.query.QueryExecutionFactory; -import org.apache.jena.rdf.model.Model; -import org.apache.jena.rdf.model.ModelFactory; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer; -import edu.cornell.mannlib.vitro.webapp.visualization.utilities.VisualizationCaches; -import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UtilityFunctions; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.jena.iri.IRI; -import org.apache.jena.iri.IRIFactory; -import org.apache.jena.iri.Violation; - -import org.apache.jena.query.QuerySolution; -import org.apache.jena.query.Syntax; -import org.apache.jena.rdf.model.RDFNode; - import edu.cornell.mannlib.vitro.webapp.visualization.collaborationutils.CoAuthorshipData; import edu.cornell.mannlib.vitro.webapp.visualization.collaborationutils.CollaboratorComparator; import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants; import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryFieldLabels; import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.utilities.VisualizationCaches; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Activity; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Collaboration; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Collaborator; import edu.cornell.mannlib.vitro.webapp.visualization.visutils.QueryRunner; import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UniqueIDGenerator; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UtilityFunctions; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.jena.iri.IRI; +import org.apache.jena.iri.IRIFactory; +import org.apache.jena.iri.Violation; +import org.apache.jena.query.QueryExecution; +import org.apache.jena.query.QueryExecutionFactory; +import org.apache.jena.query.QuerySolution; +import org.apache.jena.query.Syntax; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.RDFNode; /** * This query runner is used to execute a sparql query to get all the publications @@ -97,6 +94,8 @@ protected void processQuerySolution(QuerySolution qs) { RDFNode documentNode = qs.get(QueryFieldLabels.DOCUMENT_URL); RDFNode coAuthorURLNode = qs.get(QueryFieldLabels.CO_AUTHOR_URL); RDFNode coAuthorLabelNode = qs.get(QueryFieldLabels.CO_AUTHOR_LABEL); + RDFNode coAuthorFamilyNode = qs.get(QueryFieldLabels.CO_AUTHOR_PERSON_FAMILY); + RDFNode coAuthorGivenNode = qs.get(QueryFieldLabels.CO_AUTHOR_PERSON_GIVEN); RDFNode publicationDateNode = qs.get(QueryFieldLabels.DOCUMENT_PUBLICATION_DATE); String authorURI = egoAuthorURLNode == null ? null : egoAuthorURLNode.asLiteral().getString(); @@ -106,10 +105,28 @@ protected void processQuerySolution(QuerySolution qs) { String coAuthorURI = coAuthorURLNode == null ? null : coAuthorURLNode.asLiteral().getString(); String coAuthorName = coAuthorLabelNode == null ? null : coAuthorLabelNode.asLiteral().getString(); - processEntry(authorURI, authorName, documentURI, documentDate, coAuthorURI, coAuthorName); + if (StringUtils.isEmpty(coAuthorName)) { + String familyStr = coAuthorFamilyNode == null ? null : coAuthorFamilyNode.asLiteral().getString(); + String givenStr = coAuthorGivenNode == null ? null : coAuthorGivenNode.asLiteral().getString(); + boolean isVcard = false; + if (StringUtils.isEmpty(coAuthorURI)) { + coAuthorURI = "info://vcard/" + familyStr + "/" + givenStr; + isVcard = true; + } + if (StringUtils.isEmpty(familyStr)) { + processEntry(authorURI, authorName, documentURI, documentDate, coAuthorURI, givenStr, isVcard); + } else if (StringUtils.isEmpty(givenStr)) { + processEntry(authorURI, authorName, documentURI, documentDate, coAuthorURI, familyStr, isVcard); + } else { + processEntry(authorURI, authorName, documentURI, documentDate, coAuthorURI, familyStr + ", " + givenStr, isVcard); + } + } else if (!StringUtils.isEmpty(coAuthorURI)) { + processEntry(authorURI, authorName, documentURI, documentDate, coAuthorURI, coAuthorName, false); + } } - public void processEntry(String authorURI, String authorName, String documentURI, String documentDate, String coAuthorURI, String coAuthorName) { + public void processEntry(String authorURI, String authorName, String documentURI, String documentDate, String coAuthorURI, String coAuthorName, boolean coAuthorIsVCard) { + /* * We only want to create only ONE ego node. * */ @@ -157,6 +174,10 @@ public void processEntry(String authorURI, String authorName, String documentURI if (coAuthorName != null) { coAuthorNode.setCollaboratorName(coAuthorName); } + + if (coAuthorIsVCard) { + coAuthorNode.setIsVCard(); + } } coAuthorNode.addActivity(biboDocument); @@ -377,7 +398,6 @@ private void removeLowQualityNodesAndEdges( } nodes.removeAll(nodesToBeRemoved); } - /* END QUERY RUNNER */ } @@ -390,16 +410,21 @@ private String generateEgoCoAuthorshipSparqlQuery(String queryURI) { + " (str(?authorLabel) as ?" + QueryFieldLabels.AUTHOR_LABEL + ") \n" + " (str(?coAuthorPerson) as ?" + QueryFieldLabels.CO_AUTHOR_URL + ") \n" + " (str(?coAuthorPersonLabel) as ?" + QueryFieldLabels.CO_AUTHOR_LABEL + ") \n" + + " (str(?coAuthorPersonFamilyName) as ?coAuthorPersonFamily) \n" + + " (str(?coAuthorPersonGivenName) as ?coAuthorPersonGiven) \n" + " (str(?document) as ?" + QueryFieldLabels.DOCUMENT_URL + ") \n" + " (str(?publicationDate) as ?" + QueryFieldLabels.DOCUMENT_PUBLICATION_DATE + ") \n" + "WHERE { \n" + " <" + queryURI + "> local:authorLabel ?authorLabel ;" + " local:authorOf ?document . \n" - + " ?document local:coAuthor ?coAuthorPerson . \n" - + " ?coAuthorPerson rdfs:label ?coAuthorPersonLabel . \n" + + " ?document local:coAuthorship ?coAuthorshipNode . \n" + + " OPTIONAL { ?coAuthorshipNode local:coAuthor ?coAuthorPerson . } \n" + + " OPTIONAL { ?coAuthorshipNode rdfs:label ?coAuthorPersonLabel . } \n" + + " OPTIONAL { ?coAuthorshipNode local:familyName ?coAuthorPersonFamilyName . } \n" + + " OPTIONAL { ?coAuthorshipNode local:givenName ?coAuthorPersonGivenName . } \n" + " OPTIONAL { ?document local:publicationDate ?publicationDate . } \n" + "} \n" - + "ORDER BY ?document ?coAuthorPerson\n"; + + "ORDER BY ?document ?coAuthorshipNode\n"; log.debug("COAUTHORSHIP QUERY - " + sparqlQuery); @@ -414,8 +439,11 @@ private String generateEgoCoAuthorshipSparqlConstruct(String queryURI) { + " <" + queryURI + "> local:authorLabel ?authorLabel .\n" + " <" + queryURI + "> local:authorOf ?document .\n" + " ?document local:publicationDate ?publicationDate .\n" - + " ?document local:coAuthor ?coAuthorPerson .\n" - + " ?coAuthorPerson rdfs:label ?coAuthorPersonLabel .\n" + + " ?document local:coAuthorship ?coAuthorshipNode .\n" + + " ?coAuthorshipNode local:coAuthor ?coAuthorPerson .\n" + + " ?coAuthorshipNode rdfs:label ?coAuthorPersonLabel .\n" + + " ?coAuthorshipNode local:familyName ?coAuthorPersonFamilyName .\n" + + " ?coAuthorshipNode local:givenName ?coAuthorPersonGivenName .\n" + "}\n" + "WHERE\n" + "{\n" @@ -432,7 +460,23 @@ private String generateEgoCoAuthorshipSparqlConstruct(String queryURI) { + " ?coAuthorPerson rdf:type foaf:Person ; \n" + " rdfs:label ?coAuthorPersonLabel . \n" + " }\n" - + " UNION\n" + + " UNION\n" + + " {\n" + + " <" + queryURI + "> rdf:type foaf:Person ;" + + " rdfs:label ?authorLabel ;" + + " core:relatedBy ?authorshipNode . \n" + + " ?authorshipNode rdf:type core:Authorship ;" + + " core:relates ?document . \n" + + " ?document rdf:type ; \n" + + " core:relatedBy ?coAuthorshipNode . \n" + + " ?coAuthorshipNode rdf:type core:Authorship ; \n" + + " core:relates ?coAuthorVCard . \n" + + " ?coAuthorVCard rdf:type ; \n" + + " ?coAuthorVCardName . \n" + + " ?coAuthorVCardName ?coAuthorPersonFamilyName ; \n" + + " ?coAuthorPersonGivenName . \n" + + " }\n" + + " UNION\n" + " {\n" + " <" + queryURI + "> rdf:type foaf:Person ;" + " rdfs:label ?authorLabel ;" @@ -512,7 +556,7 @@ private synchronized CoAuthorshipData getQueryResultAndCache() String documentDate = publicationToYearMap.get(documentURI); for (String coAuthorURI : publicationToPersonMap.get(documentURI)) { String coAuthorName = personLabelsMap.get(coAuthorURI); - consumer.processEntry(authorURI, authorName, documentURI, documentDate, coAuthorURI, coAuthorName); + consumer.processEntry(authorURI, authorName, documentURI, documentDate, coAuthorURI, coAuthorName, false); } } consumer.endProcessing(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryFieldLabels.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryFieldLabels.java index 7ad97d162c..89a5ec6d3b 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryFieldLabels.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryFieldLabels.java @@ -3,7 +3,7 @@ package edu.cornell.mannlib.vitro.webapp.visualization.constants; /** - * Thsi contains the sparql fields which are used to capture data for the value objects. + * This contains the sparql fields which are used to capture data for the value objects. * @author cdtank */ public class QueryFieldLabels { @@ -47,6 +47,8 @@ public class QueryFieldLabels { * */ public static final String CO_AUTHOR_URL = "coAuthPersonLit"; public static final String CO_AUTHOR_LABEL = "coAuthPersonLabelLit"; + public static final String CO_AUTHOR_PERSON_GIVEN = "coAuthorPersonGiven"; + public static final String CO_AUTHOR_PERSON_FAMILY = "coAuthorPersonFamily"; /* * College related field labels diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Collaborator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Collaborator.java index 325fd63f0a..d6788f0b91 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Collaborator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Collaborator.java @@ -22,6 +22,7 @@ public class Collaborator extends Individual { private int collaboratorID; + private boolean isVCard = false; private Map yearToActivityCount; private Set activities = new HashSet(); @@ -32,6 +33,10 @@ public Collaborator(String collaboratorURI, collaboratorID = uniqueIDGenerator.getNextNumericID(); } + public void setIsVCard() { isVCard = true; } + + public boolean getIsVCard() { return isVCard; } + public int getCollaboratorID() { return collaboratorID; } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/visutils/CollaborationDataViewHelper.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/visutils/CollaborationDataViewHelper.java index da1205052e..2d2f215f2e 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/visutils/CollaborationDataViewHelper.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/visualization/visutils/CollaborationDataViewHelper.java @@ -2,15 +2,34 @@ package edu.cornell.mannlib.vitro.webapp.visualization.visutils; +import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.visualization.collaborationutils.CollaborationData; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Collaboration; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Collaborator; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import java.util.ArrayList; import java.util.List; public class CollaborationDataViewHelper { - private static final int MAX_COLLABORATORS = 35; + + private static final String DEFAULT_PERSON_COLLABORATORS_BOOST = "0"; + + private static final String DEFAULT_MAX_COLLABORATORS = "35"; + + private static final String MAX_COLLABORATORS_PROPERTY = "visualization.coAuthorNetwork.maxCollaborators"; + + private static final String PERSON_COLLABORATORS_BOOST_PROPERTY = "visualization.coAuthorNetwork.personBoost"; + + private static Log log = LogFactory.getLog(CollaborationDataViewHelper.class.getName()); + + private static final int MAX_COLLABORATORS = getPropertyIntValue(MAX_COLLABORATORS_PROPERTY, + DEFAULT_MAX_COLLABORATORS); + + private static final int PERSON_COLLABORATORS_BOOST = getPropertyIntValue(PERSON_COLLABORATORS_BOOST_PROPERTY, + DEFAULT_PERSON_COLLABORATORS_BOOST); + private CollaborationData data; private List collaborators = null; @@ -36,6 +55,21 @@ public List getCollaborators() { return collaborators; } + private static int getPropertyIntValue(String property, String defaultValue) { + ConfigurationProperties props = ConfigurationProperties.getInstance(); + String propertyValue = props.getProperty(property, defaultValue); + try { + return Integer.parseInt(propertyValue); + } catch (Exception e) { + log.error(String.format( + "Can't convert %s to integer value. " + + "Property %s should be set to an integer value. " + + "Use fallback to default value %s.", + propertyValue, property, defaultValue)); + return Integer.parseInt(defaultValue); + } + } + private synchronized void init(int max) { if (collaborators != null) { return; @@ -56,7 +90,7 @@ private synchronized void init(int max) { if (collaborator.getCollaboratorID() != data.getEgoCollaborator().getCollaboratorID()) { // If the number of activities exceeds the threshold, it needs to be included in the top N - if (collaborator.getNumOfActivities() > threshold) { + if (collaborator.getNumOfActivities() + boost(collaborator) > threshold) { // If we've filled the Top N if (collaborators.size() == max - 1) { // Remove the last (lowest) entry of the Top N @@ -67,7 +101,8 @@ private synchronized void init(int max) { int insert = collaborators.size(); while (insert > 0) { insert--; - if (collaborators.get(insert).getNumOfActivities() > collaborator.getNumOfActivities()) { + Collaborator collaboratorAtInsert = collaborators.get(insert); + if (collaboratorAtInsert.getNumOfActivities() + boost(collaboratorAtInsert) > collaborator.getNumOfActivities() + boost(collaborator)) { insert++; break; } @@ -85,7 +120,8 @@ private synchronized void init(int max) { } // Update the threshold with the new lowest position entry - threshold = collaborators.get(collaborators.size() - 1).getNumOfActivities(); + Collaborator thresholdCollaborator = collaborators.get(collaborators.size() - 1); + threshold = thresholdCollaborator.getNumOfActivities() + boost(thresholdCollaborator); } else { // If we are below the threshold, check if the top N is full if (collaborators.size() < max - 1) { @@ -93,7 +129,7 @@ private synchronized void init(int max) { collaborators.add(collaborator); // And record the new collaboration as the threshold - threshold = collaborator.getNumOfActivities(); + threshold = collaborator.getNumOfActivities() + boost(collaborator); } } } @@ -162,4 +198,11 @@ private synchronized void init(int max) { // Reset the activity count for the top left matrix entry (focus - focus collaboration) collaborationMatrix[0][0] = 0; } + + private int boost(Collaborator collaborator) { + if (!collaborator.getIsVCard()) { + return PERSON_COLLABORATORS_BOOST; + } + return 0; + } } diff --git a/home/src/main/resources/config/example.runtime.properties b/home/src/main/resources/config/example.runtime.properties index 8817ce777b..4fea75f5d0 100644 --- a/home/src/main/resources/config/example.runtime.properties +++ b/home/src/main/resources/config/example.runtime.properties @@ -411,6 +411,16 @@ visualization.temporal = enabled # visualization.mapOfScience = enabled + #Maximum number of co-authors displayed on co-authors network. +visualization.coAuthorNetwork.maxCollaborators = 35 + + #Prioritize co-authors stored as Persons in lists with VCard co-authors + #In case you would like to prioritize person co-authors over co-authors stored as VCards + #when there are more than maximum number of collaborators this property can be set to 10000. + #In that case list of coauthors to display limited by maximum number collaborators will be + #first sorted by the type of stored collaborator (Person first, then VCard) and second by + #the number of joint publications. +visualization.coAuthorNetwork.personBoost = 0 # # Types of individual for which we can create proxy editors. # If this is omitted, defaults to http://www.w3.org/2002/07/owl#Thing diff --git a/home/src/main/resources/rdf/display/everytime/searchIndexerConfigurationVivo.n3 b/home/src/main/resources/rdf/display/everytime/searchIndexerConfigurationVivo.n3 index bdc8a4fa8c..3b42574fa3 100644 --- a/home/src/main/resources/rdf/display/everytime/searchIndexerConfigurationVivo.n3 +++ b/home/src/main/resources/rdf/display/everytime/searchIndexerConfigurationVivo.n3 @@ -27,6 +27,15 @@ :hasIncomingProperty "http://vivoweb.org/ontology/core#relatedBy" ; :hasOutgoingProperty "http://vivoweb.org/ontology/core#relates" . +# Special case for VCards being linked to Authorships (no label present) +:extension_forContextNodeVCards + a searchIndex:indexing.IndexingUriFinder , + searchIndex:documentBuilding.DocumentModifier , + searchIndex:extensions.VCardsAcrossContextNodes ; + rdfs:label "VCards across relatedBy/relates" ; + :hasIncomingProperty "http://vivoweb.org/ontology/core#relatedBy" ; + :hasOutgoingProperty "http://vivoweb.org/ontology/core#relates" . + # Some roles look like this: bearerOf ==> role ==> roleContributesTo # inheresIn <== role <== contributingRole :extension_forContextNodes_role_contributes_1 diff --git a/home/src/main/resources/rdf/display/firsttime/PropertyConfig.n3 b/home/src/main/resources/rdf/display/firsttime/PropertyConfig.n3 index 6e98de098a..b03b0f5879 100644 --- a/home/src/main/resources/rdf/display/firsttime/PropertyConfig.n3 +++ b/home/src/main/resources/rdf/display/firsttime/PropertyConfig.n3 @@ -1914,7 +1914,7 @@ local:bfo_0000055Context a :ConfigContext ; :qualifiedBy . local:bfo_0000055Config a :ObjectPropertyDisplayConfig ; - :listViewConfigFile "listViewConfig-relatedRole.xml"^^xsd:string ; + :listViewConfigFile "listViewConfig-relatedExternalSpeakerRole.xml"^^xsd:string ; rdfs:label "relatedRole"@en-US; :displayName "participant" ; vitro:displayRankAnnot 17; diff --git a/home/src/main/resources/rdf/i18n/de_DE/interface-i18n/firsttime/vivo_UiLabel.ttl b/home/src/main/resources/rdf/i18n/de_DE/interface-i18n/firsttime/vivo_UiLabel.ttl index 0e9ed9861a..1b88061dcf 100644 --- a/home/src/main/resources/rdf/i18n/de_DE/interface-i18n/firsttime/vivo_UiLabel.ttl +++ b/home/src/main/resources/rdf/i18n/de_DE/interface-i18n/firsttime/vivo_UiLabel.ttl @@ -6269,3 +6269,31 @@ uil-data:degree_candidacy.VIVO uil:hasApp "VIVO" ; uil:hasKey "degree_candidacy" ; uil:hasPackage "VIVO-languages" . + +uil-data:vis_coauthor_vcard.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Einbeziehung unbestätigter Co-Autoren"@de-DE ; + uil:hasApp "VIVO" ; + uil:hasKey "vis_coauthor_vcard" . + +uil-data:add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Zur Profilseite der Person hinzufügen?"@de-DE ; + uil:hasApp "VIVO" ; + uil:hasKey "add_to_person_profile" . + +uil-data:yes_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Ja"@de-DE ; + uil:hasApp "VIVO" ; + uil:hasKey "yes_add_to_person_profile" . + +uil-data:no_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Nein"@de-DE ; + uil:hasApp "VIVO" ; + uil:hasKey "no_add_to_person_profile" . \ No newline at end of file diff --git a/home/src/main/resources/rdf/i18n/en_CA/interface-i18n/firsttime/vivo_UiLabel.ttl b/home/src/main/resources/rdf/i18n/en_CA/interface-i18n/firsttime/vivo_UiLabel.ttl index ce9bc35f38..8efa4f62d3 100644 --- a/home/src/main/resources/rdf/i18n/en_CA/interface-i18n/firsttime/vivo_UiLabel.ttl +++ b/home/src/main/resources/rdf/i18n/en_CA/interface-i18n/firsttime/vivo_UiLabel.ttl @@ -6266,3 +6266,31 @@ uil-data:degree_candidacy.VIVO uil:hasApp "VIVO" ; uil:hasKey "degree_candidacy" ; uil:hasPackage "VIVO-languages" . + +uil-data:vis_coauthor_vcard.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Include external co-authors"@en-CA ; + uil:hasApp "VIVO" ; + uil:hasKey "vis_coauthor_vcard" . + +uil-data:add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label ""Add to person’s profile page?"@en-CA ; + uil:hasApp "VIVO" ; + uil:hasKey "add_to_person_profile" . + +uil-data:yes_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Yes"@en-CA ; + uil:hasApp "VIVO" ; + uil:hasKey "yes_add_to_person_profile" . + +uil-data:no_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "No"@en-CA ; + uil:hasApp "VIVO" ; + uil:hasKey "no_add_to_person_profile" . 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..5116262649 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 @@ -6266,3 +6266,31 @@ uil-data:degree_candidacy.VIVO uil:hasApp "VIVO" ; uil:hasKey "degree_candidacy" ; uil:hasPackage "VIVO-languages" . + +uil-data:vis_coauthor_vcard.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Include external co-authors"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "vis_coauthor_vcard" . + +uil-data:add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Add to person’s profile page?"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "add_to_person_profile" . + +uil-data:yes_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Yes"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "yes_add_to_person_profile" . + +uil-data:no_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "No"@en-US ; + uil:hasApp "VIVO" ; + uil:hasKey "no_add_to_person_profile" . diff --git a/home/src/main/resources/rdf/i18n/es/interface-i18n/firsttime/vivo_UiLabel.ttl b/home/src/main/resources/rdf/i18n/es/interface-i18n/firsttime/vivo_UiLabel.ttl index e8299e28fb..00357aa29b 100644 --- a/home/src/main/resources/rdf/i18n/es/interface-i18n/firsttime/vivo_UiLabel.ttl +++ b/home/src/main/resources/rdf/i18n/es/interface-i18n/firsttime/vivo_UiLabel.ttl @@ -6266,3 +6266,31 @@ uil-data:degree_candidacy.VIVO uil:hasApp "VIVO" ; uil:hasKey "degree_candidacy" ; uil:hasPackage "VIVO-languages" . + +uil-data:vis_coauthor_vcard.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Incluir coautores externos"@es ; + uil:hasApp "VIVO" ; + uil:hasKey "vis_coauthor_vcard" . + +uil-data:add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "¿Agregar a la página de perfil de la persona?"@es ; + uil:hasApp "VIVO" ; + uil:hasKey "add_to_person_profile" . + +uil-data:yes_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Sí"@es ; + uil:hasApp "VIVO" ; + uil:hasKey "yes_add_to_person_profile" . + +uil-data:no_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "No"@es ; + uil:hasApp "VIVO" ; + uil:hasKey "no_add_to_person_profile" . diff --git a/home/src/main/resources/rdf/i18n/fr_CA/interface-i18n/firsttime/vivo_UiLabel.ttl b/home/src/main/resources/rdf/i18n/fr_CA/interface-i18n/firsttime/vivo_UiLabel.ttl index 97cdf09e7e..75549e2eb8 100644 --- a/home/src/main/resources/rdf/i18n/fr_CA/interface-i18n/firsttime/vivo_UiLabel.ttl +++ b/home/src/main/resources/rdf/i18n/fr_CA/interface-i18n/firsttime/vivo_UiLabel.ttl @@ -6266,3 +6266,31 @@ uil-data:degree_candidacy.VIVO uil:hasApp "VIVO" ; uil:hasKey "degree_candidacy" ; uil:hasPackage "VIVO-languages" . + +uil-data:vis_coauthor_vcard.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Inclure des co-auteurs externes"@fr-CA ; + uil:hasApp "VIVO" ; + uil:hasKey "vis_coauthor_vcard" . + +uil-data:add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Ajouter à la page de profil de la personne ?"@fr-CA ; + uil:hasApp "VIVO" ; + uil:hasKey "add_to_person_profile" . + +uil-data:yes_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Oui"@fr-CA ; + uil:hasApp "VIVO" ; + uil:hasKey "yes_add_to_person_profile" . + +uil-data:no_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Non"@fr-CA ; + uil:hasApp "VIVO" ; + uil:hasKey "no_add_to_person_profile" . diff --git a/home/src/main/resources/rdf/i18n/pt_BR/interface-i18n/firsttime/vivo_UiLabel.ttl b/home/src/main/resources/rdf/i18n/pt_BR/interface-i18n/firsttime/vivo_UiLabel.ttl index ac7c639abb..0b821492d3 100644 --- a/home/src/main/resources/rdf/i18n/pt_BR/interface-i18n/firsttime/vivo_UiLabel.ttl +++ b/home/src/main/resources/rdf/i18n/pt_BR/interface-i18n/firsttime/vivo_UiLabel.ttl @@ -6266,3 +6266,31 @@ uil-data:degree_candidacy.VIVO uil:hasApp "VIVO" ; uil:hasKey "degree_candidacy" ; uil:hasPackage "VIVO-languages" . + +uil-data:vis_coauthor_vcard.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Incluir coautores externos"@pt-BR ; + uil:hasApp "VIVO" ; + uil:hasKey "vis_coauthor_vcard" . + +uil-data:add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Adicionar à página de perfil da pessoa?"@pt-BR ; + uil:hasApp "VIVO" ; + uil:hasKey "add_to_person_profile" . + +uil-data:yes_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Sim"@pt-BR ; + uil:hasApp "VIVO" ; + uil:hasKey "yes_add_to_person_profile" . + +uil-data:no_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Não"@pt-BR ; + uil:hasApp "VIVO" ; + uil:hasKey "no_add_to_person_profile" . diff --git a/home/src/main/resources/rdf/i18n/ru_RU/interface-i18n/firsttime/vivo_UiLabel.ttl b/home/src/main/resources/rdf/i18n/ru_RU/interface-i18n/firsttime/vivo_UiLabel.ttl index cd1ba10c29..b873c9739b 100644 --- a/home/src/main/resources/rdf/i18n/ru_RU/interface-i18n/firsttime/vivo_UiLabel.ttl +++ b/home/src/main/resources/rdf/i18n/ru_RU/interface-i18n/firsttime/vivo_UiLabel.ttl @@ -6266,3 +6266,31 @@ uil-data:degree_candidacy.VIVO uil:hasApp "VIVO" ; uil:hasKey "degree_candidacy" ; uil:hasPackage "VIVO-languages" . + +uil-data:vis_coauthor_vcard.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Включить внешних соавторов"@ru-RU ; + uil:hasApp "VIVO" ; + uil:hasKey "vis_coauthor_vcard" . + +uil-data:add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Добавить в профиль персоны?"@ru-RU ; + uil:hasApp "VIVO" ; + uil:hasKey "add_to_person_profile" . + +uil-data:yes_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Да"@ru-RU ; + uil:hasApp "VIVO" ; + uil:hasKey "yes_add_to_person_profile" . + +uil-data:no_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Нет"@ru-RU ; + uil:hasApp "VIVO" ; + uil:hasKey "no_add_to_person_profile" . diff --git a/home/src/main/resources/rdf/i18n/sr_Latn_RS/interface-i18n/firsttime/vivo_UiLabel.ttl b/home/src/main/resources/rdf/i18n/sr_Latn_RS/interface-i18n/firsttime/vivo_UiLabel.ttl index 87fcf6cb43..ba01e91abf 100644 --- a/home/src/main/resources/rdf/i18n/sr_Latn_RS/interface-i18n/firsttime/vivo_UiLabel.ttl +++ b/home/src/main/resources/rdf/i18n/sr_Latn_RS/interface-i18n/firsttime/vivo_UiLabel.ttl @@ -6265,3 +6265,31 @@ uil-data:degree_candidacy.VIVO uil:hasApp "VIVO" ; uil:hasKey "degree_candidacy" ; uil:hasPackage "VIVO-languages" . + +uil-data:vis_coauthor_vcard.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Uključite spoljne koautore"@sr-Latn-RS ; + uil:hasApp "VIVO" ; + uil:hasKey "vis_coauthor_vcard" . + +uil-data:select_vcard_or_person.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Dodati na stranicu profila osobe?"@sr-Latn-RS ; + uil:hasApp "VIVO" ; + uil:hasKey "select_vcard_or_person" . + +uil-data:yes_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Da"@sr-Latn-RS ; + uil:hasApp "VIVO" ; + uil:hasKey "yes_add_to_person_profile" . + +uil-data:no_add_to_person_profile.VIVO + rdf:type owl:NamedIndividual ; + rdf:type uil:UILabel ; + rdfs:label "Ne"@sr-Latn-RS ; + uil:hasApp "VIVO" ; + uil:hasKey "no_add_to_person_profile" . diff --git a/webapp/src/main/webapp/config/listViewConfig-informationResourceInEditorship.xml b/webapp/src/main/webapp/config/listViewConfig-informationResourceInEditorship.xml index e6281ca01c..06d7703bf8 100644 --- a/webapp/src/main/webapp/config/listViewConfig-informationResourceInEditorship.xml +++ b/webapp/src/main/webapp/config/listViewConfig-informationResourceInEditorship.xml @@ -5,15 +5,16 @@ - PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> + 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 vcard: <http://www.w3.org/2006/vcard/ns#> PREFIX fn: <http://www.w3.org/2005/xpath-functions#> - - SELECT DISTINCT ?subclass + + SELECT DISTINCT ?subclass ?editorship - ?person ?personName + ?editor ?editorName WHERE { ?subject ?property ?editorship . ?editorship a core:Editorship . @@ -25,24 +26,60 @@ OPTIONAL { ?subject ?property ?editorship . ?editorship a core:Editorship . - ?editorship core:relates ?person . - ?person a foaf:Person . - ?person rdfs:label ?personName . - } - + ?editorship core:relates ?editor . + ?editor a foaf:Agent . + ?editor rdfs:label ?editorName . + OPTIONAL { + ?subject ?property ?editorship . + ?editorship a core:Editorship . + ?editorship core:relates ?editor . + ?editor a foaf:Agent . + ?editor vitro:mostSpecificType ?subclass . + ?subclass rdfs:subClassOf foaf:Agent . + } + } OPTIONAL { ?subject ?property ?editorship . ?editorship a core:Editorship . - ?editorship core:relates ?person . - ?person a foaf:Person . - ?person vitro:mostSpecificType ?subclass . - ?subclass rdfs:subClassOf foaf:Person . + ?editorship core:relates ?editor . + ?editor a vcard:Kind . + ?editor vcard:hasName ?vName . + ?vName vcard:familyName ?lastName . + OPTIONAL { + ?subject ?property ?editorship . + ?editorship a core:Editorship . + ?editorship core:relates ?editor . + ?editor a vcard:Kind . + ?editor vcard:hasName ?vName . + ?vName vcard:givenName ?firstName . + } + OPTIONAL { + ?subject ?property ?editorship . + ?editorship a core:Editorship . + ?editorship core:relates ?editor . + ?editor a vcard:Kind . + ?editor vcard:hasName ?vName . + ?vName core:middleName ?middleName . + } + bind ( COALESCE(?firstName, "") As ?firstName1) . + bind ( COALESCE(?middleName, "") As ?middleName1) . + bind ( COALESCE(?lastName, "") As ?lastName1) . + bind (concat(str(str(?lastName1) + ", "),str(str(?firstName1) + " "),str(?middleName1)) as ?editorName) . + + OPTIONAL { + ?subject ?property ?editorship . + ?editorship a core:Editorship . + ?editorship core:relates ?editor . + ?editor a vcard:Kind . + ?editor vitro:mostSpecificType ?subclass . + ?subclass rdfs:subClassOf vcard:Kind . + } } - + - FILTER ( bound(?person) ) + FILTER ( bound(?editor) ) - } ORDER BY ?subclass ?rank (fn:lower-case(?personName)) + } ORDER BY ?subclass ?rank (fn:lower-case(?editorName)) diff --git a/webapp/src/main/webapp/config/listViewConfig-relatedExternalSpeakerRole.xml b/webapp/src/main/webapp/config/listViewConfig-relatedExternalSpeakerRole.xml new file mode 100644 index 0000000000..6a33b34efc --- /dev/null +++ b/webapp/src/main/webapp/config/listViewConfig-relatedExternalSpeakerRole.xml @@ -0,0 +1,128 @@ + + + + + + + + + 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 vcard: <http://www.w3.org/2006/vcard/ns#> + + + SELECT DISTINCT ?subclass + ?vSubclass + # send the property to the template, since this view supports multiple role properties + ?property + ?role + ?roleLabel ?roleTypeLabel + ?indivInRole (REPLACE(STR(?indivInRole),"^.*(#)(.*)$", "$2") AS ?indivName) + ?indivLabel + ?dateTimeInterval ?dateTimeStart ?dateTimeEnd ?objectType + WHERE { + + ?subject ?property ?role . + ?role a ?objectType . + + OPTIONAL { + ?subject ?property ?role . + ?role a ?objectType . + ?role rdfs:label ?roleLabel . + } + + # We need ?subclass in the uncollated query to get the roleTypeLabel + # for roles that have no label. + OPTIONAL { + ?subject ?property ?role . + ?role a ?objectType . + ?role vitro:mostSpecificType ?subclass . + } + OPTIONAL { + ?subject ?property ?role . + ?role a ?objectType . + ?role vitro:mostSpecificType ?subclass . + ?subclass rdfs:label ?roleTypeLabel . + } + OPTIONAL { + ?subject ?property ?role . + ?role a ?objectType . + ?role <http://purl.obolibrary.org/obo/RO_0000052> ?indivInRole . + } + OPTIONAL { + ?subject ?property ?role . + ?role a ?objectType . + ?role <http://purl.obolibrary.org/obo/RO_0000052> ?indivInRole . + ?indivInRole a foaf:Person . + ?indivInRole rdfs:label ?indivLabel . + } + OPTIONAL { + ?subject ?property ?role . + ?role a ?objectType . + ?role <http://purl.obolibrary.org/obo/RO_0000052> ?indivInRole . + ?indivInRole vitro:mostSpecificType ?vSubclass . + ?vSubclass rdfs:subClassOf vcard:Kind . + #?indivInRole a vcard:Kind . + ?indivInRole vcard:hasName ?vName . + ?vName vcard:familyName ?lastName . + OPTIONAL { + ?subject ?property ?role . + ?role a ?objectType . + ?role <http://purl.obolibrary.org/obo/RO_0000052> ?indivInRole . + ?indivInRole a vcard:Kind . + ?indivInRole vcard:hasName ?vName . + ?vName vcard:givenName ?firstName . + } + OPTIONAL { + ?subject ?property ?role . + ?role a ?objectType . + ?role <http://purl.obolibrary.org/obo/RO_0000052> ?indivInRole . + ?indivInRole a vcard:Kind . + ?indivInRole vcard:hasName ?vName . + ?vName core:middleName ?middleName . + } + bind ( COALESCE(?firstName, "") As ?firstName1) . + bind ( COALESCE(?middleName, "") As ?middleName1) . + bind ( COALESCE(?lastName, "") As ?lastName1) . + bind (concat(str(?lastName1), ", ", str(?firstName1), " ", str(?middleName1)) as ?indivLabel) . + OPTIONAL { + ?subject ?property ?role . + ?role a ?objectType . + ?role <http://purl.obolibrary.org/obo/RO_0000052> ?indivInRole . + ?indivInRole a vcard:Kind . + ?indivInRole vitro:mostSpecificType ?vSubclass . + ?vSubclass rdfs:subClassOf vcard:Kind . + } + } + OPTIONAL { + ?subject ?property ?role . + ?role a ?objectType . + ?role <http://purl.obolibrary.org/obo/RO_0000052> ?indivInRole . + ?indivInRole a foaf:Person . + ?indivInRole vitro:mostSpecificType ?vSubclass . + ?vSubclass rdfs:subClassOf foaf:Person . + } + OPTIONAL { + ?subject ?property ?role . + ?role a ?objectType . + ?role core:dateTimeInterval ?dateTimeInterval . + ?dateTimeInterval core:start ?dateTimeStartValue . + ?dateTimeStartValue core:dateTime ?dateTimeStart . + } + OPTIONAL { + ?subject ?property ?role . + ?role a ?objectType . + ?role core:dateTimeInterval ?dateTimeInterval . + ?dateTimeInterval core:end ?dateTimeEndValue . + ?dateTimeEndValue core:dateTime ?dateTimeEnd . + } + + FILTER ( bound(?indivInRole) ) + + } ORDER BY ?subclass ?indivLabel ?roleLabel ?roleTypeLabel ?indivName + + + + diff --git a/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-informationResourceInEditorship.ftl b/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-informationResourceInEditorship.ftl index 840484b566..01239d1345 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-informationResourceInEditorship.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-informationResourceInEditorship.ftl @@ -7,13 +7,24 @@ --> <#import "lib-sequence.ftl" as s> +<#import "lib-meta-tags.ftl" as lmt> + <@showEditorship statement /> <#-- Use a macro to keep variable assignments local; otherwise the values carry over to the next statement --> <#macro showEditorship statement> - <#if statement.person??> - ${statement.personName} + <#if statement.editor??> + <#if statement.subclass?? && statement.subclass?contains("vcard")> + <#if statement.editorName?replace(" ","")?length == statement.editorName?replace(" ","")?last_index_of(",") + 1 > + ${statement.editorName?replace(",","")} + <#else> + ${statement.editorName!i18n().missing_editor} + + <#else> + ${statement.editorName} + + <@lmt.addCitationMetaTag uri="http://vivoweb.org/ontology/core#Editorship" content=statement.editorName /> <#else> <#-- This shouldn't happen, but we must provide for it --> ${i18n().missing_editor} diff --git a/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-relatedRole.ftl b/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-relatedRole.ftl index d07da7d106..39953d8f82 100644 --- a/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-relatedRole.ftl +++ b/webapp/src/main/webapp/templates/freemarker/body/partials/individual/propStatement-relatedRole.ftl @@ -17,10 +17,10 @@ <#local linkedIndividual> <#if statement.indivInRole??> <#if statement.vSubclass?? && statement.vSubclass?contains("vcard")> - <#if statement.indivLabel?replace(" ","")?length == statement.indivLabel?replace(" ","")?last_index_of(",") + 1 > - ${statement.indivLabel?replace(",","")} + <#if statement.indivLabel!?replace(" ","")?length == statement.indivLabel!?replace(" ","")?last_index_of(",") + 1 > + ${statement.indivLabel!?replace(",","")} <#else> - ${statement.indivLabel} + ${statement.indivLabel!} <#else> ${statement.indivLabel!statement.indivName} diff --git a/webapp/src/main/webapp/templates/freemarker/edit/forms/addAuthorsToInformationResource.ftl b/webapp/src/main/webapp/templates/freemarker/edit/forms/addAuthorsToInformationResource.ftl index 65ba356783..ad2ce4ba49 100644 --- a/webapp/src/main/webapp/templates/freemarker/edit/forms/addAuthorsToInformationResource.ftl +++ b/webapp/src/main/webapp/templates/freemarker/edit/forms/addAuthorsToInformationResource.ftl @@ -122,15 +122,22 @@

-

- - +

+ +

- -

- - +

+ +

+ +
+

${i18n().add_to_person_profile} ${requiredHint}

+ + + + +

@@ -140,6 +147,8 @@

+ +

@@ -194,6 +203,12 @@ var i18nStrings = { helpTextSelect: '${i18n().select_an_existing?js_string}', helpTextAdd: '${i18n().or_add_new_one?js_string}' }; + +$(document).ready(function () { + $('input[type=radio].radiotypes').change(function() { + $('input[type=radio].radiotypes:checked').not(this).prop('checked', false); + }); +}); ${stylesheets.add('', diff --git a/webapp/src/main/webapp/templates/freemarker/edit/forms/addEditorsToInformationResource.ftl b/webapp/src/main/webapp/templates/freemarker/edit/forms/addEditorsToInformationResource.ftl index 6f5131aee5..2f1e6bfbd8 100644 --- a/webapp/src/main/webapp/templates/freemarker/edit/forms/addEditorsToInformationResource.ftl +++ b/webapp/src/main/webapp/templates/freemarker/edit/forms/addEditorsToInformationResource.ftl @@ -18,6 +18,7 @@ <#assign lastNameValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "lastName") /> <#assign firstNameValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "firstName") /> <#assign middleNameValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "middleName") /> +<#assign orgNameValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "orgName") /> <#--UL class based on size of existing editors--> <#assign ulClass = ""/> @@ -101,24 +102,39 @@

${i18n().add_an_editor}

+
+ + + + +
+
<#--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().add_to_person_profile} ${requiredHint}

+ + + + +
+

@@ -129,6 +145,22 @@

+
+

+ + +

+ +
+

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

+
+
+ @@ -153,6 +185,7 @@ var customFormData = { acUrl: '${urls.base}/autocomplete?type=', tokenize: '&tokenize=true', personUrl: 'http://xmlns.com/foaf/0.1/Person', + orgUrl: 'http://xmlns.com/foaf/0.1/Organization', reorderUrl: '${urls.base}/edit/reorder' }; var i18nStrings = { @@ -161,9 +194,16 @@ var i18nStrings = { removeEditorshipMessage: '${i18n().confirm_editor_removal?js_string}', removeEditorshipAlert: '${i18n().error_processing_editor_request?js_string}', editorTypeText: '${i18n().editor_capitalized?js_string}', + organizationTypeText: '${i18n().organization_capitalized?js_string}', helpTextSelect: '${i18n().select_an_existing?js_string}', helpTextAdd: '${i18n().or_add_new_one?js_string}' }; + +$(document).ready(function () { + $('input[type=radio].radiotypes').change(function() { + $('input[type=radio].radiotypes:checked').not(this).prop('checked', false); + }); +}); ${stylesheets.add('', diff --git a/webapp/src/main/webapp/templates/freemarker/edit/forms/js/addAuthorsToInformationResource.js b/webapp/src/main/webapp/templates/freemarker/edit/forms/js/addAuthorsToInformationResource.js index e711821351..36a5804f10 100644 --- a/webapp/src/main/webapp/templates/freemarker/edit/forms/js/addAuthorsToInformationResource.js +++ b/webapp/src/main/webapp/templates/freemarker/edit/forms/js/addAuthorsToInformationResource.js @@ -202,11 +202,13 @@ var addAuthorForm = { showFieldsForNewPerson: function() { this.firstNameWrapper.show(); this.middleNameWrapper.show(); + $('#createVCard').parent().show(); }, hideFieldsForNewPerson: function() { this.hideFields(this.firstNameWrapper); this.hideFields(this.middleNameWrapper); + $('#createVCard').parent().hide(); }, /* *** Ajax initializations *** */ diff --git a/webapp/src/main/webapp/templates/freemarker/edit/forms/js/addEditorsToInformationResource.js b/webapp/src/main/webapp/templates/freemarker/edit/forms/js/addEditorsToInformationResource.js index ebc103399e..4daf6421dc 100644 --- a/webapp/src/main/webapp/templates/freemarker/edit/forms/js/addEditorsToInformationResource.js +++ b/webapp/src/main/webapp/templates/freemarker/edit/forms/js/addEditorsToInformationResource.js @@ -64,9 +64,20 @@ var addEditorForm = { this.selectedEditorName = $('#selectedEditorName'); this.acHelpTextClass = 'acSelectorWithHelpText'; this.verifyMatch = this.form.find('.verifyMatch'); + this.personRadio = $('input.person-radio'); + this.orgRadio = $('input.org-radio'); this.personSection = $('section#personFields'); + this.orgSection = $('section#organizationFields'); + this.orgName = $('input#orgName'); + this.orgNameWrapper = this.orgName.parent(); + this.orgUriField = $('input#orgUri'); + this.selectedOrg = $('div#selectedOrg'); + this.selectedOrgName = $('span#selectedOrgName'); + this.orgLink = $('a#orgLink'); this.personLink = $('a#personLink'); this.returnLink = $('a#returnLink'); + + this.orgSection.hide(); }, // Initial page setup. Called only at page load. @@ -158,6 +169,8 @@ var addEditorForm = { this.hideSelectedPerson(); + addEditorForm.setEditorType("person"); + this.cancel.unbind('click'); this.cancel.bind('click', function() { addEditorForm.showEditorListOnlyView(); @@ -181,14 +194,22 @@ var addEditorForm = { this.personUriField.val(''); }, + hideSelectedOrg: function() { + this.selectedOrg.hide(); + this.selectedOrgName.html(''); + this.orgUriField.val(''); + }, + showFieldsForNewPerson: function() { this.firstNameWrapper.show(); this.middleNameWrapper.show(); + $('#createVCard').parent().show(); }, hideFieldsForNewPerson: function() { this.hideFields(this.firstNameWrapper); this.hideFields(this.middleNameWrapper); + $('#createVCard').parent().hide(); }, /* *** Ajax initializations *** */ @@ -200,10 +221,20 @@ var addEditorForm = { // an editor. this.acCache = {}; this.setAcFilter(); - var $acField = this.lastNameField; - var urlString = addEditorForm.acUrl + addEditorForm.personUrl + addEditorForm.tokenize; - var authType = "person"; - + var $acField; + var urlString; + var editorType; + + if ( this.personRadio.prop("checked") ) { + $acField = this.lastNameField; + urlString = addEditorForm.acUrl + addEditorForm.personUrl + addEditorForm.tokenize; + editorType = "person"; + } + else { + $acField = this.orgName; + urlString = addEditorForm.acUrl + addEditorForm.orgUrl + addEditorForm.tokenize; + editorType = "org"; + } $acField.autocomplete({ minLength: 2, source: function(request, response) { @@ -241,7 +272,7 @@ var addEditorForm = { // 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) { - addEditorForm.showSelectedEditor(ui,authType); + addEditorForm.showSelectedEditor(ui,editorType); } }); @@ -297,9 +328,9 @@ var addEditorForm = { }, // Action taken after selecting an editor from the autocomplete list - showSelectedEditor: function(ui,authType) { + showSelectedEditor: function(ui,editorType) { - if ( authType == "person" ) { + if ( editorType == "person" ) { this.personUriField.val(ui.item.uri); this.selectedEditor.show(); @@ -315,12 +346,23 @@ var addEditorForm = { this.hideFieldsForNewPerson(); this.personLink.attr('href', this.verifyMatch.data('baseHref') + ui.item.uri); } + else { + // do the same as above but for the organization fields + this.orgUriField.val(ui.item.uri); + this.selectedOrg.show(); + + this.selectedOrgName.html(ui.item.label); + + this.hideFields(this.orgNameWrapper); + + this.orgLink.attr('href', this.verifyMatch.data('baseHref') + ui.item.uri); + } // Cancel restores initial form view this.cancel.unbind('click'); this.cancel.bind('click', function() { addEditorForm.initFormView(); - addEditorForm.setEditorType(authType); + addEditorForm.setEditorType(editorType); return false; }); }, @@ -444,13 +486,21 @@ var addEditorForm = { return false; }); + this.orgRadio.click(function() { + addEditorForm.setEditorType("org"); + }); + + this.personRadio.click(function() { + addEditorForm.setEditorType("person"); + }); + this.form.submit(function() { // NB Important JavaScript scope issue: if we call it this way, this = addEditorForm // in prepareSubmit. If we do this.form.submit(this.prepareSubmit); then // this != addEditorForm in prepareSubmit. $selectedObj = addEditorForm.form.find('input.acSelector'); addEditorForm.deleteAcHelpText($selectedObj); - addEditorForm.prepareSubmit(); + addEditorForm.prepareSubmit(); }); this.lastNameField.blur(function() { @@ -469,13 +519,27 @@ var addEditorForm = { return false; }); - this.acSelector.focus(function() { - addEditorForm.deleteAcHelpText(this); - }); + this.orgLink.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() { + addEditorForm.deleteAcHelpText(this); + }); + + this.acSelector.blur(function() { + addEditorForm.addAcHelpText(this); + }); + + this.orgName.focus(function() { + addEditorForm.deleteAcHelpText(this); + }); + + this.orgName.blur(function() { + addEditorForm.addAcHelpText(this); + }); - this.acSelector.blur(function() { - addEditorForm.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 @@ -501,7 +565,7 @@ var addEditorForm = { name; // If selecting an existing person, don't submit name fields - if (this.personUriField.val() != '' ) { + if (this.personUriField.val() != '' || this.orgUriField.val() != '' || this.orgName.val() != '' ) { this.firstNameField.attr('disabled', 'disabled'); this.middleNameField.attr('disabled', 'disabled'); this.lastNameField.attr('disabled', 'disabled'); @@ -521,6 +585,10 @@ var addEditorForm = { this.labelField.val(name); } + // If user selected org via autocomplete, clear the org name field + if ( this.orgUriField.val() != '' ) { + this.orgName.val(""); + } }, @@ -657,44 +725,94 @@ var addEditorForm = { // when clicking undo: add the editor back, and change link text to 'remove' }, - // Set the initial help text in the lastName field and change the class name. - addAcHelpText: function(selectedObj) { + // 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 = addEditorForm.editorTypeText; } + else { + typeText = addEditorForm.organizationTypeText; + } if (!$(selectedObj).val()) { - $(selectedObj).val(addEditorForm.helpTextSelect + " " + typeText + " " + addEditorForm.helpTextAdd) - .addClass(this.acHelpTextClass); - } - }, - - deleteAcHelpText: function(selectedObj) { - if ($(selectedObj).hasClass(this.acHelpTextClass)) { - $(selectedObj).val('') - .removeClass(this.acHelpTextClass); - } - }, + $(selectedObj).val(addEditorForm.helpTextSelect + " " + typeText + " " + addEditorForm.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 ... - setEditorType: function(authType) { - if ( authType == "person" ) { - this.personSection.show(); + setEditorType: function(editorType) { + if ( editorType == "org" ) { + this.personSection.hide(); + this.orgSection.show(); + this.orgNameWrapper.show(); + // person fields + this.personRadio.prop('checked', false); // needed for reset when cancel button is clicked + this.acSelector.removeClass("acSelector"); + this.acSelector.removeClass(this.acHelpTextClass); + this.selectedEditor.removeClass("acSelection"); + this.selectedEditorName.removeClass("acSelectionInfo"); + this.personLink.removeClass("verifyMatch"); + this.acSelector.attr('disabled', 'disabled'); + this.firstNameField.attr('disabled', 'disabled'); + this.middleNameField.attr('disabled', 'disabled'); + this.lastNameField.attr('disabled', 'disabled'); + this.acSelector.val(''); + this.firstNameField.val(''); + this.middleNameField.val(''); + this.lastNameField.val(''); + // org fields + this.orgRadio.prop('checked', true); // needed for reset when cancel button is clicked + this.orgName.addClass("acSelector"); + this.selectedOrg.addClass("acSelection"); + this.selectedOrgName.addClass("acSelectionInfo"); + this.orgLink.addClass("verifyMatch"); + this.orgName.attr('disabled', false); + this.orgUriField.attr('disabled', false); + + addEditorForm.addAcHelpText(this.orgName); + addEditorForm.initAutocomplete(); + addEditorForm.hideSelectedPerson(); + } + else if ( editorType == "person" ) { + this.orgSection.hide(); + this.personSection.show(); + // org fields + this.orgRadio.prop('checked', false); // needed for reset when cancel button is clicked + this.orgName.removeClass("acSelector"); + this.orgName.removeClass(this.acHelpTextClass); + this.selectedOrg.removeClass("acSelection"); + this.selectedOrgName.removeClass("acSelectionInfo"); + this.orgLink.removeClass("verifyMatch"); + this.orgName.attr('disabled', 'disabled'); + this.orgUriField.attr('disabled', 'disabled'); + this.orgName.val(''); + this.orgUriField.val(''); + // person fields this.acSelector.addClass("acSelector"); this.personRadio.prop('checked', true); // needed for reset when cancel button is clicked - this.selectedEditor.addClass("acSelection"); - this.selectedEditorName.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); - - addEditorForm.addAcHelpText(this.acSelector); - addEditorForm.initAutocomplete(); - } + this.selectedEditor.addClass("acSelection"); + this.selectedEditorName.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); + + addEditorForm.addAcHelpText(this.acSelector); + addEditorForm.initAutocomplete(); + addEditorForm.hideSelectedOrg(); + + } } }; diff --git a/webapp/src/main/webapp/templates/freemarker/edit/forms/projectHasParticipant.ftl b/webapp/src/main/webapp/templates/freemarker/edit/forms/projectHasParticipant.ftl index 468f5400a4..de89da2cbb 100644 --- a/webapp/src/main/webapp/templates/freemarker/edit/forms/projectHasParticipant.ftl +++ b/webapp/src/main/webapp/templates/freemarker/edit/forms/projectHasParticipant.ftl @@ -113,6 +113,13 @@ Set this flag on the input acUriReceiver where you would like this behavior to o
+
+ ${i18n().add_to_person_profile} ${requiredHint}
+ + + + +

@@ -160,6 +167,9 @@ var i18nStrings = { $(document).ready(function() { projectHasParticipantUtils.onLoad('${blankSentinel}'); + $('input[type=radio].radiotypes').change(function() { + $('input[type=radio].radiotypes:checked').not(this).prop('checked', false); + }); }); diff --git a/webapp/src/main/webapp/templates/freemarker/visualization/collaboratorToActivityCountTable.ftl b/webapp/src/main/webapp/templates/freemarker/visualization/collaboratorToActivityCountTable.ftl index ce6309dec7..12e1eb3326 100644 --- a/webapp/src/main/webapp/templates/freemarker/visualization/collaboratorToActivityCountTable.ftl +++ b/webapp/src/main/webapp/templates/freemarker/visualization/collaboratorToActivityCountTable.ftl @@ -16,8 +16,17 @@ + <#assign addLine = true /> <#list tableContent.collaborators as collaborator> <#if collaborator_index gt 0> + <#if addLine && collaborator.isVCard> + <#assign addLine = false /> + + +
+ + + ${collaborator.collaboratorName} diff --git a/webapp/src/main/webapp/templates/freemarker/visualization/personlevel/coAuthorPersonLevelD3.ftl b/webapp/src/main/webapp/templates/freemarker/visualization/personlevel/coAuthorPersonLevelD3.ftl index ee785e41c3..12160850c5 100644 --- a/webapp/src/main/webapp/templates/freemarker/visualization/personlevel/coAuthorPersonLevelD3.ftl +++ b/webapp/src/main/webapp/templates/freemarker/visualization/personlevel/coAuthorPersonLevelD3.ftl @@ -96,57 +96,82 @@ $(document).ready(function(){ } }); + render_chord(); +}); + // RENDER CHORD var labels = []; var uris = []; var matrix = []; + var width = 725; + var height = 725; + var padding = 175; + var svg; + +function render_chord() { + var showVCards = $("#vcards").is(':checked'); + vcards = []; + labels = []; + uris = []; + matrix = []; var matrixX = 0; + <#list coAuthorshipData.collaborators as collaborator> + <#if collaborator.isVCard> + vcards.push(true); + $("#vcardstoggle").show(); + if (showVCards) { + labels.push("${collaborator.collaboratorName}"); + uris.push(""); + } + <#else> + vcards.push(false); + labels.push("${collaborator.collaboratorName}"); + uris.push("${collaborator.collaboratorURI}"); + + <#list coAuthorshipData.collaborationMatrix as row> + if (showVCards || !vcards[${row_index}]) { matrix[matrixX] = []; <#list row as cell> - matrix[matrixX].push(${cell?c}); + matrix[matrixX].push(${cell?c}); matrixX++; + } - <#list coAuthorshipData.collaborators as collaborator> - labels.push("${collaborator.collaboratorName}"); - uris.push("${collaborator.collaboratorURI}"); - + + $( "#chord" ).empty(); var chord = d3.chord() - .padAngle(0.05) - .sortSubgroups(d3.descending); + .padAngle(0.05) + .sortSubgroups(d3.descending); - var width = 725; - var height = 725; - var padding = 175; var inner_radius = Math.min(width, height) * 0.37; var outer_radius = Math.min(width, height) * 0.39; var fill = d3.scaleOrdinal() - .domain(d3.range(20)) - .range(["#000000", "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", - "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", - "#c5b0d5", "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", - "#7f7f7f", "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf" - ]); + .domain(d3.range(20)) + .range(["#000000", "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", + "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", + "#c5b0d5", "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", + "#7f7f7f", "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf" + ]); // #9edae5 var svg = d3.select('#chord').append('svg') - .attr('width', width+padding) - .attr('height', height+padding) - .append('g').attr('transform', 'translate(' + (width+padding) / 2 + ',' + (height+padding) / 2 +')') - .datum(chord(matrix)); + .attr('width', width+padding) + .attr('height', height+padding) + .append('g').attr('transform', 'translate(' + (width+padding) / 2 + ',' + (height+padding) / 2 +')') + .datum(chord(matrix)); svg.append('g').selectAll('path').data(function(chords) { return chords.groups; }).enter() - .append('path').style('fill', function(val) { return fill(val.index); }) - .style('stroke', function(val) { return fill(val.index); }) - .attr('d', d3.arc().innerRadius(inner_radius).outerRadius(outer_radius)) - .on('click', chord_click()) - .on("mouseover", chord_hover(.05)) - .on("mouseout", chord_hover(.8)); + .append('path').style('fill', function(val) { return fill(val.index); }) + .style('stroke', function(val) { return fill(val.index); }) + .attr('d', d3.arc().innerRadius(inner_radius).outerRadius(outer_radius)) + .on('click', chord_click()) + .on("mouseover", chord_hover(.05)) + .on("mouseout", chord_hover(.8)); var group_ticks = function (d) { var k = (d.endAngle - d.startAngle) / d.value; @@ -159,44 +184,45 @@ $(document).ready(function(){ }; var chord_ticks = svg.append('g') - .selectAll('g') - .data(function (chords) { return chords.groups; }) - .enter().append('g') - .selectAll('g') - .data(group_ticks) - .enter().append('g') - .attr('transform', function (d) { - return 'rotate(' + (d.angle * 180 / Math.PI - 90) + ') translate(' + outer_radius + ',0)'; - }); + .selectAll('g') + .data(function (chords) { return chords.groups; }) + .enter().append('g') + .selectAll('g') + .data(group_ticks) + .enter().append('g') + .attr('transform', function (d) { + return 'rotate(' + (d.angle * 180 / Math.PI - 90) + ') translate(' + outer_radius + ',0)'; + }); svg.append('g') - .attr('class', 'chord') - .selectAll('path') - .data(function (chords) { return chords; }) - .enter().append('path') - .style('fill', function (d) { return fill(d.target.index); }) - .attr('d', d3.ribbon().radius(inner_radius)) - .style('opacity', .8); + .attr('class', 'chord') + .selectAll('path') + .data(function (chords) { return chords; }) + .enter().append('path') + .style('fill', function (d) { return fill(d.target.index); }) + .attr('d', d3.ribbon().radius(inner_radius)) + .style('opacity', .8); svg.append("g").selectAll(".arc") - .data(function (chords) { return chords.groups; }) - .enter().append("svg:text") - .attr("dy", ".35em") - .attr("style", function(d) { return d.index == 0 ? "font-size: .75em; font-weight: bold;" : "font-size: .70em;"; } ) - .attr("text-anchor", function(d) { return ((d.startAngle + d.endAngle) / 2) > Math.PI ? "end" : null; }) - .attr("transform", function(d) { - return "rotate(" + (((d.startAngle + d.endAngle) / 2) * 180 / Math.PI - 90) + ")" - + "translate(" + (height *.40) + ")" - + (((d.startAngle + d.endAngle) / 2) > Math.PI ? "rotate(180)" : ""); - }) - .text(function(d) { - return labels[d.index]; - }) - .on('click', chord_click()) - .on("mouseover", chord_hover(.05)) - .on("mouseout", chord_hover(.8)); - - function chord_hover(opacity) { + .data(function (chords) { return chords.groups; }) + .enter().append("svg:text") + .attr("dy", ".35em") + .attr("style", function(d) { return d.index == 0 ? "font-size: .75em; font-weight: bold;" : "font-size: .70em;"; } ) + .attr("text-anchor", function(d) { return ((d.startAngle + d.endAngle) / 2) > Math.PI ? "end" : null; }) + .attr("transform", function(d) { + return "rotate(" + (((d.startAngle + d.endAngle) / 2) * 180 / Math.PI - 90) + ")" + + "translate(" + (height *.40) + ")" + + (((d.startAngle + d.endAngle) / 2) > Math.PI ? "rotate(180)" : ""); + }) + .text(function(d) { + return labels[d.index]; + }) + .on('click', chord_click()) + .on("mouseover", chord_hover(.05)) + .on("mouseout", chord_hover(.8)); +} + +function chord_hover(opacity) { return function(g, i) { if (opacity > .5) { var chordInfoDiv = d3.select('#chord-info-div'); @@ -214,7 +240,7 @@ $(document).ready(function(){ if (i > 0) { hoverMsg += matrix[i][0] + " Joint ${i18n().publication_s_capitalized}
"; } else { - hoverMsg += "${coAuthorshipData.collaboratorsCount} ${i18n().co_author_s_capitalized}
"; + hoverMsg += "${coAuthorshipData.collaboratorsCount - 1} ${i18n().co_author_s_capitalized}
"; } chordInfoDiv.html(hoverMsg); @@ -244,11 +270,13 @@ $(document).ready(function(){ function chord_click() { return function (g, i) { if (i >= 0) { - window.location.href = getWellFormedURLs(uris[i], "profile"); + if (uris[i] != null && uris[i] != "") { + window.location.href = getWellFormedURLs(uris[i], "profile"); + } } }; } -}); +
@@ -283,6 +311,9 @@ $(document).ready(function(){ <#if (numOfCoAuthorShips?? && numOfCoAuthorShips > 0) || (numOfAuthors?? && numOfAuthors > 0) >
+ + +