diff --git a/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java b/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java index 3c002459ff1..a2fe951c484 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java @@ -152,7 +152,7 @@ public List findByTypeGroupAction(Context context, DSpaceObject criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.actionId), action) ) ); - return list(context, criteriaQuery, false, ResourcePolicy.class, 1, -1); + return list(context, criteriaQuery, false, ResourcePolicy.class, -1, -1); } @Override @@ -170,7 +170,7 @@ public List findByTypeGroupActionExceptId(Context context, DSpac criteriaBuilder.notEqual(resourcePolicyRoot.get(ResourcePolicy_.id), notPolicyID) ) ); - return list(context, criteriaQuery, false, ResourcePolicy.class, 1, -1); + return list(context, criteriaQuery, false, ResourcePolicy.class, -1, -1); } public List findByEPersonGroupTypeIdAction(Context context, EPerson e, List groups, @@ -187,7 +187,7 @@ public List findByEPersonGroupTypeIdAction(Context context, EPer (resourcePolicyRoot.get(ResourcePolicy_.epersonGroup).in(groups))) ) ); - return list(context, criteriaQuery, false, ResourcePolicy.class, 1, -1); + return list(context, criteriaQuery, false, ResourcePolicy.class, -1, -1); } @Override @@ -291,7 +291,7 @@ public List findByDSoAndActionExceptRpType(Context context, DSpa ) ); } - return list(context, criteriaQuery, false, ResourcePolicy.class, 1, 1); + return list(context, criteriaQuery, false, ResourcePolicy.class, -1, 1); } @Override diff --git a/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java b/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java index 3676133a89f..c9b966c8256 100644 --- a/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java +++ b/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java @@ -8,7 +8,6 @@ package org.dspace.browse; import java.io.Serializable; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -181,7 +180,6 @@ private DiscoverResult getSolrResponse() throws BrowseException { if (sResponse == null) { DiscoverQuery query = new DiscoverQuery(); addLocationScopeFilter(query); - addStatusFilter(query); addExtraFilter(query); addDefaultFilterQueries(query); if (distinct) { @@ -241,18 +239,6 @@ private void addExtraFilter(DiscoverQuery query) { } } - private void addStatusFilter(DiscoverQuery query) { - try { - if (!authorizeService.isAdmin(context) - && (authorizeService.isCommunityAdmin(context) - || authorizeService.isCollectionAdmin(context))) { - query.addFilterQueries(searcher.createLocationQueryForAdministrableItems(context)); - } - } catch (SQLException ex) { - log.error("Error looking up authorization rights of current user", ex); - } - } - private void addLocationScopeFilter(DiscoverQuery query) { if (container != null) { if (containerIDField.startsWith("collection")) { @@ -356,7 +342,6 @@ public int doOffsetQuery(String column, String value, boolean isAscending) throws BrowseException { DiscoverQuery query = new DiscoverQuery(); addLocationScopeFilter(query); - addStatusFilter(query); addExtraFilter(query); addDefaultFilterQueries(query); query.setMaxResults(0); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BrowsesResourceControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BrowsesResourceControllerIT.java index 41ee6be0e17..242aa6fb281 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BrowsesResourceControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BrowsesResourceControllerIT.java @@ -517,6 +517,263 @@ public void findBrowseBySubjectItems() throws Exception { .andExpect(jsonPath("$.page.size", is(20))); } + @Test + public void findBrowseBySubjectItemsWithScope() 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) + .withEntityType("Publication") + .withName("Collection 1") + .build(); + Collection col2 = CollectionBuilder.createCollection(context, child1) + .withEntityType("Publication") + .withName("Collection 2") + .build(); + + //2. Two public items with the same subject and another public item that contains that same subject, but also + // another one + // All of the items are readable by an Anonymous user + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("zPublic item more") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry").withSubject("AnotherTest") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 3") + .withIssueDate("2016-02-14") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest") + .build(); + + Item withdrawnItem1 = ItemBuilder.createItem(context, col2) + .withTitle("Withdrawn item 1") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("WithdrawnEntry") + .withdrawn() + .build(); + Item privateItem1 = ItemBuilder.createItem(context, col2) + .withTitle("Private item 1") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("PrivateEntry") + .makeUnDiscoverable() + .build(); + + context.restoreAuthSystemState(); + + //** WHEN ** + //An anonymous user browses the items that correspond with the ExtraEntry subject query + getClient().perform(get("/api/discover/browses/subject/items") + .param("scope", String.valueOf(col2.getID())) + .param("filterValue", "ExtraEntry")) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be no elements in collection 2 + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$.page.size", is(20))); + + //** WHEN ** + //An anonymous user browses the items that correspond with the AnotherTest subject query + getClient().perform(get("/api/discover/browses/subject/items") + .param("scope", String.valueOf(col2.getID())) + .param("filterValue", "AnotherTest")) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be only two elements, the ones that we've added with the requested subject + // in collection 2 + .andExpect(jsonPath("$.page.totalElements", is(2))) + .andExpect(jsonPath("$.page.size", is(20))) + //Verify that the title of the public and embargoed items are present and sorted descending + .andExpect(jsonPath("$._embedded.items", contains( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, "Public item 2", "2016-02-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, "Public item 3", "2016-02-14") + ))); + + //** WHEN ** + //An anonymous user browses the items that correspond with the PrivateEntry subject query + getClient().perform(get("/api/discover/browses/subject/items") + .param("scope", String.valueOf(col2.getID())) + .param("filterValue", "PrivateEntry")) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be no elements because the item is private + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$.page.size", is(20))); + + //** WHEN ** + //An anonymous user browses the items that correspond with the WithdrawnEntry subject query + getClient().perform(get("/api/discover/browses/subject/items") + .param("scope", String.valueOf(col2.getID())) + .param("filterValue", "WithdrawnEntry")) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be no elements because the item is withdrawn + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$.page.size", is(20))); + } + + @Test + public void findBrowseBySubjectItemsWithScopeAsAdmin() 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) + .withEntityType("Publication") + .withName("Collection 1") + .build(); + Collection col2 = CollectionBuilder.createCollection(context, child1) + .withEntityType("Publication") + .withName("Collection 2") + .build(); + + //2. Two public items with the same subject and another public item that contains that same subject, but also + // another one + // All of the items are readable by an Anonymous user + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("zPublic item more") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry").withSubject("AnotherTest") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 3") + .withIssueDate("2016-02-14") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest") + .build(); + + Item withdrawnItem1 = ItemBuilder.createItem(context, col2) + .withTitle("Withdrawn item 1") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("WithdrawnEntry") + .withdrawn() + .build(); + Item privateItem1 = ItemBuilder.createItem(context, col2) + .withTitle("Private item 1") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("PrivateEntry") + .makeUnDiscoverable() + .build(); + + context.restoreAuthSystemState(); + + String adminToken = getAuthToken(admin.getEmail(), password); + + + //** WHEN ** + //An admin user browses the items that correspond with the ExtraEntry subject query + getClient(adminToken).perform(get("/api/discover/browses/subject/items") + .param("scope", String.valueOf(col2.getID())) + .param("filterValue", "ExtraEntry")) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be no elements in collection 2 + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$.page.size", is(20))); + + //** WHEN ** + //An admin user browses the items that correspond with the AnotherTest subject query + getClient(adminToken).perform(get("/api/discover/browses/subject/items") + .param("scope", String.valueOf(col2.getID())) + .param("filterValue", "AnotherTest")) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be only two elements, the ones that we've added with the requested subject + // in collection 2 + .andExpect(jsonPath("$.page.totalElements", is(2))) + .andExpect(jsonPath("$.page.size", is(20))) + //Verify that the title of the public and embargoed items are present and sorted descending + .andExpect(jsonPath("$._embedded.items", contains( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, "Public item 2", "2016-02-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, "Public item 3", "2016-02-14") + ))); + + //** WHEN ** + //An admin user browses the items that correspond with the PrivateEntry subject query + getClient(adminToken).perform(get("/api/discover/browses/subject/items") + .param("scope", String.valueOf(col2.getID())) + .param("filterValue", "PrivateEntry")) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be no elements because the item is private + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$.page.size", is(20))); + + //** WHEN ** + //An admin user browses the items that correspond with the WithdrawnEntry subject query + getClient(adminToken).perform(get("/api/discover/browses/subject/items") + .param("scope", String.valueOf(col2.getID())) + .param("filterValue", "WithdrawnEntry")) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be no elements because the item is withdrawn + .andExpect(jsonPath("$.page.totalElements", is(0))) + .andExpect(jsonPath("$.page.size", is(20))); + } + @Test public void findBrowseByTitleItems() throws Exception { context.turnOffAuthorisationSystem(); @@ -648,10 +905,145 @@ public void findBrowseByTitleItems() throws Exception { "2017-08-10") ))) - //The private and internal items must not be present + //The private and internal items must not be present + .andExpect(jsonPath("$._embedded.items[*].metadata", Matchers.allOf( + not(matchMetadata("dc.title", "This is a private item")), + not(matchMetadata("dc.title", "Internal publication"))))); + } + + @Test + public void findBrowseByTitleItemsWithScope() 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) + .withEntityType("Publication") + .withName("Collection 1") + .build(); + Collection col2 = CollectionBuilder.createCollection(context, child1) + .withEntityType("Publication") + .withName("Collection 2") + .build(); + + //2. Two public items that are readable by Anonymous + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("Java").withSubject("Unit Testing") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("Angular").withSubject("Unit Testing") + .build(); + + //3. An item that has been made private + Item privateItem = ItemBuilder.createItem(context, col2) + .withTitle("This is a private item") + .withIssueDate("2015-03-12") + .withAuthor("Duck, Donald") + .withSubject("Cartoons").withSubject("Ducks") + .makeUnDiscoverable() + .build(); + + //4. An item with an item-level embargo + Item embargoedItem = ItemBuilder.createItem(context, col2) + .withTitle("An embargoed publication") + .withIssueDate("2017-08-10") + .withAuthor("Mouse, Mickey") + .withSubject("Cartoons").withSubject("Mice") + .withEmbargoPeriod("12 months") + .build(); + + //5. An item that is only readable for an internal groups + Group internalGroup = GroupBuilder.createGroup(context) + .withName("Internal Group") + .build(); + + Item internalItem = ItemBuilder.createItem(context, col2) + .withTitle("Internal publication") + .withIssueDate("2016-09-19") + .withAuthor("Doe, John") + .withSubject("Unknown") + .withReaderGroup(internalGroup) + .build(); + + context.restoreAuthSystemState(); + + //** WHEN ** + //An anonymous user browses the items in the Browse by item endpoint + //sorted descending by tile + getClient().perform(get("/api/discover/browses/title/items") + .param("scope", String.valueOf(col2.getID())) + .param("sort", "title,desc")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))) + .andExpect(jsonPath("$.page.totalPages", is(1))) + .andExpect(jsonPath("$.page.number", is(0))) + + .andExpect(jsonPath("$._embedded.items", + contains(ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, + "Public item 2", + "2016-02-13")))) + + //The private and internal items must not be present + .andExpect(jsonPath("$._embedded.items[*].metadata", Matchers.allOf( + not(matchMetadata("dc.title", "This is a private item")), + not(matchMetadata("dc.title", "Internal publication"))))); + + String adminToken = getAuthToken(admin.getEmail(), password); + //** WHEN ** + //An admin user browses the items in the Browse by item endpoint + //sorted descending by tile + getClient(adminToken).perform(get("/api/discover/browses/title/items") + .param("scope", String.valueOf(col2.getID())) + .param("sort", "title,desc")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(3))) + .andExpect(jsonPath("$.page.totalPages", is(1))) + .andExpect(jsonPath("$.page.number", is(0))) + .andExpect(jsonPath("$._embedded.items", contains( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, + "Public item 2", + "2016-02-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(internalItem, + "Internal publication", + "2016-09-19"), + ItemMatcher.matchItemWithTitleAndDateIssued(embargoedItem, + "An embargoed publication", + "2017-08-10") + + ))) + + + //The private and internal items must not be present .andExpect(jsonPath("$._embedded.items[*].metadata", Matchers.allOf( - not(matchMetadata("dc.title", "This is a private item")), - not(matchMetadata("dc.title", "Internal publication"))))); + not(matchMetadata("dc.title", "This is a private item")) + ))); } @Test @@ -879,6 +1271,138 @@ public void testPaginationBrowseByDateIssuedItems() throws Exception { ))); } + @Test + public void testPaginationBrowseByDateIssuedItemsWithScope() 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) + .withEntityType("Publication") + .withName("Collection 1") + .build(); + Collection col2 = CollectionBuilder.createCollection(context, child1) + .withEntityType("Publication") + .withName("Collection 2") + .build(); + + //2. 7 public items that are readable by Anonymous + Item item1 = ItemBuilder.createItem(context, col1) + .withTitle("Item 1") + .withIssueDate("2017-10-17") + .build(); + + Item item2 = ItemBuilder.createItem(context, col2) + .withTitle("Item 2") + .withIssueDate("2016-02-13") + .build(); + + Item item3 = ItemBuilder.createItem(context, col1) + .withTitle("Item 3") + .withIssueDate("2016-02-12") + .build(); + + Item item4 = ItemBuilder.createItem(context, col2) + .withTitle("Item 4") + .withIssueDate("2016-02-11") + .build(); + + Item item5 = ItemBuilder.createItem(context, col1) + .withTitle("Item 5") + .withIssueDate("2016-02-10") + .build(); + + Item item6 = ItemBuilder.createItem(context, col2) + .withTitle("Item 6") + .withIssueDate("2016-01-13") + .build(); + + Item item7 = ItemBuilder.createItem(context, col1) + .withTitle("Item 7") + .withIssueDate("2016-01-12") + .build(); + + Item withdrawnItem1 = ItemBuilder.createItem(context, col2) + .withTitle("Withdrawn item 1") + .withIssueDate("2016-02-13") + .withdrawn() + .build(); + + Item privateItem1 = ItemBuilder.createItem(context, col2) + .withTitle("Private item 1") + .makeUnDiscoverable() + .build(); + + + context.restoreAuthSystemState(); + + //** WHEN ** + //An anonymous user browses the items in the Browse by date issued endpoint + //sorted ascending by tile with a page size of 5 + getClient().perform(get("/api/discover/browses/dateissued/items") + .param("scope", String.valueOf(col2.getID())) + .param("sort", "title,asc") + .param("size", "5")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //We expect only the first five items to be present + .andExpect(jsonPath("$.page.size", is(5))) + .andExpect(jsonPath("$.page.totalElements", is(3))) + .andExpect(jsonPath("$.page.totalPages", is(1))) + .andExpect(jsonPath("$.page.number", is(0))) + + //Verify that the title and date of the items match and that they are sorted ascending + .andExpect(jsonPath("$._embedded.items", + contains( + ItemMatcher.matchItemWithTitleAndDateIssued(item2, + "Item 2", "2016-02-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(item4, + "Item 4", "2016-02-11"), + ItemMatcher.matchItemWithTitleAndDateIssued(item6, + "Item 6", "2016-01-13") + ))); + + String adminToken = getAuthToken(admin.getEmail(), password); + getClient(adminToken).perform(get("/api/discover/browses/dateissued/items") + .param("scope", String.valueOf(col2.getID())) + .param("sort", "title,asc") + .param("size", "5")) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + //We expect only the first five items to be present + .andExpect(jsonPath("$.page.size", is(5))) + .andExpect(jsonPath("$.page.totalElements", is(3))) + .andExpect(jsonPath("$.page.totalPages", is(1))) + .andExpect(jsonPath("$.page.number", is(0))) + + //Verify that the title and date of the items match and that they are sorted ascending + .andExpect(jsonPath("$._embedded.items", + contains( + ItemMatcher.matchItemWithTitleAndDateIssued(item2, + "Item 2", "2016-02-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(item4, + "Item 4", "2016-02-11"), + ItemMatcher.matchItemWithTitleAndDateIssued(item6, + "Item 6", "2016-01-13") + ))); + + } @Test public void testBrowseByEntriesStartsWith() throws Exception { @@ -1772,4 +2296,304 @@ public void findBrowseLinksWithMissingParameter() throws Exception { // The status has to be 400 BAD REQUEST .andExpect(status().isBadRequest()); } + + @Test + public void findBrowseItemsWithScopeAsMultipleCollectionAdmin() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with two 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) + .withEntityType("Publication") + .withName("Collection 1") + .build(); + Collection col2 = CollectionBuilder.createCollection(context, child1) + .withEntityType("Publication") + .withName("Collection 2") + .withAdminGroup(eperson) + .build(); + Group collAdminGroup = col2.getAdministrators(); + + Community secondParentCommunity = CommunityBuilder.createCommunity(context) + .withName("Second Parent Community") + .build(); + Community secondChild1 = CommunityBuilder.createSubCommunity(context, secondParentCommunity) + .withName("Second Sub Community") + .build(); + Collection secondCol1 = CollectionBuilder.createCollection(context, secondChild1) + .withEntityType("Publication") + .withName("Second Collection 1") + .build(); + Collection secondCol2 = CollectionBuilder.createCollection(context, child1) + .withEntityType("Publication") + .withName("Second Collection 2") + .withAdminGroup(eperson) + .build(); + Group secondCollAdminGroup = col2.getAdministrators(); + + //2. Two public items with the same subject and another public item that contains that same subject, but also + // another one + // All of the items are readable by an Anonymous user + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("zPublic item more") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry").withSubject("AnotherTest") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest") + .build(); + + Item publicItem3 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 3") + .withIssueDate("2016-02-14") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest") + .build(); + + Item withdrawnItem1 = ItemBuilder.createItem(context, col2) + .withTitle("Withdrawn item 1") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("WithdrawnEntry") + .withdrawn() + .build(); + Item UnDiscoverableItem1 = ItemBuilder.createItem(context, col2) + .withTitle("UnDiscoverable item 1") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("PrivateEntry") + .makeUnDiscoverable() + .build(); + Item privateItem1 = ItemBuilder.createItem(context, col2) + .withTitle("Private item 1") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("PrivateEntry") + .withReaderGroup(collAdminGroup) + .build(); + + // Second community + Item secondPublicItem1 = ItemBuilder.createItem(context, secondCol1) + .withTitle("Second Public item more") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry").withSubject("AnotherTest") + .build(); + + Item secondPublicItem2 = ItemBuilder.createItem(context, secondCol2) + .withTitle("Second Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest") + .build(); + + Item secondPublicItem3 = ItemBuilder.createItem(context, secondCol2) + .withTitle("Second Public item 3") + .withIssueDate("2016-02-14") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest") + .build(); + + Item secondWithdrawnItem1 = ItemBuilder.createItem(context, secondCol2) + .withTitle("Second Withdrawn item 1") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("WithdrawnEntry") + .withdrawn() + .build(); + Item secondUnDiscoverableItem1 = ItemBuilder.createItem(context, secondCol2) + .withTitle("Second UnDiscoverable item 1") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("PrivateEntry") + .makeUnDiscoverable() + .build(); + Item secondPrivateItem1 = ItemBuilder.createItem(context, secondCol2) + .withTitle("Second Private item 1") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("PrivateEntry") + .withReaderGroup(secondCollAdminGroup) + .build(); + + context.restoreAuthSystemState(); + + String token = getAuthToken(eperson.getEmail(), password); + + // USING THE COLLECTION IN THE Parent Community + //** WHEN ** + //A collection admin user browses the author items + getClient(token).perform(get("/api/discover/browses/author/entries") + .param("scope", String.valueOf(col2.getID()))) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be only two elements, the ones that we've added with the requested subject + // in collection 2 + .andExpect(jsonPath("$.page.totalElements", is(2))) + .andExpect(jsonPath("$.page.size", is(20))) + //Verify that the authors + .andExpect(jsonPath("$._embedded.entries", containsInAnyOrder( + BrowseEntryResourceMatcher.matchBrowseEntry("Smith, Maria", 3), + BrowseEntryResourceMatcher.matchBrowseEntry("Doe, Jane", 3) + ))); + //A collection admin user browses the items + getClient(token).perform(get("/api/discover/browses/title/items") + .param("scope", String.valueOf(col2.getID()))) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(3))) + .andExpect(jsonPath("$.page.totalPages", is(1))) + .andExpect(jsonPath("$.page.number", is(0))) + + .andExpect(jsonPath("$._embedded.items", containsInAnyOrder( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, "Public item 2", "2016-02-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, "Public item 3", "2016-02-14"), + ItemMatcher.matchItemWithTitleAndDateIssued(privateItem1, "Private item 1", "2016-02-13") + ))); + + //** WHEN ** + //An anonymous user browses the author items + getClient().perform(get("/api/discover/browses/author/entries") + .param("scope", String.valueOf(col2.getID()))) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be only two elements, the ones that we've added with the requested subject + // in collection 2 + .andExpect(jsonPath("$.page.totalElements", is(2))) + .andExpect(jsonPath("$.page.size", is(20))) + //Verify that the authors + .andExpect(jsonPath("$._embedded.entries", containsInAnyOrder( + BrowseEntryResourceMatcher.matchBrowseEntry("Smith, Maria", 2), + BrowseEntryResourceMatcher.matchBrowseEntry("Doe, Jane", 2) + ))); + //An anonymous user browses the items + getClient().perform(get("/api/discover/browses/title/items") + .param("scope", String.valueOf(col2.getID()))) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(2))) + .andExpect(jsonPath("$.page.totalPages", is(1))) + .andExpect(jsonPath("$.page.number", is(0))) + + .andExpect(jsonPath("$._embedded.items", containsInAnyOrder( + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, "Public item 2", "2016-02-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, "Public item 3", "2016-02-14") + ))); + + + + // USING THE COLLECTION IN THE Second Parent Community + //** WHEN ** + //A collection admin user browses the author items + getClient(token).perform(get("/api/discover/browses/author/entries") + .param("scope", String.valueOf(secondCol2.getID()))) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be only two elements, the ones that we've added with the requested subject + // in collection 2 + .andExpect(jsonPath("$.page.totalElements", is(2))) + .andExpect(jsonPath("$.page.size", is(20))) + //Verify that the authors + .andExpect(jsonPath("$._embedded.entries", containsInAnyOrder( + BrowseEntryResourceMatcher.matchBrowseEntry("Smith, Maria", 3), + BrowseEntryResourceMatcher.matchBrowseEntry("Doe, Jane", 3) + ))); + //A collection admin user browses the items + getClient(token).perform(get("/api/discover/browses/title/items") + .param("scope", String.valueOf(secondCol2.getID()))) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(3))) + .andExpect(jsonPath("$.page.totalPages", is(1))) + .andExpect(jsonPath("$.page.number", is(0))) + + .andExpect(jsonPath("$._embedded.items", containsInAnyOrder( + ItemMatcher.matchItemWithTitleAndDateIssued(secondPublicItem2, "Second Public item 2", "2016-02-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(secondPublicItem3, "Second Public item 3", "2016-02-14"), + ItemMatcher.matchItemWithTitleAndDateIssued(secondPrivateItem1, "Second Private item 1", "2016-02-13") + ))); + + //** WHEN ** + //An anonymous user browses the author items + getClient().perform(get("/api/discover/browses/author/entries") + .param("scope", String.valueOf(secondCol2.getID()))) + //** THEN ** + //The status has to be 200 + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + //We expect there to be only two elements, the ones that we've added with the requested subject + // in collection 2 + .andExpect(jsonPath("$.page.totalElements", is(2))) + .andExpect(jsonPath("$.page.size", is(20))) + //Verify that the authors + .andExpect(jsonPath("$._embedded.entries", containsInAnyOrder( + BrowseEntryResourceMatcher.matchBrowseEntry("Smith, Maria", 2), + BrowseEntryResourceMatcher.matchBrowseEntry("Doe, Jane", 2) + ))); + //An anonymous user browses the items + getClient().perform(get("/api/discover/browses/title/items") + .param("scope", String.valueOf(secondCol2.getID()))) + + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //We expect the content type to be "application/hal+json;charset=UTF-8" + .andExpect(content().contentType(contentType)) + + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(2))) + .andExpect(jsonPath("$.page.totalPages", is(1))) + .andExpect(jsonPath("$.page.number", is(0))) + + .andExpect(jsonPath("$._embedded.items", containsInAnyOrder( + ItemMatcher.matchItemWithTitleAndDateIssued(secondPublicItem2, "Second Public item 2", "2016-02-13"), + ItemMatcher.matchItemWithTitleAndDateIssued(secondPublicItem3, "Second Public item 3", "2016-02-14") + ))); + + } }