diff --git a/doc/release-notes/11414-add-dvobject-type-to-featured-items.md b/doc/release-notes/11414-add-dvobject-type-to-featured-items.md index 4abd52697d0..162c83264ef 100644 --- a/doc/release-notes/11414-add-dvobject-type-to-featured-items.md +++ b/doc/release-notes/11414-add-dvobject-type-to-featured-items.md @@ -3,5 +3,3 @@ Dataverse Featured Items can now be linked to Dataverses, Datasets, or Datafiles. Pre-existing featured items as well as new items without dvObjects will be defaulted to type=custom. - -Featured Items with dvObjects will be filtered out of lists if the dvObject should not be viewed (i.e. datafiles that are restricted or datasets that are deaccessioned) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 51a6dae2bb4..c3299513c54 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -1218,9 +1218,9 @@ The ``file`` parameter must be specified for each image we want to attach to fea The ``id`` parameter must be ``0`` for new items or set to the item's identifier for updates. The ``fileName`` parameter should be empty to exclude an image or match the name of a file sent in a ``file`` parameter to set a new image. ``keepFile`` must always be set to ``false``, unless it's an update to a featured item where we want to preserve the existing image, if one exists. -The ``type`` and ``dvObject`` parameters are optional. These allow you to link the featured item to a Dataverse, Dataset, or Datafile. -The ``dvObject`` can be passed as the id or the persistent identifier and the ``type`` must be passed as either "dataverse", "dataset", or "datafile", depending on the type of object. -If no ``dvObject`` is passed the ``type`` will default to "custom" designating no linked object. +The ``type`` and ``dvObjectIdentifier`` parameters are optional. These allow you to link the featured item to a Dataverse, Dataset, or Datafile. +The ``dvObjectIdentifier`` can be passed as the alias, id, or the persistent identifier and the ``type`` must be passed as either "dataverse", "dataset", or "datafile", depending on the type of object. +If no ``dvObjectIdentifier`` is passed the ``type`` will default to "custom" designating no linked object. Note that any existing featured item not included in the call with its associated identifier and corresponding properties will be removed from the collection. @@ -1250,7 +1250,7 @@ The following example creates two featured items, with an image and a dataset as -F "keepFile=false" -F "keepFile=false" \ -F "file=@$SECOND_ITEM_IMAGE_FILENAME" \ -F "type=" -F "type=@$SECOND_ITEM_TYPE" \ - -F "dvObject=" -F "dvObject=@$SECOND_ITEM_DVOBJECT" \ + -F "dvObjectIdentifier=" -F "dvObjectIdentifier=@$SECOND_ITEM_DVOBJECT" \ "$SERVER_URL/api/dataverses/$ID/featuredItems" @@ -1267,7 +1267,7 @@ The fully expanded example above (without environment variables) looks like this -F "keepFile=false" -F "keepFile=false" \ -F "file=@image.png" \ -F "type=" -F "type=dataset" \ - -F "dvObject=" -F "dvObject=doi:ZZ7/MOSEISLEYDB94" \ + -F "dvObjectIdentifier=" -F "dvObjectIdentifier=doi:ZZ7/MOSEISLEYDB94" \ "https://demo.dataverse.org/api/dataverses/root/featuredItems" The following example creates one featured item and updates a second one, keeping the existing image it may have had but removes the dataset link and defaults the type to "custom": diff --git a/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java b/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java index 92455378209..018657bff4d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java @@ -590,7 +590,14 @@ protected DvObject findDvo(@NotNull final String id) throws WrappedResponse { protected DvObject findDvoByIdAndFeaturedItemTypeOrDie(@NotNull final String dvIdtf, String type) throws WrappedResponse { try { DataverseFeaturedItem.TYPES dvType = DataverseFeaturedItem.getDvType(type); - DvObject dvObject = isNumeric(dvIdtf) ? findDvo(Long.valueOf(dvIdtf)) : null; + DvObject dvObject = null; + if (isNumeric(dvIdtf)) { + try { + dvObject = findDvo(Long.valueOf(dvIdtf)); + } catch (Exception e) { + throw new WrappedResponse(error(Response.Status.BAD_REQUEST,BundleUtil.getStringFromBundle("find.dvo.error.dvObjectNotFound", Arrays.asList(dvIdtf)))); + } + } if (dvObject == null) { List types = new ArrayList<>(); types.addAll(List.of(DataverseFeaturedItem.TYPES.values())); diff --git a/src/main/java/edu/harvard/iq/dataverse/api/DataverseFeaturedItems.java b/src/main/java/edu/harvard/iq/dataverse/api/DataverseFeaturedItems.java index f45e9641e6b..30c3146fbfb 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/DataverseFeaturedItems.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/DataverseFeaturedItems.java @@ -53,7 +53,7 @@ public Response updateFeaturedItem(@Context ContainerRequestContext crc, @PathParam("id") Long id, @FormDataParam("content") String content, @FormDataParam("type") String type, - @FormDataParam("dvObject") String dvObjectIdtf, + @FormDataParam("dvObjectIdentifier") String dvObjectIdtf, @FormDataParam("displayOrder") int displayOrder, @FormDataParam("keepFile") boolean keepFile, @FormDataParam("file") InputStream imageFileInputStream, 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 dcab1519d77..b1d56b6b8a9 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -1793,7 +1793,7 @@ public Response getUserPermissionsOnDataverse(@Context ContainerRequestContext c public Response createFeaturedItem(@Context ContainerRequestContext crc, @PathParam("identifier") String dvIdtf, @FormDataParam("type") String type, - @FormDataParam("dvObject") String dvObjectIdtf, + @FormDataParam("dvObjectIdentifier") String dvObjectIdtf, @FormDataParam("content") String content, @FormDataParam("displayOrder") int displayOrder, @FormDataParam("file") InputStream imageFileInputStream, @@ -1844,7 +1844,7 @@ public Response updateFeaturedItems( @FormDataParam("id") List ids, @FormDataParam("content") List contents, @FormDataParam("type") List types, - @FormDataParam("dvObject") List dvObjectIdtf, + @FormDataParam("dvObjectIdentifier") List dvObjectIdtf, @FormDataParam("displayOrder") List displayOrders, @FormDataParam("keepFile") List keepFiles, @FormDataParam("fileName") List fileNames, diff --git a/src/main/java/edu/harvard/iq/dataverse/dataverse/featured/DataverseFeaturedItem.java b/src/main/java/edu/harvard/iq/dataverse/dataverse/featured/DataverseFeaturedItem.java index 416af7dc729..563db096c62 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dataverse/featured/DataverseFeaturedItem.java +++ b/src/main/java/edu/harvard/iq/dataverse/dataverse/featured/DataverseFeaturedItem.java @@ -11,6 +11,7 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Size; +import org.apache.commons.text.CaseUtils; import java.util.Arrays; import java.util.List; @@ -144,6 +145,17 @@ public static void validateTypeAndDvObject(String dvIdtf, DvObject dvObject, Dat (dvObject instanceof DataFile && dvType != DataverseFeaturedItem.TYPES.DATAFILE)) { throw new IllegalArgumentException(BundleUtil.getStringFromBundle("dataverse.update.featuredItems.error.typeAndDvObjectMismatch")); } + if (dvObject instanceof DataFile) { + DataFile df = (DataFile)dvObject; + if (df.isRestricted()) { + throw new IllegalArgumentException(BundleUtil.getStringFromBundle("dataverseFeaturedItems.errors.restricted")); + } + if (!df.isReleased()) { + throw new IllegalArgumentException(BundleUtil.getStringFromBundle("dataverseFeaturedItems.errors.notPublished", List.of("Dataset"))); + } + } else if (!dvObject.isReleased()) { + throw new IllegalArgumentException(BundleUtil.getStringFromBundle("dataverseFeaturedItems.errors.notPublished", List.of(CaseUtils.toCamelCase(dvType.name(), true)))); + } } else { if (dvType != DataverseFeaturedItem.TYPES.CUSTOM) { throw new IllegalArgumentException(BundleUtil.getStringFromBundle("find.dvo.error.dvObjectNotFound", List.of(dvIdtf == null ? "unknown" : dvIdtf))); diff --git a/src/main/java/edu/harvard/iq/dataverse/dataverse/featured/DataverseFeaturedItemServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/dataverse/featured/DataverseFeaturedItemServiceBean.java index cf8e30bec7e..2598260aa80 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dataverse/featured/DataverseFeaturedItemServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/dataverse/featured/DataverseFeaturedItemServiceBean.java @@ -1,10 +1,6 @@ package edu.harvard.iq.dataverse.dataverse.featured; -import com.google.common.collect.Lists; import edu.harvard.iq.dataverse.*; -import edu.harvard.iq.dataverse.authorization.Permission; -import edu.harvard.iq.dataverse.authorization.users.User; -import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.settings.JvmSettings; import edu.harvard.iq.dataverse.util.BundleUtil; import edu.harvard.iq.dataverse.util.FileUtil; @@ -13,7 +9,6 @@ import jakarta.inject.Named; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import jakarta.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; @@ -22,12 +17,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.util.EnumSet; +import java.util.ArrayList; import java.util.List; +import java.util.logging.Logger; @Stateless @Named public class DataverseFeaturedItemServiceBean implements Serializable { + private static final Logger logger = Logger.getLogger(DataverseFeaturedItemServiceBean.class.getCanonicalName()); public static class InvalidImageFileException extends Exception { public InvalidImageFileException(String message) { @@ -70,6 +67,25 @@ public void deleteAllByDvObjectId(Long id) { .executeUpdate(); } + public void deleteInvalidatedFeaturedItemsByDataset(Dataset dataset) { + // Delete any Featured Items that contain Datafiles that were removed or restricted in the latest published version + List featuredItems = findAllByDataverseOrdered(dataset.getOwner()); + for (DataverseFeaturedItem featuredItem : featuredItems) { + if (featuredItem.getDvObject() != null && featuredItem.getType().equalsIgnoreCase(DataverseFeaturedItem.TYPES.DATAFILE.name())) { + DataFile df = (DataFile) featuredItem.getDvObject(); + List latestVersionFileIds = new ArrayList<>(); + dataset.getLatestVersion().getFileMetadatas().stream() + .map(FileMetadata::getId) + .forEachOrdered(latestVersionFileIds::add); + // If the datafile is restricted or part of this dataset but not in the latest version we need to delete the featured item + if (df.isRestricted() || (dataset.getFiles().contains(df) && !latestVersionFileIds.contains(df.getId()))) { + logger.fine("Deleting invalidated Featured Item for " + (df.isRestricted() ? "Restricted" : "Deleted") + "Datafile ID: " + df.getId()); + deleteAllByDvObjectId(df.getId()); + } + } + } + } + public List findAllByDataverseOrdered(Dataverse dataverse) { List items = em .createNamedQuery("DataverseFeaturedItem.findByDataverseOrderedByDisplayOrder", DataverseFeaturedItem.class) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/FinalizeDatasetPublicationCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/FinalizeDatasetPublicationCommand.java index fa8cfeb810a..9bfdd958189 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/FinalizeDatasetPublicationCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/FinalizeDatasetPublicationCommand.java @@ -246,6 +246,9 @@ public Dataset execute(CommandContext ctxt) throws CommandException { logger.info("Successfully published the dataset "+readyDataset.getGlobalId().asString()); readyDataset = ctxt.em().merge(readyDataset); + + // Delete any Featured Items that are invalidated by publishing this version + ctxt.dataverseFeaturedItems().deleteInvalidatedFeaturedItemsByDataset(readyDataset); return readyDataset; } diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index 9d3d1ceae20..fe1d96ce761 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -1493,13 +1493,33 @@ public static JsonArrayBuilder jsonDataverseFeaturedItems(ListA titlelink"; String sanitizedContent = "

A title

link"; updateFeatureItemResponse = UtilIT.updateDataverseFeaturedItem(featuredItemId, unsafeContent, 2, false, "src/test/resources/images/coffeeshop.png", apiToken); - verifyUpdatedFeaturedItem(updateFeatureItemResponse, sanitizedContent, "coffeeshop.png", 2,"custom", null); + verifyUpdatedFeaturedItem(updateFeatureItemResponse, sanitizedContent, "coffeeshop.png", 2,"custom", null, null); // Update featured item: set dataverse type updateFeatureItemResponse = UtilIT.updateDataverseFeaturedItem(featuredItemId, "updatedTitle2", 3, false, null, "dataverse", dataverseAlias, apiToken); - verifyUpdatedFeaturedItem(updateFeatureItemResponse, null, null, 3, "dataverse", dataverseId); + updateFeatureItemResponse.prettyPrint(); + verifyUpdatedFeaturedItem(updateFeatureItemResponse, null, null, 3, "dataverse", dataverseAlias, dataverseName); // Test mismatch between type and dvObject updateFeatureItemResponse = UtilIT.updateDataverseFeaturedItem(featuredItemId, "updatedTitle2", 3, false, null, "dataset", dataverseAlias, apiToken); @@ -131,7 +342,7 @@ public void testUpdateFeaturedItemUnicode() { * "????????.png" but once we fix the test, "καφενείο.png" should be * asserted. */ - verifyUpdatedFeaturedItem(createFeatureItemResponse, "test", "????????.png", 0,"custom", null); + verifyUpdatedFeaturedItem(createFeatureItemResponse, "test", "????????.png", 0,"custom", null, null); long featuredItemId = JsonPath.from(createFeatureItemResponse.body().asString()).getLong("data.id"); @@ -145,15 +356,15 @@ public void testUpdateFeaturedItemUnicode() { updateFeatureItemResponse.prettyPrint(); // TODO: Fix this REST Assured assertion too (see above). // The equivalent curl command: scripts/issues/11429/update-featured-item.sh - verifyUpdatedFeaturedItem(updateFeatureItemResponse, "updatedTitle1", "????????.png", 1,"custom", null); + verifyUpdatedFeaturedItem(updateFeatureItemResponse, "updatedTitle1", "????????.png", 1,"custom", null, null); // remove image updateFeatureItemResponse = UtilIT.updateDataverseFeaturedItem(featuredItemId, "updatedTitle1", 2, false, null, apiToken); - verifyUpdatedFeaturedItem(updateFeatureItemResponse, "updatedTitle1", null, 2,"custom", null); + verifyUpdatedFeaturedItem(updateFeatureItemResponse, "updatedTitle1", null, 2,"custom", null, null); // add non-unicode image updateFeatureItemResponse = UtilIT.updateDataverseFeaturedItem(featuredItemId, "updatedTitle1", 2, false, coffeeShopEnglish, apiToken); - verifyUpdatedFeaturedItem(updateFeatureItemResponse, "updatedTitle1", "coffeeshop.png", 2,"custom", null); + verifyUpdatedFeaturedItem(updateFeatureItemResponse, "updatedTitle1", "coffeeshop.png", 2,"custom", null, null); updateFeatureItemResponse = UtilIT.deleteDataverseFeaturedItem(featuredItemId, apiToken); updateFeatureItemResponse.then().assertThat().statusCode(OK.getStatusCode()); @@ -194,14 +405,15 @@ private Long createFeaturedItemAndGetId(String dataverseAlias, String apiToken, return createdFeaturedItem.getLong("data.id"); } - private void verifyUpdatedFeaturedItem(Response response, String expectedContent, String expectedImageFileName, int expectedDisplayOrder, String type, Integer dvObject) { + private void verifyUpdatedFeaturedItem(Response response, String expectedContent, String expectedImageFileName, int expectedDisplayOrder, String type, String dvObject, String dvObjectDisplayName) { response.prettyPrint(); response.then().assertThat() .body("data.content", equalTo(expectedContent)) .body("data.imageFileName", equalTo(expectedImageFileName)) .body("data.displayOrder", equalTo(expectedDisplayOrder)) .body("data.type", equalTo(type)) - .body("data.dvObject", equalTo(dvObject)) + .body("data.dvObjectIdentifier", equalTo(dvObject)) + .body("data.dvObjectDisplayName", equalTo(dvObjectDisplayName)) .statusCode(OK.getStatusCode()); } } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java index 1094935182f..2e7fc34bd0c 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java @@ -1680,7 +1680,12 @@ public void testCreateFeaturedItem() { String pathToFile1 = "src/main/webapp/resources/images/cc0.png"; Response uploadFileResponse = UtilIT.uploadFileViaNative(datasetId.toString(), pathToFile1, apiToken); uploadFileResponse.prettyPrint(); - Integer datafileId = UtilIT.getDataFileIdFromResponse(uploadFileResponse); + String datafileId = String.valueOf(UtilIT.getDataFileIdFromResponse(uploadFileResponse)); + assertTrue(UtilIT.sleepForLock(datasetId, "Ingest", apiToken, UtilIT.MAXIMUM_INGEST_LOCK_DURATION), "Failed test if Ingest Lock exceeds max duration"); + + // Publish Dataverse and Dataset with Datafile + UtilIT.publishDataverseViaNativeApi(dataverseAlias, apiToken).prettyPrint(); + UtilIT.publishDatasetViaNativeApi(datasetId, "major", apiToken).prettyPrint(); // Should not return any error when not passing a file @@ -1725,16 +1730,16 @@ public void testCreateFeaturedItem() { .statusCode(NOT_FOUND.getStatusCode()); // Testing new dvobject-type featured items - createFeatureItemResponse = UtilIT.createDataverseFeaturedItem(dataverseAlias, apiToken, "test dataset", 10, null, "dataset", datasetPersistentId); + createFeatureItemResponse = UtilIT.createDataverseFeaturedItem(dataverseAlias, apiToken, null, 10, null, "dataset", datasetPersistentId); createFeatureItemResponse.prettyPrint(); - createFeatureItemResponse = UtilIT.createDataverseFeaturedItem(dataverseAlias, apiToken, "test datafile", 11, null, "datafile", String.valueOf(datafileId)); + createFeatureItemResponse = UtilIT.createDataverseFeaturedItem(dataverseAlias, apiToken, null, 11, null, "datafile", datafileId); createFeatureItemResponse.prettyPrint(); Response listDataverseFeaturedItemsResponse = UtilIT.listDataverseFeaturedItems(dataverseAlias, apiToken); listDataverseFeaturedItemsResponse.prettyPrint(); listDataverseFeaturedItemsResponse.then().assertThat() - .body("data[2].dvObject", equalTo(datasetId)) + .body("data[2].dvObjectIdentifier", equalTo(datasetPersistentId)) .body("data[2].type", equalTo("dataset")) - .body("data[3].dvObject", equalTo(datafileId)) + .body("data[3].dvObjectIdentifier", equalTo(datafileId)) .body("data[3].type", equalTo("datafile")); } @@ -1798,8 +1803,11 @@ public void testUpdateFeaturedItems() { createDataverseResponse.then().assertThat().statusCode(CREATED.getStatusCode()); String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse); String baseUri = UtilIT.getRestAssuredBaseUri(); + UtilIT.publishDataverseViaNativeApi(dataverseAlias, apiToken).prettyPrint(); Response createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, apiToken); Integer datasetId = UtilIT.getDatasetIdFromResponse(createDatasetResponse); + String datasetPersistentId = UtilIT.getDatasetPersistentIdFromResponse(createDatasetResponse); + UtilIT.publishDatasetViaNativeApi(datasetId, "major", apiToken).prettyPrint(); // Create new items @@ -1863,7 +1871,7 @@ public void testUpdateFeaturedItems() { .body("data[2].imageFileUrl", equalTo(null)) .body("data[2].displayOrder", equalTo(2)) .body("data[2].type", equalTo("dataset")) - .body("data[2].dvObject", equalTo(datasetId)) + .body("data[2].dvObjectIdentifier", equalTo(datasetPersistentId)) .statusCode(OK.getStatusCode()); Long firstItemIdAfterUpdate = JsonPath.from(updateDataverseFeaturedItemsResponse.body().asString()).getLong("data[1].id"); @@ -1952,6 +1960,7 @@ public void testDeleteFeaturedItemWithDvObject() { createDataverseResponse.then().assertThat().statusCode(CREATED.getStatusCode()); String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse); Response createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, apiToken); + String datasetPersistentId = UtilIT.getDatasetPersistentIdFromResponse(createDatasetResponse); Integer datasetId = UtilIT.getDatasetIdFromResponse(createDatasetResponse); // Upload a file @@ -1960,6 +1969,11 @@ public void testDeleteFeaturedItemWithDvObject() { uploadFileResponse.prettyPrint(); Integer datafileId = UtilIT.getDataFileIdFromResponse(uploadFileResponse); assertTrue(UtilIT.sleepForLock(datasetId.longValue(), "Ingest", apiToken, UtilIT.MAXIMUM_INGEST_LOCK_DURATION), "Failed test if Ingest Lock exceeds max duration " + pathToFile1); + + // Publish the Dataverse and Dataset + UtilIT.publishDataverseViaNativeApi(dataverseAlias, apiToken).prettyPrint(); + UtilIT.publishDatasetViaNativeApi(datasetPersistentId, "major", apiToken).prettyPrint(); + Response createDataverseFeaturedItemResponse = UtilIT.createDataverseFeaturedItem(dataverseAlias, apiToken, null, 0, pathToFile1, "datafile", String.valueOf(datafileId)); createDataverseFeaturedItemResponse.prettyPrint(); int featuredItemId = UtilIT.getDatasetIdFromResponse(createDataverseFeaturedItemResponse); @@ -1970,15 +1984,23 @@ public void testDeleteFeaturedItemWithDvObject() { .body("data.size()", equalTo(1)) .assertThat().statusCode(OK.getStatusCode()); - // delete file (cascade deletes the featured item) + // delete the file creates a new DRAFT version of the Dataset but the File still exists in the latest published version UtilIT.deleteFile(datafileId,apiToken).prettyPrint(); listFeaturedItemsResponse = UtilIT.listDataverseFeaturedItems(dataverseAlias, apiToken); listFeaturedItemsResponse.prettyPrint(); + listFeaturedItemsResponse.then() + .body("data.size()", equalTo(1)) + .assertThat().statusCode(OK.getStatusCode()); + + // publish the draft version with the file deleted will cause the featured item to be deleted + UtilIT.publishDatasetViaNativeApi(datasetPersistentId, "major", apiToken).prettyPrint(); + listFeaturedItemsResponse = UtilIT.listDataverseFeaturedItems(dataverseAlias, apiToken); + listFeaturedItemsResponse.prettyPrint(); listFeaturedItemsResponse.then() .body("data.size()", equalTo(0)) .assertThat().statusCode(OK.getStatusCode()); - // try to delete the featured item and if it's already deleted (by deleting the file) it should be NOT FOUND + // try to delete the featured item if it's already deleted should be NOT FOUND Response deleteItemResponse = UtilIT.deleteDataverseFeaturedItem(featuredItemId, apiToken); deleteItemResponse.prettyPrint(); deleteItemResponse.then() diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index 979a305af7a..3e54a57dafc 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -4653,7 +4653,7 @@ static Response createDataverseFeaturedItem(String dataverseAlias, requestSpecification.multiPart("type", type); } if (dvObjectId != null) { - requestSpecification.multiPart("dvObject", dvObjectId); + requestSpecification.multiPart("dvObjectIdentifier", dvObjectId); } return requestSpecification @@ -4695,7 +4695,7 @@ static Response updateDataverseFeaturedItem(long featuredItemId, requestSpecification.multiPart("type", type); } if (dvObjectId != null) { - requestSpecification.multiPart("dvObject", dvObjectId); + requestSpecification.multiPart("dvObjectIdentifier", dvObjectId); } if (pathToFile != null) { @@ -4732,7 +4732,7 @@ static Response updateDataverseFeaturedItems( List keepFiles, List pathsToFiles, List dvTypes, - List dvObjects, + List dvObjectIdentifiers, String apiToken) { RequestSpecification requestSpec = given() @@ -4747,8 +4747,8 @@ static Response updateDataverseFeaturedItems( if (dvTypes != null && !dvTypes.isEmpty()) { requestSpec.multiPart("type", dvTypes.get(i)); } - if (dvObjects != null && !dvObjects.isEmpty()) { - requestSpec.multiPart("dvObject", dvObjects.get(i)); + if (dvObjectIdentifiers != null && !dvObjectIdentifiers.isEmpty()) { + requestSpec.multiPart("dvObjectIdentifier", dvObjectIdentifiers.get(i)); } String pathToFile = pathsToFiles != null ? pathsToFiles.get(i) : null; diff --git a/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDataverseFeaturedItemCommandTest.java b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDataverseFeaturedItemCommandTest.java index 9d79251d4a5..0171997e69f 100644 --- a/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDataverseFeaturedItemCommandTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDataverseFeaturedItemCommandTest.java @@ -19,7 +19,9 @@ import java.io.IOException; import java.io.InputStream; +import java.sql.Timestamp; import java.text.MessageFormat; +import java.time.Instant; import java.util.List; import static edu.harvard.iq.dataverse.mocks.MocksFactory.makeRequest; @@ -45,6 +47,7 @@ void setUp() throws AbstractApiBean.WrappedResponse { testDataverse = new Dataverse(); testDataverse.setId(123L); + testDataverse.setPublicationDate(Timestamp.from(Instant.now())); testNewDataverseFeaturedItemDTO = new NewDataverseFeaturedItemDTO(); testNewDataverseFeaturedItemDTO.setImageFileName("test.png"); diff --git a/src/test/java/edu/harvard/iq/dataverse/featured/DataverseFeaturedItemTest.java b/src/test/java/edu/harvard/iq/dataverse/featured/DataverseFeaturedItemTest.java index 6f58a0a569f..f20a80eadbf 100644 --- a/src/test/java/edu/harvard/iq/dataverse/featured/DataverseFeaturedItemTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/featured/DataverseFeaturedItemTest.java @@ -7,6 +7,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.sql.Timestamp; +import java.time.Instant; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -28,11 +30,13 @@ public void setUp() { @Test public void test_validTypeAndDvObject() { // set a Dataset + ds.setPublicationDate(Timestamp.from(Instant.now())); dfi.setDvObject("Dataset", ds); assertEquals("dataset", dfi.getType()); assertEquals(ds, dfi.getDvObject()); // update with Datafile + df.setPublicationDate(Timestamp.from(Instant.now())); dfi.setDvObject("Datafile", df); assertEquals("datafile", dfi.getType()); assertEquals(df, dfi.getDvObject()); diff --git a/src/test/java/edu/harvard/iq/dataverse/util/json/JsonPrinterTest.java b/src/test/java/edu/harvard/iq/dataverse/util/json/JsonPrinterTest.java index 9d37a554820..df7045327fd 100644 --- a/src/test/java/edu/harvard/iq/dataverse/util/json/JsonPrinterTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/util/json/JsonPrinterTest.java @@ -5,11 +5,15 @@ import edu.harvard.iq.dataverse.authorization.DataverseRole; import edu.harvard.iq.dataverse.authorization.RoleAssignee; import edu.harvard.iq.dataverse.authorization.users.PrivateUrlUser; +import edu.harvard.iq.dataverse.dataverse.featured.DataverseFeaturedItem; import edu.harvard.iq.dataverse.mocks.MockDatasetFieldSvc; +import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider; import edu.harvard.iq.dataverse.privateurl.PrivateUrl; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.UserNotification.Type; +import java.sql.Timestamp; +import java.time.Instant; import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; @@ -405,4 +409,119 @@ public void testMetadataBlockAnonymized() { assertEquals("primitive", actualAuthorJsonObject.getString("typeClass")); assertFalse(actualAuthorJsonObject.getBoolean("multiple")); } + + @Test + public void testDataverseFeaturedItemDataverseTest() { + Dataverse dataverse = createDataverse(42); + Dataverse dvObject = createDataverse(1); + + DataverseFeaturedItem fi = new DataverseFeaturedItem(); + fi.setDataverse(dataverse); + fi.setContent(null); + fi.setDisplayOrder(0); + fi.setImageFileName("testfile"); + + fi.setDvObject("dataverse", dvObject); + JsonObject jsonObject = JsonPrinter.json(fi).build(); + assertNotNull(jsonObject); + + System.out.println("json: " + JsonUtil.prettyPrint(jsonObject.toString())); + assertEquals(fi.getType(), jsonObject.getString("type")); + assertEquals(dvObject.getAlias(), jsonObject.getString("dvObjectIdentifier")); + assertEquals(dvObject.getName(), jsonObject.getString("dvObjectDisplayName")); + } + @Test + public void testDataverseFeaturedItemDatasetTest() { + Dataverse dataverse = createDataverse(42); + Dataset dvObject = createDataset(1); + + DataverseFeaturedItem fi = new DataverseFeaturedItem(); + fi.setDataverse(dataverse); + fi.setContent(null); + fi.setDisplayOrder(0); + fi.setImageFileName("testfile"); + + fi.setDvObject("dataset", dvObject); + JsonObject jsonObject = JsonPrinter.json(fi).build(); + assertNotNull(jsonObject); + + System.out.println("json: " + JsonUtil.prettyPrint(jsonObject.toString())); + assertEquals(fi.getType(), jsonObject.getString("type")); + assertEquals(dvObject.getGlobalId().asString(), jsonObject.getString("dvObjectIdentifier")); + assertEquals(dvObject.getDisplayName(), jsonObject.getString("dvObjectDisplayName")); + } + + @Test + public void testDataverseFeaturedItemDatafileTest() { + Dataverse dataverse = createDataverse(42); + DataFile dvObject = createDatafile(1L); + dvObject.setPublicationDate(Timestamp.from(Instant.now())); + + DataverseFeaturedItem fi = new DataverseFeaturedItem(); + fi.setDataverse(dataverse); + fi.setContent(null); + fi.setDisplayOrder(0); + fi.setImageFileName("testfile"); + + fi.setDvObject("datafile", dvObject); + JsonObject jsonObject = JsonPrinter.json(fi).build(); + assertNotNull(jsonObject); + + System.out.println("json: " + JsonUtil.prettyPrint(jsonObject.toString())); + assertEquals(fi.getType(), jsonObject.getString("type")); + assertEquals(dvObject.getId().toString(), jsonObject.getString("dvObjectIdentifier")); + assertEquals(dvObject.getDisplayName(), jsonObject.getString("dvObjectDisplayName")); + + assertNotNull(jsonObject); + } + + private Dataverse createDataverse(long id) { + Dataverse dataverse = new Dataverse(); + dataverse.setId(id); + dataverse.setAlias("dv" + id); + dataverse.setName("Dataverse " + id); + dataverse.setAffiliation(id + " Inc."); + dataverse.setDescription("Description for Dataverse " + id + "."); + dataverse.setPublicationDate(Timestamp.from(Instant.now())); + return dataverse; + } + private Dataset createDataset(long id) { + Dataset dataset = new Dataset(); + DatasetVersion dsVersion = new DatasetVersion(); + dsVersion.setDataset(dataset); + dsVersion.setVersion(1L); + List dsFields = new ArrayList<>(); + DatasetField titleField = new DatasetField(); + DatasetFieldType dsft = new DatasetFieldType(); + DatasetFieldValue dsfv = new DatasetFieldValue(); + dsfv.setValue("Dataset Title " + id); + dsfv.setDatasetField(titleField); + dsft.setName(DatasetFieldConstant.title); + dsft.setFieldType(FieldType.TEXT); + titleField.setDatasetFieldType(dsft); + titleField.setDatasetFieldValues(List.of(dsfv)); + dsFields.add(titleField); + dsVersion.setDatasetFields(dsFields); + dsVersion.setVersionState(DatasetVersion.VersionState.RELEASED); + dataset.setId(id); + + dataset.setVersions(List.of(dsVersion)); + dataset.setPublicationDate(Timestamp.from(Instant.now())); + dataset.setGlobalId(new GlobalId(AbstractDOIProvider.DOI_PROTOCOL,"10.5072","FK2/BYM3IW", "/", AbstractDOIProvider.DOI_RESOLVER_URL, null)); + + return dataset; + } + private DataFile createDatafile(long id) { + DataFile datafile = new DataFile(); + datafile.setId(1L); + datafile.setRestricted(false); + + FileMetadata fm = new FileMetadata(); + fm.setLabel("xyz.txt"); + fm.setDataFile(datafile); + + datafile.setFileMetadatas(List.of(fm)); + + return datafile; + } }