Skip to content

Commit

Permalink
Add basic pagination to /groups/[uuid]/epersons endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
tdonohue committed Oct 31, 2023
1 parent 9dbfa17 commit 74c7235
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 7 deletions.
Expand Up @@ -567,14 +567,29 @@ public List<String> getDeleteConstraints(Context context, EPerson ePerson) throw

@Override
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.
if (CollectionUtils.isNotEmpty(groups)) {
return ePersonDAO.findByGroups(c, groups);
return ePersonDAO.findByGroups(c, groups, pageSize, offset);
} else {
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
public List<EPerson> findEPeopleWithSubscription(Context context) throws SQLException {
return ePersonDAO.findAllSubscribers(context);
Expand Down
24 changes: 23 additions & 1 deletion dspace-api/src/main/java/org/dspace/eperson/dao/EPersonDAO.java
Expand Up @@ -38,7 +38,29 @@ public List<EPerson> search(Context context, String query, List<MetadataField> q

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;

Expand Down
Expand Up @@ -112,7 +112,7 @@ public List<EPerson> findAll(Context context, MetadataField metadataSortField, S
}

@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,
"SELECT DISTINCT e FROM EPerson e " +
"JOIN e.groups g " +
Expand All @@ -125,7 +125,24 @@ public List<EPerson> findByGroups(Context context, Set<Group> groups) throws SQL

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
Expand Down
Expand Up @@ -252,14 +252,43 @@ public EPerson create(Context context) 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 groups set of eperson groups
* @return a list of epeople
* @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.
Expand Down
Expand Up @@ -8,14 +8,18 @@
package org.dspace.app.rest.repository;

import java.sql.SQLException;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;

import org.dspace.app.rest.model.GroupRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.eperson.service.EPersonService;
import org.dspace.eperson.service.GroupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
Expand All @@ -31,6 +35,9 @@
public class GroupEPersonLinkRepository extends AbstractDSpaceRestRepository
implements LinkRestRepository {

@Autowired
EPersonService epersonService;

@Autowired
GroupService groupService;

Expand All @@ -45,7 +52,11 @@ public Page<GroupRest> getMembers(@Nullable HttpServletRequest request,
if (group == null) {
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) {
throw new RuntimeException(e);
}
Expand Down

0 comments on commit 74c7235

Please sign in to comment.