diff --git a/doc/release-notes/8535-metadata-types-static-facet.md b/doc/release-notes/8535-metadata-types-static-facet.md new file mode 100644 index 00000000000..023000c0977 --- /dev/null +++ b/doc/release-notes/8535-metadata-types-static-facet.md @@ -0,0 +1,6 @@ +## Adding new static search facet: Metadata Types +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. + +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. + +To configure the new facet, use the Metadata Block Facet API: \ No newline at end of file diff --git a/doc/sphinx-guides/source/_static/api/dataverse-facets.json b/doc/sphinx-guides/source/_static/api/dataverse-facets.json new file mode 100644 index 00000000000..20a8412440d --- /dev/null +++ b/doc/sphinx-guides/source/_static/api/dataverse-facets.json @@ -0,0 +1 @@ +["authorName", "authorAffiliation"] \ No newline at end of file diff --git a/doc/sphinx-guides/source/_static/api/metadata-block-facets.json b/doc/sphinx-guides/source/_static/api/metadata-block-facets.json new file mode 100644 index 00000000000..bc497846592 --- /dev/null +++ b/doc/sphinx-guides/source/_static/api/metadata-block-facets.json @@ -0,0 +1 @@ +["socialscience", "geospatial"] \ No newline at end of file diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 75eb7b5424e..1c00053ef4f 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -219,15 +219,82 @@ Assign search facets for a given Dataverse collection identified by ``id``: export SERVER_URL=https://demo.dataverse.org export ID=root - curl -H X-Dataverse-key:$API_TOKEN" -X POST $SERVER_URL/api/dataverses/$ID/facets --upload-file facets.json + curl -H X-Dataverse-key:$API_TOKEN" -X POST $SERVER_URL/api/dataverses/$ID/facets --upload-file dataverse-facets.json The fully expanded example above (without environment variables) looks like this: .. code-block:: bash - curl -H X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -X POST https://demo.dataverse.org/api/dataverses/root/facets --upload-file facets.json + 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 -Where ``facets.json`` contains a JSON encoded list of metadata keys (e.g. ``["authorName","authorAffiliation"]``). +Where :download:`dataverse-facets.json <../_static/api/dataverse-facets.json>` contains a JSON encoded list of metadata keys (e.g. ``["authorName","authorAffiliation"]``). + +List Metadata Block Facets Configured for a Dataverse Collection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +|CORS| List the metadata block facet configuration with all the metadata block configured for a given Dataverse collection ``id``: + +.. code-block:: bash + + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + export SERVER_URL=https://demo.dataverse.org + export ID=root + + curl -H X-Dataverse-key:$API_TOKEN $SERVER_URL/api/dataverses/$ID/metadatablockfacets + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + curl -H X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx https://demo.dataverse.org/api/dataverses/root/metadatablockfacets + +Set Metadata Block Facets for a Dataverse Collection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sets the metadata blocks that will appear in the ``Dataset Features`` facet category for a given Dataverse collection identified by ``id``. + +In order to set or clear the metadata blocks for a collection, you must first :ref:`set the metadata block facet root to true`. + +To clear the metadata blocks set by a parent collection, submit an empty array (e.g. ``[]``): + +.. code-block:: bash + + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + export SERVER_URL=https://demo.dataverse.org + export ID=root + + 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 + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + 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 + +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. ``[]``) + +.. _metadata-block-facet-root-api: + +Configure a Dataverse Collection to Inherit Its Metadata Block Facets from Its Parent +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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). + +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: + +.. code-block:: bash + + export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + export SERVER_URL=https://demo.dataverse.org + export ID=root + + curl -H X-Dataverse-key:$API_TOKEN -X POST -H "Content-type:application/json" $SERVER_URL/api/dataverses/$ID/metadatablockfacets/isRoot -d 'true' + +The fully expanded example above (without environment variables) looks like this: + +.. code-block:: bash + + 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' Create a New Role in a Dataverse Collection ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/main/java/edu/harvard/iq/dataverse/Dataverse.java b/src/main/java/edu/harvard/iq/dataverse/Dataverse.java index db5f9d172cd..bc8716b6129 100644 --- a/src/main/java/edu/harvard/iq/dataverse/Dataverse.java +++ b/src/main/java/edu/harvard/iq/dataverse/Dataverse.java @@ -324,8 +324,31 @@ public boolean isHarvested() { return harvestingClient != null; } */ - - + private boolean metadataBlockFacetRoot; + + public boolean isMetadataBlockFacetRoot() { + return metadataBlockFacetRoot; + } + + public void setMetadataBlockFacetRoot(boolean metadataBlockFacetRoot) { + this.metadataBlockFacetRoot = metadataBlockFacetRoot; + } + + @OneToMany(mappedBy = "dataverse",cascade={ CascadeType.REMOVE, CascadeType.MERGE,CascadeType.PERSIST }, orphanRemoval=true) + private List metadataBlockFacets = new ArrayList<>(); + + public List getMetadataBlockFacets() { + if (isMetadataBlockFacetRoot() || getOwner() == null) { + return metadataBlockFacets; + } else { + return getOwner().getMetadataBlockFacets(); + } + } + + public void setMetadataBlockFacets(List metadataBlockFacets) { + this.metadataBlockFacets = metadataBlockFacets; + } + public List getParentGuestbooks() { List retList = new ArrayList<>(); Dataverse testDV = this; diff --git a/src/main/java/edu/harvard/iq/dataverse/DataverseMetadataBlockFacet.java b/src/main/java/edu/harvard/iq/dataverse/DataverseMetadataBlockFacet.java new file mode 100644 index 00000000000..a2659b81974 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/DataverseMetadataBlockFacet.java @@ -0,0 +1,82 @@ +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.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import java.io.Serializable; +import java.util.Objects; + +/** + * + * @author adaybujeda + */ +@Entity +@Table(indexes = {@Index(columnList="dataverse_id") + , @Index(columnList="metadatablock_id")}) +public class DataverseMetadataBlockFacet implements Serializable { + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "dataverse_id") + private Dataverse dataverse; + + @ManyToOne + @JoinColumn(name = "metadatablock_id") + private MetadataBlock metadataBlock; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Dataverse getDataverse() { + return dataverse; + } + + public void setDataverse(Dataverse dataverse) { + this.dataverse = dataverse; + } + + public MetadataBlock getMetadataBlock() { + return metadataBlock; + } + + public void setMetadataBlock(MetadataBlock metadataBlock) { + this.metadataBlock = metadataBlock; + } + + @Override + public int hashCode() { + int hash = 0; + hash += (this.id != null ? this.id.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof DataverseMetadataBlockFacet)) { + return false; + } + DataverseMetadataBlockFacet other = (DataverseMetadataBlockFacet) object; + return !(!Objects.equals(this.id, other.id) && (this.id == null || !this.id.equals(other.id))); + } + + @Override + public String toString() { + return String.format("edu.harvard.iq.dataverse.DataverseMetadataBlockFacet[ id=%s ]", id); + } + +} + diff --git a/src/main/java/edu/harvard/iq/dataverse/MetadataBlock.java b/src/main/java/edu/harvard/iq/dataverse/MetadataBlock.java index 844c0ec5be7..33e75efffb5 100644 --- a/src/main/java/edu/harvard/iq/dataverse/MetadataBlock.java +++ b/src/main/java/edu/harvard/iq/dataverse/MetadataBlock.java @@ -202,10 +202,18 @@ public String toString() { return "edu.harvard.iq.dataverse.MetadataBlock[ id=" + id + " ]"; } - public String getLocaleDisplayName() - { + public String getLocaleDisplayName() { + return getLocaleValue("metadatablock.displayName"); + } + + public String getLocaleDisplayFacet() { + return getLocaleValue("metadatablock.displayFacet"); + } + + // Visible for testing + String getLocaleValue(String metadataBlockKey) { try { - return BundleUtil.getStringFromPropertyFile("metadatablock.displayName", getName()); + return BundleUtil.getStringFromPropertyFile(metadataBlockKey, getName()); } catch (MissingResourceException e) { return displayName; } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java index d15b0f1c48f..90130cb3944 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -7,17 +7,17 @@ import edu.harvard.iq.dataverse.Dataverse; import edu.harvard.iq.dataverse.DataverseFacet; import edu.harvard.iq.dataverse.DataverseContact; +import edu.harvard.iq.dataverse.DataverseMetadataBlockFacet; import edu.harvard.iq.dataverse.DataverseServiceBean; import edu.harvard.iq.dataverse.api.datadeposit.SwordServiceBean; +import edu.harvard.iq.dataverse.api.dto.DataverseMetadataBlockFacetDTO; import edu.harvard.iq.dataverse.authorization.DataverseRole; import edu.harvard.iq.dataverse.DvObject; -import edu.harvard.iq.dataverse.DvObjectContainer; import edu.harvard.iq.dataverse.GlobalId; import edu.harvard.iq.dataverse.GuestbookResponseServiceBean; import edu.harvard.iq.dataverse.GuestbookServiceBean; import edu.harvard.iq.dataverse.MetadataBlock; import edu.harvard.iq.dataverse.RoleAssignment; -import static edu.harvard.iq.dataverse.api.AbstractApiBean.error; import edu.harvard.iq.dataverse.api.dto.ExplicitGroupDTO; import edu.harvard.iq.dataverse.api.dto.RoleAssignmentDTO; import edu.harvard.iq.dataverse.api.dto.RoleDTO; @@ -41,6 +41,7 @@ import edu.harvard.iq.dataverse.engine.command.impl.DeleteDataverseCommand; import edu.harvard.iq.dataverse.engine.command.impl.DeleteDataverseLinkingDataverseCommand; import edu.harvard.iq.dataverse.engine.command.impl.DeleteExplicitGroupCommand; +import edu.harvard.iq.dataverse.engine.command.impl.UpdateMetadataBlockFacetRootCommand; import edu.harvard.iq.dataverse.engine.command.impl.GetDataverseCommand; import edu.harvard.iq.dataverse.engine.command.impl.GetDataverseStorageSizeCommand; import edu.harvard.iq.dataverse.engine.command.impl.GetExplicitGroupCommand; @@ -49,6 +50,7 @@ import edu.harvard.iq.dataverse.engine.command.impl.ListDataverseContentCommand; import edu.harvard.iq.dataverse.engine.command.impl.ListExplicitGroupsCommand; import edu.harvard.iq.dataverse.engine.command.impl.ListFacetsCommand; +import edu.harvard.iq.dataverse.engine.command.impl.ListMetadataBlockFacetsCommand; import edu.harvard.iq.dataverse.engine.command.impl.ListMetadataBlocksCommand; import edu.harvard.iq.dataverse.engine.command.impl.ListRoleAssignments; import edu.harvard.iq.dataverse.engine.command.impl.ListRolesCommand; @@ -62,6 +64,7 @@ import edu.harvard.iq.dataverse.engine.command.impl.UpdateDataverseDefaultContributorRoleCommand; import edu.harvard.iq.dataverse.engine.command.impl.UpdateDataverseMetadataBlocksCommand; import edu.harvard.iq.dataverse.engine.command.impl.UpdateExplicitGroupCommand; +import edu.harvard.iq.dataverse.engine.command.impl.UpdateMetadataBlockFacetsCommand; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.BundleUtil; import edu.harvard.iq.dataverse.util.ConstraintViolationUtil; @@ -69,7 +72,6 @@ import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty; import edu.harvard.iq.dataverse.util.json.JSONLDUtil; -import edu.harvard.iq.dataverse.util.json.JsonLDTerm; import edu.harvard.iq.dataverse.util.json.JsonParseException; import static edu.harvard.iq.dataverse.util.json.JsonPrinter.brief; import java.io.StringReader; @@ -91,7 +93,6 @@ import javax.json.JsonValue; import javax.json.JsonValue.ValueType; import javax.json.stream.JsonParsingException; -import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import javax.ws.rs.BadRequestException; import javax.ws.rs.Consumes; @@ -114,9 +115,9 @@ import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; -import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; @@ -713,6 +714,78 @@ public Response setFacets(@PathParam("identifier") String dvIdtf, String facetId } } + @GET + @Path("{identifier}/metadatablockfacets") + @Produces(MediaType.APPLICATION_JSON) + public Response listMetadataBlockFacets(@PathParam("identifier") String dvIdtf) { + try { + User u = findUserOrDie(); + DataverseRequest request = createDataverseRequest(u); + Dataverse dataverse = findDataverseOrDie(dvIdtf); + List metadataBlockFacets = Optional.ofNullable(execCommand(new ListMetadataBlockFacetsCommand(request, dataverse))).orElse(Collections.emptyList()); + List metadataBlocksDTOs = metadataBlockFacets.stream() + .map(item -> new DataverseMetadataBlockFacetDTO.MetadataBlockDTO(item.getMetadataBlock().getName(), item.getMetadataBlock().getLocaleDisplayFacet())) + .collect(Collectors.toList()); + DataverseMetadataBlockFacetDTO response = new DataverseMetadataBlockFacetDTO(dataverse.getId(), dataverse.getAlias(), dataverse.isMetadataBlockFacetRoot(), metadataBlocksDTOs); + return Response.ok(response).build(); + } catch (WrappedResponse e) { + return e.getResponse(); + } + } + + @POST + @Path("{identifier}/metadatablockfacets") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response setMetadataBlockFacets(@PathParam("identifier") String dvIdtf, List metadataBlockNames) { + try { + Dataverse dataverse = findDataverseOrDie(dvIdtf); + + if(!dataverse.isMetadataBlockFacetRoot()) { + return badRequest(String.format("Dataverse: %s must have metadata block facet root set to true", dvIdtf)); + } + + List metadataBlockFacets = new LinkedList<>(); + for(String metadataBlockName: metadataBlockNames) { + MetadataBlock metadataBlock = findMetadataBlock(metadataBlockName); + if (metadataBlock == null) { + return badRequest(String.format("Invalid metadata block name: %s", metadataBlockName)); + } + + DataverseMetadataBlockFacet metadataBlockFacet = new DataverseMetadataBlockFacet(); + metadataBlockFacet.setDataverse(dataverse); + metadataBlockFacet.setMetadataBlock(metadataBlock); + metadataBlockFacets.add(metadataBlockFacet); + } + + execCommand(new UpdateMetadataBlockFacetsCommand(createDataverseRequest(findUserOrDie()), dataverse, metadataBlockFacets)); + return ok(String.format("Metadata block facets updated. DataverseId: %s blocks: %s", dvIdtf, metadataBlockNames)); + + } catch (WrappedResponse ex) { + return ex.getResponse(); + } + } + + @POST + @Path("{identifier}/metadatablockfacets/isRoot") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response updateMetadataBlockFacetsRoot(@PathParam("identifier") String dvIdtf, String body) { + try { + final boolean blockFacetsRoot = parseBooleanOrDie(body); + Dataverse dataverse = findDataverseOrDie(dvIdtf); + if(dataverse.isMetadataBlockFacetRoot() == blockFacetsRoot) { + return ok(String.format("No update needed, dataverse already consistent with new value. DataverseId: %s blockFacetsRoot: %s", dvIdtf, blockFacetsRoot)); + } + + execCommand(new UpdateMetadataBlockFacetRootCommand(createDataverseRequest(findUserOrDie()), dataverse, blockFacetsRoot)); + return ok(String.format("Metadata block facets root updated. DataverseId: %s blockFacetsRoot: %s", dvIdtf, blockFacetsRoot)); + + } catch (WrappedResponse ex) { + return ex.getResponse(); + } + } + // FIXME: This listContent method is way too optimistic, always returning "ok" and never "error". // TODO: Investigate why there was a change in the timeframe of when pull request #4350 was merged // (2438-4295-dois-for-files branch) such that a contributor API token no longer allows this method diff --git a/src/main/java/edu/harvard/iq/dataverse/api/dto/DataverseMetadataBlockFacetDTO.java b/src/main/java/edu/harvard/iq/dataverse/api/dto/DataverseMetadataBlockFacetDTO.java new file mode 100644 index 00000000000..65b6f0ff58f --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/api/dto/DataverseMetadataBlockFacetDTO.java @@ -0,0 +1,56 @@ +package edu.harvard.iq.dataverse.api.dto; + +import java.util.List; + +/** + * + * @author adaybujeda + */ +public class DataverseMetadataBlockFacetDTO { + + private Long dataverseId; + private String dataverseAlias; + private boolean isMetadataBlockFacetRoot; + private List metadataBlocks; + + public DataverseMetadataBlockFacetDTO(Long dataverseId, String dataverseAlias, boolean isMetadataBlockFacetRoot, List metadataBlocks) { + this.dataverseId = dataverseId; + this.dataverseAlias = dataverseAlias; + this.isMetadataBlockFacetRoot = isMetadataBlockFacetRoot; + this.metadataBlocks = metadataBlocks; + } + + public Long getDataverseId() { + return dataverseId; + } + + public String getDataverseAlias() { + return dataverseAlias; + } + + public boolean isMetadataBlockFacetRoot() { + return isMetadataBlockFacetRoot; + } + + public List getMetadataBlocks() { + return metadataBlocks; + } + + public static class MetadataBlockDTO { + private String metadataBlockName; + private String metadataBlockFacet; + + public MetadataBlockDTO(String metadataBlockName, String metadataBlockFacet) { + this.metadataBlockName = metadataBlockName; + this.metadataBlockFacet = metadataBlockFacet; + } + + public String getMetadataBlockName() { + return metadataBlockName; + } + + public String getMetadataBlockFacet() { + return metadataBlockFacet; + } + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListMetadataBlockFacetsCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListMetadataBlockFacetsCommand.java new file mode 100644 index 00000000000..abc444dc538 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/ListMetadataBlockFacetsCommand.java @@ -0,0 +1,40 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + +import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.DataverseMetadataBlockFacet; +import edu.harvard.iq.dataverse.authorization.Permission; +import edu.harvard.iq.dataverse.engine.command.AbstractCommand; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.exception.CommandException; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * + * @author adaybujeda + */ +public class ListMetadataBlockFacetsCommand extends AbstractCommand> { + + private final Dataverse dv; + + public ListMetadataBlockFacetsCommand(DataverseRequest aRequest, Dataverse aDataverse) { + super(aRequest, aDataverse); + dv = aDataverse; + } + + @Override + public List execute(CommandContext ctxt) throws CommandException { + return dv.getMetadataBlockFacets(); + } + + @Override + public Map> getRequiredPermissions() { + return Collections.singletonMap("", + dv.isReleased() ? Collections.emptySet() + : Collections.singleton(Permission.ViewUnpublishedDataverse)); + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateMetadataBlockFacetRootCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateMetadataBlockFacetRootCommand.java new file mode 100644 index 00000000000..2e5b6b59ebe --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateMetadataBlockFacetRootCommand.java @@ -0,0 +1,65 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + +import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.DataverseMetadataBlockFacet; +import edu.harvard.iq.dataverse.authorization.Permission; +import edu.harvard.iq.dataverse.engine.command.AbstractCommand; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; +import edu.harvard.iq.dataverse.engine.command.exception.CommandException; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * + * @author adaybujeda + */ +@RequiredPermissions( Permission.EditDataverse ) +public class UpdateMetadataBlockFacetRootCommand extends AbstractCommand { + + private final Dataverse editedDv; + private final boolean metadataBlockFacetRoot; + + public UpdateMetadataBlockFacetRootCommand(DataverseRequest aRequest, Dataverse editedDv, boolean metadataBlockFacetRoot) { + super(aRequest, editedDv); + this.editedDv = editedDv; + this.metadataBlockFacetRoot = metadataBlockFacetRoot; + } + + @Override + public Dataverse execute(CommandContext ctxt) throws CommandException { + if(editedDv.isMetadataBlockFacetRoot() != metadataBlockFacetRoot) { + // Update metadata block facets when root changes value + // if you set root to be false (i.e. inherit), it should clear the blocks. + // if you set to true (i.e. use your own), it should make a copy of what is in the parent + List newBlockFacets = Collections.emptyList(); + if (metadataBlockFacetRoot) { + newBlockFacets = editedDv.getMetadataBlockFacets().stream().map(blockFacet -> { + DataverseMetadataBlockFacet metadataBlockFacet = new DataverseMetadataBlockFacet(); + metadataBlockFacet.setDataverse(editedDv); + metadataBlockFacet.setMetadataBlock(blockFacet.getMetadataBlock()); + return metadataBlockFacet; + }).collect(Collectors.toList()); + } + editedDv.setMetadataBlockFacets(newBlockFacets); + + editedDv.setMetadataBlockFacetRoot(metadataBlockFacetRoot); + return ctxt.dataverses().save(editedDv); + } + + return editedDv; + } + + // Visible for testing + public Dataverse getEditedDataverse() { + return this.editedDv; + } + + // Visible for testing + public boolean getMetadataBlockFacetRoot() { + return metadataBlockFacetRoot; + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateMetadataBlockFacetsCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateMetadataBlockFacetsCommand.java new file mode 100644 index 00000000000..72a41f5cc3c --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateMetadataBlockFacetsCommand.java @@ -0,0 +1,52 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + +import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.DataverseMetadataBlockFacet; +import edu.harvard.iq.dataverse.authorization.Permission; +import edu.harvard.iq.dataverse.engine.command.AbstractCommand; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; +import edu.harvard.iq.dataverse.engine.command.exception.CommandException; +import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; + +import java.util.List; + +/** + * + * @author adaybujeda + */ +@RequiredPermissions( Permission.EditDataverse ) +public class UpdateMetadataBlockFacetsCommand extends AbstractCommand { + + private final Dataverse editedDv; + private final List metadataBlockFacets; + + public UpdateMetadataBlockFacetsCommand(DataverseRequest aRequest, Dataverse editedDv, List metadataBlockFacets) { + super(aRequest, editedDv); + this.editedDv = editedDv; + this.metadataBlockFacets = metadataBlockFacets; + } + + @Override + public Dataverse execute(CommandContext ctxt) throws CommandException { + if (!editedDv.isMetadataBlockFacetRoot()) { + throw new IllegalCommandException("Cannot update metadata blocks facets when dataverse has metadata block facet root set to false", this); + } + + editedDv.setMetadataBlockFacets(metadataBlockFacets); + Dataverse updated = ctxt.dataverses().save(editedDv); + return updated; + } + + // Visible for testing + public Dataverse getEditedDataverse() { + return this.editedDv; + } + + // Visible for testing + public List getMetadataBlockFacets() { + return this.metadataBlockFacets; + } + +} diff --git a/src/main/java/edu/harvard/iq/dataverse/search/IndexServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/search/IndexServiceBean.java index bd66e822c20..484e5768eb1 100644 --- a/src/main/java/edu/harvard/iq/dataverse/search/IndexServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/search/IndexServiceBean.java @@ -49,6 +49,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.Future; import java.util.function.Function; @@ -816,6 +817,7 @@ public SolrInputDocuments toSolrDocs(IndexableDataset indexableDataset, Set langs = settingsService.getConfiguredLanguages(); Map cvocMap = datasetFieldService.getCVocConf(false); + Set metadataBlocksWithValue = new HashSet<>(); for (DatasetField dsf : datasetVersion.getFlatDatasetFields()) { DatasetFieldType dsfType = dsf.getDatasetFieldType(); @@ -823,6 +825,11 @@ public SolrInputDocuments toSolrDocs(IndexableDataset indexableDataset, Set dataversePaths = retrieveDVOPaths(dataset); diff --git a/src/main/java/edu/harvard/iq/dataverse/search/SearchFields.java b/src/main/java/edu/harvard/iq/dataverse/search/SearchFields.java index 63b5a777b0e..2e75a81ed5f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/search/SearchFields.java +++ b/src/main/java/edu/harvard/iq/dataverse/search/SearchFields.java @@ -206,6 +206,7 @@ public class SearchFields { * A dataverse, a dataset, or a file. */ public static final String TYPE = "dvObjectType"; + public static final String METADATA_TYPES = "metadata_type_ss"; public static final String NAME_SORT = "nameSort"; // PUBLICATION_YEAR used to be called PUBLICATION_DATE. public static final String PUBLICATION_YEAR = "publicationDate"; diff --git a/src/main/java/edu/harvard/iq/dataverse/search/SearchIncludeFragment.java b/src/main/java/edu/harvard/iq/dataverse/search/SearchIncludeFragment.java index 6da4960679d..9bb83c88add 100644 --- a/src/main/java/edu/harvard/iq/dataverse/search/SearchIncludeFragment.java +++ b/src/main/java/edu/harvard/iq/dataverse/search/SearchIncludeFragment.java @@ -32,6 +32,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.logging.Logger; import javax.ejb.EJB; @@ -1150,9 +1151,20 @@ public List getFriendlyNamesFromFilterQuery(String filterQuery) { friendlyNames.add(key); } } + String noLeadingQuote = value.replaceAll("^\"", ""); String noTrailingQuote = noLeadingQuote.replaceAll("\"$", ""); String valueWithoutQuotes = noTrailingQuote; + + if (key.equals(SearchFields.METADATA_TYPES) && getDataverse() != null && getDataverse().getMetadataBlockFacets() != null) { + Optional friendlyName = getDataverse().getMetadataBlockFacets().stream().filter(block -> block.getMetadataBlock().getName().equals(valueWithoutQuotes)).findFirst().map(block -> block.getMetadataBlock().getLocaleDisplayFacet()); + logger.fine(String.format("action=getFriendlyNamesFromFilterQuery key=%s value=%s friendlyName=%s", key, value, friendlyName)); + if(friendlyName.isPresent()) { + friendlyNames.add(friendlyName.get()); + return friendlyNames; + } + } + friendlyNames.add(valueWithoutQuotes); return friendlyNames; } diff --git a/src/main/java/edu/harvard/iq/dataverse/search/SearchServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/search/SearchServiceBean.java index 8dc367ec5c9..ca158198204 100644 --- a/src/main/java/edu/harvard/iq/dataverse/search/SearchServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/search/SearchServiceBean.java @@ -7,6 +7,7 @@ import edu.harvard.iq.dataverse.DatasetVersionServiceBean; import edu.harvard.iq.dataverse.Dataverse; import edu.harvard.iq.dataverse.DataverseFacet; +import edu.harvard.iq.dataverse.DataverseMetadataBlockFacet; import edu.harvard.iq.dataverse.DvObjectServiceBean; import edu.harvard.iq.dataverse.authorization.groups.Group; import edu.harvard.iq.dataverse.authorization.groups.GroupServiceBean; @@ -26,9 +27,11 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.MissingResourceException; import java.util.logging.Level; @@ -207,6 +210,7 @@ public SolrQueryResponse search(DataverseRequest dataverseRequest, List metadataBlockFacets = new LinkedList<>(); //I'm not sure if just adding null here is good for hte permissions system... i think it needs something if(dataverses != null) { for(Dataverse dataverse : dataverses) { @@ -244,6 +249,8 @@ public SolrQueryResponse search(DataverseRequest dataverseRequest, List 0) { if(metadataBlockName.length() > 0 ) { localefriendlyName = getLocaleTitle(datasetFieldName,facetFieldCount.getName(), metadataBlockName); - } else { + } else if (facetField.getName().equals(SearchFields.METADATA_TYPES)) { + Optional metadataBlockFacet = metadataBlockFacets.stream().filter(blockFacet -> blockFacet.getMetadataBlock().getName().equals(facetFieldCount.getName())).findFirst(); + if (metadataBlockFacet.isEmpty()) { + // metadata block facet is not configured to be displayed => ignore + continue; + } + + localefriendlyName = metadataBlockFacet.get().getMetadataBlock().getLocaleDisplayFacet(); + } else { try { localefriendlyName = BundleUtil.getStringFromPropertyFile(facetFieldCount.getName(), "Bundle"); } catch (Exception e) { @@ -694,7 +709,7 @@ public SolrQueryResponse search(DataverseRequest dataverseRequest, List 0) { facetCategory.setFriendlyName(friendlyName); } else { @@ -749,7 +764,7 @@ public SolrQueryResponse search(DataverseRequest dataverseRequest, List 0) { - FacetLabel facetLabel = new FacetLabel(start + "-" + end, new Long(rangeFacetCount.getCount())); + FacetLabel facetLabel = new FacetLabel(start + "-" + end, Long.valueOf(rangeFacetCount.getCount())); // special [12 TO 34] syntax for range facets facetLabel.setFilterQuery(rangeFacet.getName() + ":" + "[" + start + " TO " + end + "]"); facetLabelList.add(facetLabel); diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 5b6216aaff1..f954ec99024 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -2739,17 +2739,6 @@ jsonparser.error.parsing.number=Error parsing number: {0} #ConfigureFragmentBean.java configurefragmentbean.apiTokenGenerated=API Token will be generated. Please keep it secure as you would do with a password. -#FacetCategory - staticSearchFields -staticSearchFields.dvCategory=Dataverse Category -staticSearchFields.metadataSource=Metadata Source -staticSearchFields.publicationDate=Publication Year -staticSearchFields.fileTypeGroupFacet=File Type -staticSearchFields.dvObjectType=Type -staticSearchFields.fileTag=File Tag -staticSearchFields.fileAccess=Access -staticSearchFields.publicationStatus=Publication Status -staticSearchFields.subject_ss=Subject - #dataverse category - Facet Labels Researcher=Researcher Research\u0020Project=Research Project diff --git a/src/main/java/propertyFiles/astrophysics.properties b/src/main/java/propertyFiles/astrophysics.properties index be81ccdc883..a49b8b66510 100644 --- a/src/main/java/propertyFiles/astrophysics.properties +++ b/src/main/java/propertyFiles/astrophysics.properties @@ -1,5 +1,6 @@ metadatablock.name=astrophysics metadatablock.displayName=Astronomy and Astrophysics Metadata +metadatablock.displayFacet=Astronomy and Astrophysics datasetfieldtype.astroType.title=Type datasetfieldtype.astroFacility.title=Facility datasetfieldtype.astroInstrument.title=Instrument diff --git a/src/main/java/propertyFiles/biomedical.properties b/src/main/java/propertyFiles/biomedical.properties index 723a4ac2f40..1bffed2ee03 100644 --- a/src/main/java/propertyFiles/biomedical.properties +++ b/src/main/java/propertyFiles/biomedical.properties @@ -1,5 +1,6 @@ metadatablock.name=biomedical metadatablock.displayName=Life Sciences Metadata +metadatablock.displayFacet=Life Sciences datasetfieldtype.studyDesignType.title=Design Type datasetfieldtype.studyOtherDesignType.title=Other Design Type datasetfieldtype.studyFactorType.title=Factor Type diff --git a/src/main/java/propertyFiles/citation.properties b/src/main/java/propertyFiles/citation.properties index b69a8e1549c..668542c92be 100644 --- a/src/main/java/propertyFiles/citation.properties +++ b/src/main/java/propertyFiles/citation.properties @@ -1,5 +1,6 @@ metadatablock.name=citation metadatablock.displayName=Citation Metadata +metadatablock.displayFacet=Citation datasetfieldtype.title.title=Title datasetfieldtype.subtitle.title=Subtitle datasetfieldtype.alternativeTitle.title=Alternative Title diff --git a/src/main/java/propertyFiles/customARCS.properties b/src/main/java/propertyFiles/customARCS.properties index e6665b94e64..8a19405208a 100644 --- a/src/main/java/propertyFiles/customARCS.properties +++ b/src/main/java/propertyFiles/customARCS.properties @@ -1,5 +1,6 @@ metadatablock.name=customARCS metadatablock.displayName=Alliance for Research on Corporate Sustainability Metadata +metadatablock.displayFacet=Alliance for Research on Corporate Sustainability datasetfieldtype.ARCS1.title=1) Were any of these data sets a) purchased, b) obtained through licensed databases, or c) provided by an organization under a nondisclosure or other agreement? datasetfieldtype.ARCS2.title=2) If you responded Yes to Q1, have you ensured that sharing the data does not violate terms of the agreement? If you responded No to Q1, please enter N/A here. datasetfieldtype.ARCS3.title=3) Do any of these data sets include individual-level data (either collected or pre-existing in the dataset) that might make them subject to U.S. or international human subjects considerations? diff --git a/src/main/java/propertyFiles/customCHIA.properties b/src/main/java/propertyFiles/customCHIA.properties index 0b05e388cee..0d59493da96 100644 --- a/src/main/java/propertyFiles/customCHIA.properties +++ b/src/main/java/propertyFiles/customCHIA.properties @@ -1,5 +1,6 @@ metadatablock.name=customCHIA metadatablock.displayName=CHIA Metadata +metadatablock.displayFacet=CHIA datasetfieldtype.sourceCHIA.title=Source datasetfieldtype.datesAdditionalInformationCHIA.title=Dates - Additional Information datasetfieldtype.variablesCHIA.title=Variables diff --git a/src/main/java/propertyFiles/customDigaai.properties b/src/main/java/propertyFiles/customDigaai.properties index 85d7df1f2b7..10bb8f23786 100644 --- a/src/main/java/propertyFiles/customDigaai.properties +++ b/src/main/java/propertyFiles/customDigaai.properties @@ -1,5 +1,6 @@ metadatablock.name=customDigaai metadatablock.displayName=Digaai Metadata +metadatablock.displayFacet=Digaai datasetfieldtype.titulo.title=Título datasetfieldtype.numero.title=Número datasetfieldtype.datadePublicao.title=Data de Publicação @@ -52,4 +53,4 @@ controlledvocabulary.titulo.tc_brazil=TC Brazil controlledvocabulary.titulo.texas_magazine=Texas Magazine controlledvocabulary.titulo.the_brazilian_journal=The Brazilian Journal controlledvocabulary.titulo.today_magazine=Today Magazine -controlledvocabulary.titulo.viver_magazine=Viver Magazine \ No newline at end of file +controlledvocabulary.titulo.viver_magazine=Viver Magazine diff --git a/src/main/java/propertyFiles/customGSD.properties b/src/main/java/propertyFiles/customGSD.properties index 15f118c73c4..40dc0328053 100644 --- a/src/main/java/propertyFiles/customGSD.properties +++ b/src/main/java/propertyFiles/customGSD.properties @@ -1,5 +1,6 @@ metadatablock.name=customGSD metadatablock.displayName=Graduate School of Design Metadata +metadatablock.displayFacet=Graduate School of Design datasetfieldtype.gsdStudentName.title=Student Name datasetfieldtype.gsdStudentProgram.title=Student's Program of Study datasetfieldtype.gsdCourseName.title=Course Name diff --git a/src/main/java/propertyFiles/customMRA.properties b/src/main/java/propertyFiles/customMRA.properties index 8d905d266f0..5a702b980cc 100644 --- a/src/main/java/propertyFiles/customMRA.properties +++ b/src/main/java/propertyFiles/customMRA.properties @@ -1,5 +1,6 @@ metadatablock.name=customMRA metadatablock.displayName=MRA Metadata +metadatablock.displayFacet=MRA datasetfieldtype.mraCollection.title=Murray Research Archive Collection datasetfieldtype.mraCollection.description=Browse the Murray Research Archive collection with the following terms. datasetfieldtype.mraCollection.watermark= diff --git a/src/main/java/propertyFiles/customPSI.properties b/src/main/java/propertyFiles/customPSI.properties index e72e4e50222..a88b7409c5a 100644 --- a/src/main/java/propertyFiles/customPSI.properties +++ b/src/main/java/propertyFiles/customPSI.properties @@ -1,5 +1,6 @@ metadatablock.name=customPSI metadatablock.displayName=PSI Metadata +metadatablock.displayFacet=PSI datasetfieldtype.psiBehavior.title=Behavior datasetfieldtype.psiDonor.title=Donor datasetfieldtype.psiHealthArea.title=Health Area diff --git a/src/main/java/propertyFiles/customPSRI.properties b/src/main/java/propertyFiles/customPSRI.properties index 61370bb9fd1..9e76b412bd8 100644 --- a/src/main/java/propertyFiles/customPSRI.properties +++ b/src/main/java/propertyFiles/customPSRI.properties @@ -1,5 +1,6 @@ metadatablock.name=customPSRI metadatablock.displayName=Political Science Replication Initiative Metadata +metadatablock.displayFacet=Political Science Replication Initiative datasetfieldtype.PSRI1.title=Are the original data publicly available? datasetfieldtype.PSRI2.title=Is the original code available? datasetfieldtype.PSRI3.title=Where are the original data archived (name and url)? diff --git a/src/main/java/propertyFiles/custom_hbgdki.properties b/src/main/java/propertyFiles/custom_hbgdki.properties index 087c706d014..2386b5d00a2 100644 --- a/src/main/java/propertyFiles/custom_hbgdki.properties +++ b/src/main/java/propertyFiles/custom_hbgdki.properties @@ -1,5 +1,6 @@ metadatablock.name=custom_hbgdki metadatablock.displayName=HBGDki Custom Metadata +metadatablock.displayFacet=HBGDki datasetfieldtype.hbgdkiStudyName.title=Name of Study datasetfieldtype.hbgdkiStudyRegistry.title=Study Registry datasetfieldtype.hbgdkiStudyRegistryType.title=ID Type diff --git a/src/main/java/propertyFiles/geospatial.properties b/src/main/java/propertyFiles/geospatial.properties index e47982377cb..04db8d3d05f 100644 --- a/src/main/java/propertyFiles/geospatial.properties +++ b/src/main/java/propertyFiles/geospatial.properties @@ -1,5 +1,6 @@ metadatablock.name=geospatial metadatablock.displayName=Geospatial Metadata +metadatablock.displayFacet=Geospatial datasetfieldtype.geographicCoverage.title=Geographic Coverage datasetfieldtype.country.title=Country / Nation datasetfieldtype.state.title=State / Province @@ -281,4 +282,4 @@ controlledvocabulary.country.western_sahara=Western Sahara controlledvocabulary.country.yemen=Yemen controlledvocabulary.country.zambia=Zambia controlledvocabulary.country.zimbabwe=Zimbabwe -controlledvocabulary.country.aland_islands=Åland Islands \ No newline at end of file +controlledvocabulary.country.aland_islands=Åland Islands diff --git a/src/main/java/propertyFiles/journal.properties b/src/main/java/propertyFiles/journal.properties index e17a9bd6d89..753b5895f0a 100644 --- a/src/main/java/propertyFiles/journal.properties +++ b/src/main/java/propertyFiles/journal.properties @@ -1,5 +1,6 @@ metadatablock.name=journal metadatablock.displayName=Journal Metadata +metadatablock.displayFacet=Journal datasetfieldtype.journalVolumeIssue.title=Journal datasetfieldtype.journalVolume.title=Volume datasetfieldtype.journalIssue.title=Issue diff --git a/src/main/java/propertyFiles/socialscience.properties b/src/main/java/propertyFiles/socialscience.properties index 91e73fa78b9..3698b32573f 100644 --- a/src/main/java/propertyFiles/socialscience.properties +++ b/src/main/java/propertyFiles/socialscience.properties @@ -1,5 +1,6 @@ metadatablock.name=socialscience metadatablock.displayName=Social Science and Humanities Metadata +metadatablock.displayFacet=Social Science and Humanities datasetfieldtype.unitOfAnalysis.title=Unit of Analysis datasetfieldtype.universe.title=Universe datasetfieldtype.timeMethod.title=Time Method diff --git a/src/main/java/propertyFiles/staticSearchFields.properties b/src/main/java/propertyFiles/staticSearchFields.properties new file mode 100644 index 00000000000..ab03de64f23 --- /dev/null +++ b/src/main/java/propertyFiles/staticSearchFields.properties @@ -0,0 +1,11 @@ +#FacetCategory - staticSearchFields +staticSearchFields.metadata_type_ss=Dataset Feature +staticSearchFields.dvCategory=Dataverse Category +staticSearchFields.metadataSource=Metadata Source +staticSearchFields.publicationDate=Publication Year +staticSearchFields.fileTypeGroupFacet=File Type +staticSearchFields.dvObjectType=Type +staticSearchFields.fileTag=File Tag +staticSearchFields.fileAccess=Access +staticSearchFields.publicationStatus=Publication Status +staticSearchFields.subject_ss=Subject \ No newline at end of file diff --git a/src/main/resources/db/migration/V5.11.1.5__8536-metadata-block-facet.sql b/src/main/resources/db/migration/V5.11.1.5__8536-metadata-block-facet.sql new file mode 100644 index 00000000000..47435004b6d --- /dev/null +++ b/src/main/resources/db/migration/V5.11.1.5__8536-metadata-block-facet.sql @@ -0,0 +1,11 @@ +ALTER TABLE dataverse + ADD COLUMN IF NOT EXISTS metadatablockfacetroot BOOLEAN; + +UPDATE dataverse SET metadatablockfacetroot = false; + +CREATE TABLE IF NOT EXISTS dataversemetadatablockfacet ( + id SERIAL NOT NULL, + dataverse_id BIGINT NOT NULL, + metadatablock_id BIGINT NOT NULL, + PRIMARY KEY (ID) +); diff --git a/src/test/java/edu/harvard/iq/dataverse/DataverseMetadataBlockFacetTest.java b/src/test/java/edu/harvard/iq/dataverse/DataverseMetadataBlockFacetTest.java new file mode 100644 index 00000000000..7ae2d26a113 --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/DataverseMetadataBlockFacetTest.java @@ -0,0 +1,45 @@ +package edu.harvard.iq.dataverse; + +import edu.harvard.iq.dataverse.mocks.MocksFactory; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * + * @author adaybujeda + */ +public class DataverseMetadataBlockFacetTest { + + @Test + public void equals_should_be_based_on_id() { + Long sameId = MocksFactory.nextId(); + DataverseMetadataBlockFacet target1 = new DataverseMetadataBlockFacet(); + target1.setId(sameId); + target1.setDataverse(new Dataverse()); + target1.setMetadataBlock(new MetadataBlock()); + + DataverseMetadataBlockFacet target2 = new DataverseMetadataBlockFacet(); + target2.setId(sameId); + target2.setDataverse(new Dataverse()); + target2.setMetadataBlock(new MetadataBlock()); + + MatcherAssert.assertThat(target1.equals(target2), Matchers.is(true)); + + + Dataverse sameDataverse = new Dataverse(); + MetadataBlock sameMetadataBlock = new MetadataBlock(); + target1 = new DataverseMetadataBlockFacet(); + target1.setId(MocksFactory.nextId()); + target1.setDataverse(sameDataverse); + target1.setMetadataBlock(sameMetadataBlock); + + target2 = new DataverseMetadataBlockFacet(); + target2.setId(MocksFactory.nextId()); + target2.setDataverse(sameDataverse); + target2.setMetadataBlock(sameMetadataBlock); + + MatcherAssert.assertThat(target1.equals(target2), Matchers.is(false)); + } + +} \ No newline at end of file diff --git a/src/test/java/edu/harvard/iq/dataverse/DataverseTest.java b/src/test/java/edu/harvard/iq/dataverse/DataverseTest.java new file mode 100644 index 00000000000..cb0561dd0f4 --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/DataverseTest.java @@ -0,0 +1,65 @@ +package edu.harvard.iq.dataverse; + +import edu.harvard.iq.dataverse.mocks.MocksFactory; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +/** + * + * @author adaybujeda + */ +public class DataverseTest { + + private Dataverse OWNER; + private List OWNER_METADATABLOCKFACETS; + + @Before + public void beforeEachTest() { + OWNER = new Dataverse(); + OWNER.setId(MocksFactory.nextId()); + OWNER.setMetadataBlockRoot(true); + + DataverseMetadataBlockFacet metadataBlockFacet = new DataverseMetadataBlockFacet(); + metadataBlockFacet.setId(MocksFactory.nextId()); + OWNER_METADATABLOCKFACETS = Arrays.asList(metadataBlockFacet); + OWNER.setMetadataBlockFacets(OWNER_METADATABLOCKFACETS); + } + + @Test + public void getMetadataBlockFacets_should_return_internal_metadatablockfacets_when_metadatablockfacetroot_is_true() { + Dataverse target = new Dataverse(); + target.setId(MocksFactory.nextId()); + target.setMetadataBlockFacetRoot(true); + target.setOwner(OWNER); + + DataverseMetadataBlockFacet metadataBlockFacet = new DataverseMetadataBlockFacet(); + metadataBlockFacet.setId(MocksFactory.nextId()); + List internalMetadataBlockFacets = Arrays.asList(metadataBlockFacet); + target.setMetadataBlockFacets(internalMetadataBlockFacets); + List result = target.getMetadataBlockFacets(); + + MatcherAssert.assertThat(result, Matchers.is(internalMetadataBlockFacets)); + } + + @Test + public void getMetadataBlockFacets_should_return_owner_metadatablockfacets_when_metadatablockfacetroot_is_false() { + Dataverse target = new Dataverse(); + target.setId(MocksFactory.nextId()); + target.setMetadataBlockFacetRoot(false); + target.setOwner(OWNER); + + DataverseMetadataBlockFacet metadataBlockFacet = new DataverseMetadataBlockFacet(); + metadataBlockFacet.setId(MocksFactory.nextId()); + List internalMetadataBlockFacets = Arrays.asList(metadataBlockFacet); + target.setMetadataBlockFacets(internalMetadataBlockFacets); + List result = target.getMetadataBlockFacets(); + + MatcherAssert.assertThat(result, Matchers.is(OWNER_METADATABLOCKFACETS)); + } + +} \ No newline at end of file diff --git a/src/test/java/edu/harvard/iq/dataverse/MetadataBlockTest.java b/src/test/java/edu/harvard/iq/dataverse/MetadataBlockTest.java new file mode 100644 index 00000000000..85aaa37bb30 --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/MetadataBlockTest.java @@ -0,0 +1,79 @@ +package edu.harvard.iq.dataverse; + +import edu.harvard.iq.dataverse.mocks.MocksFactory; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.UUID; + +public class MetadataBlockTest { + + private static final String PROPERTIES_FILE_NAME = "metadataBlockTest"; + + @Test + public void equals_should_be_based_on_id_only() { + Long id = MocksFactory.nextId(); + MetadataBlock metadataBlock1 = new MetadataBlock(); + metadataBlock1.setId(id); + metadataBlock1.setName(UUID.randomUUID().toString()); + MetadataBlock metadataBlock2 = new MetadataBlock(); + metadataBlock2.setId(id); + metadataBlock1.setName(UUID.randomUUID().toString()); + + MatcherAssert.assertThat(metadataBlock1.equals(metadataBlock2), Matchers.is(true)); + + metadataBlock1 = new MetadataBlock(); + metadataBlock1.setId(MocksFactory.nextId()); + metadataBlock1.setName("EQUAL"); + metadataBlock2 = new MetadataBlock(); + metadataBlock2.setId(MocksFactory.nextId()); + metadataBlock1.setName("EQUAL"); + + MatcherAssert.assertThat(metadataBlock1.equals(metadataBlock2), Matchers.is(false)); + } + + @Test + public void getLocaleDisplayName_should_default_value_from_displayName_when_bundle_not_found() { + MetadataBlock target = Mockito.spy(new MetadataBlock()); + target.setName(UUID.randomUUID().toString()); + target.setDisplayName(UUID.randomUUID().toString()); + + //Value when no resource file found with metadata block name + MatcherAssert.assertThat(target.getLocaleDisplayName(), Matchers.is(target.getDisplayName())); + Mockito.verify(target).getLocaleValue("metadatablock.displayName"); + } + + @Test + public void getLocaleDisplayName_should_get_value_from_properties_based_on_name() { + MetadataBlock target = Mockito.spy(new MetadataBlock()); + target.setName(PROPERTIES_FILE_NAME); + target.setDisplayName(UUID.randomUUID().toString()); + + // Values is coming from the metadataBlockTest.properties file + MatcherAssert.assertThat(target.getLocaleDisplayName(), Matchers.is("property_value_for_displayName")); + Mockito.verify(target).getLocaleValue("metadatablock.displayName"); + } + + @Test + public void getLocaleDisplayFacet_should_default_value_from_displayName_when_bundle_not_found() { + MetadataBlock target = Mockito.spy(new MetadataBlock()); + target.setName(UUID.randomUUID().toString()); + target.setDisplayName(UUID.randomUUID().toString()); + + MatcherAssert.assertThat(target.getLocaleDisplayFacet(), Matchers.is(target.getDisplayName())); + Mockito.verify(target).getLocaleValue("metadatablock.displayFacet"); + } + + @Test + public void getLocaleDisplayFacet_should_get_value_from_properties_based_on_name() { + MetadataBlock target = Mockito.spy(new MetadataBlock()); + target.setName(PROPERTIES_FILE_NAME); + target.setDisplayName(UUID.randomUUID().toString()); + + // Values is coming from the metadataBlockTest.properties file + MatcherAssert.assertThat(target.getLocaleDisplayFacet(), Matchers.is("property_value_for_displayFacet")); + Mockito.verify(target).getLocaleValue("metadatablock.displayFacet"); + } +} \ No newline at end of file diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DataversesTest.java b/src/test/java/edu/harvard/iq/dataverse/api/DataversesTest.java new file mode 100644 index 00000000000..10113110b66 --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/api/DataversesTest.java @@ -0,0 +1,237 @@ +package edu.harvard.iq.dataverse.api; + +import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.DataverseMetadataBlockFacet; +import edu.harvard.iq.dataverse.DataverseServiceBean; +import edu.harvard.iq.dataverse.EjbDataverseEngine; +import edu.harvard.iq.dataverse.GuestbookResponseServiceBean; +import edu.harvard.iq.dataverse.GuestbookServiceBean; +import edu.harvard.iq.dataverse.MetadataBlock; +import edu.harvard.iq.dataverse.MetadataBlockServiceBean; +import edu.harvard.iq.dataverse.api.datadeposit.SwordServiceBean; +import edu.harvard.iq.dataverse.api.dto.DataverseMetadataBlockFacetDTO; +import edu.harvard.iq.dataverse.api.imports.ImportServiceBean; +import edu.harvard.iq.dataverse.authorization.groups.impl.explicit.ExplicitGroupServiceBean; +import edu.harvard.iq.dataverse.authorization.users.PrivateUrlUser; +import edu.harvard.iq.dataverse.engine.command.impl.ListMetadataBlockFacetsCommand; +import edu.harvard.iq.dataverse.engine.command.impl.UpdateMetadataBlockFacetRootCommand; +import edu.harvard.iq.dataverse.engine.command.impl.UpdateMetadataBlockFacetsCommand; +import edu.harvard.iq.dataverse.mocks.MocksFactory; +import edu.harvard.iq.dataverse.privateurl.PrivateUrlServiceBean; +import edu.harvard.iq.dataverse.settings.SettingsServiceBean; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.Response; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * + * @author adaybujeda + */ +@RunWith(MockitoJUnitRunner.class) +public class DataversesTest { + // From AbstractApiBean class + @Mock + private EjbDataverseEngine engineSvc; + @Mock + private MetadataBlockServiceBean metadataBlockSvc; + @Mock + private PrivateUrlServiceBean privateUrlSvc; + @Mock + private HttpServletRequest httpRequest; + + // From Dataverses class + @Mock + private ExplicitGroupServiceBean explicitGroupSvc; + @Mock + private ImportServiceBean importService; + @Mock + private SettingsServiceBean settingsService; + @Mock + private GuestbookResponseServiceBean guestbookResponseService; + @Mock + private GuestbookServiceBean guestbookService; + @Mock + private DataverseServiceBean dataverseService; + @Mock + private SwordServiceBean swordService; + + @InjectMocks + private Dataverses target; + + private Dataverse VALID_DATAVERSE; + + @Before + public void beforeEachTest() { + VALID_DATAVERSE = new Dataverse(); + VALID_DATAVERSE.setId(MocksFactory.nextId()); + VALID_DATAVERSE.setAlias(UUID.randomUUID().toString()); + VALID_DATAVERSE.setMetadataBlockFacetRoot(true); + + Mockito.lenient().when(dataverseService.findByAlias(VALID_DATAVERSE.getAlias())).thenReturn(VALID_DATAVERSE); + Mockito.lenient().when(httpRequest.getHeader("X-Dataverse-key")).thenReturn(UUID.randomUUID().toString()); + Mockito.lenient().when(privateUrlSvc.getPrivateUrlUserFromToken(Mockito.anyString())).thenReturn(new PrivateUrlUser(0)); + } + + @Test + public void listMetadataBlockFacets_should_return_404_when_dataverse_is_not_found() { + String dataverseAlias = UUID.randomUUID().toString(); + Mockito.when(dataverseService.findByAlias(dataverseAlias)).thenReturn(null); + Response result = target.listMetadataBlockFacets(dataverseAlias); + + MatcherAssert.assertThat(result.getStatus(), Matchers.is(404)); + Mockito.verifyNoMoreInteractions(engineSvc); + } + + @Test + public void listMetadataBlockFacets_should_return_the_list_of_metadataBlockFacetDTOs() throws Exception{ + MetadataBlock metadataBlock = Mockito.mock(MetadataBlock.class); + Mockito.when(metadataBlock.getName()).thenReturn("test_metadata_block_name"); + Mockito.when(metadataBlock.getLocaleDisplayFacet()).thenReturn("test_metadata_facet_name"); + DataverseMetadataBlockFacet dataverseMetadataBlockFacet = new DataverseMetadataBlockFacet(); + dataverseMetadataBlockFacet.setDataverse(VALID_DATAVERSE); + dataverseMetadataBlockFacet.setMetadataBlock(metadataBlock); + Mockito.when(engineSvc.submit(Mockito.any(ListMetadataBlockFacetsCommand.class))).thenReturn(Arrays.asList(dataverseMetadataBlockFacet)); + + Response response = target.listMetadataBlockFacets(VALID_DATAVERSE.getAlias()); + + MatcherAssert.assertThat(response.getStatus(), Matchers.is(200)); + MatcherAssert.assertThat(response.getEntity(), Matchers.notNullValue()); + DataverseMetadataBlockFacetDTO result = (DataverseMetadataBlockFacetDTO)response.getEntity(); + MatcherAssert.assertThat(result.getDataverseId(), Matchers.is(VALID_DATAVERSE.getId())); + MatcherAssert.assertThat(result.getDataverseAlias(), Matchers.is(VALID_DATAVERSE.getAlias())); + MatcherAssert.assertThat(result.isMetadataBlockFacetRoot(), Matchers.is(VALID_DATAVERSE.isMetadataBlockFacetRoot())); + MatcherAssert.assertThat(result.getMetadataBlocks().size(), Matchers.is(1)); + MatcherAssert.assertThat(result.getMetadataBlocks().get(0).getMetadataBlockName(), Matchers.is("test_metadata_block_name")); + MatcherAssert.assertThat(result.getMetadataBlocks().get(0).getMetadataBlockFacet(), Matchers.is("test_metadata_facet_name")); + + Mockito.verify(engineSvc).submit(Mockito.any(ListMetadataBlockFacetsCommand.class)); + } + + @Test + public void listMetadataBlockFacets_should_return_empty_list_when_metadata_block_facet_is_null() throws Exception{ + Mockito.when(engineSvc.submit(Mockito.any(ListMetadataBlockFacetsCommand.class))).thenReturn(null); + + Response response = target.listMetadataBlockFacets(VALID_DATAVERSE.getAlias()); + + MatcherAssert.assertThat(response.getStatus(), Matchers.is(200)); + DataverseMetadataBlockFacetDTO result = (DataverseMetadataBlockFacetDTO)response.getEntity(); + MatcherAssert.assertThat(result.getDataverseId(), Matchers.is(VALID_DATAVERSE.getId())); + MatcherAssert.assertThat(result.getDataverseAlias(), Matchers.is(VALID_DATAVERSE.getAlias())); + MatcherAssert.assertThat(result.isMetadataBlockFacetRoot(), Matchers.is(VALID_DATAVERSE.isMetadataBlockFacetRoot())); + MatcherAssert.assertThat(result.getMetadataBlocks(), Matchers.is(Collections.emptyList())); + + Mockito.verify(engineSvc).submit(Mockito.any(ListMetadataBlockFacetsCommand.class)); + } + + @Test + public void setMetadataBlockFacets_should_return_404_when_dataverse_is_not_found() { + String dataverseAlias = UUID.randomUUID().toString(); + Mockito.when(dataverseService.findByAlias(dataverseAlias)).thenReturn(null); + Response result = target.setMetadataBlockFacets(dataverseAlias, Collections.emptyList()); + + MatcherAssert.assertThat(result.getStatus(), Matchers.is(404)); + Mockito.verifyNoMoreInteractions(engineSvc); + } + + @Test + public void setMetadataBlockFacets_should_return_400_when_dataverse_has_metadata_facet_root_set_to_false() { + String dataverseAlias = UUID.randomUUID().toString(); + Dataverse dataverse = Mockito.mock(Dataverse.class); + Mockito.when(dataverse.isMetadataBlockFacetRoot()).thenReturn(false); + Mockito.when(dataverseService.findByAlias(dataverseAlias)).thenReturn(dataverse); + + Response result = target.setMetadataBlockFacets(dataverseAlias, Collections.emptyList()); + + MatcherAssert.assertThat(result.getStatus(), Matchers.is(400)); + Mockito.verifyNoMoreInteractions(engineSvc); + } + + @Test + public void setMetadataBlockFacets_should_return_400_when_invalid_metadata_block() { + Mockito.when(metadataBlockSvc.findByName("valid_block")).thenReturn(new MetadataBlock()); + Mockito.when(metadataBlockSvc.findByName("invalid_block")).thenReturn(null); + List metadataBlocks = Arrays.asList("valid_block", "invalid_block"); + Response result = target.setMetadataBlockFacets(VALID_DATAVERSE.getAlias(), metadataBlocks); + + MatcherAssert.assertThat(result.getStatus(), Matchers.is(400)); + Mockito.verifyNoMoreInteractions(engineSvc); + } + + @Test + public void setMetadataBlockFacets_should_return_200_when_update_is_successful() throws Exception { + MetadataBlock validBlock = new MetadataBlock(); + Mockito.when(metadataBlockSvc.findByName("valid_block")).thenReturn(validBlock); + List metadataBlocks = Arrays.asList("valid_block"); + Response result = target.setMetadataBlockFacets(VALID_DATAVERSE.getAlias(), metadataBlocks); + + MatcherAssert.assertThat(result.getStatus(), Matchers.is(200)); + ArgumentCaptor updateCommand = ArgumentCaptor.forClass(UpdateMetadataBlockFacetsCommand.class); + Mockito.verify(engineSvc).submit(updateCommand.capture()); + + MatcherAssert.assertThat(updateCommand.getValue().getEditedDataverse(), Matchers.is(VALID_DATAVERSE)); + MatcherAssert.assertThat(updateCommand.getValue().getMetadataBlockFacets().size(), Matchers.is(1)); + MatcherAssert.assertThat(updateCommand.getValue().getMetadataBlockFacets().get(0).getDataverse(), Matchers.is(VALID_DATAVERSE)); + MatcherAssert.assertThat(updateCommand.getValue().getMetadataBlockFacets().get(0).getMetadataBlock(), Matchers.is(validBlock)); + } + + @Test + public void setMetadataBlockFacets_should_support_empty_metadatablock_list() throws Exception{ + Response result = target.setMetadataBlockFacets(VALID_DATAVERSE.getAlias(), Collections.emptyList()); + + MatcherAssert.assertThat(result.getStatus(), Matchers.is(200)); + Mockito.verify(engineSvc).submit(Mockito.any(UpdateMetadataBlockFacetsCommand.class)); + } + + @Test + public void updateMetadataBlockFacetsRoot_should_return_404_when_dataverse_is_not_found() { + String dataverseAlias = UUID.randomUUID().toString(); + Mockito.when(dataverseService.findByAlias(dataverseAlias)).thenReturn(null); + Response result = target.updateMetadataBlockFacetsRoot(dataverseAlias, "true"); + + MatcherAssert.assertThat(result.getStatus(), Matchers.is(404)); + Mockito.verifyNoMoreInteractions(engineSvc); + } + + @Test + public void updateMetadataBlockFacetsRoot_should_return_400_when_invalid_boolean() throws Exception{ + Response result = target.updateMetadataBlockFacetsRoot(VALID_DATAVERSE.getAlias(), "invalid"); + + MatcherAssert.assertThat(result.getStatus(), Matchers.is(400)); + Mockito.verifyNoMoreInteractions(engineSvc); + } + + @Test + public void updateMetadataBlockFacetsRoot_should_return_200_and_make_no_update_when_dataverse_is_found_and_facet_root_has_not_changed() { + // VALID_DATAVERSE.metadataBlockFacetRoot is true + Response result = target.updateMetadataBlockFacetsRoot(VALID_DATAVERSE.getAlias(), "true"); + + MatcherAssert.assertThat(result.getStatus(), Matchers.is(200)); + Mockito.verifyZeroInteractions(engineSvc); + } + + @Test + public void updateMetadataBlockFacetsRoot_should_return_200_and_execute_command_when_dataverse_is_found_and_facet_root_has_changed() throws Exception { + // VALID_DATAVERSE.metadataBlockFacetRoot is true + Response result = target.updateMetadataBlockFacetsRoot(VALID_DATAVERSE.getAlias(), "false"); + + MatcherAssert.assertThat(result.getStatus(), Matchers.is(200)); + ArgumentCaptor updateRootCommand = ArgumentCaptor.forClass(UpdateMetadataBlockFacetRootCommand.class); + Mockito.verify(engineSvc).submit(updateRootCommand.capture()); + + MatcherAssert.assertThat(updateRootCommand.getValue().getEditedDataverse(), Matchers.is(VALID_DATAVERSE)); + } +} \ No newline at end of file diff --git a/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/ListMetadataBlocksCommandTest.java b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/ListMetadataBlocksCommandTest.java new file mode 100644 index 00000000000..520c91f47ff --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/ListMetadataBlocksCommandTest.java @@ -0,0 +1,66 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + +import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.DataverseMetadataBlockFacet; +import edu.harvard.iq.dataverse.authorization.Permission; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.exception.CommandException; +import edu.harvard.iq.dataverse.mocks.MocksFactory; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.Arrays; +import java.util.List; + +/** + * + * @author adaybujeda + */ +public class ListMetadataBlocksCommandTest { + + private DataverseRequest dataverseRequest; + private Dataverse dataverse; + private DataverseMetadataBlockFacet metadataBlockFacet; + + @Before + public void beforeEachTest() { + dataverseRequest = Mockito.mock(DataverseRequest.class); + dataverse = Mockito.mock(Dataverse.class); + metadataBlockFacet = new DataverseMetadataBlockFacet(); + metadataBlockFacet.setId(MocksFactory.nextId()); + Mockito.when(dataverse.getMetadataBlockFacets()).thenReturn(Arrays.asList(metadataBlockFacet)); + } + + @Test + public void execute_should_return_dataverse_metadata_block_facets() throws CommandException { + ListMetadataBlockFacetsCommand target = new ListMetadataBlockFacetsCommand(dataverseRequest, dataverse); + + List result = target.execute(Mockito.mock(CommandContext.class)); + + MatcherAssert.assertThat(result.size(), Matchers.is(1)); + MatcherAssert.assertThat(result.get(0), Matchers.is(metadataBlockFacet)); + } + + + @Test + public void getRequiredPermissions_should_return_empty_for_all_when_dataverse_is_released() { + Mockito.when(dataverse.isReleased()).thenReturn(true); + ListMetadataBlockFacetsCommand target = new ListMetadataBlockFacetsCommand(dataverseRequest, dataverse); + + MatcherAssert.assertThat(target.getRequiredPermissions().get(""), Matchers.emptyCollectionOf(Permission.class)); + } + + @Test + public void getRequiredPermissions_should_return_ViewUnpublishedDataverse_for_all_when_dataverse_is_not_released() { + Mockito.when(dataverse.isReleased()).thenReturn(false); + ListMetadataBlockFacetsCommand target = new ListMetadataBlockFacetsCommand(dataverseRequest, dataverse); + + MatcherAssert.assertThat(target.getRequiredPermissions().get("").size(), Matchers.is(1)); + MatcherAssert.assertThat(target.getRequiredPermissions().get(""), Matchers.hasItems(Permission.ViewUnpublishedDataverse)); + } + +} \ No newline at end of file diff --git a/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateMetadataBlockFacetRootCommandTest.java b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateMetadataBlockFacetRootCommandTest.java new file mode 100644 index 00000000000..711e7881af5 --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateMetadataBlockFacetRootCommandTest.java @@ -0,0 +1,111 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + +import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.DataverseMetadataBlockFacet; +import edu.harvard.iq.dataverse.MetadataBlock; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.exception.CommandException; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * + * @author adaybujeda + */ +public class UpdateMetadataBlockFacetRootCommandTest { + + private DataverseRequest dataverseRequest; + private Dataverse dataverse; + + @Before + public void beforeEachTest() { + dataverseRequest = Mockito.mock(DataverseRequest.class); + dataverse = Mockito.mock(Dataverse.class); + } + + @Test + public void should_not_update_dataverse_when_root_value_does_not_change() throws CommandException { + boolean metadataBlockFacetRoot = true; + Mockito.when(dataverse.isMetadataBlockFacetRoot()).thenReturn(metadataBlockFacetRoot); + UpdateMetadataBlockFacetRootCommand target = new UpdateMetadataBlockFacetRootCommand(dataverseRequest, dataverse, metadataBlockFacetRoot); + + CommandContext context = Mockito.mock(CommandContext.class, Mockito.RETURNS_DEEP_STUBS); + target.execute(context); + + Mockito.verify(dataverse).isMetadataBlockFacetRoot(); + Mockito.verifyNoMoreInteractions(dataverse); + Mockito.verifyZeroInteractions(context.dataverses()); + } + + @Test + public void should_set_metadataBlockFacetRoot_and_update_metadata_block_facets_to_empty_list_when_root_value_changes_to_false() throws CommandException { + Mockito.when(dataverse.isMetadataBlockFacetRoot()).thenReturn(true); + UpdateMetadataBlockFacetRootCommand target = new UpdateMetadataBlockFacetRootCommand(dataverseRequest, dataverse, false); + + CommandContext context = Mockito.mock(CommandContext.class, Mockito.RETURNS_DEEP_STUBS); + target.execute(context); + + Mockito.verify(dataverse).isMetadataBlockFacetRoot(); + Mockito.verify(dataverse).setMetadataBlockFacetRoot(false); + Mockito.verify(dataverse).setMetadataBlockFacets(Collections.emptyList()); + Mockito.verifyNoMoreInteractions(dataverse); + Mockito.verify(context.dataverses()).save(dataverse); + } + + @Test + public void should_set_metadataBlockFacetRoot_and_update_metadata_block_facets_to_parent_list_when_root_value_changes_to_true() throws CommandException { + Dataverse parentDataverse = Mockito.mock(Dataverse.class); + DataverseMetadataBlockFacet blockFacet1 = new DataverseMetadataBlockFacet(); + MetadataBlock block1 = Mockito.mock(MetadataBlock.class); + blockFacet1.setDataverse(parentDataverse); + blockFacet1.setMetadataBlock(block1); + DataverseMetadataBlockFacet blockFacet2 = new DataverseMetadataBlockFacet(); + MetadataBlock block2 = Mockito.mock(MetadataBlock.class); + blockFacet2.setDataverse(parentDataverse); + blockFacet2.setMetadataBlock(block2); + Mockito.when(dataverse.isMetadataBlockFacetRoot()).thenReturn(false); + Mockito.when(dataverse.getMetadataBlockFacets()).thenReturn(Arrays.asList(blockFacet1, blockFacet2)); + UpdateMetadataBlockFacetRootCommand target = new UpdateMetadataBlockFacetRootCommand(dataverseRequest, dataverse, true); + + CommandContext context = Mockito.mock(CommandContext.class, Mockito.RETURNS_DEEP_STUBS); + target.execute(context); + + Mockito.verify(dataverse).isMetadataBlockFacetRoot(); + Mockito.verify(dataverse).getMetadataBlockFacets(); + Mockito.verify(dataverse).setMetadataBlockFacetRoot(true); + + ArgumentCaptor> createdBlockFacets = ArgumentCaptor.forClass(List.class); + Mockito.verify(dataverse).setMetadataBlockFacets(createdBlockFacets.capture()); + MatcherAssert.assertThat(createdBlockFacets.getValue().size(), Matchers.is(2)); + MatcherAssert.assertThat(createdBlockFacets.getValue().get(0).getDataverse(), Matchers.is(dataverse)); + MatcherAssert.assertThat(createdBlockFacets.getValue().get(0).getMetadataBlock(), Matchers.is(block1)); + MatcherAssert.assertThat(createdBlockFacets.getValue().get(1).getDataverse(), Matchers.is(dataverse)); + MatcherAssert.assertThat(createdBlockFacets.getValue().get(1).getMetadataBlock(), Matchers.is(block2)); + Mockito.verifyNoMoreInteractions(dataverse); + Mockito.verify(context.dataverses()).save(dataverse); + } + + @Test + public void getEditedDataverse_should_return_set_dataverse() { + UpdateMetadataBlockFacetRootCommand target = new UpdateMetadataBlockFacetRootCommand(dataverseRequest, dataverse, true); + + MatcherAssert.assertThat(target.getEditedDataverse(), Matchers.is(dataverse)); + } + + @Test + public void getMetadataBlockFacetRoot_should_return_set_metadata_block_facet_root() { + UpdateMetadataBlockFacetRootCommand target = new UpdateMetadataBlockFacetRootCommand(dataverseRequest, dataverse, true); + + MatcherAssert.assertThat(target.getMetadataBlockFacetRoot(), Matchers.is(true)); + } + +} \ No newline at end of file diff --git a/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateMetadataBlockFacetsCommandTest.java b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateMetadataBlockFacetsCommandTest.java new file mode 100644 index 00000000000..2d64de80f3d --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateMetadataBlockFacetsCommandTest.java @@ -0,0 +1,78 @@ +package edu.harvard.iq.dataverse.engine.command.impl; + +import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.DataverseMetadataBlockFacet; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.exception.CommandException; +import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; +import edu.harvard.iq.dataverse.mocks.MocksFactory; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * + * @author adaybujeda + */ +public class UpdateMetadataBlockFacetsCommandTest { + + private DataverseRequest dataverseRequest; + private Dataverse dataverse; + + @Before + public void beforeEachTest() { + dataverseRequest = Mockito.mock(DataverseRequest.class); + dataverse = Mockito.mock(Dataverse.class); + } + + @Test(expected = IllegalCommandException.class) + public void should_throw_IllegalCommandException_when_dataverse_is_not_metadata_facet_root() throws CommandException { + Mockito.when(dataverse.isMetadataBlockFacetRoot()).thenReturn(false); + + UpdateMetadataBlockFacetsCommand target = new UpdateMetadataBlockFacetsCommand(dataverseRequest, dataverse, Collections.emptyList()); + + CommandContext context = Mockito.mock(CommandContext.class, Mockito.RETURNS_DEEP_STUBS); + target.execute(context); + } + + @Test + public void should_update_facets() throws CommandException { + Mockito.when(dataverse.isMetadataBlockFacetRoot()).thenReturn(true); + DataverseMetadataBlockFacet metadataBlockFacet = new DataverseMetadataBlockFacet(); + metadataBlockFacet.setId(MocksFactory.nextId()); + List metadataBlockFacets = Arrays.asList(metadataBlockFacet); + + UpdateMetadataBlockFacetsCommand target = new UpdateMetadataBlockFacetsCommand(dataverseRequest, dataverse, metadataBlockFacets); + + CommandContext context = Mockito.mock(CommandContext.class, Mockito.RETURNS_DEEP_STUBS); + target.execute(context); + + Mockito.verify(dataverse).setMetadataBlockFacets(metadataBlockFacets); + Mockito.verify(context.dataverses()).save(dataverse); + } + + @Test + public void getEditedDataverse_should_return_set_dataverse() { + UpdateMetadataBlockFacetsCommand target = new UpdateMetadataBlockFacetsCommand(dataverseRequest, dataverse, Collections.emptyList()); + + MatcherAssert.assertThat(target.getEditedDataverse(), Matchers.is(dataverse)); + } + + @Test + public void getMetadataBlockFacets_should_return_set_metadata_block_facets() { + DataverseMetadataBlockFacet metadataBlockFacet = new DataverseMetadataBlockFacet(); + metadataBlockFacet.setId(MocksFactory.nextId()); + List metadataBlockFacets = Arrays.asList(metadataBlockFacet); + UpdateMetadataBlockFacetsCommand target = new UpdateMetadataBlockFacetsCommand(dataverseRequest, dataverse, metadataBlockFacets); + + MatcherAssert.assertThat(target.getMetadataBlockFacets(), Matchers.is(metadataBlockFacets)); + } + +} \ No newline at end of file diff --git a/src/test/java/edu/harvard/iq/dataverse/search/SearchIncludeFragmentTest.java b/src/test/java/edu/harvard/iq/dataverse/search/SearchIncludeFragmentTest.java new file mode 100644 index 00000000000..f94da336ca3 --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/search/SearchIncludeFragmentTest.java @@ -0,0 +1,126 @@ +package edu.harvard.iq.dataverse.search; + +import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.DataverseMetadataBlockFacet; +import edu.harvard.iq.dataverse.MetadataBlock; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public class SearchIncludeFragmentTest { + + + @Test + public void getFriendlyNamesFromFilterQuery_should_return_null_when_null_or_empty_filter_query() { + SearchIncludeFragment target = new SearchIncludeFragment(); + + MatcherAssert.assertThat(target.getFriendlyNamesFromFilterQuery(null), Matchers.nullValue()); + MatcherAssert.assertThat(target.getFriendlyNamesFromFilterQuery(""), Matchers.nullValue()); + } + + @Test + public void getFriendlyNamesFromFilterQuery_should_return_null_when_filter_query_does_not_have_key_value_pair_separated_by_colon() { + SearchIncludeFragment target = new SearchIncludeFragment(); + + MatcherAssert.assertThat(target.getFriendlyNamesFromFilterQuery("key_value_no_colon"), Matchers.nullValue()); + } + + @Test + public void getFriendlyNamesFromFilterQuery_key_should_return_key_when_filter_query_key_does_not_match_any_friendly_names() { + SearchIncludeFragment target = new SearchIncludeFragment(); + + List result = target.getFriendlyNamesFromFilterQuery("key:value"); + MatcherAssert.assertThat(result.get(0), Matchers.is("key")); + } + + @Test + public void getFriendlyNamesFromFilterQuery_key_should_return_friendly_name_when_filter_query_key_does_match_friendly_name() { + SearchIncludeFragment target = new SearchIncludeFragment(); + target.datasetfieldFriendlyNamesBySolrField = Map.of("key", "KeyFriendlyName"); + + List result = target.getFriendlyNamesFromFilterQuery("key:value"); + MatcherAssert.assertThat(result.get(0), Matchers.is("KeyFriendlyName")); + } + + @Test + public void getFriendlyNamesFromFilterQuery_key_should_return_static_friendly_name_when_filter_query_key_does_not_match_friendly_name_but_matches_static_names() { + SearchIncludeFragment target = new SearchIncludeFragment(); + target.staticSolrFieldFriendlyNamesBySolrField = Map.of("key", "staticKeyFriendlyName"); + + List result = target.getFriendlyNamesFromFilterQuery("key:value"); + MatcherAssert.assertThat(result.get(0), Matchers.is("staticKeyFriendlyName")); + } + + @Test + public void getFriendlyNamesFromFilterQuery_value_should_return_metadata_block_facet_label_when_key_is_metadata_types_and_value_matches_metadata_block_name() { + SearchIncludeFragment target = new SearchIncludeFragment(); + Dataverse dataverse = Mockito.mock(Dataverse.class); + MetadataBlock block = Mockito.mock(MetadataBlock.class); + Mockito.when(block.getName()).thenReturn("metadata_block_name"); + Mockito.when(block.getLocaleDisplayFacet()).thenReturn("display_facet"); + DataverseMetadataBlockFacet blockFacet = new DataverseMetadataBlockFacet(); + blockFacet.setMetadataBlock(block); + Mockito.when(dataverse.getMetadataBlockFacets()).thenReturn(Arrays.asList(blockFacet)); + target.setDataverse(dataverse); + + List result = target.getFriendlyNamesFromFilterQuery(String.format("%s:\"metadata_block_name\"", SearchFields.METADATA_TYPES)); + MatcherAssert.assertThat(result.get(1), Matchers.is("display_facet")); + + Mockito.verify(dataverse, Mockito.times(2)).getMetadataBlockFacets(); + Mockito.verify(block).getName(); + Mockito.verify(block).getLocaleDisplayFacet(); + } + + @Test + public void getFriendlyNamesFromFilterQuery_value_should_return_value_when_key_is_metadata_types_and_value_does_not_matches_metadata_block_name() { + SearchIncludeFragment target = new SearchIncludeFragment(); + Dataverse dataverse = Mockito.mock(Dataverse.class); + MetadataBlock block = Mockito.mock(MetadataBlock.class); + Mockito.when(block.getName()).thenReturn("metadata_block_name"); + Mockito.when(block.getLocaleDisplayFacet()).thenReturn("display_facet"); + DataverseMetadataBlockFacet blockFacet = new DataverseMetadataBlockFacet(); + blockFacet.setMetadataBlock(block); + Mockito.when(dataverse.getMetadataBlockFacets()).thenReturn(Arrays.asList(blockFacet)); + target.setDataverse(dataverse); + + List result = target.getFriendlyNamesFromFilterQuery(String.format("%s:\"no_match_block_name\"", SearchFields.METADATA_TYPES)); + MatcherAssert.assertThat(result.get(1), Matchers.is("no_match_block_name")); + + Mockito.verify(dataverse, Mockito.times(2)).getMetadataBlockFacets(); + Mockito.verify(block).getName(); + } + + @Test + public void getFriendlyNamesFromFilterQuery_value_should_return_value_when_key_is_metadata_types_and_dataverse_is_null() { + SearchIncludeFragment target = new SearchIncludeFragment(); + + List result = target.getFriendlyNamesFromFilterQuery(String.format("%s:\"no_dataverse\"", SearchFields.METADATA_TYPES)); + MatcherAssert.assertThat(result.get(1), Matchers.is("no_dataverse")); + } + + @Test + public void getFriendlyNamesFromFilterQuery_value_should_return_value_when_key_is_metadata_types_and_metadata_blocks_are_null() { + SearchIncludeFragment target = new SearchIncludeFragment(); + Dataverse dataverse = Mockito.mock(Dataverse.class); + Mockito.when(dataverse.getMetadataBlockFacets()).thenReturn(null); + target.setDataverse(dataverse); + + List result = target.getFriendlyNamesFromFilterQuery(String.format("%s:\"no_metadata_blocks\"", SearchFields.METADATA_TYPES)); + MatcherAssert.assertThat(result.get(1), Matchers.is("no_metadata_blocks")); + + Mockito.verify(dataverse).getMetadataBlockFacets(); + } + + @Test + public void getFriendlyNamesFromFilterQuery_value_should_remove_quotes_from_beginning_and_end() { + SearchIncludeFragment target = new SearchIncludeFragment(); + + List result = target.getFriendlyNamesFromFilterQuery("key:\"value_\"_with_quotes\""); + MatcherAssert.assertThat(result.get(1), Matchers.is("value_\"_with_quotes")); + } +} \ No newline at end of file diff --git a/src/test/resources/propertyFiles/metadataBlockTest.properties b/src/test/resources/propertyFiles/metadataBlockTest.properties new file mode 100644 index 00000000000..25ec317c14f --- /dev/null +++ b/src/test/resources/propertyFiles/metadataBlockTest.properties @@ -0,0 +1,2 @@ +metadatablock.displayName=property_value_for_displayName +metadatablock.displayFacet=property_value_for_displayFacet \ No newline at end of file