Merge pull request #3321 from tdonohue/fix_pagination_count

Fix `/api/core/items` endpoint's `totalElements` count to avoid empty pages at end
This commit is contained in:
Tim Donohue
2021-07-16 13:34:24 -05:00
committed by GitHub
3 changed files with 66 additions and 6 deletions

View File

@@ -23,6 +23,7 @@ import org.dspace.core.Context;
import org.dspace.discovery.SearchServiceException; import org.dspace.discovery.SearchServiceException;
import org.dspace.eperson.EPerson; import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group; import org.dspace.eperson.Group;
import org.dspace.xmlworkflow.WorkflowConfigurationException;
/** /**
* Builder to construct Collection objects. * Builder to construct Collection objects.
@@ -177,7 +178,7 @@ public class CollectionBuilder extends AbstractDSpaceObjectBuilder<Collection> {
/** /**
* Generate and populate a workflow group for the Collection. Obsolete: * Generate and populate a workflow group for the Collection. Obsolete:
* the 3-step workflow model has been removed. * the 3-step workflow model has been removed. Use other withWorkflowGroup() method instead
* *
* @param step number of the workflow step. * @param step number of the workflow step.
* @param members make these users members of the group. * @param members make these users members of the group.
@@ -196,6 +197,25 @@ public class CollectionBuilder extends AbstractDSpaceObjectBuilder<Collection> {
return this; return this;
} }
/**
* Generate and populate a role-based workflow group for the Collection.
*
* @param roleName the rolename for the group
* @param members make these users members of the group.
* @return this
* @throws SQLException passed through.
* @throws AuthorizeException passed through.
*/
public CollectionBuilder withWorkflowGroup(String roleName, EPerson... members)
throws SQLException, AuthorizeException, IOException, WorkflowConfigurationException {
Group g = workflowService.createWorkflowRoleGroup(context, collection, roleName);
for (EPerson e : members) {
groupService.addMember(context, g, e);
}
groupService.update(context, g);
return this;
}
/** /**
* Create an admin group for the collection with the specified members * Create an admin group for the collection with the specified members
* *

View File

@@ -121,7 +121,8 @@ public class ItemRestRepository extends DSpaceObjectRestRepository<Item, ItemRes
@PreAuthorize("hasAuthority('ADMIN')") @PreAuthorize("hasAuthority('ADMIN')")
public Page<ItemRest> findAll(Context context, Pageable pageable) { public Page<ItemRest> findAll(Context context, Pageable pageable) {
try { try {
long total = itemService.countTotal(context); // This endpoint only returns archived items
long total = itemService.countArchivedItems(context);
Iterator<Item> it = itemService.findAll(context, pageable.getPageSize(), Iterator<Item> it = itemService.findAll(context, pageable.getPageSize(),
Math.toIntExact(pageable.getOffset())); Math.toIntExact(pageable.getOffset()));
List<Item> items = new ArrayList<>(); List<Item> items = new ArrayList<>();

View File

@@ -62,6 +62,7 @@ import org.dspace.builder.ItemBuilder;
import org.dspace.builder.RelationshipBuilder; import org.dspace.builder.RelationshipBuilder;
import org.dspace.builder.RelationshipTypeBuilder; import org.dspace.builder.RelationshipTypeBuilder;
import org.dspace.builder.ResourcePolicyBuilder; import org.dspace.builder.ResourcePolicyBuilder;
import org.dspace.builder.WorkflowItemBuilder;
import org.dspace.builder.WorkspaceItemBuilder; import org.dspace.builder.WorkspaceItemBuilder;
import org.dspace.content.Bitstream; import org.dspace.content.Bitstream;
import org.dspace.content.Bundle; import org.dspace.content.Bundle;
@@ -76,6 +77,7 @@ import org.dspace.content.service.CollectionService;
import org.dspace.core.Constants; import org.dspace.core.Constants;
import org.dspace.eperson.EPerson; import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group; import org.dspace.eperson.Group;
import org.dspace.workflow.WorkflowItem;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.Test; import org.junit.Test;
@@ -171,8 +173,17 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
.withName("Sub Community") .withName("Sub Community")
.build(); .build();
Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); // Create one Collection with an enabled "reviewer" Workflow step. This lets us create a WorkflowItem below.
Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); Collection col1 = CollectionBuilder.createCollection(context, child1)
.withName("Collection 1")
.withWorkflowGroup("reviewer", admin)
.build();
// Create a second Collection with a template Item. This is used to ensure that Template Items are
// NOT counted/listed in this endpoint.
Collection col2 = CollectionBuilder.createCollection(context, child1)
.withName("Collection 2")
.withTemplateItem()
.build();
//2. Three public items that are readable by Anonymous with different subjects //2. Three public items that are readable by Anonymous with different subjects
Item publicItem1 = ItemBuilder.createItem(context, col1) Item publicItem1 = ItemBuilder.createItem(context, col1)
@@ -197,6 +208,24 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
.withSubject("ExtraEntry") .withSubject("ExtraEntry")
.build(); .build();
// Create a Workspace Item (which in turn creates an Item with "in_archive=false")
// This is only created to prove that WorkspaceItems are NOT counted/listed in this endpoint
WorkspaceItem workspaceItem = WorkspaceItemBuilder.createWorkspaceItem(context, col2)
.withTitle("In Progress Item")
.withIssueDate("2018-02-05")
.withAuthor("Doe, Jane").withAuthor("Smith, Jennifer")
.build();
Item itemInWorkspace = workspaceItem.getItem();
// Also create a Workflow Item (in the workflow-enabled Collection), to ensure WorkflowItems are
// NOT counted/listed in this endpoint
WorkflowItem workflowItem = WorkflowItemBuilder.createWorkflowItem(context, col1)
.withTitle("Item in Workflow")
.withIssueDate("2019-06-03")
.withAuthor("Smith, Jennifer").withAuthor("Doe, John")
.build();
Item itemInWorkflow = workflowItem.getItem();
context.restoreAuthSystemState(); context.restoreAuthSystemState();
String token = getAuthToken(admin.getEmail(), password); String token = getAuthToken(admin.getEmail(), password);
@@ -212,7 +241,12 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
.andExpect(jsonPath("$._embedded.items", Matchers.not( .andExpect(jsonPath("$._embedded.items", Matchers.not(
Matchers.contains( Matchers.contains(
ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3,
"Public item 3", "2016-02-13") "Public item 3", "2016-02-13"),
ItemMatcher.matchItemWithTitleAndDateIssued(itemInWorkspace,
"In Progress Item", "2018-02-05"),
ItemMatcher.matchItemWithTitleAndDateIssued(itemInWorkflow,
"Item in Workflow", "2019-06-03"),
ItemMatcher.matchItemProperties(col2.getTemplateItem())
) )
))) )))
.andExpect(jsonPath("$._links.first.href", Matchers.allOf( .andExpect(jsonPath("$._links.first.href", Matchers.allOf(
@@ -245,7 +279,12 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1, ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1,
"Public item 1", "2017-10-17"), "Public item 1", "2017-10-17"),
ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2,
"Public item 2", "2016-02-13") "Public item 2", "2016-02-13"),
ItemMatcher.matchItemWithTitleAndDateIssued(itemInWorkspace,
"In Progress Item", "2018-02-05"),
ItemMatcher.matchItemWithTitleAndDateIssued(itemInWorkflow,
"Item in Workflow", "2019-06-03"),
ItemMatcher.matchItemProperties(col2.getTemplateItem())
) )
))) )))
.andExpect(jsonPath("$._links.first.href", Matchers.allOf( .andExpect(jsonPath("$._links.first.href", Matchers.allOf(