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 ea7b41b9ca9..d4bbb50b971 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -1788,50 +1788,61 @@ public Response updateFeaturedItems( @FormDataParam("content") List contents, @FormDataParam("displayOrder") List displayOrders, @FormDataParam("keepFile") List keepFiles, + @FormDataParam("fileName") List fileNames, @FormDataParam("file") List files) { try { - if (ids == null || contents == null || displayOrders == null || keepFiles == null || files == null) { - throw new WrappedResponse(error(Response.Status.BAD_REQUEST, BundleUtil.getStringFromBundle("dataverse.update.featuredItems.error.missingInputParams"))); + if (ids == null || contents == null || displayOrders == null || keepFiles == null || fileNames == null) { + throw new WrappedResponse(error(Response.Status.BAD_REQUEST, + BundleUtil.getStringFromBundle("dataverse.update.featuredItems.error.missingInputParams"))); } int size = ids.size(); - if (contents.size() != size || displayOrders.size() != size || keepFiles.size() != size || files.size() != size) { - throw new WrappedResponse(error(Response.Status.BAD_REQUEST, BundleUtil.getStringFromBundle("dataverse.update.featuredItems.error.inputListsSizeMismatch"))); + if (contents.size() != size || displayOrders.size() != size || keepFiles.size() != size || fileNames.size() != size) { + throw new WrappedResponse(error(Response.Status.BAD_REQUEST, + BundleUtil.getStringFromBundle("dataverse.update.featuredItems.error.inputListsSizeMismatch"))); } Dataverse dataverse = findDataverseOrDie(dvIdtf); - List newDataverseFeaturedItemDTOs = new ArrayList<>(); - Map dataverseFeaturedItemsToUpdate = new HashMap<>(); + List newItems = new ArrayList<>(); + Map itemsToUpdate = new HashMap<>(); for (int i = 0; i < contents.size(); i++) { - Long id = ids.get(i); - String content = contents.get(i); - Integer displayOrder = displayOrders.get(i); - boolean keepFile = keepFiles.get(i); - FormDataBodyPart fileBodyPart = files.get(i); - - InputStream fileInputStream = fileBodyPart.getValueAs(InputStream.class); - FormDataContentDisposition contentDispositionHeader = fileBodyPart.getFormDataContentDisposition(); - - if (id == 0) { - NewDataverseFeaturedItemDTO newDTO = NewDataverseFeaturedItemDTO.fromFormData(content, displayOrder, fileInputStream, contentDispositionHeader); - newDataverseFeaturedItemDTOs.add(newDTO); + String fileName = fileNames.get(i); + InputStream fileInputStream = null; + FormDataContentDisposition contentDisposition = null; + + if (files != null) { + Optional matchingFile = files.stream() + .filter(file -> file.getFormDataContentDisposition().getFileName().equals(fileName)) + .findFirst(); + + if (matchingFile.isPresent()) { + fileInputStream = matchingFile.get().getValueAs(InputStream.class); + contentDisposition = matchingFile.get().getFormDataContentDisposition(); + } + } + + if (ids.get(i) == 0) { + newItems.add(NewDataverseFeaturedItemDTO.fromFormData( + contents.get(i), displayOrders.get(i), fileInputStream, contentDisposition)); } else { - DataverseFeaturedItem existingItem = dataverseFeaturedItemServiceBean.findById(id); + DataverseFeaturedItem existingItem = dataverseFeaturedItemServiceBean.findById(ids.get(i)); if (existingItem == null) { - throw new WrappedResponse(error(Response.Status.NOT_FOUND, MessageFormat.format(BundleUtil.getStringFromBundle("dataverseFeaturedItems.errors.notFound"), id))); + throw new WrappedResponse(error(Response.Status.NOT_FOUND, + MessageFormat.format(BundleUtil.getStringFromBundle("dataverseFeaturedItems.errors.notFound"), ids.get(i)))); } - UpdatedDataverseFeaturedItemDTO updatedDTO = UpdatedDataverseFeaturedItemDTO.fromFormData(content, displayOrder, keepFile, fileInputStream, contentDispositionHeader); - dataverseFeaturedItemsToUpdate.put(existingItem, updatedDTO); + itemsToUpdate.put(existingItem, UpdatedDataverseFeaturedItemDTO.fromFormData( + contents.get(i), displayOrders.get(i), keepFiles.get(i), fileInputStream, contentDisposition)); } } List featuredItems = execCommand(new UpdateDataverseFeaturedItemsCommand( createDataverseRequest(getRequestUser(crc)), dataverse, - newDataverseFeaturedItemDTOs, - dataverseFeaturedItemsToUpdate + newItems, + itemsToUpdate )); + return ok(jsonDataverseFeaturedItems(featuredItems)); } catch (WrappedResponse wr) { return wr.getResponse(); diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDataverseFeaturedItemsCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDataverseFeaturedItemsCommand.java index afb09bdf455..8fb5f4f09c8 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDataverseFeaturedItemsCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/UpdateDataverseFeaturedItemsCommand.java @@ -8,6 +8,8 @@ import edu.harvard.iq.dataverse.engine.command.*; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; +import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Map; @@ -34,34 +36,43 @@ public UpdateDataverseFeaturedItemsCommand(DataverseRequest request, Dataverse d @Override public List execute(CommandContext ctxt) throws CommandException { - updateOrDeleteExistingFeaturedItems(ctxt); - createNewFeaturedItems(ctxt); - - return ctxt.engine().submit(new ListDataverseFeaturedItemsCommand(getRequest(), dataverse)); + List dataverseFeaturedItems = updateOrDeleteExistingFeaturedItems(ctxt); + dataverseFeaturedItems.addAll(createNewFeaturedItems(ctxt)); + dataverseFeaturedItems.sort(Comparator.comparingLong(DataverseFeaturedItem::getId)); + return dataverseFeaturedItems; } - private void updateOrDeleteExistingFeaturedItems(CommandContext ctxt) throws CommandException { + private List updateOrDeleteExistingFeaturedItems(CommandContext ctxt) throws CommandException { + List updatedFeaturedItems = new ArrayList<>(); List featuredItemsToDelete = dataverse.getDataverseFeaturedItems(); for (Map.Entry entry : dataverseFeaturedItemsToUpdate.entrySet()) { DataverseFeaturedItem featuredItem = entry.getKey(); UpdatedDataverseFeaturedItemDTO updatedDTO = entry.getValue(); - if (featuredItemsToDelete.contains(featuredItem)) { - featuredItemsToDelete.remove(featuredItem); - } + featuredItemsToDelete.stream() + .filter(item -> item.getId().equals(featuredItem.getId())) + .findFirst().ifPresent(featuredItemsToDelete::remove); - ctxt.engine().submit(new UpdateDataverseFeaturedItemCommand(getRequest(), featuredItem, updatedDTO)); + DataverseFeaturedItem updatedFeatureItem = ctxt.engine().submit(new UpdateDataverseFeaturedItemCommand(getRequest(), featuredItem, updatedDTO)); + updatedFeaturedItems.add(updatedFeatureItem); } for (DataverseFeaturedItem featuredItem : featuredItemsToDelete) { ctxt.engine().submit(new DeleteDataverseFeaturedItemCommand(getRequest(), featuredItem)); } + + return updatedFeaturedItems; } - private void createNewFeaturedItems(CommandContext ctxt) throws CommandException { + private List createNewFeaturedItems(CommandContext ctxt) throws CommandException { + List createdFeaturedItems = new ArrayList<>(); + for (NewDataverseFeaturedItemDTO dto : newDataverseFeaturedItemDTOs) { - ctxt.engine().submit(new CreateDataverseFeaturedItemCommand(getRequest(), dataverse, dto)); + DataverseFeaturedItem createdFeatureItem = ctxt.engine().submit(new CreateDataverseFeaturedItemCommand(getRequest(), dataverse, dto)); + createdFeaturedItems.add(createdFeatureItem); } + + return createdFeaturedItems; } } diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 78adae7062c..ab674a9dc15 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -982,8 +982,8 @@ dataverse.create.error.jsonparsetodataverse=Error parsing the POSTed json into a dataverse.create.featuredItem.error.imageFileProcessing=Error processing featured item file: {0} dataverse.create.featuredItem.error.fileSizeExceedsLimit=File exceeds the maximum size of {0} dataverse.create.featuredItem.error.invalidFileType=Invalid image file type -dataverse.update.featuredItems.error.missingInputParams=All input parameters (id, content, displayOrder, keepFile, file) are required. -dataverse.update.featuredItems.error.inputListsSizeMismatch=All input lists (id, content, displayOrder, keepFile, file) must have the same size. +dataverse.update.featuredItems.error.missingInputParams=All input parameters (id, content, displayOrder, keepFile, fileNames) are required. +dataverse.update.featuredItems.error.inputListsSizeMismatch=All input lists (id, content, displayOrder, keepFile, fileNames) must have the same size. # rolesAndPermissionsFragment.xhtml # advanced.xhtml 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 6089a44054c..ea29fb487fc 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java @@ -1622,7 +1622,6 @@ public void testCreateFeaturedItem() { .statusCode(NOT_FOUND.getStatusCode()); } - // TODO: Complete @Test public void testUpdateFeaturedItems() { Response createUserResponse = UtilIT.createRandomUser(); @@ -1630,17 +1629,118 @@ public void testUpdateFeaturedItems() { Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken); createDataverseResponse.then().assertThat().statusCode(CREATED.getStatusCode()); String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse); + String baseUri = UtilIT.getRestAssuredBaseUri(); // Create new items - List ids = Arrays.asList(0L, 0L); - List contents = Arrays.asList("Content 1", "Content 2"); - List orders = Arrays.asList(1, 2); - List keepFiles = Arrays.asList(false, false); - List pathsToFiles = Arrays.asList("src/test/resources/images/coffeeshop.png", "src/test/resources/images/coffeeshop.png"); + + List ids = Arrays.asList(0L, 0L, 0L); + List contents = Arrays.asList("Content 1", "Content 2", "Content 3"); + List orders = Arrays.asList(0, 1, 2); + List keepFiles = Arrays.asList(false, false, false); + List pathsToFiles = Arrays.asList("src/test/resources/images/coffeeshop.png", null, null); Response updateDataverseFeaturedItemsResponse = UtilIT.updateDataverseFeaturedItems(dataverseAlias, ids, contents, orders, keepFiles, pathsToFiles, apiToken); - updateDataverseFeaturedItemsResponse.prettyPrint(); updateDataverseFeaturedItemsResponse.then().assertThat() + .body("data.size()", equalTo(3)) + .body("data[0].content", equalTo("Content 1")) + .body("data[0].imageFileName", equalTo("coffeeshop.png")) + .body("data[0].imageFileUrl", containsString(baseUri + "/api/access/dataverseFeatureItemImage/")) + .body("data[0].displayOrder", equalTo(0)) + .body("data[1].content", equalTo("Content 2")) + .body("data[1].imageFileName", equalTo(null)) + .body("data[1].imageFileUrl", equalTo(null)) + .body("data[1].displayOrder", equalTo(1)) + .body("data[2].content", equalTo("Content 3")) + .body("data[2].imageFileName", equalTo(null)) + .body("data[2].imageFileUrl", equalTo(null)) + .body("data[2].displayOrder", equalTo(2)) + .statusCode(OK.getStatusCode()); + + Long firstItemId = JsonPath.from(updateDataverseFeaturedItemsResponse.body().asString()).getLong("data[0].id"); + Long secondItemId = JsonPath.from(updateDataverseFeaturedItemsResponse.body().asString()).getLong("data[1].id"); + Long thirdItemId = JsonPath.from(updateDataverseFeaturedItemsResponse.body().asString()).getLong("data[2].id"); + + // Update first item (content, order, and keeping image), delete the rest and create new items + + ids = Arrays.asList(firstItemId, 0L, 0L); + contents = Arrays.asList("Content 1 updated", "Content 2", "Content 3"); + orders = Arrays.asList(1, 0, 2); + keepFiles = Arrays.asList(true, false, false); + pathsToFiles = Arrays.asList(null, null, null); + + updateDataverseFeaturedItemsResponse = UtilIT.updateDataverseFeaturedItems(dataverseAlias, ids, contents, orders, keepFiles, pathsToFiles, apiToken); + updateDataverseFeaturedItemsResponse.then().assertThat() + .body("data.size()", equalTo(3)) + .body("data[0].content", equalTo("Content 1 updated")) + .body("data[0].imageFileName", equalTo("coffeeshop.png")) + .body("data[0].imageFileUrl", containsString(baseUri + "/api/access/dataverseFeatureItemImage/")) + .body("data[0].displayOrder", equalTo(1)) + .body("data[1].content", equalTo("Content 2")) + .body("data[1].imageFileName", equalTo(null)) + .body("data[1].imageFileUrl", equalTo(null)) + .body("data[1].displayOrder", equalTo(0)) + .body("data[2].content", equalTo("Content 3")) + .body("data[2].imageFileName", equalTo(null)) + .body("data[2].imageFileUrl", equalTo(null)) + .body("data[2].displayOrder", equalTo(2)) + .statusCode(OK.getStatusCode()); + + Long firstItemIdAfterUpdate = JsonPath.from(updateDataverseFeaturedItemsResponse.body().asString()).getLong("data[0].id"); + Long secondItemIdAfterUpdate = JsonPath.from(updateDataverseFeaturedItemsResponse.body().asString()).getLong("data[1].id"); + Long thirdItemIdAfterUpdate = JsonPath.from(updateDataverseFeaturedItemsResponse.body().asString()).getLong("data[2].id"); + + assertEquals(firstItemId, firstItemIdAfterUpdate); + assertNotEquals(secondItemId, secondItemIdAfterUpdate); + assertNotEquals(thirdItemId, thirdItemIdAfterUpdate); + + // Update first item (removing image), update second item (adding image), delete the third item and create a new item + + ids = Arrays.asList(firstItemId, secondItemIdAfterUpdate, 0L); + contents = Arrays.asList("Content 1 updated", "Content 2", "Content 3"); + orders = Arrays.asList(1, 0, 2); + keepFiles = Arrays.asList(false, false, false); + pathsToFiles = Arrays.asList(null, "src/test/resources/images/coffeeshop.png", null); + + updateDataverseFeaturedItemsResponse = UtilIT.updateDataverseFeaturedItems(dataverseAlias, ids, contents, orders, keepFiles, pathsToFiles, apiToken); + updateDataverseFeaturedItemsResponse.then().assertThat() + .body("data.size()", equalTo(3)) + .body("data[0].content", equalTo("Content 1 updated")) + .body("data[0].imageFileName", equalTo(null)) + .body("data[0].imageFileUrl", equalTo(null)) + .body("data[0].displayOrder", equalTo(1)) + .body("data[1].content", equalTo("Content 2")) + .body("data[1].imageFileName", equalTo("coffeeshop.png")) + .body("data[1].imageFileUrl", containsString(baseUri + "/api/access/dataverseFeatureItemImage/")) + .body("data[1].displayOrder", equalTo(0)) + .body("data[2].content", equalTo("Content 3")) + .body("data[2].imageFileName", equalTo(null)) + .body("data[2].imageFileUrl", equalTo(null)) + .body("data[2].displayOrder", equalTo(2)) + .statusCode(OK.getStatusCode()); + + Long firstItemIdAftersSecondUpdate = JsonPath.from(updateDataverseFeaturedItemsResponse.body().asString()).getLong("data[0].id"); + Long secondItemIdAfterSecondUpdate = JsonPath.from(updateDataverseFeaturedItemsResponse.body().asString()).getLong("data[1].id"); + Long thirdItemIdAfterSecondUpdate = JsonPath.from(updateDataverseFeaturedItemsResponse.body().asString()).getLong("data[2].id"); + + assertEquals(firstItemId, firstItemIdAftersSecondUpdate); + assertEquals(secondItemIdAfterUpdate, secondItemIdAfterSecondUpdate); + assertNotEquals(thirdItemIdAfterUpdate, thirdItemIdAfterSecondUpdate); + + // Only keep first featured item + + ids = List.of(firstItemId); + contents = List.of("Content 1 updated"); + orders = List.of(0); + keepFiles = List.of(false); + pathsToFiles = null; + + updateDataverseFeaturedItemsResponse = UtilIT.updateDataverseFeaturedItems(dataverseAlias, ids, contents, orders, keepFiles, pathsToFiles, apiToken); + updateDataverseFeaturedItemsResponse.then().assertThat() + .body("data.size()", equalTo(1)) + .body("data[0].content", equalTo("Content 1 updated")) + .body("data[0].imageFileName", equalTo(null)) + .body("data[0].imageFileUrl", equalTo(null)) + .body("data[0].displayOrder", equalTo(0)) .statusCode(OK.getStatusCode()); } } 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 d0da601eb9a..6e95dace0e3 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -4459,34 +4459,25 @@ static Response updateDataverseFeaturedItems( List pathsToFiles, String apiToken) { - RequestSpecification requestSpecification = given() + RequestSpecification requestSpec = given() .header(API_TOKEN_HTTP_HEADER, apiToken) .contentType(ContentType.MULTIPART); - int size = contents.size(); - if (ids.size() != size || orders.size() != size || keepFiles.size() != size || pathsToFiles.size() != size) { - throw new IllegalArgumentException("'ids', 'contents', 'orders', 'keepFiles' and 'pathsToFiles' lists must have the same size."); - } - - for (int i = 0; i < size; i++) { - Long id = ids.get(i); - String content = contents.get(i); - Integer order = orders.get(i); - boolean keepFile = keepFiles.get(i); + for (int i = 0; i < contents.size(); i++) { + requestSpec.multiPart("content", contents.get(i)) + .multiPart("displayOrder", orders.get(i)) + .multiPart("keepFile", keepFiles.get(i)) + .multiPart("id", ids.get(i)); - requestSpecification.multiPart("content", content); - requestSpecification.multiPart("displayOrder", order); - requestSpecification.multiPart("keepFile", keepFile); - requestSpecification.multiPart("id", id); - - String pathToFile = pathsToFiles.get(i); + String pathToFile = pathsToFiles != null ? pathsToFiles.get(i) : null; if (pathToFile != null && !pathToFile.isEmpty()) { - requestSpecification.multiPart("file", new File(pathToFile)); + requestSpec.multiPart("fileName", Paths.get(pathToFile).getFileName().toString()) + .multiPart("file", new File(pathToFile)); + } else { + requestSpec.multiPart("fileName", ""); } } - return requestSpecification - .when() - .put("/api/dataverses/" + dataverseAlias + "/featuredItems"); + return requestSpec.when().put("/api/dataverses/" + dataverseAlias + "/featuredItems"); } }