diff --git a/scripts/api/data/metadatablocks/citation.tsv b/scripts/api/data/metadatablocks/citation.tsv index 3aa93d67aa3..6d4041ff999 100644 --- a/scripts/api/data/metadatablocks/citation.tsv +++ b/scripts/api/data/metadatablocks/citation.tsv @@ -12,7 +12,7 @@ authorName Name The author's Family Name, Given Name or the name of the organization responsible for this Dataset. FamilyName, GivenName or Organization text 8 #VALUE TRUE FALSE FALSE TRUE TRUE TRUE author citation authorAffiliation Affiliation The organization with which the author is affiliated. text 9 (#VALUE) TRUE FALSE FALSE TRUE TRUE FALSE author citation authorIdentifierScheme Identifier Scheme Name of the identifier scheme (ORCID, ISNI). text 10 - #VALUE: FALSE TRUE FALSE FALSE TRUE FALSE author citation http://purl.org/spar/datacite/AgentIdentifierScheme - authorIdentifier Identifier Uniquely identifies an individual author or organization, according to various schemes. text 11 #VALUE FALSE FALSE FALSE FALSE TRUE FALSE author citation http://purl.org/spar/datacite/AgentIdentifier + authorIdentifier Identifier Uniquely identifies an individual author or organization, according to various schemes. textbox 11 ##authorIdentifierScheme FALSE FALSE FALSE FALSE TRUE FALSE author citation http://purl.org/spar/datacite/AgentIdentifier datasetContact Contact The contact(s) for this Dataset. none 12 FALSE FALSE TRUE FALSE TRUE FALSE citation datasetContactName Name The contact's Family Name, Given Name or the name of the organization. FamilyName, GivenName or Organization text 13 #VALUE FALSE FALSE FALSE FALSE TRUE FALSE datasetContact citation datasetContactAffiliation Affiliation The organization with which the contact is affiliated. text 14 (#VALUE) FALSE FALSE FALSE FALSE TRUE FALSE datasetContact citation @@ -79,7 +79,7 @@ originOfSources Origin of Sources For historical materials, information about the origin of the sources and the rules followed in establishing the sources should be specified. textbox 75 FALSE FALSE FALSE FALSE FALSE FALSE citation characteristicOfSources Characteristic of Sources Noted Assessment of characteristics and source material. textbox 76 FALSE FALSE FALSE FALSE FALSE FALSE citation accessToSources Documentation and Access to Sources Level of documentation of the original sources. textbox 77 FALSE FALSE FALSE FALSE FALSE FALSE citation -#controlledVocabulary DatasetField Value identifier displayOrder +#controlledVocabulary DatasetField Value identifier displayOrder displayFormat subject Agricultural Sciences D01 0 subject Arts and Humanities D0 1 subject Astronomy and Astrophysics D1 2 @@ -128,11 +128,11 @@ contributorType Supervisor 14 contributorType Work Package Leader 15 contributorType Other 16 - authorIdentifierScheme ORCID 0 - authorIdentifierScheme ISNI 1 - authorIdentifierScheme LCNA 2 - authorIdentifierScheme VIAF 3 - authorIdentifierScheme GND 4 + authorIdentifierScheme ORCID 0 #VALUE + authorIdentifierScheme ISNI 1 #VALUE + authorIdentifierScheme LCNA 2 #VALUE + authorIdentifierScheme VIAF 3 #VALUE + authorIdentifierScheme GND 4 #VALUE authorIdentifierScheme DAI 5 authorIdentifierScheme ResearcherID 6 authorIdentifierScheme ScopusID 7 diff --git a/src/main/java/edu/harvard/iq/dataverse/ControlledVocabularyValue.java b/src/main/java/edu/harvard/iq/dataverse/ControlledVocabularyValue.java index 00c264afeb7..a508be3926e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/ControlledVocabularyValue.java +++ b/src/main/java/edu/harvard/iq/dataverse/ControlledVocabularyValue.java @@ -16,15 +16,15 @@ import java.util.Objects; import java.util.MissingResourceException; import javax.persistence.CascadeType; -import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Index; -import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; +import javax.persistence.Column; +import javax.persistence.OneToOne; import javax.persistence.Table; /** @@ -111,6 +111,17 @@ public void setControlledVocabAlternates(Collection co this.controlledVocabAlternates = controlledVocabAlternates; } + @OneToOne(mappedBy = "controlledVocabularyValue",cascade={ CascadeType.REMOVE, CascadeType.MERGE,CascadeType.PERSIST}, orphanRemoval=true) + private ControlledVocabularyValueDetail controlledVocabularyValueDetail; + + public ControlledVocabularyValueDetail getControlledVocabularyValueDetail() { + return controlledVocabularyValueDetail; + } + + public void setControlledVocabularyValueDetail(ControlledVocabularyValueDetail controlledVocabularyValueDetail) { + this.controlledVocabularyValueDetail = controlledVocabularyValueDetail; + } + public String getLocaleStrValue() { String key = strValue.toLowerCase().replace(" " , "_"); diff --git a/src/main/java/edu/harvard/iq/dataverse/ControlledVocabularyValueDetail.java b/src/main/java/edu/harvard/iq/dataverse/ControlledVocabularyValueDetail.java new file mode 100644 index 00000000000..b2692de3024 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/ControlledVocabularyValueDetail.java @@ -0,0 +1,47 @@ +package edu.harvard.iq.dataverse; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Index; +import javax.persistence.Column; +import javax.persistence.OneToOne; +import javax.persistence.JoinColumn; +import javax.persistence.Table; +import java.io.Serializable; + +@Entity +@Table(indexes = {@Index(columnList = "controlledvocabularyvalue_id")}) +public class ControlledVocabularyValueDetail implements Serializable { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + @Column(columnDefinition = "TEXT") + private String displayFormat; + + public String getDisplayFormat() { return displayFormat; } + + public void setDisplayFormat(String displayFormat) { this.displayFormat = displayFormat; } + + @OneToOne + @JoinColumn(name = "controlledvocabularyvalue_id", unique = true) + private ControlledVocabularyValue controlledVocabularyValue; + + public ControlledVocabularyValue getControlledVocabularyValue() { + return controlledVocabularyValue; + } + + public void setControlledVocabularyValue(ControlledVocabularyValue controlledVocabularyValue) { + this.controlledVocabularyValue = controlledVocabularyValue; + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldCompoundValue.java b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldCompoundValue.java index 221922ea004..bc9dded4775 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldCompoundValue.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldCompoundValue.java @@ -5,6 +5,7 @@ */ package edu.harvard.iq.dataverse; +import edu.harvard.iq.dataverse.api.Access; import edu.harvard.iq.dataverse.util.BundleUtil; import edu.harvard.iq.dataverse.util.MarkupChecker; import java.io.Serializable; @@ -14,7 +15,8 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.ResourceBundle; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; @@ -133,11 +135,41 @@ public DatasetFieldCompoundValue copy(DatasetField parent) { return compoundValue; } + final private static String REGEX_FIELD_NAME = "(##[a-z]+\\w*)"; + static private Map referencesMap = new LinkedHashMap<>(); + + public Map getDisplayValueMap() { // todo - this currently only supports child datasetfields with single values // need to determine how we would want to handle multiple Map fieldMap = new LinkedHashMap<>(); boolean fixTrailingComma = false; + + Pattern pattern = Pattern.compile(REGEX_FIELD_NAME); + String fieldName = new String(); + String fieldValue = new String(); + + for (DatasetField childDatasetField : childDatasetFields){ + Matcher matcher = pattern.matcher(childDatasetField.getDatasetFieldType().getDisplayFormat()); + while (matcher.find()){ + referencesMap.put(matcher.group(0), null); + } + } + + for (DatasetField childDatasetField : childDatasetFields) { + if (referencesMap.containsKey("##"+childDatasetField.getDatasetFieldType().getName())){ + if (childDatasetField.getSingleControlledVocabularyValue() != null){ + if (childDatasetField.getSingleControlledVocabularyValue().getControlledVocabularyValueDetail() != null && !childDatasetField.getSingleControlledVocabularyValue().getControlledVocabularyValueDetail().getDisplayFormat().isEmpty()){ + referencesMap.put("##"+childDatasetField.getDatasetFieldType().getName(), childDatasetField.getSingleControlledVocabularyValue().getControlledVocabularyValueDetail().getDisplayFormat()); + } else { + referencesMap.put("##"+childDatasetField.getDatasetFieldType().getName(), "#VALUE"); + } + } else { + referencesMap.put("##"+childDatasetField.getDatasetFieldType().getName(), "#VALUE"); + } + } + } + for (DatasetField childDatasetField : childDatasetFields) { fixTrailingComma = false; // skip the value if it is empty or N/A @@ -152,27 +184,38 @@ public Map getDisplayValueMap() { } //if a series of child values is comma delimited we want to strip off the final entry's comma if (format.equals("#VALUE, ")) fixTrailingComma = true; - + + Matcher matcher = pattern.matcher(childDatasetField.getDatasetFieldType().getDisplayFormat()); + while (matcher.find()) { + if (referencesMap.containsKey(matcher.group(0)) && referencesMap.get(matcher.group(0)) != null) { + fieldName = matcher.group(0); + fieldValue = referencesMap.get(fieldName); + } + } + // replace the special values in the format (note: we replace #VALUE last since we don't // want any issues if the value itself has #NAME in it) String displayValue = format + .replaceAll(fieldName+"\\b", fieldValue) .replace("#NAME", childDatasetField.getDatasetFieldType().getTitle()) //todo: this should be handled in more generic way for any other text that can then be internationalized // if we need to use replaceAll for regexp, then make sure to use: java.util.regex.Matcher.quoteReplacement() .replace("#EMAIL", BundleUtil.getStringFromBundle("dataset.email.hiddenMessage")) .replace("#VALUE", sanitizedValue ); + fieldMap.put(childDatasetField,displayValue); + } } - + if (fixTrailingComma) { return (removeLastComma(fieldMap)); } return fieldMap; } - + private Map removeLastComma(Map mapIn) { Iterator> itr = mapIn.entrySet().iterator(); diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java index 03e677a1d74..81dbea746d1 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java @@ -153,6 +153,18 @@ public ControlledVocabAlternate findControlledVocabAlternateByControlledVocabula return (ControlledVocabAlternate) results.get(0); } } + + public ControlledVocabularyValueDetail findControlledVocabularyValueDetailByControlledVocabularyValueAndDisplayFormat(ControlledVocabularyValue cvv, String displayFormat){ + TypedQuery typedQuery = em.createQuery("SELECT OBJECT(o) FROM ControlledVocabularyValueDetail AS o WHERE o.displayFormat = :displayformat AND o.controlledVocabularyValue = :cvv", ControlledVocabularyValueDetail.class); + typedQuery.setParameter("displayformat", displayFormat); + typedQuery.setParameter("cvv", cvv); + try { + ControlledVocabularyValueDetail cvvd = typedQuery.getSingleResult(); + return cvvd; + } catch (NoResultException e){ + return null; + } + } /** * @param dsft The DatasetFieldType in which to look up a diff --git a/src/main/java/edu/harvard/iq/dataverse/api/DatasetFieldServiceApi.java b/src/main/java/edu/harvard/iq/dataverse/api/DatasetFieldServiceApi.java index d02e8f72838..166eadedfc9 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/DatasetFieldServiceApi.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/DatasetFieldServiceApi.java @@ -2,6 +2,7 @@ import edu.harvard.iq.dataverse.ControlledVocabAlternate; import edu.harvard.iq.dataverse.ControlledVocabularyValue; +import edu.harvard.iq.dataverse.ControlledVocabularyValueDetail; import edu.harvard.iq.dataverse.ControlledVocabularyValueServiceBean; import edu.harvard.iq.dataverse.DatasetField; import edu.harvard.iq.dataverse.DatasetFieldConstant; @@ -447,6 +448,7 @@ private String parseDatasetField(String[] values) { private String parseControlledVocabulary(String[] values) { DatasetFieldType dsv = datasetFieldService.findByName(values[1]); + //See if it already exists /* Matching relies on assumption that only one cv value will exist for a given identifier or display value @@ -482,6 +484,18 @@ private String parseControlledVocabulary(String[] values) { cvv.setStrValue(values[2]); cvv.setIdentifier(values[3]); cvv.setDisplayOrder(Integer.parseInt(values[4])); + + if (values.length >= 6 && values[5] != null && !values[5].isEmpty()) { + ControlledVocabularyValueDetail cvvd = datasetFieldService.findControlledVocabularyValueDetailByControlledVocabularyValueAndDisplayFormat(cvv, values[5]); + if (cvvd == null) { + cvvd = new ControlledVocabularyValueDetail(); + cvvd.setControlledVocabularyValue(cvv); + cvvd.setDisplayFormat(values[5]); + //cvvd.setStrValue(values[6]); + cvv.setControlledVocabularyValueDetail(cvvd); + } + } + datasetFieldService.save(cvv); return cvv.getStrValue(); }