Add basic pagination to /groups/[uuid]/epersons endpoint

This commit is contained in:
Tim Donohue
2023-09-14 16:08:25 -05:00
parent 9dbfa171c8
commit 74c72354b4
5 changed files with 101 additions and 7 deletions

View File

@@ -567,14 +567,29 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl<EPerson> impleme
@Override @Override
public List<EPerson> findByGroups(Context c, Set<Group> groups) throws SQLException { public List<EPerson> findByGroups(Context c, Set<Group> groups) throws SQLException {
return findByGroups(c, groups, -1, -1);
}
@Override
public List<EPerson> findByGroups(Context c, Set<Group> groups, int pageSize, int offset) throws SQLException {
//Make sure we at least have one group, if not don't even bother searching. //Make sure we at least have one group, if not don't even bother searching.
if (CollectionUtils.isNotEmpty(groups)) { if (CollectionUtils.isNotEmpty(groups)) {
return ePersonDAO.findByGroups(c, groups); return ePersonDAO.findByGroups(c, groups, pageSize, offset);
} else { } else {
return new ArrayList<>(); return new ArrayList<>();
} }
} }
@Override
public int countByGroups(Context c, Set<Group> groups) throws SQLException {
//Make sure we at least have one group, if not don't even bother counting.
if (CollectionUtils.isNotEmpty(groups)) {
return ePersonDAO.countByGroups(c, groups);
} else {
return 0;
}
}
@Override @Override
public List<EPerson> findEPeopleWithSubscription(Context context) throws SQLException { public List<EPerson> findEPeopleWithSubscription(Context context) throws SQLException {
return ePersonDAO.findAllSubscribers(context); return ePersonDAO.findAllSubscribers(context);

View File

@@ -38,7 +38,29 @@ public interface EPersonDAO extends DSpaceObjectDAO<EPerson>, DSpaceObjectLegacy
public int searchResultCount(Context context, String query, List<MetadataField> queryFields) throws SQLException; public int searchResultCount(Context context, String query, List<MetadataField> queryFields) throws SQLException;
public List<EPerson> findByGroups(Context context, Set<Group> groups) throws SQLException; /**
* Find all EPersons who are a member of one or more of the listed groups in a paginated fashion. Order is
* indeterminate.
*
* @param context current Context
* @param groups Set of group(s) to check membership in
* @param pageSize number of EPerson objects to load at one time. Set to <=0 to disable pagination
* @param offset number of page to load (starting with 1). Set to <=0 to disable pagination
* @return List of all EPersons who are a member of one or more groups.
* @throws SQLException
*/
List<EPerson> findByGroups(Context context, Set<Group> groups, int pageSize, int offset) throws SQLException;
/**
* Count total number of EPersons who are a member of one or more of the listed groups. This provides the total
* number of results to expect from corresponding findByGroups() for pagination purposes.
*
* @param context current Context
* @param groups Set of group(s) to check membership in
* @return total number of (unique) EPersons who are a member of one or more groups.
* @throws SQLException
*/
int countByGroups(Context context, Set<Group> groups) throws SQLException;
public List<EPerson> findWithPasswordWithoutDigestAlgorithm(Context context) throws SQLException; public List<EPerson> findWithPasswordWithoutDigestAlgorithm(Context context) throws SQLException;

View File

@@ -112,7 +112,7 @@ public class EPersonDAOImpl extends AbstractHibernateDSODAO<EPerson> implements
} }
@Override @Override
public List<EPerson> findByGroups(Context context, Set<Group> groups) throws SQLException { public List<EPerson> findByGroups(Context context, Set<Group> groups, int pageSize, int offset) throws SQLException {
Query query = createQuery(context, Query query = createQuery(context,
"SELECT DISTINCT e FROM EPerson e " + "SELECT DISTINCT e FROM EPerson e " +
"JOIN e.groups g " + "JOIN e.groups g " +
@@ -125,7 +125,24 @@ public class EPersonDAOImpl extends AbstractHibernateDSODAO<EPerson> implements
query.setParameter("idList", idList); query.setParameter("idList", idList);
return list(query); return list(query, pageSize, offset);
}
@Override
public int countByGroups(Context context, Set<Group> groups) throws SQLException {
Query query = createQuery(context,
"SELECT count(DISTINCT e) FROM EPerson e " +
"JOIN e.groups g " +
"WHERE g.id IN (:idList) ");
List<UUID> idList = new ArrayList<>(groups.size());
for (Group group : groups) {
idList.add(group.getID());
}
query.setParameter("idList", idList);
return count(query);
} }
@Override @Override

View File

@@ -252,14 +252,43 @@ public interface EPersonService extends DSpaceObjectService<EPerson>, DSpaceObje
public List<String> getDeleteConstraints(Context context, EPerson ePerson) throws SQLException; public List<String> getDeleteConstraints(Context context, EPerson ePerson) throws SQLException;
/** /**
* Retrieve all accounts which belong to at least one of the specified groups. * Retrieve all EPerson accounts which belong to at least one of the specified groups.
* <P>
* WARNING: This method should be used sparingly, as it could have performance issues for Groups with very large
* lists of members. In that situation, a very large number of EPerson objects will be loaded into memory.
* See https://github.com/DSpace/DSpace/issues/9052
* <P>
* For better performance, use the paginated version of this method.
* *
* @param c The relevant DSpace Context. * @param c The relevant DSpace Context.
* @param groups set of eperson groups * @param groups set of eperson groups
* @return a list of epeople * @return a list of epeople
* @throws SQLException An exception that provides information on a database access error or other errors. * @throws SQLException An exception that provides information on a database access error or other errors.
*/ */
public List<EPerson> findByGroups(Context c, Set<Group> groups) throws SQLException; List<EPerson> findByGroups(Context c, Set<Group> groups) throws SQLException;
/**
* Retrieve all EPerson accounts which belong to at least one of the specified groups, in a paginated fashion.
*
* @param c The relevant DSpace Context.
* @param groups Set of group(s) to check membership in
* @param pageSize number of EPerson objects to load at one time. Set to <=0 to disable pagination
* @param offset number of page to load (starting with 1). Set to <=0 to disable pagination
* @return a list of epeople
* @throws SQLException An exception that provides information on a database access error or other errors.
*/
List<EPerson> findByGroups(Context c, Set<Group> groups, int pageSize, int offset) throws SQLException;
/**
* Count all EPerson accounts which belong to at least one of the specified groups. This provides the total
* number of results to expect from corresponding findByGroups() for pagination purposes.
*
* @param c The relevant DSpace Context.
* @param groups Set of group(s) to check membership in
* @return total number of (unique) EPersons who are a member of one or more groups.
* @throws SQLException An exception that provides information on a database access error or other errors.
*/
int countByGroups(Context c, Set<Group> groups) throws SQLException;
/** /**
* Retrieve all accounts which are subscribed to receive information about new items. * Retrieve all accounts which are subscribed to receive information about new items.

View File

@@ -8,6 +8,8 @@
package org.dspace.app.rest.repository; package org.dspace.app.rest.repository;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@@ -15,7 +17,9 @@ import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.model.GroupRest; import org.dspace.app.rest.model.GroupRest;
import org.dspace.app.rest.projection.Projection; import org.dspace.app.rest.projection.Projection;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group; import org.dspace.eperson.Group;
import org.dspace.eperson.service.EPersonService;
import org.dspace.eperson.service.GroupService; import org.dspace.eperson.service.GroupService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -31,6 +35,9 @@ import org.springframework.stereotype.Component;
public class GroupEPersonLinkRepository extends AbstractDSpaceRestRepository public class GroupEPersonLinkRepository extends AbstractDSpaceRestRepository
implements LinkRestRepository { implements LinkRestRepository {
@Autowired
EPersonService epersonService;
@Autowired @Autowired
GroupService groupService; GroupService groupService;
@@ -45,7 +52,11 @@ public class GroupEPersonLinkRepository extends AbstractDSpaceRestRepository
if (group == null) { if (group == null) {
throw new ResourceNotFoundException("No such group: " + groupId); throw new ResourceNotFoundException("No such group: " + groupId);
} }
return converter.toRestPage(group.getMembers(), optionalPageable, projection); int total = epersonService.countByGroups(context, Set.of(group));
Pageable pageable = utils.getPageable(optionalPageable);
List<EPerson> members = epersonService.findByGroups(context, Set.of(group), pageable.getPageSize(),
Math.toIntExact(pageable.getOffset()));
return converter.toRestPage(members, pageable, total, projection);
} catch (SQLException e) { } catch (SQLException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }