diff --git a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java index b97a396e68..071bf3972f 100644 --- a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java @@ -97,7 +97,7 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp @Override public Bitstream clone(Context context, Bitstream bitstream) - throws SQLException { + throws SQLException, AuthorizeException { // Create a new bitstream with a new ID. Bitstream clonedBitstream = bitstreamDAO.create(context, new Bitstream()); // Set the internal identifier, file size, checksum, and @@ -107,18 +107,7 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp clonedBitstream.setChecksum(bitstream.getChecksum()); clonedBitstream.setChecksumAlgorithm(bitstream.getChecksumAlgorithm()); clonedBitstream.setFormat(bitstream.getBitstreamFormat()); - - try { - //Update our bitstream but turn off the authorization system since permissions - //haven't been set at this point in time. - context.turnOffAuthorisationSystem(); - update(context, clonedBitstream); - } catch (AuthorizeException e) { - log.error(e); - //Can never happen since we turn off authorization before we update - } finally { - context.restoreAuthSystemState(); - } + update(context, clonedBitstream); return clonedBitstream; } diff --git a/dspace-api/src/main/java/org/dspace/content/service/BitstreamService.java b/dspace-api/src/main/java/org/dspace/content/service/BitstreamService.java index cf7df9c489..4621c95e7c 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/BitstreamService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/BitstreamService.java @@ -54,7 +54,7 @@ public interface BitstreamService extends DSpaceObjectService, DSpace * @return the clone * @throws SQLException if database error */ - public Bitstream clone(Context context, Bitstream bitstream) throws SQLException; + public Bitstream clone(Context context, Bitstream bitstream) throws SQLException, AuthorizeException; /** * Create a new bitstream, with a new ID. The checksum and file size are diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java index de1f671ca5..8bf5d3cbd3 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java @@ -350,20 +350,30 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini */ @Override public Bitstream clone(Context context, Bitstream bitstream) throws SQLException, IOException, AuthorizeException { - Bitstream clonedBitstream = bitstreamService.clone(context, bitstream); - clonedBitstream.setStoreNumber(bitstream.getStoreNumber()); + Bitstream clonedBitstream = null; + try { + // Update our bitstream but turn off the authorization system since permissions + // haven't been set at this point in time. + context.turnOffAuthorisationSystem(); + clonedBitstream = bitstreamService.clone(context, bitstream); + clonedBitstream.setStoreNumber(bitstream.getStoreNumber()); - List metadataValues = bitstreamService - .getMetadata(bitstream, Item.ANY, Item.ANY, Item.ANY, Item.ANY); + List metadataValues = bitstreamService.getMetadata(bitstream, Item.ANY, Item.ANY, Item.ANY, + Item.ANY); - for (MetadataValue metadataValue : metadataValues) { - bitstreamService.addMetadata(context, clonedBitstream, metadataValue.getMetadataField(), - metadataValue.getLanguage(), metadataValue.getValue(), metadataValue.getAuthority(), - metadataValue.getConfidence()); + for (MetadataValue metadataValue : metadataValues) { + bitstreamService.addMetadata(context, clonedBitstream, metadataValue.getMetadataField(), + metadataValue.getLanguage(), metadataValue.getValue(), metadataValue.getAuthority(), + metadataValue.getConfidence()); + } + bitstreamService.update(context, clonedBitstream); + } catch (AuthorizeException e) { + log.error(e); + // Can never happen since we turn off authorization before we update + } finally { + context.restoreAuthSystemState(); } - bitstreamService.update(context, clonedBitstream); return clonedBitstream; - } /** diff --git a/dspace-api/src/main/java/org/dspace/versioning/VersionHistory.java b/dspace-api/src/main/java/org/dspace/versioning/VersionHistory.java index f7d0115e3a..231ccc29d9 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/VersionHistory.java +++ b/dspace-api/src/main/java/org/dspace/versioning/VersionHistory.java @@ -21,7 +21,7 @@ import javax.persistence.OrderBy; import javax.persistence.SequenceGenerator; import javax.persistence.Table; -import com.amazonaws.util.CollectionUtils; +import org.apache.commons.collections4.CollectionUtils; import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; import org.hibernate.proxy.HibernateProxyHelper; @@ -94,7 +94,7 @@ public class VersionHistory implements ReloadableEntity { * @return true if the last version in submission, otherwise false. */ public boolean hasDraftVersion() { - if (!CollectionUtils.isNullOrEmpty(versions) && Objects.nonNull(versions.get(0).getItem())) { + if (CollectionUtils.isNotEmpty(versions) && Objects.nonNull(versions.get(0).getItem())) { return !versions.get(0).getItem().isArchived(); } return false; diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/CanCreateVersionFeature.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/CanCreateVersionFeature.java index 4dbc3cdeeb..d75c441533 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/CanCreateVersionFeature.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/CanCreateVersionFeature.java @@ -55,6 +55,7 @@ public class CanCreateVersionFeature implements AuthorizationFeature { } Item item = itemService.find(context, UUID.fromString(((ItemRest) object).getUuid())); if (Objects.nonNull(item)) { + // The property versioning.block.entity is used to disable versioning for items with EntityType boolean isBlockEntity = configurationService.getBooleanProperty("versioning.block.entity", true); boolean hasEntityType = StringUtils.isNotBlank(itemService. getMetadataFirstValue(item, "dspace", "entity", "type", Item.ANY)); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ItemVersionLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ItemVersionLinkRepository.java index 7289745b1c..364ac1725a 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ItemVersionLinkRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ItemVersionLinkRepository.java @@ -49,7 +49,8 @@ public class ItemVersionLinkRepository extends AbstractDSpaceRestRepository * itemUuid param as UUID * @throws SQLException If something goes wrong */ - @PreAuthorize("hasPermission(@extractorOf.getVersionIdByItemUUID(#request, #itemUuid), 'VERSION', 'READ')") + @PreAuthorize("hasPermission(@extractorOf.getVersionIdByItemUUID(#request, #itemUuid), 'VERSION', 'READ') || " + + "@extractorOf.getVersionIdByItemUUID(#request, #itemUuid) == null" ) public VersionRest getItemVersion(@Nullable HttpServletRequest request, UUID itemUuid, @Nullable Pageable optionalPageable, diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/ExtractorOfAInprogressSubmissionInformations.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/ExtractorOfAInprogressSubmissionInformations.java index 559349d1af..c4d6667ecb 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/ExtractorOfAInprogressSubmissionInformations.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/ExtractorOfAInprogressSubmissionInformations.java @@ -60,6 +60,16 @@ public class ExtractorOfAInprogressSubmissionInformations { @Autowired private RequestService requestService; + /** + * This method is used on security checks, given a versionHistory id, + * it searches the latest version and checks if there is + * a Workspace/Workflow item in progress submission, + * if yes return the id of this one, otherwise returns null. + * + * @param request The current request + * @param versionHistoryId VersionHistoryId + * @return + */ public Integer getAInprogressSubmissionID(@Nullable HttpServletRequest request, Integer versionHistoryId) { Context context = getContext(request); if (Objects.nonNull(versionHistoryId)) { @@ -67,11 +77,11 @@ public class ExtractorOfAInprogressSubmissionInformations { VersionHistory versionHistory = versionHistoryService.find(context, versionHistoryId); if (Objects.nonNull(versionHistory)) { Version oldestVersion = versionHistoryService.getLatestVersion(context, versionHistory); - WorkflowItem workflowItem = workflowItemService.findByItem(context, oldestVersion.getItem()); WorkspaceItem workspaceItem = workspaceItemService.findByItem(context, oldestVersion.getItem()); if (Objects.nonNull(workspaceItem)) { return workspaceItem.getID(); } + WorkflowItem workflowItem = workflowItemService.findByItem(context, oldestVersion.getItem()); if (Objects.nonNull(workflowItem)) { return workflowItem.getID(); } @@ -83,6 +93,15 @@ public class ExtractorOfAInprogressSubmissionInformations { return null; } + /** + * This method is used on security checks, given a versionHistory id, + * it searches the latest version and checks if there is a Workspace/Workflow item in progress submission, + * if yes return the rest name - 'workspaceitem' or 'workflowitem', otherwise it returns the empty string. + * + * @param request The current request + * @param versionHistoryId VersionHistoryId + * @return + */ public String getAInprogressSubmissionTarget(@Nullable HttpServletRequest request, Integer versionHistoryId) { Context context = getContext(request); if (Objects.nonNull(versionHistoryId)) { @@ -90,12 +109,10 @@ public class ExtractorOfAInprogressSubmissionInformations { VersionHistory versionHistory = versionHistoryService.find(context, versionHistoryId); if (Objects.nonNull(versionHistory)) { Version oldestVersion = versionHistoryService.getLatestVersion(context, versionHistory); - WorkflowItem workflowItem = workflowItemService.findByItem(context, oldestVersion.getItem()); - WorkspaceItem workspaceItem = workspaceItemService.findByItem(context, oldestVersion.getItem()); - if (Objects.nonNull(workspaceItem)) { + if (Objects.nonNull(workspaceItemService.findByItem(context, oldestVersion.getItem()))) { return WorkspaceItemRest.NAME; } - if (Objects.nonNull(workflowItem)) { + if (Objects.nonNull(workflowItemService.findByItem(context, oldestVersion.getItem()))) { return WorkflowItemRest.NAME; } } @@ -106,6 +123,14 @@ public class ExtractorOfAInprogressSubmissionInformations { return StringUtils.EMPTY; } + /** + * This method is used on security checks, given an item UUID, + * it searches the relative version, if version exist return its id, otherwise returns null. + * + * @param request The current request + * @param uuid Item uuid + * @return + */ public Integer getVersionIdByItemUUID(@Nullable HttpServletRequest request, UUID uuid) { Context context = getContext(request); if (Objects.nonNull(uuid)) { diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/VersionRestPatchPermissionEvaluatorPlugin.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/VersionRestPatchPermissionEvaluatorPlugin.java index 84490df457..04802e5b75 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/VersionRestPatchPermissionEvaluatorPlugin.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/VersionRestPatchPermissionEvaluatorPlugin.java @@ -26,6 +26,8 @@ import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; /** + * This class evaluate ADMIN permissions to patch operation over a Version. + * * @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.it) */ @Component diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java index e37aca0877..56d8cebeb2 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java @@ -4175,8 +4175,6 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { getClient().perform(get("/api/core/items/" + item.getID() + "/version")) .andExpect(status().isUnauthorized()); - - configurationService.setProperty("versioning.item.history.view.admin", true); } @Test @@ -4207,8 +4205,47 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { String epersonToken = getAuthToken(eperson.getEmail(), password); getClient(epersonToken).perform(get("/api/core/items/" + item.getID() + "/version")) .andExpect(status().isForbidden()); + } - configurationService.setProperty("versioning.item.history.view.admin", true); + @Test + public void findVersionForItemAndProprtyHistoryViewAdminIsDisabledTest() throws Exception { + configurationService.setProperty("versioning.item.history.view.admin", false); + + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection test") + .build(); + + Item item = ItemBuilder.createItem(context, col) + .withTitle("Public test item") + .withIssueDate("2021-04-27") + .withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + VersionBuilder.createVersion(context, item, "test").build(); + + context.restoreAuthSystemState(); + + String epersonToken = getAuthToken(eperson.getEmail(), password); + getClient(epersonToken).perform(get("/api/core/items/" + item.getID() + "/version")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.allOf( + hasJsonPath("$.version", is(1)), + hasJsonPath("$.summary", emptyOrNullString()), + hasJsonPath("$.type", is("version")) + ))) + .andExpect(jsonPath("$._links.versionhistory.href", + Matchers.containsString("api/versioning/versions/1/versionhistory"))) + .andExpect(jsonPath("$._links.item.href", + Matchers.containsString("api/versioning/versions/1/item"))) + .andExpect(jsonPath("$._links.self.href", + Matchers.containsString("api/versioning/versions/1"))); } @Test @@ -4242,4 +4279,32 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { .andExpect(status().isBadRequest()); } + @Test + public void findVersionForItemWithoutVersionsTest() throws Exception { + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection test") + .build(); + + Item item = ItemBuilder.createItem(context, col) + .withTitle("Public test item") + .withIssueDate("2021-04-27") + .withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + item.setSubmitter(eperson); + + context.restoreAuthSystemState(); + + String epersonToken = getAuthToken(eperson.getEmail(), password); + getClient(epersonToken).perform(get("/api/core/items/" + item.getID() + "/version")) + .andExpect(status().isNoContent()); + } + } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/VersionHistoryRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/VersionHistoryRestRepositoryIT.java index dc83ae461e..5a0f1aaee1 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/VersionHistoryRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/VersionHistoryRestRepositoryIT.java @@ -10,6 +10,7 @@ package org.dspace.app.rest; import static com.jayway.jsonpath.JsonPath.read; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsInRelativeOrder; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -43,6 +44,7 @@ import org.dspace.versioning.service.VersionHistoryService; import org.dspace.versioning.service.VersioningService; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.hamcrest.Matchers; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -93,6 +95,13 @@ public class VersionHistoryRestRepositoryIT extends AbstractControllerIntegratio context.restoreAuthSystemState(); } + @After + public void cleanup() throws SQLException, AuthorizeException { + context.turnOffAuthorisationSystem(); + versionHistoryService.delete(context, versionHistory); + context.restoreAuthSystemState(); + } + @Test public void findOnePublicVersionHistoryTest() throws Exception { getClient().perform(get("/api/versioning/versionhistories/" + versionHistory.getID())) @@ -135,9 +144,6 @@ public class VersionHistoryRestRepositoryIT extends AbstractControllerIntegratio .andExpect(status().isOk()) .andExpect(jsonPath("$.draftVersion", Matchers.is(true))) .andExpect(jsonPath("$", is(VersionHistoryMatcher.matchEntry(versionHistory)))); - - configurationService.setProperty("versioning.item.history.view.admin", false); - } @Test @@ -147,8 +153,6 @@ public class VersionHistoryRestRepositoryIT extends AbstractControllerIntegratio String token = getAuthToken(eperson.getEmail(), password); getClient(token).perform(get("/api/versioning/versionhistories/" + versionHistory.getID())) .andExpect(status().isForbidden()); - - configurationService.setProperty("versioning.item.history.view.admin", false); } @Test @@ -184,17 +188,17 @@ public class VersionHistoryRestRepositoryIT extends AbstractControllerIntegratio .withSubject("ExtraEntry") .build(); - Version version = VersionBuilder.createVersion(context, item, "test").build(); + Version version2 = VersionBuilder.createVersion(context, item, "test").build(); VersionHistory versionHistory = versionHistoryService.findByItem(context, item); - Version version2 = versioningService.getVersion(context, item); + Version version = versioningService.getVersion(context, item); context.turnOffAuthorisationSystem(); String tokenAdmin = getAuthToken(admin.getEmail(), password); getClient(tokenAdmin).perform(get("/api/versioning/versionhistories/" + versionHistory.getID() + "/versions")) .andExpect(status().isOk()) - .andExpect(jsonPath("$._embedded.versions", containsInAnyOrder( - VersionMatcher.matchEntry(version), - VersionMatcher.matchEntry(version2) + .andExpect(jsonPath("$._embedded.versions", containsInRelativeOrder( + VersionMatcher.matchEntry(version2), + VersionMatcher.matchEntry(version) ))); context.turnOffAuthorisationSystem(); @@ -203,10 +207,10 @@ public class VersionHistoryRestRepositoryIT extends AbstractControllerIntegratio getClient(tokenAdmin).perform(get("/api/versioning/versionhistories/" + versionHistory.getID() + "/versions")) .andExpect(status().isOk()) - .andExpect(jsonPath("$._embedded.versions", containsInAnyOrder( - VersionMatcher.matchEntry(version), + .andExpect(jsonPath("$._embedded.versions", containsInRelativeOrder( + VersionMatcher.matchEntry(version3), VersionMatcher.matchEntry(version2), - VersionMatcher.matchEntry(version3) + VersionMatcher.matchEntry(version) ))); } @@ -235,8 +239,6 @@ public class VersionHistoryRestRepositoryIT extends AbstractControllerIntegratio getClient().perform(get("/api/versioning/versionhistories/" + versionHistory.getID() + "/versions")) .andExpect(status().isUnauthorized()); - - configurationService.setProperty("versioning.item.history.view.admin", true); } @Test diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/VersionRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/VersionRestRepositoryIT.java index 916aca0198..94f5f988bc 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/VersionRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/VersionRestRepositoryIT.java @@ -18,12 +18,15 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; +import org.apache.commons.io.IOUtils; import org.dspace.app.rest.authorization.Authorization; import org.dspace.app.rest.authorization.AuthorizationFeature; import org.dspace.app.rest.authorization.AuthorizationFeatureService; @@ -40,6 +43,8 @@ import org.dspace.app.rest.model.patch.ReplaceOperation; import org.dspace.app.rest.projection.DefaultProjection; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; import org.dspace.authorize.AuthorizeException; +import org.dspace.builder.BitstreamBuilder; +import org.dspace.builder.BundleBuilder; import org.dspace.builder.CollectionBuilder; import org.dspace.builder.CommunityBuilder; import org.dspace.builder.EPersonBuilder; @@ -47,6 +52,7 @@ import org.dspace.builder.ItemBuilder; import org.dspace.builder.VersionBuilder; import org.dspace.builder.WorkflowItemBuilder; import org.dspace.builder.WorkspaceItemBuilder; +import org.dspace.content.Bundle; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.Item; @@ -503,7 +509,8 @@ public class VersionRestRepositoryIT extends AbstractControllerIntegrationTest { hasJsonPath("$.summary", is("check first version")), hasJsonPath("$.submitterName", is("first (admin) last (admin)")), hasJsonPath("$.type", is("version")) - ))); + ))) + .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id"))); } finally { VersionBuilder.delete(idRef.get()); } @@ -654,7 +661,6 @@ public class VersionRestRepositoryIT extends AbstractControllerIntegrationTest { } finally { VersionBuilder.delete(idRef.get()); } - configurationService.setProperty("versioning.submitterCanCreateNewVersion", false); } @Test @@ -717,8 +723,6 @@ public class VersionRestRepositoryIT extends AbstractControllerIntegrationTest { .contentType(MediaType.parseMediaType(RestMediaTypes.TEXT_URI_LIST_VALUE)) .content("/api/core/items/" + itemA.getID())) .andExpect(status().isForbidden()); - - configurationService.setProperty("versioning.block.entity", ""); } @Test @@ -762,8 +766,6 @@ public class VersionRestRepositoryIT extends AbstractControllerIntegrationTest { } finally { VersionBuilder.delete(idRef.get()); } - - configurationService.setProperty("versioning.block.entity", ""); } @Test @@ -809,8 +811,6 @@ public class VersionRestRepositoryIT extends AbstractControllerIntegrationTest { } finally { VersionBuilder.delete(idRef.get()); } - configurationService.setProperty("versioning.submitterCanCreateNewVersion", false); - configurationService.setProperty("versioning.block.entity", ""); } @Test @@ -1434,4 +1434,58 @@ public class VersionRestRepositoryIT extends AbstractControllerIntegrationTest { Matchers.is(AuthorizationMatcher.matchAuthorization(admin2ItemA)))); } + @Test + public void createFirstVersionItemWithBitstreamBySubmitterTest() throws Exception { + configurationService.setProperty("versioning.submitterCanCreateNewVersion", true); + context.turnOffAuthorisationSystem(); + Community rootCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col = CollectionBuilder.createCollection(context, rootCommunity) + .withName("Collection 1") + .withSubmitterGroup(eperson) + .build(); + + Item itemA = ItemBuilder.createItem(context, col) + .withTitle("Public item") + .withIssueDate("2021-04-19") + .withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + itemA.setSubmitter(eperson); + + Bundle bundle = BundleBuilder.createBundle(context, itemA).withName("Bundle 0").build(); + + String bitstreamContent = "ThisIsSomeDummyText"; + + try (InputStream is = IOUtils.toInputStream(bitstreamContent, StandardCharsets.UTF_8)) { + BitstreamBuilder.createBitstream(context, bundle, is) + .withName("Bitstream0") + .withMimeType("text/plain") + .build(); + } + + context.restoreAuthSystemState(); + + AtomicReference idRef = new AtomicReference(); + String epersonToken = getAuthToken(eperson.getEmail(), password); + try { + getClient(epersonToken).perform(post("/api/versioning/versions") + .param("summary", "test summary!") + .contentType(MediaType.parseMediaType(RestMediaTypes.TEXT_URI_LIST_VALUE)) + .content("/api/core/items/" + itemA.getID())) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$", Matchers.allOf( + hasJsonPath("$.version", is(2)), + hasJsonPath("$.summary", is("test summary!")), + hasJsonPath("$.type", is("version")) + ))) + .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id"))); + } finally { + VersionBuilder.delete(idRef.get()); + } + } + } \ No newline at end of file diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanCreateVersionFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanCreateVersionFeatureIT.java index 8a6d836466..81302d891c 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanCreateVersionFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanCreateVersionFeatureIT.java @@ -144,8 +144,6 @@ public class CanCreateVersionFeatureIT extends AbstractControllerIntegrationTest .andExpect(status().isOk()) .andExpect(jsonPath("$.page.totalElements", greaterThan(0))) .andExpect(jsonPath("$._embedded").exists()); - - configurationService.setProperty("versioning.submitterCanCreateNewVersion", false); } @Test @@ -214,8 +212,6 @@ public class CanCreateVersionFeatureIT extends AbstractControllerIntegrationTest getClient(tokenUser).perform(get("/api/authz/authorizations/" + user2ItemB.getID())) .andExpect(status().isNotFound()); - - configurationService.setProperty("versioning.submitterCanCreateNewVersion", false); } @Test @@ -351,8 +347,6 @@ public class CanCreateVersionFeatureIT extends AbstractControllerIntegrationTest getClient(tokenEPerson).perform(get("/api/authz/authorizations/" + eperson2ItemA.getID())) .andExpect(status().isNotFound()); - - configurationService.setProperty("versioning.block.entity", ""); } @Test @@ -400,8 +394,6 @@ public class CanCreateVersionFeatureIT extends AbstractControllerIntegrationTest getClient(tokenEPerson).perform(get("/api/authz/authorizations/" + eperson2ItemA.getID())) .andExpect(status().isNotFound()); - - configurationService.setProperty("versioning.block.entity", ""); } @Test @@ -449,9 +441,6 @@ public class CanCreateVersionFeatureIT extends AbstractControllerIntegrationTest getClient(tokenEPerson).perform(get("/api/authz/authorizations/" + eperson2ItemA.getID())) .andExpect(status().isNotFound()); - - configurationService.setProperty("versioning.block.entity", ""); - configurationService.setProperty("versioning.submitterCanCreateNewVersion", true); } } \ No newline at end of file diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanDeleteVersionFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanDeleteVersionFeatureIT.java index 08cdc51108..0f09380d70 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanDeleteVersionFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanDeleteVersionFeatureIT.java @@ -304,8 +304,6 @@ public class CanDeleteVersionFeatureIT extends AbstractControllerIntegrationTest getClient().perform(get("/api/authz/authorizations/" + anonymous2ItemA.getID())) .andExpect(status().isNotFound()); - - configurationService.setProperty("versioning.block.entity", ""); } @Test @@ -356,8 +354,6 @@ public class CanDeleteVersionFeatureIT extends AbstractControllerIntegrationTest getClient().perform(get("/api/authz/authorizations/" + anonymous2ItemA.getID())) .andExpect(status().isNotFound()); - - configurationService.setProperty("versioning.block.entity", ""); } } \ No newline at end of file diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanEditVersionFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanEditVersionFeatureIT.java index 2aa2356ce5..4e6339aabd 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanEditVersionFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanEditVersionFeatureIT.java @@ -261,8 +261,6 @@ public class CanEditVersionFeatureIT extends AbstractControllerIntegrationTest { getClient(tokenAdmin).perform(get("/api/authz/authorizations/" + adminToVersion.getID())) .andExpect(status().isNotFound()); - - configurationService.setProperty("versioning.block.entity", ""); } @Test @@ -343,8 +341,6 @@ public class CanEditVersionFeatureIT extends AbstractControllerIntegrationTest { getClient().perform(get("/api/authz/authorizations/" + anonymousToVersion.getID())) .andExpect(status().isNotFound()); - - configurationService.setProperty("versioning.block.entity", ""); } } \ No newline at end of file diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanManageVersionsFeatureIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanManageVersionsFeatureIT.java index fe4c7cfa45..f11017449a 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanManageVersionsFeatureIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/authorization/CanManageVersionsFeatureIT.java @@ -290,8 +290,6 @@ public class CanManageVersionsFeatureIT extends AbstractControllerIntegrationTes getClient(tokenAdminCol2).perform(get("/api/authz/authorizations/" + adminOfCol2ToItemA.getID())) .andExpect(status().isNotFound()); - - configurationService.setProperty("versioning.block.entity", ""); } @Test @@ -383,8 +381,6 @@ public class CanManageVersionsFeatureIT extends AbstractControllerIntegrationTes getClient(tokenAdminCol2).perform(get("/api/authz/authorizations/" + adminOfCol2ToItemA.getID())) .andExpect(status().isNotFound()); - - configurationService.setProperty("versioning.block.entity", ""); } } \ No newline at end of file diff --git a/dspace/config/modules/versioning.cfg b/dspace/config/modules/versioning.cfg index 982034c530..2c4b82dd85 100644 --- a/dspace/config/modules/versioning.cfg +++ b/dspace/config/modules/versioning.cfg @@ -16,3 +16,7 @@ versioning.item.history.include.submitter=false # If you want to allow submitters to create new versions of there items, set # the property submitterCanCreateNewVersion true. # versioning.submitterCanCreateNewVersion=false + +# The property versioning.block.entity is used to disable versioning +# for items with EntityType, the default value is true if it unset. +# versioning.block.entity= \ No newline at end of file