Skip to content

Commit

Permalink
Refactor DB services to use new MongoDB API (#18946)
Browse files Browse the repository at this point in the history
* Add support for pagination

* Add utils to extract inserted id

* Add stream utility method

* Use stream utility method

* Add "byId" convenience methods

* Copy tests from PaginatedDbService

* Add license

* Renaming and JavaDoc

* Refactor DBNotificationService

* Fix usage of "id" instead of "_id"

* Separate helper/utils from client API

* Use changed API

* add license

* Remove TODO

* Convert DBJobTriggerService

* Support streaming of any mongo iterable

* interim support for deprecated mongojack bson objects

* Small improvements

* Use shorter method names instead of bean conventions

* Add fields for utils and pagination helper

* Change test to catch type serialization issue

The test was previously not covering the issue with polymorphic types
of trigger schedules for which the workaround with toDBUpdate was
created.

* Remove workaround for trigger schedule updates

* Remove obsolete test

* Remove dispensable interface for utility class

* Introduce MongoEntity interface

* Add @nullable annotation

* Implement MongoEntity

* Simplify constraints filter when fetching triggers

* Add idEq helper function

* Don't return nulls from #insertedId

* Use idEq in utils

* Add tests

* Use idEq

* Rename postProcessedPage to page

* Make pagination helper immutable

* Add collation support to pagination helper

* fix compile error after method rename

* Change wording

Co-authored-by: Bernd Ahlers <[email protected]>

* Change wording

Co-authored-by: Bernd Ahlers <[email protected]>

* wording

Co-authored-by: Bernd Ahlers <[email protected]>

* Add SortOrder enum

* Remove redundant sort method from pagination helper

* Use SortOrder in PageListResponse

* Use SortOrder in DBNotificationService

* Document immutability of pagination helper

* Add locale to call of toLowerCase

* Add locale to call of toLowerCase

* Fix wrong order type used in typescript mock

* Use Indexes helper

* Use saturated cast to int

* Use static import for Filters.gte

* More saturated casts to int

---------

Co-authored-by: Bernd Ahlers <[email protected]>
  • Loading branch information
thll and bernd authored May 8, 2024
1 parent 782c03f commit 8c7c892
Show file tree
Hide file tree
Showing 17 changed files with 289 additions and 418 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,46 +16,77 @@
*/
package org.graylog.events.notifications;

import com.mongodb.client.MongoCollection;
import jakarta.inject.Inject;
import org.bson.conversions.Bson;
import org.graylog.security.entities.EntityOwnershipService;
import org.graylog2.bindings.providers.MongoJackObjectMapperProvider;
import org.graylog2.database.MongoConnection;
import org.graylog2.database.PaginatedDbService;
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.plugin.database.users.User;
import org.graylog2.search.SearchQuery;

import jakarta.inject.Inject;

import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class DBNotificationService extends PaginatedDbService<NotificationDto> {
import static org.graylog2.database.utils.MongoUtils.idEq;
import static org.graylog2.database.utils.MongoUtils.insertedIdAsString;
import static org.graylog2.database.utils.MongoUtils.stream;

public class DBNotificationService {
private static final String NOTIFICATION_COLLECTION_NAME = "event_notifications";

private final EntityOwnershipService entityOwnerShipService;
private final MongoCollection<NotificationDto> collection;
private final MongoUtils<NotificationDto> mongoUtils;
private final MongoPaginationHelper<NotificationDto> paginationHelper;

@Inject
public DBNotificationService(MongoConnection mongoConnection,
MongoJackObjectMapperProvider mapper,
public DBNotificationService(MongoCollections mongoCollections,
EntityOwnershipService entityOwnerShipService) {
super(mongoConnection, mapper, NotificationDto.class, NOTIFICATION_COLLECTION_NAME);
this.collection = mongoCollections.collection(NOTIFICATION_COLLECTION_NAME, NotificationDto.class);
this.mongoUtils = mongoCollections.utils(collection);
this.paginationHelper = mongoCollections.paginationHelper(collection);
this.entityOwnerShipService = entityOwnerShipService;
}

public PaginatedList<NotificationDto> searchPaginated(SearchQuery query, Predicate<NotificationDto> filter,
String sortByField, String sortOrder, int page, int perPage) {
return findPaginatedWithQueryFilterAndSort(query.toDBQuery(), filter,
getSortBuilder(sortOrder, sortByField), page, perPage);
Bson sort, int page, int perPage) {
return paginationHelper
.filter(query.toBson())
.sort(sort)
.perPage(perPage)
.page(page, filter);
}

public NotificationDto saveWithOwnership(NotificationDto notificationDto, User user) {
final NotificationDto dto = super.save(notificationDto);
final NotificationDto dto = save(notificationDto);
entityOwnerShipService.registerNewEventNotification(dto.id(), user);
return dto;
}

@Override
public NotificationDto save(NotificationDto notificationDto) {
if (notificationDto.id() != null) {
collection.replaceOne(idEq(notificationDto.id()), notificationDto);
return notificationDto;
} else {
final var id = insertedIdAsString(collection.insertOne(notificationDto));
return notificationDto.toBuilder().id(id).build();
}
}

public int delete(String id) {
entityOwnerShipService.unregisterEventNotification(id);
return super.delete(id);
return (int) collection.deleteOne(idEq(id)).getDeletedCount();
}

public Optional<NotificationDto> get(String id) {
return mongoUtils.getById(id);
}

public Stream<NotificationDto> streamAll() {
return stream(collection.find());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.graylog2.contentpacks.ContentPackable;
import org.graylog2.contentpacks.EntityDescriptorIds;
import org.graylog2.contentpacks.model.entities.references.ValueReference;
import org.graylog2.database.MongoEntity;
import org.graylog2.plugin.rest.ValidationResult;
import org.mongojack.Id;
import org.mongojack.ObjectId;
Expand All @@ -36,7 +37,7 @@
@AutoValue
@JsonAutoDetect
@JsonDeserialize(builder = NotificationDto.Builder.class)
public abstract class NotificationDto implements ContentPackable {
public abstract class NotificationDto implements ContentPackable, MongoEntity {
public static final String FIELD_ID = "id";
public static final String FIELD_TITLE = "title";
public static final String FIELD_DESCRIPTION = "description";
Expand Down Expand Up @@ -108,9 +109,9 @@ public static Builder create() {
public Object toContentPackEntity(EntityDescriptorIds entityDescriptorIds) {
final EventNotificationConfigEntity config = config().toContentPackEntity(entityDescriptorIds);
return NotificationEntity.builder()
.description(ValueReference.of(description()))
.title(ValueReference.of(title()))
.config(config)
.build();
.description(ValueReference.of(description()))
.title(ValueReference.of(title()))
.config(config)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,23 @@
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import jakarta.inject.Inject;
import jakarta.validation.constraints.NotBlank;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.graylog.events.audit.EventsAuditEventTypes;
Expand All @@ -43,6 +60,7 @@
import org.graylog2.plugin.rest.PluginRestResource;
import org.graylog2.plugin.rest.ValidationResult;
import org.graylog2.rest.models.PaginatedResponse;
import org.graylog2.rest.models.SortOrder;
import org.graylog2.rest.models.tools.responses.PageListResponse;
import org.graylog2.rest.resources.entities.EntityAttribute;
import org.graylog2.rest.resources.entities.EntityDefaults;
Expand All @@ -53,29 +71,8 @@
import org.graylog2.shared.rest.resources.RestResource;
import org.graylog2.shared.security.RestPermissions;

import jakarta.inject.Inject;

import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;

import jakarta.validation.constraints.NotBlank;

import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

import java.util.List;
import java.util.Locale;
import java.util.Map;
Expand Down Expand Up @@ -144,14 +141,14 @@ public PageListResponse<NotificationDto> getPage(@ApiParam(name = "page") @Query
allowableValues = "title,description,type")
@DefaultValue(DEFAULT_SORT_FIELD) @QueryParam("sort") String sort,
@ApiParam(name = "order", value = "The sort direction", allowableValues = "asc, desc")
@DefaultValue(DEFAULT_SORT_DIRECTION) @QueryParam("order") String order) {
@DefaultValue(DEFAULT_SORT_DIRECTION) @QueryParam("order") SortOrder order) {
final SearchQuery searchQuery = searchQueryParser.parse(query);
if ("type".equals(sort)) {
sort = "config.type";
}
final PaginatedList<NotificationDto> result = dbNotificationService.searchPaginated(searchQuery, notification -> {
return isPermitted(RestPermissions.EVENT_NOTIFICATIONS_READ, notification.id());
}, sort, order, page, perPage);
}, order.toBsonSort(sort), page, perPage);


return PageListResponse.create(query, result.pagination(),
Expand All @@ -167,7 +164,7 @@ public PaginatedResponse<NotificationDto> listNotifications(@ApiParam(name = "pa
final SearchQuery searchQuery = searchQueryParser.parse(query);
final PaginatedList<NotificationDto> result = dbNotificationService.searchPaginated(searchQuery, notification -> {
return isPermitted(RestPermissions.EVENT_NOTIFICATIONS_READ, notification.id());
}, "title", "asc", page, perPage);
}, SortOrder.ASCENDING.toBsonSort("title"), page, perPage);
return PaginatedResponse.create("notifications", result, query);
}

Expand Down
Loading

0 comments on commit 8c7c892

Please sign in to comment.