From 3afaae74b09586e6206928b989e92402be0fec1a Mon Sep 17 00:00:00 2001 From: eskander Date: Wed, 21 Aug 2024 15:25:27 +0300 Subject: [PATCH 1/3] [DURACOM-222] Expose the item submitter over the REST --- .../org/dspace/app/rest/model/ItemRest.java | 6 ++ .../ItemSubmitterLinkRepository.java | 61 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ItemSubmitterLinkRepository.java diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ItemRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ItemRest.java index b2f540c0ac4..b3ae373ceed 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ItemRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ItemRest.java @@ -52,6 +52,10 @@ @LinkRest( name = ItemRest.THUMBNAIL, method = "getThumbnail" + ), + @LinkRest( + name = ItemRest.SUBMITTER, + method = "getItemSubmitter" ) }) public class ItemRest extends DSpaceObjectRest { @@ -69,6 +73,8 @@ public class ItemRest extends DSpaceObjectRest { public static final String TEMPLATE_ITEM_OF = "templateItemOf"; public static final String THUMBNAIL = "thumbnail"; + public static final String SUBMITTER = "submitter"; + private boolean inArchive = false; private boolean discoverable = false; private boolean withdrawn = false; diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ItemSubmitterLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ItemSubmitterLinkRepository.java new file mode 100644 index 00000000000..a345f0abe78 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ItemSubmitterLinkRepository.java @@ -0,0 +1,61 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.repository; + +import java.sql.SQLException; +import java.util.UUID; +import javax.annotation.Nullable; + +import jakarta.servlet.http.HttpServletRequest; +import org.dspace.app.rest.model.EPersonRest; +import org.dspace.app.rest.model.ItemRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.content.Item; +import org.dspace.content.service.ItemService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Component; + +/** + * Link repository for "submitter" subresource of an item. + */ +@Component(ItemRest.CATEGORY + "." + ItemRest.PLURAL_NAME + "." + ItemRest.SUBMITTER) +public class ItemSubmitterLinkRepository extends AbstractDSpaceRestRepository + implements LinkRestRepository { + + @Autowired + ItemService itemService; + + /** + * Retrieve the submitter for an item. + * + * @param request - The current request + * @param id - The item ID for which to retrieve the submitter + * @param optionalPageable - optional pageable object + * @param projection - the current projection + * @return the submitter for the item + */ + @PreAuthorize("hasPermission(#id, 'ITEM', 'READ')") + public EPersonRest getItemSubmitter(@Nullable HttpServletRequest request, UUID id, + @Nullable Pageable optionalPageable, Projection projection) { + try { + Context context = obtainContext(); + Item item = itemService.find(context, id); + if (item == null) { + throw new ResourceNotFoundException("No such item: " + id); + } + + return converter.toRest(item.getSubmitter(), projection); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file From 49e8653d038afac14a042257c702db17d26af074 Mon Sep 17 00:00:00 2001 From: eskander Date: Wed, 21 Aug 2024 16:29:35 +0300 Subject: [PATCH 2/3] [DURACOM-222] adding ITs --- .../dspace/app/rest/ItemRestRepositoryIT.java | 45 +++++++++++++++++++ .../dspace/app/rest/matcher/ItemMatcher.java | 6 ++- 2 files changed, 49 insertions(+), 2 deletions(-) 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 b2bfd048520..8a629cd31cf 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 @@ -4696,4 +4696,49 @@ public void findAccessStatusForItemTest() throws Exception { .andExpect(jsonPath("$.status", notNullValue())); } + @Test + public void findSubmitterTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + EPerson submitter = EPersonBuilder.createEPerson(context) + .withEmail("testone@mail.com") + .withPassword(password) + .withCanLogin(true) + .build(); + + context.setCurrentUser(submitter); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + context.restoreAuthSystemState(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/core/items/" + publicItem.getID()) + .param("projection", "full")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", ItemMatcher.matchFullEmbeds())); + + getClient(token).perform(get("/api/core/items/" + publicItem.getID() + "/submitter")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(submitter.getID().toString()))) + .andExpect(jsonPath("$.email", is(submitter.getEmail()))); + } + } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java index 64905f90ea2..44121b7e42d 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java @@ -58,7 +58,8 @@ public static Matcher matchFullEmbeds() { "version", "relationships[]", "templateItemOf", - "thumbnail" + "thumbnail", + "submitter" ); } @@ -76,7 +77,8 @@ public static Matcher matchLinks(UUID uuid) { "self", "version", "templateItemOf", - "thumbnail" + "thumbnail", + "submitter" ); } From 875327927cba18ad2fd18e47fc6d9a858cb077ad Mon Sep 17 00:00:00 2001 From: eskander Date: Mon, 2 Sep 2024 11:20:04 +0300 Subject: [PATCH 3/3] [DURACOM-222] adding more ITs --- .../dspace/app/rest/ItemRestRepositoryIT.java | 77 ++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) 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 8a629cd31cf..f105322a63f 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 @@ -4697,7 +4697,7 @@ public void findAccessStatusForItemTest() throws Exception { } @Test - public void findSubmitterTest() throws Exception { + public void findSubmitterByAdminTest() throws Exception { context.turnOffAuthorisationSystem(); //** GIVEN ** @@ -4741,4 +4741,79 @@ public void findSubmitterTest() throws Exception { .andExpect(jsonPath("$.email", is(submitter.getEmail()))); } + @Test + public void findSubmitterWithoutReadAccessTest() throws Exception { + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build(); + + EPerson submitter = EPersonBuilder.createEPerson(context) + .withEmail("testone@mail.com") + .withPassword(password) + .withCanLogin(true) + .build(); + + context.setCurrentUser(submitter); + + Item publicItem = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + context.restoreAuthSystemState(); + + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(get("/api/core/items/" + publicItem.getID()) + .param("projection", "full")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", ItemMatcher.matchFullEmbeds())); + +// find submitter by user has no read access + getClient(token).perform(get("/api/core/items/" + publicItem.getID() + "/submitter")) + .andExpect(status().isNoContent()); + } + + @Test + public void findSubmitterByAnonymousTest() throws Exception { + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build(); + + EPerson submitter = EPersonBuilder.createEPerson(context) + .withEmail("testone@mail.com") + .withPassword(password) + .withCanLogin(true) + .build(); + + context.setCurrentUser(submitter); + + Item publicItem = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); + + context.restoreAuthSystemState(); + + getClient().perform(get("/api/core/items/" + publicItem.getID()) + .param("projection", "full")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", ItemMatcher.matchFullEmbeds())); + + getClient().perform(get("/api/core/items/" + publicItem.getID() + "/submitter")) + .andExpect(status().isNoContent()); + } + }