From 0af1c033d9bda9957cba2ad5cf7f6b0fb7a91cfa Mon Sep 17 00:00:00 2001 From: Othello Maurer Date: Thu, 21 Nov 2024 14:36:17 +0100 Subject: [PATCH] Refactor PaginatedUserService to use new MongoDB API (#21009) --- .../rest/AuthServiceBackendsResource.java | 3 +- .../authzroles/AuthzRolesResource.java | 5 +- .../rest/resources/users/UsersResource.java | 3 +- .../graylog2/users/PaginatedUserService.java | 86 ++++++++++++------- .../org/graylog2/users/UserOverviewDTO.java | 3 +- 5 files changed, 62 insertions(+), 38 deletions(-) diff --git a/graylog2-server/src/main/java/org/graylog/security/authservice/rest/AuthServiceBackendsResource.java b/graylog2-server/src/main/java/org/graylog/security/authservice/rest/AuthServiceBackendsResource.java index da1df48f163e..4aa319f9cba2 100644 --- a/graylog2-server/src/main/java/org/graylog/security/authservice/rest/AuthServiceBackendsResource.java +++ b/graylog2-server/src/main/java/org/graylog/security/authservice/rest/AuthServiceBackendsResource.java @@ -35,6 +35,7 @@ import org.graylog2.plugin.rest.ValidationResult; import org.graylog2.rest.PaginationParameters; import org.graylog2.rest.models.PaginatedResponse; +import org.graylog2.rest.models.SortOrder; import org.graylog2.search.SearchQuery; import org.graylog2.search.SearchQueryField; import org.graylog2.search.SearchQueryParser; @@ -195,7 +196,7 @@ public PaginatedResponse getUsers( @ApiParam(name = "sort", value = "The field to sort the result on", required = true, allowableValues = "username,full_name,email") @DefaultValue(UserOverviewDTO.FIELD_FULL_NAME) @QueryParam("sort") String sort, @ApiParam(name = "order", value = "The sort direction", allowableValues = "asc, desc") - @DefaultValue("asc") @QueryParam("order") String order, + @DefaultValue("asc") @QueryParam("order") SortOrder order, @ApiParam(name = "backendId", required = true) @PathParam("backendId") @NotBlank String backendId ) { final AuthServiceBackendDTO activeConfig = loadConfig(backendId); diff --git a/graylog2-server/src/main/java/org/graylog/security/authzroles/AuthzRolesResource.java b/graylog2-server/src/main/java/org/graylog/security/authzroles/AuthzRolesResource.java index f750ea65a420..5cbac8c4d84c 100644 --- a/graylog2-server/src/main/java/org/graylog/security/authzroles/AuthzRolesResource.java +++ b/graylog2-server/src/main/java/org/graylog/security/authzroles/AuthzRolesResource.java @@ -30,6 +30,7 @@ import org.graylog2.plugin.database.ValidationException; import org.graylog2.plugin.database.users.User; import org.graylog2.rest.models.PaginatedResponse; +import org.graylog2.rest.models.SortOrder; import org.graylog2.search.SearchQuery; import org.graylog2.search.SearchQueryField; import org.graylog2.search.SearchQueryParser; @@ -151,7 +152,7 @@ public PaginatedResponse getUsersForRole( allowableValues = "username,full_name,email") @DefaultValue(AuthzRoleDTO.FIELD_NAME) @QueryParam("sort") String sort, @ApiParam(name = "order", value = "The sort direction", allowableValues = "asc, desc") - @DefaultValue("asc") @QueryParam("order") String order) { + @DefaultValue("asc") @QueryParam("order") SortOrder order) { SearchQuery searchQuery; try { @@ -283,7 +284,7 @@ public void delete(@ApiParam(name = "roleId") @PathParam("roleId") @NotBlank Str private Map>> userRoleContext(PaginatedList roles) { final PaginatedList users = paginatedUserService.findPaginatedByRole(new SearchQuery(""), - 1, 0, UserOverviewDTO.FIELD_USERNAME, "asc", + 1, 0, UserOverviewDTO.FIELD_USERNAME, SortOrder.ASCENDING, roles.stream().map(AuthzRoleDTO::id).collect(Collectors.toSet())); final Map>> userRoleMap = new HashMap<>(roles.size()); roles.forEach(authzRoleDTO -> { diff --git a/graylog2-server/src/main/java/org/graylog2/rest/resources/users/UsersResource.java b/graylog2-server/src/main/java/org/graylog2/rest/resources/users/UsersResource.java index c3b6c11bfc7f..5bc563b229dc 100644 --- a/graylog2-server/src/main/java/org/graylog2/rest/resources/users/UsersResource.java +++ b/graylog2-server/src/main/java/org/graylog2/rest/resources/users/UsersResource.java @@ -45,6 +45,7 @@ import org.graylog2.plugin.database.ValidationException; import org.graylog2.plugin.database.users.User; import org.graylog2.rest.models.PaginatedResponse; +import org.graylog2.rest.models.SortOrder; import org.graylog2.rest.models.users.requests.ChangePasswordRequest; import org.graylog2.rest.models.users.requests.CreateUserRequest; import org.graylog2.rest.models.users.requests.PermissionEditRequest; @@ -279,7 +280,7 @@ public PaginatedResponse getPage(@ApiParam(name = "page") @Quer allowableValues = "title,description") @DefaultValue(UserOverviewDTO.FIELD_FULL_NAME) @QueryParam("sort") String sort, @ApiParam(name = "order", value = "The sort direction", allowableValues = "asc, desc") - @DefaultValue("asc") @QueryParam("order") String order) { + @DefaultValue("asc") @QueryParam("order") SortOrder order) { SearchQuery searchQuery; final AllUserSessions sessions = AllUserSessions.create(sessionService); diff --git a/graylog2-server/src/main/java/org/graylog2/users/PaginatedUserService.java b/graylog2-server/src/main/java/org/graylog2/users/PaginatedUserService.java index 1e21f52bff9c..683646f004df 100644 --- a/graylog2-server/src/main/java/org/graylog2/users/PaginatedUserService.java +++ b/graylog2-server/src/main/java/org/graylog2/users/PaginatedUserService.java @@ -16,72 +16,92 @@ */ package org.graylog2.users; +import com.mongodb.client.MongoCollection; +import jakarta.inject.Inject; import org.apache.commons.lang3.StringUtils; -import org.graylog2.bindings.providers.MongoJackObjectMapperProvider; -import org.graylog2.database.MongoConnection; -import org.graylog2.database.PaginatedDbService; +import org.bson.types.ObjectId; +import org.graylog2.database.MongoCollections; import org.graylog2.database.PaginatedList; +import org.graylog2.database.pagination.MongoPaginationHelper; +import org.graylog2.database.utils.MongoUtils; +import org.graylog2.rest.models.SortOrder; import org.graylog2.search.SearchQuery; -import org.mongojack.DBQuery; -import org.mongojack.DBSort; - -import jakarta.inject.Inject; -import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static com.google.common.base.Preconditions.checkArgument; +import static com.mongodb.client.model.Filters.and; +import static com.mongodb.client.model.Filters.eq; +import static com.mongodb.client.model.Filters.in; +import static org.graylog2.database.utils.MongoUtils.stringIdsIn; -public class PaginatedUserService extends PaginatedDbService { +public class PaginatedUserService { private static final String COLLECTION_NAME = "users"; + private final MongoCollection collection; + private final MongoPaginationHelper paginationHelper; @Inject - public PaginatedUserService(MongoConnection mongoConnection, - MongoJackObjectMapperProvider mapper) { - super(mongoConnection, mapper, UserOverviewDTO.class, COLLECTION_NAME); + public PaginatedUserService(MongoCollections mongoCollections) { + collection = mongoCollections.collection(COLLECTION_NAME, UserOverviewDTO.class); + paginationHelper = mongoCollections.paginationHelper(collection); } public long count() { - return db.count(); + return collection.countDocuments(); } public PaginatedList findPaginated(SearchQuery searchQuery, int page, - int perPage, String sortField, String order) { - final DBQuery.Query dbQuery = searchQuery.toDBQuery(); - final DBSort.SortBuilder sortBuilder = getSortBuilder(order, sortField); - return findPaginatedWithQueryAndSort(dbQuery, sortBuilder, page, perPage); + int perPage, String sortField, SortOrder order) { + + return paginationHelper + .filter(searchQuery.toBson()) + .sort(order.toBsonSort(sortField)) + .perPage(perPage) + .page(page); } public PaginatedList findPaginatedByUserId(SearchQuery searchQuery, int page, - int perPage, String sortField, String order, + int perPage, String sortField, SortOrder order, Set userIds) { - final DBQuery.Query dbQuery = searchQuery.toDBQuery() - .in("_id", userIds); - final DBSort.SortBuilder sortBuilder = getSortBuilder(order, sortField); - return findPaginatedWithQueryAndSort(dbQuery, sortBuilder, page, perPage); + + return paginationHelper + .filter(and(searchQuery.toBson(), stringIdsIn(userIds))) + .sort(order.toBsonSort(sortField)) + .perPage(perPage) + .page(page); } public PaginatedList findPaginatedByRole(SearchQuery searchQuery, int page, - int perPage, String sortField, String order, + int perPage, String sortField, SortOrder order, Set roleIds) { - final DBQuery.Query dbQuery = searchQuery.toDBQuery() - .in(UserImpl.ROLES, roleIds); - final DBSort.SortBuilder sortBuilder = getSortBuilder(order, sortField); - return findPaginatedWithQueryAndSort(dbQuery, sortBuilder, page, perPage); + + final var roleObjectIds = roleIds.stream().map(ObjectId::new).collect(Collectors.toSet()); + + return paginationHelper + .filter(and(searchQuery.toBson(), in(UserImpl.ROLES, roleObjectIds))) + .sort(order.toBsonSort(sortField)) + .perPage(perPage) + .page(page); } public PaginatedList findPaginatedByAuthServiceBackend(SearchQuery searchQuery, int page, int perPage, String sortField, - String order, + SortOrder order, String authServiceBackendId) { checkArgument(!StringUtils.isBlank(authServiceBackendId), "authServiceBackendId cannot be blank"); - final DBQuery.Query query = DBQuery.and( - DBQuery.is(UserImpl.AUTH_SERVICE_ID, Optional.of(authServiceBackendId)), - searchQuery.toDBQuery() - ); - return findPaginatedWithQueryAndSort(query, getSortBuilder(order, sortField), page, perPage); + return paginationHelper + .filter(and(eq(UserImpl.AUTH_SERVICE_ID, authServiceBackendId), searchQuery.toBson())) + .sort(order.toBsonSort(sortField)) + .perPage(perPage) + .page(page); + } + + public Stream streamAll() { + return MongoUtils.stream(collection.find()); } } diff --git a/graylog2-server/src/main/java/org/graylog2/users/UserOverviewDTO.java b/graylog2-server/src/main/java/org/graylog2/users/UserOverviewDTO.java index dd4326a9d2d8..2d4b947107c6 100644 --- a/graylog2-server/src/main/java/org/graylog2/users/UserOverviewDTO.java +++ b/graylog2-server/src/main/java/org/graylog2/users/UserOverviewDTO.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.google.auto.value.AutoValue; +import org.graylog2.database.MongoEntity; import org.graylog2.plugin.database.users.User; import org.graylog2.security.MongoDbSession; import org.mongojack.Id; @@ -35,7 +36,7 @@ @AutoValue @JsonDeserialize(builder = UserOverviewDTO.Builder.class) -public abstract class UserOverviewDTO { +public abstract class UserOverviewDTO implements MongoEntity { public static final String FIELD_ID = "id"; private static final String FIELD_AUTH_SERVICE_ID = "auth_service_id";