diff --git a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java index b4ba871edf..308f7908cd 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java @@ -329,12 +329,17 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple @Override public void markNotificationAsRead(TenantId tenantId, UserId recipientId, NotificationId notificationId) { + Notification notification = notificationService.findNotificationById(tenantId, notificationId); + if (notification == null) { + return; + } boolean updated = notificationService.markNotificationAsRead(tenantId, recipientId, notificationId); if (updated) { log.trace("Marked notification {} as read (recipient id: {}, tenant id: {})", notificationId, recipientId, tenantId); NotificationUpdate update = NotificationUpdate.builder() .updated(true) .notificationId(notificationId.getId()) + .notificationType(notification.getType()) .newStatus(NotificationStatus.READ) .build(); onNotificationUpdate(tenantId, recipientId, update); diff --git a/application/src/main/java/org/thingsboard/server/service/ws/notification/DefaultNotificationCommandsHandler.java b/application/src/main/java/org/thingsboard/server/service/ws/notification/DefaultNotificationCommandsHandler.java index 0937275a0d..5490148b74 100644 --- a/application/src/main/java/org/thingsboard/server/service/ws/notification/DefaultNotificationCommandsHandler.java +++ b/application/src/main/java/org/thingsboard/server/service/ws/notification/DefaultNotificationCommandsHandler.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.ws.notification; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -26,6 +27,7 @@ import org.thingsboard.server.common.data.id.NotificationId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.Notification; import org.thingsboard.server.common.data.notification.NotificationStatus; +import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.dao.notification.NotificationService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; @@ -76,6 +78,7 @@ public class DefaultNotificationCommandsHandler implements NotificationCommandsH .entityId(securityCtx.getId()) .updateProcessor(this::handleNotificationsSubscriptionUpdate) .limit(cmd.getLimit()) + .notificationTypes(CollectionUtils.isNotEmpty(cmd.getTypes()) ? cmd.getTypes() : NotificationType.all) .build(); localSubscriptionService.addSubscription(subscription); @@ -103,8 +106,8 @@ public class DefaultNotificationCommandsHandler implements NotificationCommandsH private void fetchUnreadNotifications(NotificationsSubscription subscription) { log.trace("[{}, subId: {}] Fetching unread notifications from DB", subscription.getSessionId(), subscription.getSubscriptionId()); - PageData notifications = notificationService.findLatestUnreadNotificationsByRecipientId(subscription.getTenantId(), - (UserId) subscription.getEntityId(), subscription.getLimit()); + PageData notifications = notificationService.findLatestUnreadNotificationsByRecipientIdAndNotificationTypes(subscription.getTenantId(), + (UserId) subscription.getEntityId(), subscription.getNotificationTypes(), subscription.getLimit()); subscription.getLatestUnreadNotifications().clear(); notifications.getData().forEach(notification -> { subscription.getLatestUnreadNotifications().put(notification.getUuidId(), notification); @@ -137,6 +140,11 @@ public class DefaultNotificationCommandsHandler implements NotificationCommandsH log.trace("[{}, subId: {}] Handling notification update: {}", subscription.getSessionId(), subscription.getSubscriptionId(), update); Notification notification = update.getNotification(); UUID notificationId = notification != null ? notification.getUuidId() : update.getNotificationId(); + NotificationType notificationType = notification != null ? notification.getType() : update.getNotificationType(); + if (notificationType != null && !subscription.checkNotificationType(notificationType)) { + return; + } + if (update.isCreated()) { subscription.getLatestUnreadNotifications().put(notificationId, notification); subscription.getTotalUnreadCounter().incrementAndGet(); diff --git a/application/src/main/java/org/thingsboard/server/service/ws/notification/cmd/NotificationsSubCmd.java b/application/src/main/java/org/thingsboard/server/service/ws/notification/cmd/NotificationsSubCmd.java index e022d2c49f..f827f46209 100644 --- a/application/src/main/java/org/thingsboard/server/service/ws/notification/cmd/NotificationsSubCmd.java +++ b/application/src/main/java/org/thingsboard/server/service/ws/notification/cmd/NotificationsSubCmd.java @@ -18,6 +18,9 @@ package org.thingsboard.server.service.ws.notification.cmd; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import org.thingsboard.server.common.data.notification.NotificationType; + +import java.util.Set; @Data @NoArgsConstructor @@ -25,4 +28,5 @@ import lombok.NoArgsConstructor; public class NotificationsSubCmd implements WsCmd { private int cmdId; private int limit; + private Set types; } diff --git a/application/src/main/java/org/thingsboard/server/service/ws/notification/cmd/UnreadNotificationsUpdate.java b/application/src/main/java/org/thingsboard/server/service/ws/notification/cmd/UnreadNotificationsUpdate.java index e64624d16e..c0de2103ed 100644 --- a/application/src/main/java/org/thingsboard/server/service/ws/notification/cmd/UnreadNotificationsUpdate.java +++ b/application/src/main/java/org/thingsboard/server/service/ws/notification/cmd/UnreadNotificationsUpdate.java @@ -24,13 +24,13 @@ import org.thingsboard.server.common.data.notification.Notification; import org.thingsboard.server.service.ws.telemetry.cmd.v2.CmdUpdate; import org.thingsboard.server.service.ws.telemetry.cmd.v2.CmdUpdateType; -import java.util.Collection; +import java.util.List; @Getter @ToString(exclude = "notifications") public class UnreadNotificationsUpdate extends CmdUpdate { - private final Collection notifications; + private final List notifications; private final Notification update; private final int totalUnreadCount; @@ -38,7 +38,7 @@ public class UnreadNotificationsUpdate extends CmdUpdate { @JsonCreator public UnreadNotificationsUpdate(@JsonProperty("cmdId") int cmdId, @JsonProperty("errorCode") int errorCode, @JsonProperty("errorMsg") String errorMsg, - @JsonProperty("notifications") Collection notifications, + @JsonProperty("notifications") List notifications, @JsonProperty("update") Notification update, @JsonProperty("totalUnreadCount") int totalUnreadCount) { super(cmdId, errorCode, errorMsg); diff --git a/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java b/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java index b00231a5c9..41191bc8d2 100644 --- a/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java +++ b/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java @@ -21,6 +21,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.notification.Notification; import org.thingsboard.server.common.data.notification.NotificationStatus; +import org.thingsboard.server.common.data.notification.NotificationType; import java.util.UUID; @@ -31,6 +32,7 @@ import java.util.UUID; public class NotificationUpdate { private UUID notificationId; + private NotificationType notificationType; private boolean created; private Notification notification; diff --git a/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationsSubscription.java b/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationsSubscription.java index ede82f9ff7..8751745030 100644 --- a/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationsSubscription.java +++ b/application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationsSubscription.java @@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.Notification; +import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.service.subscription.TbSubscription; import org.thingsboard.server.service.subscription.TbSubscriptionType; import org.thingsboard.server.service.ws.notification.cmd.UnreadNotificationsUpdate; @@ -29,6 +30,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; @@ -39,14 +41,20 @@ public class NotificationsSubscription extends TbSubscription latestUnreadNotifications = new HashMap<>(); private final int limit; + private final Set notificationTypes; private final AtomicInteger totalUnreadCounter = new AtomicInteger(); @Builder public NotificationsSubscription(String serviceId, String sessionId, int subscriptionId, TenantId tenantId, EntityId entityId, BiConsumer, NotificationsSubscriptionUpdate> updateProcessor, - int limit) { + int limit, Set notificationTypes) { super(serviceId, sessionId, subscriptionId, tenantId, entityId, TbSubscriptionType.NOTIFICATIONS, updateProcessor); this.limit = limit; + this.notificationTypes = notificationTypes; + } + + public boolean checkNotificationType(NotificationType type) { + return notificationTypes.contains(type); } public UnreadNotificationsUpdate createFullUpdate() { diff --git a/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java index 27a0eed1a4..364ef2e18a 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java @@ -129,6 +129,14 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest return submitNotificationRequest(targetId, text, 0, deliveryMethods); } + protected NotificationRequest submitNotificationRequest(NotificationType type, NotificationTargetId targetId, String text, NotificationDeliveryMethod... deliveryMethods) { + if (deliveryMethods.length == 0) { + deliveryMethods = new NotificationDeliveryMethod[]{NotificationDeliveryMethod.WEB}; + } + NotificationTemplate notificationTemplate = createNotificationTemplate(type, DEFAULT_NOTIFICATION_SUBJECT, text, deliveryMethods); + return submitNotificationRequest(List.of(targetId), notificationTemplate.getId(), 0); + } + protected NotificationRequest submitNotificationRequest(NotificationTargetId targetId, String text, int delayInSec, NotificationDeliveryMethod... deliveryMethods) { return submitNotificationRequest(List.of(targetId), text, delayInSec, deliveryMethods); } diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java index ba0b4e4763..f47dae90a8 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java @@ -183,6 +183,88 @@ public class NotificationApiTest extends AbstractNotificationApiTest { checkPartialNotificationsUpdate(otherWsClient.getLastDataUpdate(), notificationText, 1); } + @Test + public void testNotificationUpdates_typesFilter_multipleSubs() { + int generalSub = wsClient.subscribeForUnreadNotificationsAndWait(10, NotificationType.GENERAL); + int alarmSub = wsClient.subscribeForUnreadNotificationsAndWait(10, NotificationType.ALARM, NotificationType.GENERAL); + int entityActionSub = wsClient.subscribeForUnreadNotificationsAndWait(10, NotificationType.ENTITY_ACTION, NotificationType.GENERAL); + NotificationTarget notificationTarget = createNotificationTarget(customerUserId); + + String generalNotificationText1 = "General notification 1"; + submitNotificationRequest(NotificationType.GENERAL, notificationTarget.getId(), generalNotificationText1); + // expecting all 3 subs to received update + await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> { + assertThat(wsClient.getLastUpdates()).extractingByKeys(generalSub, alarmSub, entityActionSub) + .allMatch(update -> update.getUpdate().getText().equals(generalNotificationText1) + && update.getTotalUnreadCount() == 1); + }); + Notification generalNotification1 = wsClient.getLastDataUpdate().getUpdate(); + + String generalNotificationText2 = "General notification 2"; + submitNotificationRequest(NotificationType.GENERAL, notificationTarget.getId(), generalNotificationText2); + // expecting all 3 subs to received update + await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> { + assertThat(wsClient.getLastUpdates()).extractingByKeys(generalSub, alarmSub, entityActionSub) + .allMatch(update -> update.getUpdate().getText().equals(generalNotificationText2) + && update.getTotalUnreadCount() == 2); + }); + Notification generalNotification2 = wsClient.getLastDataUpdate().getUpdate(); + + // marking as read, expecting all 3 subs to received update + wsClient.markNotificationAsRead(generalNotification1.getUuidId()); + await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> { + assertThat(wsClient.getLastUpdates()).extractingByKeys(generalSub, alarmSub, entityActionSub) + .allMatch(update -> update.getTotalUnreadCount() == 1 && update.getNotifications().size() == 1 + && update.getNotifications().get(0).getText().equals(generalNotificationText2)); + }); + wsClient.getLastUpdates().clear(); + + String alarmNotificationText1 = "Alarm notification 1"; + submitNotificationRequest(NotificationType.ALARM, notificationTarget.getId(), alarmNotificationText1); + // expecting only 1 sub to received update + await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> { + assertThat(wsClient.getLastUpdates()).extractingByKey(alarmSub) + .matches(update -> update.getUpdate().getText().equals(alarmNotificationText1) + && update.getTotalUnreadCount() == 2); + }); + Notification alarmNotification1 = wsClient.getLastDataUpdate().getUpdate(); + + String alarmNotificationText2 = "Alarm notification 2"; + submitNotificationRequest(NotificationType.ALARM, notificationTarget.getId(), alarmNotificationText2); + // expecting only 1 sub to received update + await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> { + assertThat(wsClient.getLastUpdates()).extractingByKey(alarmSub) + .matches(update -> update.getUpdate().getText().equals(alarmNotificationText2) + && update.getTotalUnreadCount() == 3); + }); + await().during(3, TimeUnit.SECONDS) + .untilAsserted(() -> { + assertThat(wsClient.getLastUpdates()).extractingByKeys(generalSub, entityActionSub) + .containsOnlyNulls(); + }); + + // marking as read, expecting only 1 sub to receive update + wsClient.markNotificationAsRead(alarmNotification1.getUuidId()); + await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> { + assertThat(wsClient.getLastUpdates()).extractingByKey(alarmSub) + .matches(update -> update.getTotalUnreadCount() == 2 && update.getNotifications().size() == 2); + }); + await().during(3, TimeUnit.SECONDS).untilAsserted(() -> { + assertThat(wsClient.getLastUpdates()).extractingByKeys(generalSub, entityActionSub) + .containsOnlyNulls(); + }); + + // marking as read, expecting general and entity action subs with 0 unread, and alarm with 1 unread + wsClient.markNotificationAsRead(generalNotification2.getUuidId()); + await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> { + assertThat(wsClient.getLastUpdates()).extractingByKeys(generalSub, entityActionSub) + .allMatch(update -> update.getTotalUnreadCount() == 0 && update.getNotifications().isEmpty()); + assertThat(wsClient.getLastUpdates()).extractingByKey(alarmSub) + .matches(update -> update.getTotalUnreadCount() == 1 && update.getNotifications().size() == 1 + && update.getNotifications().get(0).getText().equals(alarmNotificationText2)); + }); + } + @Test public void testMarkingAsRead_multipleSessions() throws Exception { connectOtherWsClient(); diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiWsClient.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiWsClient.java index 31023fe258..30d3ceef5e 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiWsClient.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiWsClient.java @@ -21,6 +21,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.notification.Notification; +import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.controller.TbTestWebSocketClient; import org.thingsboard.server.service.ws.notification.cmd.MarkAllNotificationsAsReadCmd; import org.thingsboard.server.service.ws.notification.cmd.MarkNotificationsAsReadCmd; @@ -36,7 +37,10 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; @Slf4j @Getter @@ -49,21 +53,33 @@ public class NotificationApiWsClient extends TbTestWebSocketClient { private int unreadCount; private List notifications; + private final Map lastUpdates = new ConcurrentHashMap<>(); + public NotificationApiWsClient(String wsUrl, String token) throws URISyntaxException { super(new URI(wsUrl + "/api/ws/plugins/telemetry?token=" + token)); } - public NotificationApiWsClient subscribeForUnreadNotifications(int limit) { + public NotificationApiWsClient subscribeForUnreadNotifications(int limit, NotificationType... types) { WsCmdsWrapper cmdsWrapper = new WsCmdsWrapper(); - cmdsWrapper.setUnreadNotificationsSubCmd(new NotificationsSubCmd(1, limit)); + cmdsWrapper.setUnreadNotificationsSubCmd(new NotificationsSubCmd(newCmdId(), limit, Arrays.stream(types).collect(Collectors.toSet()))); sendCmd(cmdsWrapper); this.limit = limit; return this; } + public int subscribeForUnreadNotificationsAndWait(int limit, NotificationType... types) { + WsCmdsWrapper cmdsWrapper = new WsCmdsWrapper(); + int subId = newCmdId(); + cmdsWrapper.setUnreadNotificationsSubCmd(new NotificationsSubCmd(subId, limit, Arrays.stream(types).collect(Collectors.toSet()))); + sendCmd(cmdsWrapper); + waitForReply(); + this.limit = limit; + return subId; + } + public NotificationApiWsClient subscribeForUnreadNotificationsCount() { WsCmdsWrapper cmdsWrapper = new WsCmdsWrapper(); - cmdsWrapper.setUnreadNotificationsCountSubCmd(new NotificationsCountSubCmd(2)); + cmdsWrapper.setUnreadNotificationsCountSubCmd(new NotificationsCountSubCmd(newCmdId())); sendCmd(cmdsWrapper); return this; } @@ -98,6 +114,7 @@ public class NotificationApiWsClient extends TbTestWebSocketClient { CmdUpdateType updateType = CmdUpdateType.valueOf(update.get("cmdUpdateType").asText()); if (updateType == CmdUpdateType.NOTIFICATIONS) { lastDataUpdate = JacksonUtil.treeToValue(update, UnreadNotificationsUpdate.class); + lastUpdates.put(lastDataUpdate.getCmdId(), lastDataUpdate); unreadCount = lastDataUpdate.getTotalUnreadCount(); if (lastDataUpdate.getNotifications() != null) { notifications = new ArrayList<>(lastDataUpdate.getNotifications()); @@ -126,7 +143,7 @@ public class NotificationApiWsClient extends TbTestWebSocketClient { super.onMessage(s); } - private static int newCmdId() { + private int newCmdId() { return RandomUtils.nextInt(1, 1000); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java index e747d6ba30..34668af158 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationService.java @@ -19,9 +19,12 @@ import org.thingsboard.server.common.data.id.NotificationId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.Notification; +import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import java.util.Set; + public interface NotificationService { Notification saveNotification(TenantId tenantId, Notification notification); @@ -34,7 +37,7 @@ public interface NotificationService { PageData findNotificationsByRecipientIdAndReadStatus(TenantId tenantId, UserId recipientId, boolean unreadOnly, PageLink pageLink); - PageData findLatestUnreadNotificationsByRecipientId(TenantId tenantId, UserId recipientId, int limit); + PageData findLatestUnreadNotificationsByRecipientIdAndNotificationTypes(TenantId tenantId, UserId recipientId, Set types, int limit); int countUnreadNotificationsByRecipientId(TenantId tenantId, UserId recipientId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java index 251fae2ac0..9e95ce3cf2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java @@ -15,6 +15,9 @@ */ package org.thingsboard.server.common.data.notification; +import java.util.EnumSet; +import java.util.Set; + public enum NotificationType { GENERAL, @@ -28,6 +31,8 @@ public enum NotificationType { ENTITIES_LIMIT, API_USAGE_LIMIT, RULE_NODE, - RATE_LIMITS + RATE_LIMITS; + + public static final Set all = EnumSet.allOf(NotificationType.class); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java index 20a32efbe0..93e5a051dc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.Notification; import org.thingsboard.server.common.data.notification.NotificationStatus; +import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.SortOrder; @@ -33,6 +34,7 @@ import org.thingsboard.server.dao.entity.EntityDaoService; import org.thingsboard.server.dao.sql.query.EntityKeyMapping; import java.util.Optional; +import java.util.Set; @Service @Slf4j @@ -71,10 +73,10 @@ public class DefaultNotificationService implements NotificationService, EntityDa } @Override - public PageData findLatestUnreadNotificationsByRecipientId(TenantId tenantId, UserId recipientId, int limit) { + public PageData findLatestUnreadNotificationsByRecipientIdAndNotificationTypes(TenantId tenantId, UserId recipientId, Set types, int limit) { SortOrder sortOrder = new SortOrder(EntityKeyMapping.CREATED_TIME, SortOrder.Direction.DESC); PageLink pageLink = new PageLink(limit, 0, null, sortOrder); - return findNotificationsByRecipientIdAndReadStatus(tenantId, recipientId, true, pageLink); + return notificationDao.findUnreadByRecipientIdAndNotificationTypesAndPageLink(tenantId, recipientId, types, pageLink); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java index fb3890fcbb..ad97bcc3ba 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java @@ -21,14 +21,19 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.Notification; import org.thingsboard.server.common.data.notification.NotificationStatus; +import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.Dao; +import java.util.Set; + public interface NotificationDao extends Dao { PageData findUnreadByRecipientIdAndPageLink(TenantId tenantId, UserId recipientId, PageLink pageLink); + PageData findUnreadByRecipientIdAndNotificationTypesAndPageLink(TenantId tenantId, UserId recipientId, Set types, PageLink pageLink); + PageData findByRecipientIdAndPageLink(TenantId tenantId, UserId recipientId, PageLink pageLink); boolean updateStatusByIdAndRecipientId(TenantId tenantId, UserId recipientId, NotificationId notificationId, NotificationStatus status); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java index 57a8306fc1..f0adc10223 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java @@ -16,8 +16,8 @@ package org.thingsboard.server.dao.sql.notification; import com.datastax.oss.driver.api.core.uuid.Uuids; -import com.google.common.base.Strings; import lombok.RequiredArgsConstructor; +import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Component; @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.Notification; import org.thingsboard.server.common.data.notification.NotificationStatus; +import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.DaoUtil; @@ -38,6 +39,7 @@ import org.thingsboard.server.dao.sql.JpaAbstractDao; import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository; import org.thingsboard.server.dao.util.SqlDao; +import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -70,6 +72,15 @@ public class JpaNotificationDao extends JpaAbstractDao findUnreadByRecipientIdAndNotificationTypesAndPageLink(TenantId tenantId, UserId recipientId, Set types, PageLink pageLink) { + if (CollectionUtils.isEmpty(types)) { + types = NotificationType.all; + } + return DaoUtil.toPageData(notificationRepository.findByRecipientIdAndTypeInAndStatusNot(recipientId.getId(), types, NotificationStatus.READ, + pageLink.getTextSearch(), DaoUtil.toPageable(pageLink))); + } + @Override public PageData findByRecipientIdAndPageLink(TenantId tenantId, UserId recipientId, PageLink pageLink) { return DaoUtil.toPageData(notificationRepository.findByRecipientId(recipientId.getId(), diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java index 6b986716bb..6ec81effe7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java @@ -24,8 +24,10 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import org.thingsboard.server.common.data.notification.NotificationStatus; +import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.dao.model.sql.NotificationEntity; +import java.util.Set; import java.util.UUID; @Repository @@ -39,6 +41,16 @@ public interface NotificationRepository extends JpaRepository :status AND (n.type IN :types) " + + "AND (:searchText is NULL OR ilike(n.subject, concat('%', :searchText, '%')) = true " + + "OR ilike(n.text, concat('%', :searchText, '%')) = true)") + Page findByRecipientIdAndTypeInAndStatusNot(@Param("recipientId") UUID recipientId, + @Param("types") Set types, + @Param("status") NotificationStatus status, + @Param("searchText") String searchText, + Pageable pageable); + @Query("SELECT n FROM NotificationEntity n WHERE n.recipientId = :recipientId " + "AND (:searchText is NULL OR ilike(n.subject, concat('%', :searchText, '%')) = true " + "OR ilike(n.text, concat('%', :searchText, '%')) = true)")