Skip to content

Commit 6ca1c9d

Browse files
authored
Merge pull request #8793 from adaybujeda/8535-new-static-facet-show-metadata-blocks
Added new static facet to show metadata blocks with values
2 parents dc6c6bc + 34f64cd commit 6ca1c9d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1376
-29
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
## Adding new static search facet: Metadata Types
2+
A new static search facet has been added to the search side panel. This new facet is called "Metadata Types" and is driven from metadata blocks. When a metadata field value is inserted into a dataset, an entry for the metadata block it belongs to is added to this new facet.
3+
4+
This new facet needs to be configured for it to appear on the search side panel. The configuration assigns to a dataverse what metadata blocks to show. The configuration is inherited by child dataverses.
5+
6+
To configure the new facet, use the Metadata Block Facet API: <https://guides.dataverse.org/en/latest/api/native-api.html#set-metadata-block-facet-for-a-dataverse-collection>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
["authorName", "authorAffiliation"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
["socialscience", "geospatial"]

doc/sphinx-guides/source/api/native-api.rst

+70-3
Original file line numberDiff line numberDiff line change
@@ -219,15 +219,82 @@ Assign search facets for a given Dataverse collection identified by ``id``:
219219
export SERVER_URL=https://demo.dataverse.org
220220
export ID=root
221221
222-
curl -H X-Dataverse-key:$API_TOKEN" -X POST $SERVER_URL/api/dataverses/$ID/facets --upload-file facets.json
222+
curl -H X-Dataverse-key:$API_TOKEN" -X POST $SERVER_URL/api/dataverses/$ID/facets --upload-file dataverse-facets.json
223223
224224
The fully expanded example above (without environment variables) looks like this:
225225
226226
.. code-block:: bash
227227
228-
curl -H X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -X POST https://demo.dataverse.org/api/dataverses/root/facets --upload-file facets.json
228+
curl -H X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -X POST https://demo.dataverse.org/api/dataverses/root/facets --upload-file dataverse-facets.json
229229
230-
Where ``facets.json`` contains a JSON encoded list of metadata keys (e.g. ``["authorName","authorAffiliation"]``).
230+
Where :download:`dataverse-facets.json <../_static/api/dataverse-facets.json>` contains a JSON encoded list of metadata keys (e.g. ``["authorName","authorAffiliation"]``).
231+
232+
List Metadata Block Facets Configured for a Dataverse Collection
233+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
234+
235+
|CORS| List the metadata block facet configuration with all the metadata block configured for a given Dataverse collection ``id``:
236+
237+
.. code-block:: bash
238+
239+
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
240+
export SERVER_URL=https://demo.dataverse.org
241+
export ID=root
242+
243+
curl -H X-Dataverse-key:$API_TOKEN $SERVER_URL/api/dataverses/$ID/metadatablockfacets
244+
245+
The fully expanded example above (without environment variables) looks like this:
246+
247+
.. code-block:: bash
248+
249+
curl -H X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx https://demo.dataverse.org/api/dataverses/root/metadatablockfacets
250+
251+
Set Metadata Block Facets for a Dataverse Collection
252+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
253+
254+
Sets the metadata blocks that will appear in the ``Dataset Features`` facet category for a given Dataverse collection identified by ``id``.
255+
256+
In order to set or clear the metadata blocks for a collection, you must first :ref:`set the metadata block facet root to true<metadata-block-facet-root-api>`.
257+
258+
To clear the metadata blocks set by a parent collection, submit an empty array (e.g. ``[]``):
259+
260+
.. code-block:: bash
261+
262+
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
263+
export SERVER_URL=https://demo.dataverse.org
264+
export ID=root
265+
266+
curl -H X-Dataverse-key:$API_TOKEN" -X POST -H "Content-type:application/json" $SERVER_URL/api/dataverses/$ID/metadatablockfacets --upload-file metadata-block-facets.json
267+
268+
The fully expanded example above (without environment variables) looks like this:
269+
270+
.. code-block:: bash
271+
272+
curl -H X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -X POST -H "Content-type:application/json" https://demo.dataverse.org/api/dataverses/root/metadatablockfacets --upload-file metadata-block-facets.json
273+
274+
Where :download:`metadata-block-facets.json <../_static/api/metadata-block-facets.json>` contains a JSON encoded list of metadata block names (e.g. ``["socialscience","geospatial"]``). This endpoint supports an empty list (e.g. ``[]``)
275+
276+
.. _metadata-block-facet-root-api:
277+
278+
Configure a Dataverse Collection to Inherit Its Metadata Block Facets from Its Parent
279+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
280+
281+
Set whether the Dataverse collection is a metadata block facet root, or does it uses its parent metadata block facets. Possible values are ``true`` and ``false`` (both are valid JSON expressions).
282+
283+
When updating the root to false, it will clear any metadata block facets from the collection. When updating to true, it will copy the metadata block facets from the parent collection:
284+
285+
.. code-block:: bash
286+
287+
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
288+
export SERVER_URL=https://demo.dataverse.org
289+
export ID=root
290+
291+
curl -H X-Dataverse-key:$API_TOKEN -X POST -H "Content-type:application/json" $SERVER_URL/api/dataverses/$ID/metadatablockfacets/isRoot -d 'true'
292+
293+
The fully expanded example above (without environment variables) looks like this:
294+
295+
.. code-block:: bash
296+
297+
curl -H X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -X POST -H "Content-type:application/json" https://demo.dataverse.org/api/dataverses/root/metadatablockfacets/isRoot -d 'true'
231298
232299
Create a New Role in a Dataverse Collection
233300
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

src/main/java/edu/harvard/iq/dataverse/Dataverse.java

+25-2
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,31 @@ public boolean isHarvested() {
324324
return harvestingClient != null;
325325
}
326326
*/
327-
328-
327+
private boolean metadataBlockFacetRoot;
328+
329+
public boolean isMetadataBlockFacetRoot() {
330+
return metadataBlockFacetRoot;
331+
}
332+
333+
public void setMetadataBlockFacetRoot(boolean metadataBlockFacetRoot) {
334+
this.metadataBlockFacetRoot = metadataBlockFacetRoot;
335+
}
336+
337+
@OneToMany(mappedBy = "dataverse",cascade={ CascadeType.REMOVE, CascadeType.MERGE,CascadeType.PERSIST }, orphanRemoval=true)
338+
private List<DataverseMetadataBlockFacet> metadataBlockFacets = new ArrayList<>();
339+
340+
public List<DataverseMetadataBlockFacet> getMetadataBlockFacets() {
341+
if (isMetadataBlockFacetRoot() || getOwner() == null) {
342+
return metadataBlockFacets;
343+
} else {
344+
return getOwner().getMetadataBlockFacets();
345+
}
346+
}
347+
348+
public void setMetadataBlockFacets(List<DataverseMetadataBlockFacet> metadataBlockFacets) {
349+
this.metadataBlockFacets = metadataBlockFacets;
350+
}
351+
329352
public List<Guestbook> getParentGuestbooks() {
330353
List<Guestbook> retList = new ArrayList<>();
331354
Dataverse testDV = this;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package edu.harvard.iq.dataverse;
2+
3+
import javax.persistence.Entity;
4+
import javax.persistence.GeneratedValue;
5+
import javax.persistence.GenerationType;
6+
import javax.persistence.Id;
7+
import javax.persistence.Index;
8+
import javax.persistence.JoinColumn;
9+
import javax.persistence.ManyToOne;
10+
import javax.persistence.Table;
11+
import java.io.Serializable;
12+
import java.util.Objects;
13+
14+
/**
15+
*
16+
* @author adaybujeda
17+
*/
18+
@Entity
19+
@Table(indexes = {@Index(columnList="dataverse_id")
20+
, @Index(columnList="metadatablock_id")})
21+
public class DataverseMetadataBlockFacet implements Serializable {
22+
private static final long serialVersionUID = 1L;
23+
24+
@Id
25+
@GeneratedValue(strategy = GenerationType.IDENTITY)
26+
private Long id;
27+
28+
@ManyToOne
29+
@JoinColumn(name = "dataverse_id")
30+
private Dataverse dataverse;
31+
32+
@ManyToOne
33+
@JoinColumn(name = "metadatablock_id")
34+
private MetadataBlock metadataBlock;
35+
36+
public Long getId() {
37+
return id;
38+
}
39+
40+
public void setId(Long id) {
41+
this.id = id;
42+
}
43+
44+
public Dataverse getDataverse() {
45+
return dataverse;
46+
}
47+
48+
public void setDataverse(Dataverse dataverse) {
49+
this.dataverse = dataverse;
50+
}
51+
52+
public MetadataBlock getMetadataBlock() {
53+
return metadataBlock;
54+
}
55+
56+
public void setMetadataBlock(MetadataBlock metadataBlock) {
57+
this.metadataBlock = metadataBlock;
58+
}
59+
60+
@Override
61+
public int hashCode() {
62+
int hash = 0;
63+
hash += (this.id != null ? this.id.hashCode() : 0);
64+
return hash;
65+
}
66+
67+
@Override
68+
public boolean equals(Object object) {
69+
if (!(object instanceof DataverseMetadataBlockFacet)) {
70+
return false;
71+
}
72+
DataverseMetadataBlockFacet other = (DataverseMetadataBlockFacet) object;
73+
return !(!Objects.equals(this.id, other.id) && (this.id == null || !this.id.equals(other.id)));
74+
}
75+
76+
@Override
77+
public String toString() {
78+
return String.format("edu.harvard.iq.dataverse.DataverseMetadataBlockFacet[ id=%s ]", id);
79+
}
80+
81+
}
82+

src/main/java/edu/harvard/iq/dataverse/MetadataBlock.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,18 @@ public String toString() {
202202
return "edu.harvard.iq.dataverse.MetadataBlock[ id=" + id + " ]";
203203
}
204204

205-
public String getLocaleDisplayName()
206-
{
205+
public String getLocaleDisplayName() {
206+
return getLocaleValue("metadatablock.displayName");
207+
}
208+
209+
public String getLocaleDisplayFacet() {
210+
return getLocaleValue("metadatablock.displayFacet");
211+
}
212+
213+
// Visible for testing
214+
String getLocaleValue(String metadataBlockKey) {
207215
try {
208-
return BundleUtil.getStringFromPropertyFile("metadatablock.displayName", getName());
216+
return BundleUtil.getStringFromPropertyFile(metadataBlockKey, getName());
209217
} catch (MissingResourceException e) {
210218
return displayName;
211219
}

src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java

+78-5
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@
77
import edu.harvard.iq.dataverse.Dataverse;
88
import edu.harvard.iq.dataverse.DataverseFacet;
99
import edu.harvard.iq.dataverse.DataverseContact;
10+
import edu.harvard.iq.dataverse.DataverseMetadataBlockFacet;
1011
import edu.harvard.iq.dataverse.DataverseServiceBean;
1112
import edu.harvard.iq.dataverse.api.datadeposit.SwordServiceBean;
13+
import edu.harvard.iq.dataverse.api.dto.DataverseMetadataBlockFacetDTO;
1214
import edu.harvard.iq.dataverse.authorization.DataverseRole;
1315
import edu.harvard.iq.dataverse.DvObject;
14-
import edu.harvard.iq.dataverse.DvObjectContainer;
1516
import edu.harvard.iq.dataverse.GlobalId;
1617
import edu.harvard.iq.dataverse.GuestbookResponseServiceBean;
1718
import edu.harvard.iq.dataverse.GuestbookServiceBean;
1819
import edu.harvard.iq.dataverse.MetadataBlock;
1920
import edu.harvard.iq.dataverse.RoleAssignment;
20-
import static edu.harvard.iq.dataverse.api.AbstractApiBean.error;
2121
import edu.harvard.iq.dataverse.api.dto.ExplicitGroupDTO;
2222
import edu.harvard.iq.dataverse.api.dto.RoleAssignmentDTO;
2323
import edu.harvard.iq.dataverse.api.dto.RoleDTO;
@@ -41,6 +41,7 @@
4141
import edu.harvard.iq.dataverse.engine.command.impl.DeleteDataverseCommand;
4242
import edu.harvard.iq.dataverse.engine.command.impl.DeleteDataverseLinkingDataverseCommand;
4343
import edu.harvard.iq.dataverse.engine.command.impl.DeleteExplicitGroupCommand;
44+
import edu.harvard.iq.dataverse.engine.command.impl.UpdateMetadataBlockFacetRootCommand;
4445
import edu.harvard.iq.dataverse.engine.command.impl.GetDataverseCommand;
4546
import edu.harvard.iq.dataverse.engine.command.impl.GetDataverseStorageSizeCommand;
4647
import edu.harvard.iq.dataverse.engine.command.impl.GetExplicitGroupCommand;
@@ -49,6 +50,7 @@
4950
import edu.harvard.iq.dataverse.engine.command.impl.ListDataverseContentCommand;
5051
import edu.harvard.iq.dataverse.engine.command.impl.ListExplicitGroupsCommand;
5152
import edu.harvard.iq.dataverse.engine.command.impl.ListFacetsCommand;
53+
import edu.harvard.iq.dataverse.engine.command.impl.ListMetadataBlockFacetsCommand;
5254
import edu.harvard.iq.dataverse.engine.command.impl.ListMetadataBlocksCommand;
5355
import edu.harvard.iq.dataverse.engine.command.impl.ListRoleAssignments;
5456
import edu.harvard.iq.dataverse.engine.command.impl.ListRolesCommand;
@@ -62,14 +64,14 @@
6264
import edu.harvard.iq.dataverse.engine.command.impl.UpdateDataverseDefaultContributorRoleCommand;
6365
import edu.harvard.iq.dataverse.engine.command.impl.UpdateDataverseMetadataBlocksCommand;
6466
import edu.harvard.iq.dataverse.engine.command.impl.UpdateExplicitGroupCommand;
67+
import edu.harvard.iq.dataverse.engine.command.impl.UpdateMetadataBlockFacetsCommand;
6568
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
6669
import edu.harvard.iq.dataverse.util.BundleUtil;
6770
import edu.harvard.iq.dataverse.util.ConstraintViolationUtil;
6871
import edu.harvard.iq.dataverse.util.StringUtil;
6972
import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty;
7073

7174
import edu.harvard.iq.dataverse.util.json.JSONLDUtil;
72-
import edu.harvard.iq.dataverse.util.json.JsonLDTerm;
7375
import edu.harvard.iq.dataverse.util.json.JsonParseException;
7476
import static edu.harvard.iq.dataverse.util.json.JsonPrinter.brief;
7577
import java.io.StringReader;
@@ -91,7 +93,6 @@
9193
import javax.json.JsonValue;
9294
import javax.json.JsonValue.ValueType;
9395
import javax.json.stream.JsonParsingException;
94-
import javax.validation.ConstraintViolation;
9596
import javax.validation.ConstraintViolationException;
9697
import javax.ws.rs.BadRequestException;
9798
import javax.ws.rs.Consumes;
@@ -114,9 +115,9 @@
114115
import java.text.SimpleDateFormat;
115116
import java.util.Arrays;
116117
import java.util.Date;
117-
import java.util.HashMap;
118118
import java.util.Map;
119119
import java.util.Optional;
120+
import java.util.stream.Collectors;
120121
import javax.servlet.http.HttpServletResponse;
121122
import javax.ws.rs.WebApplicationException;
122123
import javax.ws.rs.core.Context;
@@ -713,6 +714,78 @@ public Response setFacets(@PathParam("identifier") String dvIdtf, String facetId
713714
}
714715
}
715716

717+
@GET
718+
@Path("{identifier}/metadatablockfacets")
719+
@Produces(MediaType.APPLICATION_JSON)
720+
public Response listMetadataBlockFacets(@PathParam("identifier") String dvIdtf) {
721+
try {
722+
User u = findUserOrDie();
723+
DataverseRequest request = createDataverseRequest(u);
724+
Dataverse dataverse = findDataverseOrDie(dvIdtf);
725+
List<DataverseMetadataBlockFacet> metadataBlockFacets = Optional.ofNullable(execCommand(new ListMetadataBlockFacetsCommand(request, dataverse))).orElse(Collections.emptyList());
726+
List<DataverseMetadataBlockFacetDTO.MetadataBlockDTO> metadataBlocksDTOs = metadataBlockFacets.stream()
727+
.map(item -> new DataverseMetadataBlockFacetDTO.MetadataBlockDTO(item.getMetadataBlock().getName(), item.getMetadataBlock().getLocaleDisplayFacet()))
728+
.collect(Collectors.toList());
729+
DataverseMetadataBlockFacetDTO response = new DataverseMetadataBlockFacetDTO(dataverse.getId(), dataverse.getAlias(), dataverse.isMetadataBlockFacetRoot(), metadataBlocksDTOs);
730+
return Response.ok(response).build();
731+
} catch (WrappedResponse e) {
732+
return e.getResponse();
733+
}
734+
}
735+
736+
@POST
737+
@Path("{identifier}/metadatablockfacets")
738+
@Consumes(MediaType.APPLICATION_JSON)
739+
@Produces(MediaType.APPLICATION_JSON)
740+
public Response setMetadataBlockFacets(@PathParam("identifier") String dvIdtf, List<String> metadataBlockNames) {
741+
try {
742+
Dataverse dataverse = findDataverseOrDie(dvIdtf);
743+
744+
if(!dataverse.isMetadataBlockFacetRoot()) {
745+
return badRequest(String.format("Dataverse: %s must have metadata block facet root set to true", dvIdtf));
746+
}
747+
748+
List<DataverseMetadataBlockFacet> metadataBlockFacets = new LinkedList<>();
749+
for(String metadataBlockName: metadataBlockNames) {
750+
MetadataBlock metadataBlock = findMetadataBlock(metadataBlockName);
751+
if (metadataBlock == null) {
752+
return badRequest(String.format("Invalid metadata block name: %s", metadataBlockName));
753+
}
754+
755+
DataverseMetadataBlockFacet metadataBlockFacet = new DataverseMetadataBlockFacet();
756+
metadataBlockFacet.setDataverse(dataverse);
757+
metadataBlockFacet.setMetadataBlock(metadataBlock);
758+
metadataBlockFacets.add(metadataBlockFacet);
759+
}
760+
761+
execCommand(new UpdateMetadataBlockFacetsCommand(createDataverseRequest(findUserOrDie()), dataverse, metadataBlockFacets));
762+
return ok(String.format("Metadata block facets updated. DataverseId: %s blocks: %s", dvIdtf, metadataBlockNames));
763+
764+
} catch (WrappedResponse ex) {
765+
return ex.getResponse();
766+
}
767+
}
768+
769+
@POST
770+
@Path("{identifier}/metadatablockfacets/isRoot")
771+
@Consumes(MediaType.APPLICATION_JSON)
772+
@Produces(MediaType.APPLICATION_JSON)
773+
public Response updateMetadataBlockFacetsRoot(@PathParam("identifier") String dvIdtf, String body) {
774+
try {
775+
final boolean blockFacetsRoot = parseBooleanOrDie(body);
776+
Dataverse dataverse = findDataverseOrDie(dvIdtf);
777+
if(dataverse.isMetadataBlockFacetRoot() == blockFacetsRoot) {
778+
return ok(String.format("No update needed, dataverse already consistent with new value. DataverseId: %s blockFacetsRoot: %s", dvIdtf, blockFacetsRoot));
779+
}
780+
781+
execCommand(new UpdateMetadataBlockFacetRootCommand(createDataverseRequest(findUserOrDie()), dataverse, blockFacetsRoot));
782+
return ok(String.format("Metadata block facets root updated. DataverseId: %s blockFacetsRoot: %s", dvIdtf, blockFacetsRoot));
783+
784+
} catch (WrappedResponse ex) {
785+
return ex.getResponse();
786+
}
787+
}
788+
716789
// FIXME: This listContent method is way too optimistic, always returning "ok" and never "error".
717790
// TODO: Investigate why there was a change in the timeframe of when pull request #4350 was merged
718791
// (2438-4295-dois-for-files branch) such that a contributor API token no longer allows this method

0 commit comments

Comments
 (0)